Compare commits

...
80 Commits
Author SHA1 Message Date
Even Rouault b377bf1258 Merge pull request #1857 from rouault/rfc4_doc_improvements
[RFC4_dev] Doc improvements
2020-01-22 14:09:54 +01:00
Even Rouault a95431d866 Merge pull request #1855 from rouault/rfc4_merge_back_master
[RFC4_dev] Merge master back to rfc4 latest branch
2020-01-22 14:09:35 +01:00
Even Rouault c5fb541686 Merge pull request #1839 from rouault/rfc4_utf8
[RFC4_dev] Use Win32 Unicode APIs and expect all strings to be UTF-8 (fixes #1765)
2020-01-22 14:09:14 +01:00
Even Rouault bc31bda210 scripts/reformat_cpp.sh: update to take into account sqlite3.hpp/cpp renaming to sqlite3_utils.hpp/cpp 2020-01-21 21:27:14 +01:00
Even Rouault c4191f3057 Address @hobu 's review comment of https://github.com/OSGeo/PROJ/pull/1839#pullrequestreview-345535380 2020-01-20 23:45:19 +01:00
Even Rouault a6390b59ae Merge pull request #1826 from rouault/rfc4_code_review
[RFC4_dev] Address code review comments
2020-01-20 15:01:33 +01:00
Even Rouault 9bb87ea478 resource_files.rst: update user writable directory to ~/Library/Application Support for OSX 2020-01-18 15:40:27 +01:00
Even Rouault 9d2851ad36 pj_context_get_user_writable_directory(): use ~/Library/Application Support for OSX 2020-01-18 15:36:09 +01:00
Even Rouault 0a4aa2317d Doc: network and geotiff grid improvements
- Add a usage/network.rst document for all network related information (fixes #1852)
- reference it from cs2cs and cct docs
- Create a specification/ section
- Move usage/projjson.json to specification/
- Move the description of the GeoTIFF format from RFC-4 text to a
  specifications/geodetictiffgrids.rst (refs #1850)
2020-01-17 16:20:21 +01:00
Even Rouault 4724025e6c Merge branch 'master' into rfc4_merge_back_master 2020-01-17 00:52:19 +01:00
Even Rouault f1209ff020 Merge pull request #1817 from rouault/rfc4_network_disk_cache
[RFC4_dev] Add a SQLite3 local cache of downloaded chunks
2020-01-16 21:32:28 +01:00
Even Rouault 66fd99a883 Address review comments for https://github.com/OSGeo/PROJ/pull/1817 2020-01-16 14:39:39 +01:00
Even Rouault 7040857c1f Merge pull request #1816 from rouault/deformation_with_geotiff_file
[RFC4_dev] deformation: add support for +grids= for GeoTIFF grids
2020-01-15 14:55:16 +01:00
Even Rouault 2afa147d29 Doc: add notes in deformation.rst regarding +xy_grids/+z_grids being exclusive of new option +grids 2020-01-15 14:54:34 +01:00
Even Rouault 7468536f07 Merge pull request #1813 from rouault/rfc4_network
[RFC4_dev] Add networking capabilities
2020-01-15 14:35:31 +01:00
Even Rouault c40ee9dfbb Integrate into .rst doxygen-generated doc for custom I/O and network functionality 2020-01-15 00:06:25 +01:00
Even Rouault 941bb82c7e Add test/unit/test_grids.cpp to improve testing coverage 2020-01-14 23:33:16 +01:00
Even Rouault 9cb40a8322 Add proj_context_set_fileapi() and proj_context_set_sqlite3_vfs_name() (fixes #866) 2020-01-14 23:33:16 +01:00
Even Rouault 034238e501 Fix reading resources from user-writable directory & test it 2020-01-14 22:42:18 +01:00
Even Rouault 0961d15ac1 cct doc: mention use or remote grids 2020-01-13 22:17:22 +01:00
Even Rouault 9d61bf83af Horizontal grid shift: fix failures on points slightly outside a subgrid (fixes #209) 2020-01-13 22:17:22 +01:00
Even Rouault 9d8647371d Merge pull request #1777 from rouault/rfc4_impl
[RFC4_dev] Grid loading refactoring
2020-01-13 00:22:56 +01:00
Even Rouault f6c4241652 Use Win32 Unicode APIs and expect all strings to be UTF-8 (fixes #1765)
For backward compatibility, if PROJ_LIB content is found to be not UTF-8 or
pointing to a non existing directory, then an attempt at interpretating it
in the ANSI page encoding is done.

proj_context_set_search_paths() now assumes strings to be in UTF-8, and
functions returning paths will also return values in UTF-8.
2020-01-11 00:27:49 +01:00
Even Rouault 90b6685a99 Add proj_is_download_needed() and proj_download_file() 2020-01-09 23:46:20 +01:00
Even Rouault 9263e1d36e Add capability to read resource files from the user writable directory 2020-01-08 22:32:54 +01:00
Even Rouault da93fe3bea NTv2GridSet::open(): reject files with GS_TYPE!=SECONDS (fixes #1294) 2020-01-08 12:00:51 +01:00
Even Rouault dd9afa39d7 pj_bilinear_interpolation_three_samples(): fix MSVC warning about uninitialized variables 2020-01-07 22:48:27 +01:00
Even Rouault 8821b3591e Doc: address code review comments 2020-01-07 22:40:47 +01:00
Even Rouault 316ca96fc9 network: handle opening remote grids whose local name has no extension 2020-01-07 21:52:32 +01:00
Even Rouault 408cb1e427 deformation.cpp and xyzgridshift.cpp: factor out common code (addresses https://github.com/OSGeo/PROJ/pull/1790#discussion_r363748615) 2020-01-07 15:01:36 +01:00
Even Rouault 32fc01c08f CMake: use more neutral DISABLE_TIFF switch (refs https://github.com/OSGeo/PROJ/pull/1790#discussion_r363750361) 2020-01-07 14:50:44 +01:00
Even Rouault 13d651a730 geotiff_grids.gie: add comment 2020-01-07 14:36:22 +01:00
Even Rouault e8459c135d xyzgridshift.rst: fix typo 2020-01-07 14:21:29 +01:00
Even Rouault 237296b7e8 Remote grid: add mechanism to re-open a grid if it has changed while being opened 2020-01-07 12:29:35 +01:00
Even Rouault fc73b2f2ca DiskChunkCache::closeAndUnlink(): avoid use-after-free in the destructor 2020-01-07 03:32:20 +01:00
Even Rouault eafeb61ce5 Grid refactoring: address review comments of https://github.com/OSGeo/PROJ/pull/1777
- Move content of legacy apply_gridshift.cpp and apply_vgridshift.cpp in grids.cpp
- Rename nad_ functions to pj_hgrid_
- Rename internal proj_hgrid_/proj_vgrid_ functions to pj_
2020-01-07 02:24:36 +01:00
Even Rouault 19841f21f4 curl implementation: add retry logic on some HTTP errors 2020-01-01 21:55:20 +01:00
Even Rouault 08ae5764f5 Merge branch 'deformation_with_geotiff_file' into rfc4_network_disk_cache 2020-01-01 14:32:36 +01:00
Even Rouault 11f63432d3 deformation.cpp: check that unit in TIFF file is 'millimetres per year' which is the official name in EPSG 2020-01-01 14:31:04 +01:00
Even Rouault ea106578ee CMake build: install proj.ini 2019-12-31 19:27:33 +01:00
Even Rouault db040122c5 Add a SQLite3 local cache of downloaded chunks 2019-12-31 19:07:38 +01:00
Even Rouault ea73297ea4 deformation: add support for +grids= for GeoTIFF grids
This option is to load grid(s) that have both the horizontal and
vertical velocities in the same file.

Can be tested with the following grid
https://github.com/rouault/sample_proj_gtiff_grids/blob/master/nkgrf03vel_realigned.tif
converted from the original .ct2 and .gtx with
```
gdal_translate nkgrf03vel_realigned.vrt nkgrf03vel_realigned.tif -co COMPRESS=DEFLATE -co PREDICTOR=3 -co BLOCKYSIZE=241 -co INTERLEAVE=BAND
```

where nkgrf03vel_realigned.vrt is
```
<VRTDataset rasterXSize="223" rasterYSize="241">
  <SRS dataAxisToSRSAxisMapping="2,1">GEOGCRS["Unknown based on GRS80",
    DATUM["Unknown based on GRS80",
        ELLIPSOID["GRS 1980",6378137,298.257222101,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]]]
</SRS>
  <GeoTransform>  2.9166666666666670e+00,  1.6666666666666666e-01,  0.0000000000000000e+00,  7.3041666666666686e+01,  0.0000000000000000e+00, -8.3333333333333329e-02</GeoTransform>
  <Metadata>
    <MDI key="DESCRIPTION"></MDI>
    <MDI key="area_of_use">Nordic and Baltic countries</MDI>
    <MDI key="AREA_OR_POINT">Point</MDI>
    <MDI key="TIFFTAG_COPYRIGHT">The Nordic Geodetic Commission. Creative Commons Attribution 4.0 https://creativecommons.org/licenses/by/4.0/</MDI>
    <MDI key="TIFFTAG_DATETIME">2019:12:30 00:00:00</MDI>
    <MDI key="TIFFTAG_IMAGEDESCRIPTION">Deformation model covering the Nordic and Baltic countries. Used in transformations between global reference frames and the local realisations of ETRS89 in the Nordic and Baltic countries</MDI>
    <MDI key="TYPE">VELOCITY</MDI>
  </Metadata>
  <VRTRasterBand dataType="Float32" band="1">
    <Description>east_velocity</Description>
    <UnitType>mm/year</UnitType>
    <SimpleSource>
      <SourceFilename relativeToVRT="0">/home/even/proj/proj-datumgrid/europe/nkgrf03vel_realigned_xy.ct2</SourceFilename>
      <SourceBand>2</SourceBand> <!-- GDAL exposes the first physical component of the file (longitude offset normally, here east velocity) as the second band -->
      <SrcRect xOff="0" yOff="0" xSize="223" ySize="241" />
      <DstRect xOff="0" yOff="0" xSize="223" ySize="241" />
    </SimpleSource>
  </VRTRasterBand>
  <VRTRasterBand dataType="Float32" band="2">
    <Description>north_velocity</Description>
    <UnitType>mm/year</UnitType>
    <SimpleSource>
      <SourceFilename relativeToVRT="0">/home/even/proj/proj-datumgrid/europe/nkgrf03vel_realigned_xy.ct2</SourceFilename>
      <SourceBand>1</SourceBand> <!-- and the second physical component (latitude offset normally, here north velocity) as the first band -->
      <SrcRect xOff="0" yOff="0" xSize="223" ySize="241" />
      <DstRect xOff="0" yOff="0" xSize="223" ySize="241" />
    </SimpleSource>
  </VRTRasterBand>
  <VRTRasterBand dataType="Float32" band="3">
    <Description>up_velocity</Description>
    <UnitType>mm/year</UnitType>
    <SimpleSource>
      <SourceFilename relativeToVRT="0">/home/even/proj/proj-datumgrid/europe/nkgrf03vel_realigned_z.gtx</SourceFilename>
      <SourceBand>1</SourceBand>
      <SrcRect xOff="0" yOff="0" xSize="223" ySize="241" />
      <DstRect xOff="0" yOff="0" xSize="223" ySize="241" />
    </SimpleSource>
  </VRTRasterBand>
</VRTDataset>
```
2019-12-30 02:43:36 +01:00
Even Rouault 17864e68dc Travis: fix OSX builds 2019-12-30 00:24:15 +01:00
Even Rouault 830f94a811 proj_hgrid_value(): do not apply compensation for west-oriented longitude_offset. Fixes regression due to grid refactoring work on proj=deformation use case 2019-12-29 23:57:23 +01:00
Even Rouault 28e1770f27 CurlFileHandle: set UserAgent 2019-12-27 17:42:04 +01:00
Even Rouault f934c002c0 CurlFileHandle: code improvement. No functional change 2019-12-27 17:41:33 +01:00
Even Rouault be59650039 xyzgridshift: implement defered grid loading in network context 2019-12-27 12:34:24 +01:00
Even Rouault f085b39752 Handle context reassignment for Grid/GridSet/File objects 2019-12-27 12:25:03 +01:00
Even Rouault aa8c7826cf Network: rework error handling 2019-12-27 11:14:17 +01:00
Even Rouault 2093aca072 Network: make CDN endpoint configurable either in proj.ini, PROJ_NETWORK_ENDPOINT or proj_context_set_url_endpoint() 2019-12-27 11:14:16 +01:00
Even Rouault c4589fbe42 Network: automatically use CDN resources when local resources not available, and networking enabled 2019-12-27 11:14:16 +01:00
Even Rouault 0a1f1fe469 Network: only enable it if PROJ_NETWORK=ON or proj_context_set_enable_network(ctx, true) 2019-12-23 23:54:34 +01:00
Even Rouault 9d0bd793b5 Network: remove dedicated get_file_size() callback to use get_header_value(), and test 2019-12-23 18:19:35 +01:00
Even Rouault d3bdbb8417 Add testing of network functionality 2019-12-23 13:13:51 +01:00
Even Rouault ed92965937 Network: add a memory cache and I/O chunking strategy 2019-12-22 23:10:43 +01:00
Even Rouault f73527fa20 Add very minimalistic and slow libcurl implementation 2019-12-19 23:42:02 +01:00
Even Rouault a06f4a258f Add proj_context_set_network_callbacks() with an empty implementation 2019-12-19 22:31:37 +01:00
Even Rouault 2aeb122fb2 travis/osx/before_install.sh: do not install md5sha1sum from brew 2019-12-19 17:45:50 +01:00
Even Rouault d6ae5289b6 Build: add optional curl dependency 2019-12-19 17:45:50 +01:00
Even Rouault cde119a251 grids.cpp: use FileManager/File interfaces 2019-12-19 17:45:50 +01:00
Even Rouault 2dfe2cdd1f Add a FileManager and File class 2019-12-19 17:45:49 +01:00
Even Rouault 7baf00c5bc Add test for legacy proj_api.h fileapi before further reworks 2019-12-19 17:45:49 +01:00
Even Rouault a70e477087 Rename PJ_CONTEXT::fileapi member as fileapi_legacy 2019-12-18 21:00:00 +01:00
Even Rouault f36d237426 Horizontal grid shift: fix issue on iterative inverse computation when switching between (sub)grids (fixes #1663)
Given in.txt with
53.999759140 5.144478208 252.6995

Before the fix,
cct  -t 0 -d 4 +proj=pipeline +step +proj=axisswap +order=2,1,3,4 +step +proj=hgridshift +inv +grids=rdtrans2018.gsb +step +proj=vgridshift +grids=naptrans2018.gtx +step +proj=sterea +lat_0=52.156160556 +lon_0=5.387638889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel in.txt

returned:
  139079.8814    668306.0302      212.1724        0.0000

It now returns:
  139079.8850    668306.0458      212.1724        0.0000

which meets with the 1mm accuracy the expected result of test point
```
30010049	53.999759140	5.144478208	252.6995	139079.8850	668306.0460	212.1723
```
2019-12-14 00:16:17 +01:00
Even Rouault b934fd3885 Grid class: add a name() method 2019-12-14 00:15:27 +01:00
Even Rouault 49f8ea7ea4 Add configure/CMake option, strongly discouraged, to disable TIFF support 2019-12-13 15:25:59 +01:00
Even Rouault c165952bcf grids.cpp: use 'parent_grid_name' as stated in RFC4 2019-12-12 19:27:57 +01:00
Even Rouault 8063c0b992 test/gie/geotiff_grids.gie: use of subset of gr3df97a.tif for systematic testing 2019-12-11 20:36:01 +01:00
Even Rouault 3fa5d486b9 .cirrus.yml: add libtiff dependency 2019-12-11 18:20:24 +01:00
Even Rouault 6d45bbc88b Add a +proj=xyzgridshift method to perform geocentric translation by grid. Used for French NTF to RGF93 transformation using gr3df97a.tif grid 2019-12-11 17:15:03 +01:00
Even Rouault e872984b46 grids.hpp: add a GenericShiftGridSet and GenericShiftGrid classes, that are going to be used by later commit 2019-12-11 16:56:24 +01:00
Even Rouault 2804ee5ec0 GTiff grid: use a block cache per dataset for faster access 2019-12-10 19:42:38 +01:00
Even Rouault 1f01ecb90a Add support for horizontal and vertical grids in GeoTIFF 2019-12-10 17:49:00 +01:00
Even Rouault 9f908ae47c Horizontal shift grids: hide the 'positive longitude shift value = westward correction' in the CTable2/NTv1/NTv2 backends 2019-12-09 23:26:51 +01:00
Even Rouault 1b702a82f5 Build and CI: add libtiff dependency 2019-12-07 02:18:15 +01:00
Even Rouault 22792cd55b Add a Grid base class for HorizontalShiftGrid and VerticalShiftGrid 2019-12-06 21:35:15 +01:00
Even Rouault 916a92062f Remove hgrids and vgrids member from PJ structure, and store them in hgridshift/vgridshift/deformation structures 2019-12-06 21:35:15 +01:00
Even Rouault 6875ef7116 horizontal grid shift: rework to no longer load whole grid into memory 2019-12-06 21:35:14 +01:00
Even Rouault 126384854b vertical grid shift: rework to no longer load whole grid into memory 2019-12-06 21:35:14 +01:00
Even Rouault 41ff94791a Remove obsolete and presumably unfinished implementation of grid catalog functionality 2019-12-06 16:06:35 +01:00
154 changed files with 13912 additions and 4624 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ task:
folder: $HOME/.ccache
pkginstall_script:
- pkg install -y autoconf automake libtool pkgconf sqlite3 wget unzip ccache gmake
- pkg install -y autoconf automake libtool pkgconf sqlite3 tiff wget unzip ccache gmake
download_grid_script:
- wget https://download.osgeo.org/proj/proj-datumgrid-1.8.zip
- (cd data && unzip -o ../proj-datumgrid-1.8.zip)
+34
View File
@@ -83,6 +83,7 @@ elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Intel")
set(PROJ_CXX_WARN_FLAGS -Wall)
endif()
endif()
set(PROJ_C_WARN_FLAGS "${PROJ_C_WARN_FLAGS}"
CACHE STRING "C flags used to compile PROJ targets")
set(PROJ_CXX_WARN_FLAGS "${PROJ_CXX_WARN_FLAGS}"
@@ -133,6 +134,39 @@ IF("${SQLITE3_VERSION}" VERSION_LESS "3.11")
message(SEND_ERROR "sqlite3 >= 3.11 required!")
ENDIF()
################################################################################
# Check for libtiff
################################################################################
option(DISABLE_TIFF "Disable TIFF support" OFF)
mark_as_advanced(DISABLE_TIFF)
if(DISABLE_TIFF)
message(WARNING "TIFF support has been disabled and will result in the inability to read some grids")
else()
find_package(TIFF REQUIRED)
if(TIFF_FOUND)
boost_report_value(TIFF_FOUND)
else()
message(SEND_ERROR "libtiff dependency not found!")
endif()
add_definitions(-DTIFF_ENABLED)
endif()
################################################################################
# Check for curl
################################################################################
option(ENABLE_CURL "Enable Curl support" ON)
if(ENABLE_CURL)
find_package(CURL REQUIRED)
if(CURL_FOUND)
boost_report_value(CURL_FOUND)
else()
message(SEND_ERROR "curl dependency not found!")
endif()
add_definitions(-DCURL_ENABLED)
endif()
################################################################################
# threading configuration
################################################################################
+1 -1
View File
@@ -772,7 +772,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = src/iso19111 include/proj src/proj.h src/proj_experimental.h src/general_doc.dox
INPUT = src/iso19111 include/proj src/proj.h src/proj_experimental.h src/general_doc.dox src/filemanager.cpp src/networkfilemanager.cpp
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+4 -1
View File
@@ -27,9 +27,10 @@ build_script:
- set PATH=%CD%;%PATH%
- cd ..
- vcpkg install sqlite3:"%platform%"-windows
- vcpkg install tiff:"%platform%"-windows
- vcpkg install curl:"%platform%"-windows
- set SQLITE3_BIN=%APPVEYOR_BUILD_FOLDER%\sqlite3\bin
- mkdir %SQLITE3_BIN%
- copy c:\projects\proj\vcpkg\installed\"%platform%"-windows\bin\sqlite3.dll %SQLITE3_BIN%
- ps: |
appveyor DownloadFile https://sqlite.org/2018/sqlite-tools-win32-x86-3250100.zip
7z x sqlite-tools-win32-x86-3250100.zip
@@ -50,6 +51,8 @@ build_script:
- set PROJ_DIR=%APPVEYOR_BUILD_FOLDER%\proj_dir
- cmake -G "%VS_FULL%" .. -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBPROJ_SHARED="%BUILD_LIBPROJ_SHARED%" -DCMAKE_C_FLAGS="/WX" -DCMAKE_CXX_FLAGS="/WX" -DCMAKE_TOOLCHAIN_FILE=C:/projects/proj/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX="%PROJ_DIR%"
- cmake --build . --config Release --target install
- copy c:\projects\proj\vcpkg\installed\"%platform%"-windows\bin\*.dll %PROJ_DIR%\bin
- dir %PROJ_DIR%\bin
test_script:
- echo test_script
+8 -5
View File
@@ -2,6 +2,11 @@
# add test with sh script
#
function(proj_test_set_properties TESTNAME)
set_tests_properties( ${TESTNAME}
PROPERTIES ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests")
endfunction()
function(proj_add_test_script_sh SH_NAME BIN_USE)
if(UNIX)
get_filename_component(testname ${SH_NAME} NAME_WE)
@@ -26,8 +31,8 @@ function(proj_add_test_script_sh SH_NAME BIN_USE)
COMMAND ${PROJECT_SOURCE_DIR}/test/cli/${SH_NAME}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${${BIN_USE}}
)
set_tests_properties( ${testname}
PROPERTIES ENVIRONMENT "PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests")
proj_test_set_properties(${testname})
endif()
endif()
@@ -43,8 +48,6 @@ function(proj_add_gie_test TESTNAME TESTCASE)
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${GIE_BIN}
${TESTFILE}
)
set_tests_properties( ${TESTNAME}
PROPERTIES ENVIRONMENT "PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests")
proj_test_set_properties(${TESTNAME})
endfunction()
+83
View File
@@ -20,6 +20,8 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AM_PROG_LIBTOOL
PKG_PROG_PKG_CONFIG
dnl Enable as much warnings as possible
AX_CFLAGS_WARN_ALL(C_WFLAGS)
AX_CXXFLAGS_WARN_ALL(CXX_WFLAGS)
@@ -169,6 +171,15 @@ AC_SUBST(NO_ZERO_AS_NULL_POINTER_CONSTANT_FLAG,$NO_ZERO_AS_NULL_POINTER_CONSTANT
CFLAGS="${CFLAGS} -fvisibility=hidden"
CXXFLAGS="${CXXFLAGS} -fvisibility=hidden"
case "${host_os}" in
cygwin* | mingw32* | pw32* | beos* | darwin*)
CFLAGS="${CFLAGS} -DNOMINMAX"
CXXFLAGS="${CXXFLAGS} -DNOMINMAX"
;;
*)
;;
esac
dnl Checks for libraries.
save_CFLAGS="$CFLAGS"
CFLAGS=`echo "$CFLAGS" | sed "s/-Werror/ /"`
@@ -240,6 +251,78 @@ if test x"$SQLITE3_CHECK" != x"yes" ; then
AC_MSG_ERROR([Please install sqlite3 binary.])
fi
dnl ---------------------------------------------------------------------------
dnl Check for libtiff
dnl ---------------------------------------------------------------------------
AC_ARG_ENABLE([tiff-is-strongly-discouraged],
AS_HELP_STRING([--disable-tiff-is-strongly-discouraged],
[Disable TIFF support. Strongly discouraged !]),
[enable_tiff=no],
[enable_tiff=yes])
if test "x$enable_tiff" = "xyes" -o "x$enable_tiff" = ""; then
if test "x$TIFF_CFLAGS$TIFF_LIBS" = "x" ; then
if $PKG_CONFIG libtiff; then
PKG_CHECK_MODULES([TIFF], [libtiff])
else
PKG_CHECK_MODULES([TIFF], [libtiff-4])
fi
fi
TIFF_ENABLED_FLAGS=-DTIFF_ENABLED
fi
AC_SUBST(TIFF_CFLAGS,$TIFF_CFLAGS)
AC_SUBST(TIFF_LIBS,$TIFF_LIBS)
AC_SUBST(TIFF_ENABLED_FLAGS,$TIFF_ENABLED_FLAGS)
dnl ---------------------------------------------------------------------------
dnl Check for curl
dnl ---------------------------------------------------------------------------
FOUND_CURL=no
CURL_CFLAGS=
CURL_LIB=
AC_ARG_WITH(curl,
[ --with-curl[=ARG] Enable curl support (ARG=path to curl-config.)],,,)
dnl Clear some cache variables
unset ac_cv_path_LIBCURL
if test "`basename xx/$with_curl`" = "curl-config" ; then
LIBCURL_CONFIG="$with_curl"
elif test "$with_curl" = "no" ; then
LIBCURL_CONFIG=no
else
AC_PATH_PROG(LIBCURL_CONFIG, curl-config, not-found)
fi
if test "$LIBCURL_CONFIG" = "not-found" ; then
AC_MSG_ERROR([curl not found. If wanting to do a build without curl support (and thus without built-in networking capability), explictly disable it with --without-curl])
elif test "$LIBCURL_CONFIG" != "no" ; then
CURL_VERNUM=`$LIBCURL_CONFIG --vernum`
CURL_VER=`$LIBCURL_CONFIG --version | awk '{print $2}'`
AC_MSG_RESULT([ found libcurl version $CURL_VER])
AC_CHECK_LIB(curl,curl_global_init,FOUND_CURL=yes,FOUND_CURL=no,`$LIBCURL_CONFIG --libs`)
if test "$FOUND_CURL" = "no" ; then
AC_MSG_ERROR([curl not found. If wanting to do a build without curl support (and thus without built-in networking capability), explictly disable it with --without-curl])
fi
CURL_ENABLED_FLAGS=-DCURL_ENABLED
fi
if test "$FOUND_CURL" = "yes" ; then
CURL_CFLAGS=`$LIBCURL_CONFIG --cflags`
CURL_LIBS=`$LIBCURL_CONFIG --libs`
fi
AC_SUBST(CURL_CFLAGS,$CURL_CFLAGS)
AC_SUBST(CURL_LIBS,$CURL_LIBS)
AC_SUBST(CURL_ENABLED_FLAGS,$CURL_ENABLED_FLAGS)
dnl ---------------------------------------------------------------------------
dnl Check for external Google Test
dnl ---------------------------------------------------------------------------
+13 -2
View File
@@ -2,6 +2,10 @@
# files containing dictionary of useful projection
#
set(CONFIG_FILES
proj.ini
)
set(PROJ_DICTIONARY
null
world
@@ -54,7 +58,7 @@ add_custom_command(
add_custom_target(generate_proj_db ALL DEPENDS ${PROJ_DB})
if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
foreach(FILE ${PROJ_DICTIONARY} ${GRIDSHIFT_FILES})
foreach(FILE ${CONFIG_FILES} ${PROJ_DICTIONARY} ${GRIDSHIFT_FILES})
configure_file(${FILE} ${FILE} COPYONLY)
endforeach()
endif()
@@ -78,18 +82,25 @@ set(DATA_FOR_TESTS
nzgd2kgrid0005.gsb
ITRF2000
BETA2007.gsb)
file(GLOB DATA_TESTS tests/*)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/for_tests)
foreach(FILE ${DATA_FOR_TESTS})
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/for_tests/tests)
foreach(FILE ${DATA_FOR_TESTS} ${CONFIG_FILES})
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${FILE} ${CMAKE_CURRENT_BINARY_DIR}/for_tests/${FILE} COPYONLY)
endif()
endforeach()
foreach(FILE ${DATA_TESTS})
get_filename_component(FILENAME ${FILE} NAME)
configure_file(${FILE} ${CMAKE_CURRENT_BINARY_DIR}/for_tests/tests/${FILENAME} COPYONLY)
endforeach()
#
#install
#
set(ALL_DATA_FILE
${CONFIG_FILES}
${PROJ_DICTIONARY}
${GRIDSHIFT_FILES}
${PROJ_DB}
+48 -3
View File
@@ -1,6 +1,6 @@
DATAPATH = $(top_srcdir)/data
pkgdata_DATA = GL27 nad.lst nad27 nad83 world other.extra \
pkgdata_DATA = proj.ini GL27 nad.lst nad27 nad83 world other.extra \
CH null \
ITRF2000 ITRF2008 ITRF2014 proj.db \
projjson.schema.json
@@ -38,12 +38,55 @@ SQL_ORDERED_LIST = sql/begin.sql \
sql/customizations.sql \
sql/commit.sql
EXTRA_DIST = GL27 nad.lst nad27 nad83 \
EXTRA_DIST = proj.ini GL27 nad.lst nad27 nad83 \
world other.extra \
CH \
ITRF2000 ITRF2008 ITRF2014 \
projjson.schema.json \
CMakeLists.txt tests/test_nodata.gtx null \
CMakeLists.txt \
tests/test_nodata.gtx \
tests/test_vgrid_bigendian_bigtiff.tif \
tests/test_vgrid_bigendian.tif \
tests/test_vgrid_bigtiff.tif \
tests/test_vgrid_bottomup_with_matrix.tif \
tests/test_vgrid_bottomup_with_scale.tif \
tests/test_vgrid_deflate_floatingpointpredictor.tif \
tests/test_vgrid_deflate.tif \
tests/test_vgrid_float64.tif \
tests/test_vgrid_in_second_channel.tif \
tests/test_vgrid_int16.tif \
tests/test_vgrid_int32.tif \
tests/test_vgrid_uint32.tif \
tests/test_vgrid_invalid_channel_type.tif \
tests/test_vgrid_nodata.tif \
tests/test_vgrid_pixelisarea.tif \
tests/test_vgrid_pixelispoint.tif \
tests/test_vgrid_uint16.tif \
tests/test_vgrid_uint16_with_scale_offset.tif \
tests/test_vgrid_unsupported_byte.tif \
tests/test_vgrid_with_overview.tif \
tests/test_vgrid_with_subgrid.tif \
tests/test_hgrid.tif \
tests/test_hgrid_separate.tif \
tests/test_hgrid_tiled.tif \
tests/test_hgrid_tiled_separate.tif \
tests/test_hgrid_strip.tif \
tests/test_hgrid_positive_west.tif \
tests/test_hgrid_lon_shift_first.tif \
tests/test_hgrid_radian.tif \
tests/test_hgrid_degree.tif \
tests/test_hgrid_with_overview.tif \
tests/test_hgrid_extra_ifd_with_other_info.tif \
tests/test_hgrid_with_subgrid.tif \
tests/test_hgrid_with_subgrid_no_grid_name.tif \
tests/subset_of_gr3df97a.tif \
tests/egm96_15_uncompressed_truncated.tif \
tests/test_vgrid_single_strip_truncated.tif \
tests/nkgrf03vel_realigned_extract.tif \
tests/nkgrf03vel_realigned_xy_extract.ct2 \
tests/nkgrf03vel_realigned_z_extract.gtx \
tests/test_hgrid_with_two_level_of_subgrids_no_grid_name.tif \
null \
generate_all_sql_in.cmake sql_filelist.cmake \
$(SQL_ORDERED_LIST)
@@ -127,6 +170,8 @@ check-local:
echo "WARNING: grid $$x missing: some tests will be skipped"; \
fi \
done; \
ln -sf ../$(DATAPATH)/tests for_tests; \
ln -sf ../$(DATAPATH)/proj.ini for_tests; \
ln -sf ../proj.db for_tests
clean-local:
+16
View File
@@ -0,0 +1,16 @@
[general]
; Lines starting by ; are commented lines.
;
; Network capabilities disabled by default.
; Can be overriden with the PROJ_NETWORK=ON environment variable.
; network = on
; Can be overriden with the PROJ_NETWORK_ENDPOINT environment variable.
cdn_endpoint = https://cdn.proj.org
cache_enabled = on
cache_size_MB = 300
cache_ttl_sec = 86400
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11
View File
@@ -91,6 +91,17 @@ cartesian coordinates) and
*Coordinate Transformations*, which are coordinate operations where
input and output datums differ (e.g. change of reference frame).
Use of remote grids
*******************
.. versionadded:: 7.0.0
If the :envvar:`PROJ_NETWORK` environment variable is set to ``ON``,
:program:`cct` will attempt to use remote grids stored on CDN (Content
Delivery Network) storage, when they are not available locally.
More details are available in the :ref:`network` section.
Examples
********
+10
View File
@@ -171,6 +171,16 @@ normally be in DMS format (use ``-f %.12f`` for decimal degrees with 12 decimal
places), while projected (cartesian) coordinates will be in linear
(meter, feet) units.
Use of remote grids
-------------------
.. versionadded:: 7.0.0
If the :envvar:`PROJ_NETWORK` environment variable is set to ``ON``,
:program:`cs2cs` will attempt to use remote grids stored on CDN (Content
Delivery Network) storage, when they are not available locally.
More details are available in the :ref:`network` section.
Examples
********
+7 -3
View File
@@ -20,7 +20,7 @@ Synopsis
| [[--area name_or_code] | [--bbox west_long,south_lat,east_long,north_lat]]
| [--spatial-test contains|intersects]
| [--crs-extent-use none|both|intersection|smallest]
| [--grid-check none|discard_missing|sort] [--show-superseded]
| [--grid-check none|discard_missing|sort|known_available] [--show-superseded]
| [--pivot-crs always|if_no_direct_transformation|never|{auth:code[,auth:code]*}]
| [--boundcrs-to-wgs84]
| [--main-db-path path] [--aux-db-path path]*
@@ -151,12 +151,13 @@ The following control parameters can appear in any order:
.. note:: only used for coordinate operation computation
.. option:: --grid-check none|discard_missing|sort
.. option:: --grid-check none|discard_missing|sort|known_available
Specify how the presence or absence of a horizontal or vertical shift grid
required for a coordinate operation affects the results returned when
researching coordinate operations between 2 CRS.
The default strategy is ``sort``: in that case, all candidate
The default strategy is ``sort`` (if :envvar:`PROJ_NETWORK` is not defined).
In that case, all candidate
operations are returned, but the actual availability of the grids is used
to determine the sorting order. That is, if a coordinate operation involves
using a grid that is not available in the PROJ resource directories
@@ -166,6 +167,9 @@ The following control parameters can appear in any order:
this returns the results as if all the grids where available.
The ``discard_missing`` strategy discards results that involve grids not
present in the PROJ resource directories.
The ``known_available`` strategy discards results that involve grids not
present in the PROJ resource directories and that are not known of the CDN.
This is the default strategy is :envvar:`PROJ_NETWORK` is set to ``ON``.
.. note:: only used for coordinate operation computation
+3 -605
View File
@@ -695,613 +695,11 @@ choice.
.. _description_geotiff_format:
Description of the PROJ GeoTIFF format
++++++++++++++++++++++++++++++++++++++
The general principles that guide the following requirements and recommendations
are such that files will be properly recognized by PROJ, and also by GDAL which
is an easy way to inspect such grid files:
- `TIFF 6.0 <https://www.awaresystems.be/imaging/tiff/specification/TIFF6.pdf>`_
based (could possibly be BigTIFF without code changes, if we ever
need some day to handle grids larger than 4GB)
- `GeoTIFF 1.1 <http://docs.opengeospatial.org/is/19-008r4/19-008r4.html>`_ for the georeferencing.
GeoTIFF 1.1 is a recent standard, compared to the original GeoTIFF 1.0 version,
but its backward compatibility is excellent, so that should not cause much trouble
to readers that are not official GeoTIFF 1.1 compliant.
- Files hosted on the CDN will use a Geographic 2D CRS for the GeoTIFF GeoKeys.
That CRS is intended to be the interpolation CRS as defined in
`OGC Abstract Specification Topic 2 <http://docs.opengeospatial.org/as/18-005r4/18-005r4.html>`_,
that is the CRS to which grid values are refered to.
Given that they will nominally be related to the EPSG dataset, the `GeodeticCRSGeoKey
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_requirements_class_geodeticcrsgeokey>`_
will be used to store the EPSG code of the CRS. If the CRS cannot be reliably
encoded through that key or other geokeys, the ``interpolation_crs_wkt`` metadata
item detailed afterwards should be used.
This CRS will be generally the source CRS (for geographic to
geographic horizontal shift grids, or geographic to vertical shift grids), but
for vertical to vertical CRS adjustment, this will be the geographic CRS to
which the grid is referenced. In some very rare cases of geographic to vertical
shift grids, the interpolation CRS might be a geographic CRS that is not the
same as the source CRS (into which ellipsoidal height are expressed). The only
instance we have in mind is for the EPSG:7001 "ETRS89 to NAP height (1)" transformation
using the naptrans2008 VDatum-grid which is referenced to Amersfoort EPSG:4289
instead of ETRS89...
On the reading side, PROJ will ignore that information:
the CRS is already stored in the source_crs or interpolation_crs column of the
grid_transformation table.
For geographic to vertical shift files (geoid models), the GeoTIFF 1.1
convention will be used to store the value of the `VerticalGeoKey
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_requirements_class_verticalgeokey>`_
So a geoid model that apply to WGS 84 EPSG:4979 will have GeodeticCRSGeoKey = 4326
and VerticalGeoKey = 4979.
- Files hosted on the CDN will use the GeoTIFF defined `ModelTiepointTag and ModelPixelScaleTag
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_raster_to_model_coordinate_transformation_requirements>`_ TIFF tags
to store the coordinates of the upper-left pixel and the resolution of the pixels.
On the reading side, they will be required and ModelTransformationTag will be ignored.
.. note::
Regarding anti-meridian handling, a variety of possibilities exist.
We do not attempt to standardize this and filesh hosted on the CDN will use
a georeferencing close to the original data producer.
For example, NOAA vertical grids that apply to Conterminous USA might even have a top-left
longitude beyond 180 (for consistency with Alaska grids, whose origin is < 180)
Anti-meridian handling in PROJ has probably issues. This RFC does not attempt
to address them in particular, as they are believed to be orthogonal to the
topics it covers, and being mostly implementation issues.
- Files hosted on the CDN will use the `GTRasterTypeGeoKey
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_requirements_class_gtrastertypegeokey>`_
= PixelIsPoint convention.
This is the convention used by most existing grid formats currently. Note that GDAL
typically use a PixelIsArea convention (but can handle both conventions), so the
georeferencing it displays when opening a .gsb or .gtx file appears to have a
half-pixel shift regarding to the coordinates stored in the original grid file. On
the reading side, PROJ will accept both conventions (for equivalent georeferencing,
the value of the origin in a PixelIsArea convention is shifted by a half-pixel
towards the upper-left direction). Unspecified behaviour if this GeoKey is absent.
- Files hosted on the CDN will be tiled, presumably with 256x256 tiles (small
grids that are smaller than 256x256 will use a single strip). On the reading
side, PROJ will accept TIFF files with any strip or tile organization.
Tiling is expressed by specifying the TileWidth, TileHeight, TileOffsets
and TileByteCounts tags. Strip organization is expressed by specifying the
RowsPerStrip, StripByteCounts and StripOffsets tags.
- Files hosted on the CDN will use `Compression
<https://www.awaresystems.be/imaging/tiff/tifftags/compression.html>`_ = DEFLATE
or LZW (to be determined, possibly with
`Predictor <https://www.awaresystems.be/imaging/tiff/tifftags/predictor.html>`_ = 2
or 3)
On the reading side, PROJ will accept TIFF files with any compression method
(appropriate for the data types and PhotometricInterpretation considered)
supported by the libtiff build used by PROJ. Of course uncompressed files will be supported.
- Files hosted on the CDN will use little-endian byte ordering. On the reading
side, libtiff will transparently handle both little-endian and big-endian
ordering.
- Files hosted on the CDN will use PlanarConfiguration=Separate.
The tools described in a later section will order blocks so that blocks needed
for a given location are close to each other.
On the reading side, PROJ will handle also PlanarConfiguration=Contig.
- Files hosted on the CDN will generally use Float32 (BitsPerSample=32 and SampleFormat=IEEEFP)
Files may be created using Signed Int 16 (
`BitsPerSample <https://www.awaresystems.be/imaging/tiff/tifftags/bitspersample.html>`_ =16 and
`SampleFormat <https://www.awaresystems.be/imaging/tiff/tifftags/sampleformat.html>`_ = INT),
Unsigned Int 16 (BitsPerSample=16 and SampleFormat=UINT), Signed Int 32 or Unsigned Int 32 generally with an
associate scale/offset.
On the reading side, only those three data types will be supported as well.
- Files hosted on the CDN will have a `PhotometricInterpretation
<https://www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html>`_ = MinIsBlack.
It will be assumed, and ignored on the reading side.
- Files hosted on the CDN will nominally have:
* `SamplesPerPixel <https://www.awaresystems.be/imaging/tiff/tifftags/samplesperpixel.html>`_ = 2
for horizontal shift grid, with the first sample being the longitude offset
and the second sample being the latitude offset.
* SamplesPerPixel = 1 for vertical shift grids.
In the future, different values of SamplesPerPixel may be used to accomodate
for other needs. For example for deformation models, SamplesPerPixel = 3 to combine
horizontal and vertical adjustments.
And even for the current identified needs of horizontal or vertical shifts,
more samples may be present (to indicate for example uncertainties), but
will be ignored by PROJ.
The `ExtraSamples <https://www.awaresystems.be/imaging/tiff/tifftags/extrasamples.html>`_
tag should be set to a value of SamplesPerPixel - 1 (given the rules that
apply for PhotometricInterpretation = MinIsBlack)
- The `ImageDescription <https://www.awaresystems.be/imaging/tiff/tifftags/imagedescription.html>`_
tag may be used to convey extra information about the name, provenance, version
and last updated date of the grid.
Will be set when possible fo files hosted on the CDN.
Ignored by PROJ.
- The `Copyright <https://www.awaresystems.be/imaging/tiff/tifftags/copyright.html>`_
tag may be used to convey extra information about the copyright and license of the grid.
Will be set when possible fo files hosted on the CDN.
Ignored by PROJ.
- The `DateTime <https://www.awaresystems.be/imaging/tiff/tifftags/datetime.html>`_
tag may be used to convey the date at which the file has been created or
converted. In case of a file conversion, for example from NTv2, this will be
the date at which the conversion has been performed. The ``ImageDescription``
tag however will contain the latest of the CREATED or UPDATED fields from the NTv2 file.
Will be set when possible fo files hosted on the CDN.
Ignored by PROJ.
- Files hosted on the CDN will use the `GDAL_NODATA
<https://www.awaresystems.be/imaging/tiff/tifftags/gdal_nodata.html>`_ tag to encode
the value of the nodata / missing value, when it applies to the grid.
If offset and/or scaling is used, the nodata value corresponds to the raw value,
before applying offset and scaling.
The value found in this tag, if present, will be honoured (to the extent to
which current PROJ code makes use of nodata).
For floating point data, writers are strongly discouraged to use non-finite values
(+/- infinity, NaN) of nodata to maximimize interoperability.
The GDAL_NODATA value applies to all samples of a given TIFF IFD.
- Files hosted on the CDN will use the `GDAL_METADATA
<https://www.awaresystems.be/imaging/tiff/tifftags/gdal_metadata.html>`_ tag to encode extra
metadata not supported by baseline or extended TIFF.
* The root XML node should be ``GDALMetadata``
* Zero, one or several child XML nodes ``Item`` may be present.
* A Item should have a ``name`` attribute, and a child text node with its value.
``role`` and ``sample`` attributes may be present for attributes that have
a special semantics (recognized by GDAL). The value of `sample` should be
a integer value between 0 and number_of_samples - 1.
* Scale and offset to convert integer raw values to floating point values
may be expressed with XML `Item` elements whose name attribute is respectively
``SCALE`` and ``OFFSET``, and their ``role`` attribute is respectively ``scale``
and ``offset``. The decoded value will be: {offset} + {scale} * raw_value_from_geotiff_file
For a offset value of 1 and scaling of 2, the following payload should be
stored:
.. code-block:: xml
<GDALMetadata>
<Item name="OFFSET" sample="0" role="offset">1</Item>
<Item name="SCALE" sample="0" role="scale">2</Item>
</GDALMetadata>
* The type of the grid must be specified with a `Item` whose ``name`` is set
to ``TYPE``.
Values recognized by PROJ currently are:
- ``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.
Corresponds to PROJ ``hgridshift`` method.
- ``VERTICAL_OFFSET_GEOGRAPHIC_TO_VERTICAL``: implies the presence of at least one sample.
The first sample must contain the vertical adjustment. Must be used when
the source/interpolation CRS is a Geographic CRS and the target CRS a Vertical CRS.
Corresponds to PROJ ``vgridshift`` method.
- ``VERTICAL_OFFSET_VERTICAL_TO_VERTICAL``: implies the presence of at least one sample.
The first sample must contain the vertical adjustment. Must be used when
the source and target CRS are Vertical CRS.
Corresponds to PROJ ``vgridshift`` method.
- ``GEOCENTRIC_TRANSLATION``: implies the presence of at least 3 samples.
The first 3 samples must be respectively the geocentric adjustments along
the X, Y and Z axis. Must be used when the source and target CRS are
geocentric CRS. The interpolation CRS must be a geographic CRS.
Corresponds to PROJ ``xyzgridshift`` method.
- ``VELOCITY``: implies the presence of at least 3 samples.
The first 3 samples must be respectively the velocities along
the E(ast), N(orth), U(p) axis in the local topocentric coordinate system.
Corresponds to PROJ ``deformation`` method.
For example:
.. code-block:: xml
<Item name="TYPE">HORIZONTAL_OFFSET</Item>
* The description of each sample must be specified with a Item whose ``name``
attribute is set to ``DESCRIPTION`` and ``role`` attribute to ``description``.
Values recognized by PROJ for this Item are currently:
+ ``latitude_offset``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the value to add a latitude expressed in the CRS encoded in the GeoKeys
to obtain a latitude value expressed in the target CRS.
+ ``longitude_offset``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the value to add a longitude expressed in the CRS encoded in the GeoKeys
to obtain a longitude value expressed in the target CRS.
+ ``geoid_undulation``: valid for TYPE=VERTICAL_OFFSET_GEOGRAPHIC_TO_VERTICAL.
For a source CRS being a geographic CRS and a target CRS being a vertical CRS,
sample values should be the value to add to a geoid-related height (that
is expressed in the target CRS) to
get an ellipsoidal height (that is expressed in the source CRS), also
called the geoid undulation.
Note the possible confusion related to what is the source CRS and target CRS and
the semantics of the value stored (to convert from the source to the target,
one must subtract the value contained in the grid). This is the convention
used by the `EPSG:9665 <https://www.epsg-registry.org/export.htm?gml=urn:ogc:def:method:EPSG::9665>`_
operation method.
+ ``vertical_offset``: valid for TYPE=VERTICAL_OFFSET_VERTICAL_TO_VERTICAL.
For a source and target CRS being vertical CRS,
sample values should be the value to add to an elevation expressed in the
source CRS to obtain a longitude value expressed in the target CRS.
+ ``x_translation`` / ``y_translation`` / ``z_translation``: valid for
TYPE=GEOCENTRIC_TRANSLATION.
Sample values should be the value to add to the input geocentric coordinates
expressed in the source CRS to geocentric coordinates expressed in the target CRS.
+ ``east_velocity`` / ``north_velocity`` / ``up_velocity``: valid for
TYPE=VELOCITY.
Sample values should be the velocity in a linear/time unit in a ENU local
topocentric coordinate system.
For example:
.. code-block:: xml
<Item name="DESCRIPTION" sample="0" role="description">latitude_offset</Item>
<Item name="DESCRIPTION" sample="1" role="description">longitude_offset</Item>
Other values may be used (not used by PROJ):
+ ``latitude_offset_accuracy``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the accuracy of corresponding latitude_offset samples. Generally in metre (if converted from NTv2)
+ ``longitude_offset_accuracy``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the accuracy of corresponding longitude_offset samples. Generally in metre (if converted from NTv2)
* The sign convention for the values of the ``longitude_offset`` channel
should be indicated with an Item named ``positive_value`` whose value
can be ``west`` or ``east``. NTv2 products originally use a ``west``
convention, but when converting from them to GeoTIFF, the sign of those
samples will be inverted so they use a more natural ``east`` convention.
If this item is absent, the default value is ``east``.
* The unit of the values stored in the grid must be specified for each
sample through an Item of name ``UNITTYPE`` and role ``unittype``
Valid values should be the name of entries from the EPSG ``unitofmeasure``
table. To maximize interoperability, writers are strongly encouraged to
limit themselves to the following values:
For linear units:
- ``metre`` (default value assumed if absent for vertical shift grid files, and value used for files stored on PROJ CDN)
- ``US survey foot``
For angular units:
- ``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)
For velocity units:
- ``millimetres per year``
The longitude and latitude offset samples should use the same unit.
The geocentric translation samples should use the same unit.
The velocity samples should use the same unit.
Example:
.. code-block:: xml
<Item name="UNITTYPE" sample="0" role="unittype">arc-second</Item>
<Item name="UNITTYPE" sample="1" role="unittype">arc-second</Item>
* The ``target_crs_epsg_code`` metadata item should be present.
For a horizontal shift grid, this is the EPSG
code of the target geographic CRS. For a vertical shift grid, this is the
EPSG code of a the target vertical CRS.
If the target CRS has no associated EPSG code, ``target_crs_wkt`` must be
used.
Ignored by PROJ currently.
* The ``target_crs_wkt`` metadata item must be present if the
``target_crs_epsg_code`` cannot be used.
Its value should be a valid WKT string according to
`WKT:2015 <http://docs.opengeospatial.org/is/12-063r5/12-063r5.html>`_
or `WKT:2019 <hhttp://docs.opengeospatial.org/is/18-010r7/18-010r7.html>`_
Ignored by PROJ currently.
* The ``source_crs_epsg_code`` metadata item must be present if the source
and interpolation CRS are not the same (typical use case is vertical CRS to vertical CRS
transformation), because the GeoKeys encode the interpolation CRS and not the source CRS.
If the source CRS has no associated EPSG code, ``source_crs_wkt`` must be
used.
Ignored by PROJ currently.
* The ``source_crs_wkt`` metadata item must be present if the
``source_crs_epsg_code`` cannot be used.
Its value should be a valid WKT string according to WKT:2015 or WKT:2019.
Ignored by PROJ currently.
* The ``interpolation_crs_wkt`` metadata item may be present if the GeoKeys
cannot be used to express reliably the interpolation CRS.
Its value should be a valid WKT string according to WKT:2015 or WKT:2019.
Ignored by PROJ currently.
* The ``recommended_interpolation_method`` metadata item may be present to
describe the method to use to interpolation values at locations not
coincident with nodes stored in the grid file. Potential values: ``bilinear``,
``bicubic``.
Ignored by PROJ currently.
* The ``area_of_use`` metadata item can be used to indicate plain text information
about the area of use of the grid (like "USA - Wisconsin"). In case of multiple
subgrids, it should be set only on the first one, but applies to the whole
set of grids, not just the first one.
* The ``grid_name`` metadata item should be present if there are
subgrids for this grid (that is grids whose extent is contained in the extent
of this grid), or if this is a subgrid.
It is intended to be a relatively short identifier
Will be ignored by PROJ (this information can be inferred by the grids extent)
* The ``parent_grid_name`` metadata item should be present if this is a
subgrid and its value should be equal to the paren's ``grid_name``
Will be ignored by PROJ (this information can be inferred by the grids extent)
* The ``number_of_nested_grids`` metadata item should be present if there are
subgrids for this grid (that is grids whose extent is contained in the extent
of this grid).
Will be ignored by PROJ (this information can be inferred by the grids extent)
Example
+++++++
https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntf_r93.tif has
been converted from https://github.com/OSGeo/proj-datumgrid/blob/master/ntf_r93.gsb
with https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntv2_to_gtiff.py
::
$ tiffinfo ntf_r93.tif
TIFF Directory at offset 0x4e (78)
Image Width: 156 Image Length: 111
Bits/Sample: 32
Sample Format: IEEE floating point
Compression Scheme: AdobeDeflate
Photometric Interpretation: min-is-black
Extra Samples: 3<unspecified, unspecified, unspecified>
Samples/Pixel: 4
Rows/Strip: 111
Planar Configuration: separate image planes
ImageDescription: NTF (EPSG:4275) to RGF93 (EPSG:4171). Converted from ntf_r93.gsb (version IGN07_01, last updated on 2007-10-31)
DateTime: 2019:12:09 00:00:00
Copyright: Derived from work by IGN France. Open License https://www.etalab.gouv.fr/wp-content/uploads/2014/05/Open_Licence.pdf
Tag 33550: 0.100000,0.100000,0.000000
Tag 33922: 0.000000,0.000000,0.000000,-5.500000,52.000000,0.000000
Tag 34735: 1,1,1,3,1024,0,1,2,1025,0,1,2,2048,0,1,4275
Tag 42112: <GDALMetadata>
<Item name="grid_name">FRANCE</Item>
<Item name="target_crs_epsg_code">4171</Item>
<Item name="TYPE">HORIZONTAL_OFFSET</Item>
<Item name="UNITTYPE" sample="0" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="0" role="description">latitude_offset</Item>
<Item name="positive_value" sample="1">east</Item>
<Item name="UNITTYPE" sample="1" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="1" role="description">longitude_offset</Item>
<Item name="UNITTYPE" sample="2" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="2" role="description">latitude_offset_accuracy</Item>
<Item name="UNITTYPE" sample="3" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="3" role="description">longitude_offset_accuracy</Item>
</GDALMetadata>
Predictor: floating point predictor 3 (0x3)
::
$ listgeo ntf_r93.tif
Geotiff_Information:
Version: 1
Key_Revision: 1.1
Tagged_Information:
ModelTiepointTag (2,3):
0 0 0
-5.5 52 0
ModelPixelScaleTag (1,3):
0.1 0.1 0
End_Of_Tags.
Keyed_Information:
GTModelTypeGeoKey (Short,1): ModelTypeGeographic
GTRasterTypeGeoKey (Short,1): RasterPixelIsPoint
GeodeticCRSGeoKey (Short,1): Code-4275 (NTF)
End_Of_Keys.
End_Of_Geotiff.
GCS: 4275/NTF
Datum: 6275/Nouvelle Triangulation Francaise
Ellipsoid: 7011/Clarke 1880 (IGN) (6378249.20,6356515.00)
Prime Meridian: 8901/Greenwich (0.000000/ 0d 0' 0.00"E)
Projection Linear Units: User-Defined (1.000000m)
Corner Coordinates:
Upper Left ( 5d30' 0.00"W, 52d 0' 0.00"N)
Lower Left ( 5d30' 0.00"W, 40d54' 0.00"N)
Upper Right ( 10d 6' 0.00"E, 52d 0' 0.00"N)
Lower Right ( 10d 6' 0.00"E, 40d54' 0.00"N)
Center ( 2d18' 0.00"E, 46d27' 0.00"N)
::
$ gdalinfo ntf_r93.tif
Driver: GTiff/GeoTIFF
Files: ntf_r93.tif
Size is 156, 111
Coordinate System is:
GEOGCRS["NTF",
DATUM["Nouvelle Triangulation Francaise",
ELLIPSOID["Clarke 1880 (IGN)",6378249.2,293.466021293627,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
CS[ellipsoidal,2],
AXIS["geodetic latitude (Lat)",north,
ORDER[1],
ANGLEUNIT["degree",0.0174532925199433]],
AXIS["geodetic longitude (Lon)",east,
ORDER[2],
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4275]]
Data axis to CRS axis mapping: 2,1
Origin = (-5.550000000000000,52.049999999999997)
Pixel Size = (0.100000000000000,-0.100000000000000)
Metadata:
AREA_OR_POINT=Point
grid_name=FRANCE
target_crs_epsg_code=4171
TIFFTAG_DATETIME=2019:12:09 00:00:00
TIFFTAG_IMAGEDESCRIPTION=NTF (EPSG:4275) to RGF93 (EPSG:4171). Converted from ntf_r93.gsb (version IGN07_01, last updated on 2007-10-31)
TYPE=HORIZONTAL_OFFSET
Image Structure Metadata:
COMPRESSION=DEFLATE
INTERLEAVE=BAND
Corner Coordinates:
Upper Left ( -5.5500000, 52.0500000) ( 5d33' 0.00"W, 52d 3' 0.00"N)
Lower Left ( -5.5500000, 40.9500000) ( 5d33' 0.00"W, 40d57' 0.00"N)
Upper Right ( 10.0500000, 52.0500000) ( 10d 3' 0.00"E, 52d 3' 0.00"N)
Lower Right ( 10.0500000, 40.9500000) ( 10d 3' 0.00"E, 40d57' 0.00"N)
Center ( 2.2500000, 46.5000000) ( 2d15' 0.00"E, 46d30' 0.00"N)
Band 1 Block=156x111 Type=Float32, ColorInterp=Gray
Description = latitude_offset
Unit Type: arc-second
Band 2 Block=156x111 Type=Float32, ColorInterp=Undefined
Description = longitude_offset
Unit Type: arc-second
Metadata:
positive_value=east
Band 3 Block=156x111 Type=Float32, ColorInterp=Undefined
Description = latitude_offset_accuracy
Unit Type: arc-second
Band 4 Block=156x111 Type=Float32, ColorInterp=Undefined
Description = longitude_offset_accuracy
Unit Type: arc-second
Multi-grid storage
Format description
++++++++++++++++++
Formats like NTv2 can contain multiple subgrids. This can be transposed to
TIFF by using several IFD chained together with the last 4 bytes (or 8 bytes
for BigTIFF) of an IFD pointing to the offset of the next one.
The first IFD should have a full description according to the
:ref:`Description of the PROJ GeoTIFF format <description_geotiff_format>`.
Subsequent IFD might have a more compact description, omitting for example, CRS
information if it is identical to the main IFD (which should be the case for
the currently envisionned use cases), or Copyright / ImageDescription metadata
items.
Each IFD will have its
`NewSubfileType <https://www.awaresystems.be/imaging/tiff/tifftags/newsubfiletype.html>`_
tag set to 0.
If a low-resolution grid is available, it should be put before subgrids of
higher-resolution in the chain of IFD linking. On reading, PROJ will use the
value from the highest-resoluted grid that contains the point of interest.
For efficient reading from the network, files hosted on the CDN will use
a layout similar to the one described in the `low level paragraph of the Cloud Optimized GeoTIFF
GDAL driver page <https://gdal.org/drivers/raster/cog.html#low-level>`_
The layout for a file converted from NTv2 will for example be:
- TIFF/BigTIFF header/signature and pointer to first IFD (Image File Directory)
- "ghost area" indicating the generated process
- IFD of the first grid, followed by TIFF tags values, excluding the TileOffsets and TileByteCounts arrays
- ...
- IFD of the last grid, followed by TIFF tags values, excluding the GDAL_METADATA tag, TileOffsets and TileByteCounts arrays
- TileOffsets and TileByteCounts arrays for first IFD
- ...
- TileOffsets and TileByteCounts arrays for last IFD
- Value of GDAL_METADATA tag for IFDs following the first IFD
- First IFD: Data corresponding to latitude offset of Block_0_0
- First IFD: Data corresponding to longitude offset of Block_0_0
- First IFD: Data corresponding to latitude offset of Block_0_1
- First IFD: Data corresponding to longitude offset of Block_0_1
- ...
- First IFD: Data corresponding to latitude offset of Block_n_m
- First IFD: Data corresponding to longitude offset of Block_n_m
- ...
- Last IFD: Data corresponding to latitude offset of Block_0_0
- Last IFD: Data corresponding to longitude offset of Block_0_0
- Last IFD: Data corresponding to latitude offset of Block_0_1
- Last IFD: Data corresponding to longitude offset of Block_0_1
- ...
- Last IFD: Data corresponding to latitude offset of Block_n_m
- Last IFD: Data corresponding to longitude offset of Block_n_m
If longitude_offset_accuracy and latitude_offset_accuracy are present, this
will be followed by:
- First IFD: Data corresponding to latitude offset accuracy of Block_0_0
- First IFD: Data corresponding to longitude offset accuracy of Block_0_0
- ...
- First IFD: Data corresponding to latitude offset accuracy of Block_n_m
- First IFD: Data corresponding to longitude offset accuracy of Block_n_m
- ...
- Last IFD: Data corresponding to latitude offset accuracy of Block_0_0
- Last IFD: Data corresponding to longitude offset accuracy of Block_0_0
- ...
- Last IFD: Data corresponding to latitude offset accuracy of Block_n_m
- Last IFD: Data corresponding to longitude offset accuracy of Block_n_m
.. note::
TIFF has another mechanism to link IFDs, the SubIFD tag. This potentially
enables to define a hiearchy of IFDs (similar to HDF5 groups). There is no
support for that in most TIFF-using software, notably GDAL, and no compelling
need to have a nested hiearchy, so "flat" organization with the standard IFD chaining
mechanism is adopted.
Examples of multi-grid dataset
++++++++++++++++++++++++++++++
https://github.com/rouault/sample_proj_gtiff_grids/blob/master/GDA94_GDA2020_conformal.tif has
been converted from https://github.com/OSGeo/proj-datumgrid/blob/master/oceania/GDA94_GDA2020_conformal.gsb
with https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntv2_to_gtiff.py
It contains 5 subgrids. All essential metadata to list the subgrids and their
georeferencing is contained within the first 3 KB of the file.
The file size is 4.8 MB using DEFLATE compression and floating-point predictor.
To be compared with the 83 MB of the original .gsb file.
https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntv2_0.tif has
been converted from https://github.com/OSGeo/proj-datumgrid/blob/master/north-america/ntv2_0.gsb
It contains 114 subgrids. All essential metadata to list the subgrids and their
georeferencing is contained within the first 40 KB of the file.
The format description is available in a dedicated :ref:`geodetictiffgrids`
document.
Tooling
+++++++
+1 -1
View File
@@ -376,7 +376,7 @@ texinfo_documents = [
#texinfo_no_detailmenu = False
breathe_projects = {
"cpp_stuff":"../build/xml/",
"doxygen_api":"../build/xml/",
}
import redirects
@@ -4,5 +4,5 @@ common namespace
----------------
.. doxygennamespace:: osgeo::proj::common
:project: cpp_stuff
:project: doxygen_api
:members:
@@ -4,4 +4,4 @@ General documentation
---------------------
.. doxygenfile:: general_doc.dox.reworked.h
:project: cpp_stuff
:project: doxygen_api
@@ -4,5 +4,5 @@ crs namespace
-------------
.. doxygennamespace:: osgeo::proj::crs
:project: cpp_stuff
:project: doxygen_api
:members:
+1 -1
View File
@@ -4,5 +4,5 @@ cs namespace
------------
.. doxygennamespace:: osgeo::proj::cs
:project: cpp_stuff
:project: doxygen_api
:members:
@@ -4,5 +4,5 @@ datum namespace
---------------
.. doxygennamespace:: osgeo::proj::datum
:project: cpp_stuff
:project: doxygen_api
:members:
+1 -1
View File
@@ -4,5 +4,5 @@ io namespace
------------
.. doxygennamespace:: osgeo::proj::io
:project: cpp_stuff
:project: doxygen_api
:members:
@@ -4,5 +4,5 @@ metadata namespace
------------------
.. doxygennamespace:: osgeo::proj::metadata
:project: cpp_stuff
:project: doxygen_api
:members:
@@ -4,5 +4,5 @@ operation namespace
-------------------
.. doxygennamespace:: osgeo::proj::operation
:project: cpp_stuff
:project: doxygen_api
:members:
@@ -4,5 +4,5 @@ util namespace
--------------
.. doxygennamespace:: osgeo::proj::util
:project: cpp_stuff
:project: doxygen_api
:members:
@@ -797,11 +797,48 @@ Logging
.. versionadded:: 5.1.0
Setting custom I/O functions
-------------------------------------------------------------------------------
.. versionadded:: 7.0.0
.. doxygenstruct:: PROJ_FILE_API
:project: doxygen_api
:members:
.. doxygentypedef:: PROJ_FILE_HANDLE
:project: doxygen_api
.. doxygenenum:: PROJ_OPEN_ACCESS
:project: doxygen_api
Network related functionality
-------------------------------------------------------------------------------
.. versionadded:: 7.0.0
.. doxygentypedef:: PROJ_NETWORK_HANDLE
:project: doxygen_api
.. doxygentypedef:: proj_network_open_cbk_type
:project: doxygen_api
.. doxygentypedef:: proj_network_close_cbk_type
:project: doxygen_api
.. doxygentypedef:: proj_network_get_header_value_cbk_type
:project: doxygen_api
.. doxygentypedef:: proj_network_read_range_type
:project: doxygen_api
C API for ISO-19111 functionality
-------------------------------------------------------------------------------
.. doxygengroup:: iso19111_types
:project: cpp_stuff
:project: doxygen_api
:content-only:
@@ -697,6 +697,54 @@ Various
:returns: :c:type:`int` 1 if output units is expected in radians, otherwise 0
Setting custom I/O functions
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. versionadded:: 7.0.0
.. doxygenfunction:: proj_context_set_fileapi
:project: doxygen_api
.. doxygenfunction:: proj_context_set_sqlite3_vfs_name
:project: doxygen_api
Network related functionality
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. versionadded:: 7.0.0
.. doxygenfunction:: proj_context_set_network_callbacks
:project: doxygen_api
.. doxygenfunction:: proj_context_set_enable_network
:project: doxygen_api
.. doxygenfunction:: proj_context_set_url_endpoint
:project: doxygen_api
.. doxygenfunction:: proj_grid_cache_set_enable
:project: doxygen_api
.. doxygenfunction:: proj_grid_cache_set_filename
:project: doxygen_api
.. doxygenfunction:: proj_grid_cache_set_max_size
:project: doxygen_api
.. doxygenfunction:: proj_grid_cache_set_ttl
:project: doxygen_api
.. doxygenfunction:: proj_grid_cache_clear
:project: doxygen_api
.. doxygenfunction:: proj_is_download_needed
:project: doxygen_api
.. doxygenfunction:: proj_download_file
:project: doxygen_api
Cleanup
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -727,6 +775,6 @@ which are not of type CRS (can be tested with :c:func:`proj_is_crs`),
will return an error when used with functions of this section.
.. doxygengroup:: iso19111_functions
:project: cpp_stuff
:project: doxygen_api
:content-only:
+1
View File
@@ -17,6 +17,7 @@ PROJ
resource_files
geodesic
development/index
specifications/index
community/index
faq
glossary
@@ -35,6 +35,9 @@ 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.
Example
-------------------------------------------------------------------------------
@@ -89,13 +92,15 @@ Parameters
.. option:: +xy_grids=<list>
Comma-separated list of grids to load. If a grid is prefixed by an `@` the
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 horizontla component of a deformation model is expected to be
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
@@ -105,6 +110,36 @@ Parameters
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
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 should be in GeoTIFF format 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:
::
Band 1 Block=... Type=Float32, ColorInterp=Gray
Description = east_velocity
Unit Type: mm/year
Band 2 Block=... Type=Float32, ColorInterp=Undefined
Description = north_velocity
Unit Type: mm/year
Band 3 Block=... Type=Float32, ColorInterp=Undefined
Description = up_velocity
Unit Type: mm/year
.. note:: :option:`+grids` is mutually exclusive with :option:`+xy_grids`
and :option:`+z_grids`
.. option:: +t_epoch=<value>
Central epoch of transformation given in decimalyears. Will be used in
@@ -19,3 +19,4 @@ systems are based on different datums.
molobadekas
hgridshift
vgridshift
xyzgridshift
@@ -0,0 +1,91 @@
.. _xyzgridshift:
================================================================================
Geocentric grid shift
================================================================================
.. versionadded:: 7.0.0
Geocentric translation using a grid shift
+-----------------+-------------------------------------------------------------------+
| **Domain** | 3D |
+-----------------+-------------------------------------------------------------------+
| **Input type** | Cartesian coordinates |
+-----------------+-------------------------------------------------------------------+
| **Output type** | Cartesian coordinates |
+-----------------+-------------------------------------------------------------------+
Perform a geocentric translation by bilinear interpolation of dx, dy, dz
translation values from a grid. The grid is referenced against either the
2D geographic CRS corresponding to the input (or sometimes output) CRS.
This method is described (in French) in :cite:`NTF_88`
and as EPSG operation method code 9655 in :cite:`IOGP2018` (§2.4.4.1.1
France geocentric interpolation).
The translation in the grids are added to the input coordinates in the forward direction,
and subtracted in the reverse direction.
By default (if ``grid_ref=input_crs``), in the forward direction, the input coordinates
are converted to their geographic equivalent to directly read and interpolate from
the grid. In the reverse direction, an iterative method is used to be able to find
the grid locations to read.
If ``grid_ref=output_crs`` is used, then the reverse strategy is applied: iterative
method in the forward direction, and direct read in the reverse direction.
Example
-------------------------------------------------------------------------------
NTF to RGF93 transformation using gr3df97a.tif grid
::
+proj=pipeline
+step +proj=push +v_3
+step +proj=cart +ellps=clrk80ign
+step +proj=xyzgridshift +grids=gr3df97a.tif +grid_ref=output_crs +ellps=GRS80
+step +proj=cart +ellps=GRS80 +inv
+step +proj=pop +v_3
Parameters
################################################################################
The ellipsoid parameters should be the ones consistent with ``grid_ref``.
They are used to perform a geocentric to geographic conversion to find the
translation parameters.
Required
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. include:: ../options/ellps.rst
.. option:: +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 are expected to be in GeoTIFF format. 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.
Optional
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. option:: +grid_ref=input_crs/output_crs
Specify in which CRS the grid is referenced to. The default value is
input_crs. That is the grid is referenced in the geographic CRS corresponding
to the input geocentric CRS.
If output_crs is specified, the grid is referenced in the geographic CRS corresponding
to the output geocentric CRS. This is for example the case for the French
gr3df97a.tif grid converting from NTF to RGF93, but referenced against RGF93.
Thus in the forward direction (NTF->RGF93), an iterative method is used to find
the appropriate shift.
.. option:: +multiplier=<value>
Specify the multiplier to apply to the grid values. Defaults to 1.0
+9
View File
@@ -229,6 +229,15 @@
Doi = {10.2312/PE/PG/PG2012short/005-010}
}
@TechReport{NTF_88,
Title = {Grille de parametres de transformation de coordonnees - {GR3DF97A} - Notice d'utilisation},
Author = {IGN},
Institution = {Service de Geodesie et Nivellement, Institut Geographique National},
Year = {1997},
Url = {https://geodesie.ign.fr/contenu/fichiers/documentation/algorithmes/notice/NTG_88.pdf}
}
@TechReport{ONeilLaubscher1976,
Title = {Extended Studies of a Quadrilateralized Spherical Cube Earth Data Base},
Author = {E. M. O'Neill and R. E. Laubscher},
+54
View File
@@ -14,6 +14,8 @@ In addition to the bundled init-files the PROJ project also distributes a number
of packages containing transformation grids and additional init-files not included
in the main PROJ package.
.. _resource_file_paths:
Where are PROJ resource files looked for ?
-------------------------------------------------------------------------------
@@ -23,23 +25,43 @@ The following paths are checked in order:
- For transformation grids that have an explict relative or absolute path,
the directory specified in the grid filename.
- Path resolved by the callback function set with
the :c:func:`proj_context_set_file_finder`. If it is set, the next tests
will not be run.
- Path(s) set with the :c:func:`proj_context_set_search_paths`. If set, the
next tests will not be run.
.. _user_writable_directory:
- The PROJ user writable directory, which is :
* on Windows, ${LOCALAPPDATA}/proj
* on MacOSX, ${HOME}/Library/Application Support/proj
* on other platforms (Linux), ${XDG_DATA_HOME}/proj if :envvar:`XDG_DATA_HOME`
is defined. Else ${HOME}/.local/share/proj
- Path(s) set with by the environment variable :envvar:`PROJ_LIB`.
On Linux/MacOSX/Unix, use ``:`` to separate paths. On Windows, ``;``
- On Windows, the *..\\share\\proj\\* and its contents are found automatically
at run-time if the installation respects the build structure. That is, the
binaries and proj.dll are installed under *..\\bin\\*, and resource files
are in *..\\share\\proj\\*.
- A path built into PROJ as its resource installation directory (whose value is
$(pkgdatadir)), for builds using the Makefile build system. Note, however,
that since this is a hard-wired path setting, it only works if the whole
PROJ installation is not moved somewhere else.
- The current directory
When networking capabilities are enabled, either by API with the
:c:func:`proj_context_set_enable_network` function or when the
:envvar:`PROJ_NETWORK` environment variable is set to ``ON``, PROJ will
attempt to use remote grids stored on CDN (Content Delivery Network) storage.
.. _proj-db:
proj.db
@@ -49,6 +71,38 @@ A proj installation includes a SQLite database of transformation information
that must be accessible for the library to work properly. The library will
print an error if the database can't be found.
.. _proj-ini:
proj.ini
-------------------------------------------------------------------------------
.. versionadded:: 7.0
proj.ini is a text configuration file, mostly dedicated at setting up network
related parameters.
Its default content is:
::
[general]
; Lines starting by ; are commented lines.
;
; Network capabilities disabled by default.
; Can be overriden with the PROJ_NETWORK=ON environment variable.
; network = on
; Can be overriden with the PROJ_NETWORK_ENDPOINT environment variable.
cdn_endpoint = https://cdn.proj.org
cache_enabled = on
cache_size_MB = 300
cache_ttl_sec = 86400
Transformation grids
-------------------------------------------------------------------------------
@@ -0,0 +1,626 @@
.. _geodetictiffgrids:
================================================================================
Geodetic TIFF grids (GTG)
================================================================================
.. versionadded:: 7.0
Introduction
++++++++++++
The Geodetic TIFF grid format has been introduced per :ref:`rfc4`. It is a
profile of the TIFF and GeoTIFF formats that addresses the specific requirements
of geodetic grids: horizontal shifts, vertical shifts, velocity grids, etc...
It also follows the `Cloud Optimized GeoTIFF <http://cogeo.org>`_ principles.
Such grids are available on a :ref:`CDN of GeoTIFF grids <cdn_grids>`.
.. _gtg_general_description:
General description
+++++++++++++++++++
The general principles that guide the following requirements and recommendations
are such that files will be properly recognized by PROJ, and also by GDAL which
is an easy way to inspect such grid files:
- `TIFF 6.0 <https://www.awaresystems.be/imaging/tiff/specification/TIFF6.pdf>`_
based (could possibly be BigTIFF without code changes, if we ever
need some day to handle grids larger than 4GB)
- `GeoTIFF 1.1 <http://docs.opengeospatial.org/is/19-008r4/19-008r4.html>`_ for the georeferencing.
GeoTIFF 1.1 is a recent standard, compared to the original GeoTIFF 1.0 version,
but its backward compatibility is excellent, so that should not cause much trouble
to readers that are not official GeoTIFF 1.1 compliant.
- Files hosted on the CDN will use a Geographic 2D CRS for the GeoTIFF GeoKeys.
That CRS is intended to be the interpolation CRS as defined in
`OGC Abstract Specification Topic 2 <http://docs.opengeospatial.org/as/18-005r4/18-005r4.html>`_,
that is the CRS to which grid values are refered to.
Given that they will nominally be related to the EPSG dataset, the `GeodeticCRSGeoKey
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_requirements_class_geodeticcrsgeokey>`_
will be used to store the EPSG code of the CRS. If the CRS cannot be reliably
encoded through that key or other geokeys, the ``interpolation_crs_wkt`` metadata
item detailed afterwards should be used.
This CRS will be generally the source CRS (for geographic to
geographic horizontal shift grids, or geographic to vertical shift grids), but
for vertical to vertical CRS adjustment, this will be the geographic CRS to
which the grid is referenced. In some very rare cases of geographic to vertical
shift grids, the interpolation CRS might be a geographic CRS that is not the
same as the source CRS (into which ellipsoidal height are expressed). The only
instance we have in mind is for the EPSG:7001 "ETRS89 to NAP height (1)" transformation
using the naptrans2008 VDatum-grid which is referenced to Amersfoort EPSG:4289
instead of ETRS89...
On the reading side, PROJ will ignore that information:
the CRS is already stored in the source_crs or interpolation_crs column of the
grid_transformation table.
For geographic to vertical shift files (geoid models), the GeoTIFF 1.1
convention will be used to store the value of the `VerticalGeoKey
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_requirements_class_verticalgeokey>`_
So a geoid model that apply to WGS 84 EPSG:4979 will have GeodeticCRSGeoKey = 4326
and VerticalGeoKey = 4979.
- Files hosted on the CDN will use the GeoTIFF defined `ModelTiepointTag and ModelPixelScaleTag
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_raster_to_model_coordinate_transformation_requirements>`_ TIFF tags
to store the coordinates of the upper-left pixel and the resolution of the pixels.
On the reading side, they will be required and ModelTransformationTag will be ignored.
.. note::
Regarding anti-meridian handling, a variety of possibilities exist.
We do not attempt to standardize this and filesh hosted on the CDN will use
a georeferencing close to the original data producer.
For example, NOAA vertical grids that apply to Conterminous USA might even have a top-left
longitude beyond 180 (for consistency with Alaska grids, whose origin is < 180)
Anti-meridian handling in PROJ has probably issues. This RFC does not attempt
to address them in particular, as they are believed to be orthogonal to the
topics it covers, and being mostly implementation issues.
- Files hosted on the CDN will use the `GTRasterTypeGeoKey
<http://docs.opengeospatial.org/is/19-008r4/19-008r4.html#_requirements_class_gtrastertypegeokey>`_
= PixelIsPoint convention.
This is the convention used by most existing grid formats currently. Note that GDAL
typically use a PixelIsArea convention (but can handle both conventions), so the
georeferencing it displays when opening a .gsb or .gtx file appears to have a
half-pixel shift regarding to the coordinates stored in the original grid file. On
the reading side, PROJ will accept both conventions (for equivalent georeferencing,
the value of the origin in a PixelIsArea convention is shifted by a half-pixel
towards the upper-left direction). Unspecified behaviour if this GeoKey is absent.
- Files hosted on the CDN will be tiled, presumably with 256x256 tiles (small
grids that are smaller than 256x256 will use a single strip). On the reading
side, PROJ will accept TIFF files with any strip or tile organization.
Tiling is expressed by specifying the TileWidth, TileHeight, TileOffsets
and TileByteCounts tags. Strip organization is expressed by specifying the
RowsPerStrip, StripByteCounts and StripOffsets tags.
- Files hosted on the CDN will use `Compression
<https://www.awaresystems.be/imaging/tiff/tifftags/compression.html>`_ = DEFLATE
or LZW (to be determined, possibly with
`Predictor <https://www.awaresystems.be/imaging/tiff/tifftags/predictor.html>`_ = 2
or 3)
On the reading side, PROJ will accept TIFF files with any compression method
(appropriate for the data types and PhotometricInterpretation considered)
supported by the libtiff build used by PROJ. Of course uncompressed files will be supported.
- Files hosted on the CDN will use little-endian byte ordering. On the reading
side, libtiff will transparently handle both little-endian and big-endian
ordering.
- Files hosted on the CDN will use PlanarConfiguration=Separate.
The tools described in a later section will order blocks so that blocks needed
for a given location are close to each other.
On the reading side, PROJ will handle also PlanarConfiguration=Contig.
- Files hosted on the CDN will generally use Float32 (BitsPerSample=32 and SampleFormat=IEEEFP)
Files may be created using Signed Int 16 (
`BitsPerSample <https://www.awaresystems.be/imaging/tiff/tifftags/bitspersample.html>`_ =16 and
`SampleFormat <https://www.awaresystems.be/imaging/tiff/tifftags/sampleformat.html>`_ = INT),
Unsigned Int 16 (BitsPerSample=16 and SampleFormat=UINT), Signed Int 32 or Unsigned Int 32 generally with an
associate scale/offset.
On the reading side, only those three data types will be supported as well.
- Files hosted on the CDN will have a `PhotometricInterpretation
<https://www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html>`_ = MinIsBlack.
It will be assumed, and ignored on the reading side.
- Files hosted on the CDN will nominally have:
* `SamplesPerPixel <https://www.awaresystems.be/imaging/tiff/tifftags/samplesperpixel.html>`_ = 2
for horizontal shift grid, with the first sample being the longitude offset
and the second sample being the latitude offset.
* SamplesPerPixel = 1 for vertical shift grids.
In the future, different values of SamplesPerPixel may be used to accomodate
for other needs. For example for deformation models, SamplesPerPixel = 3 to combine
horizontal and vertical adjustments.
And even for the current identified needs of horizontal or vertical shifts,
more samples may be present (to indicate for example uncertainties), but
will be ignored by PROJ.
The `ExtraSamples <https://www.awaresystems.be/imaging/tiff/tifftags/extrasamples.html>`_
tag should be set to a value of SamplesPerPixel - 1 (given the rules that
apply for PhotometricInterpretation = MinIsBlack)
- The `ImageDescription <https://www.awaresystems.be/imaging/tiff/tifftags/imagedescription.html>`_
tag may be used to convey extra information about the name, provenance, version
and last updated date of the grid.
Will be set when possible fo files hosted on the CDN.
Ignored by PROJ.
- The `Copyright <https://www.awaresystems.be/imaging/tiff/tifftags/copyright.html>`_
tag may be used to convey extra information about the copyright and license of the grid.
Will be set when possible fo files hosted on the CDN.
Ignored by PROJ.
- The `DateTime <https://www.awaresystems.be/imaging/tiff/tifftags/datetime.html>`_
tag may be used to convey the date at which the file has been created or
converted. In case of a file conversion, for example from NTv2, this will be
the date at which the conversion has been performed. The ``ImageDescription``
tag however will contain the latest of the CREATED or UPDATED fields from the NTv2 file.
Will be set when possible fo files hosted on the CDN.
Ignored by PROJ.
- Files hosted on the CDN will use the `GDAL_NODATA
<https://www.awaresystems.be/imaging/tiff/tifftags/gdal_nodata.html>`_ tag to encode
the value of the nodata / missing value, when it applies to the grid.
If offset and/or scaling is used, the nodata value corresponds to the raw value,
before applying offset and scaling.
The value found in this tag, if present, will be honoured (to the extent to
which current PROJ code makes use of nodata).
For floating point data, writers are strongly discouraged to use non-finite values
(+/- infinity, NaN) of nodata to maximimize interoperability.
The GDAL_NODATA value applies to all samples of a given TIFF IFD.
- Files hosted on the CDN will use the `GDAL_METADATA
<https://www.awaresystems.be/imaging/tiff/tifftags/gdal_metadata.html>`_ tag to encode extra
metadata not supported by baseline or extended TIFF.
* The root XML node should be ``GDALMetadata``
* Zero, one or several child XML nodes ``Item`` may be present.
* A Item should have a ``name`` attribute, and a child text node with its value.
``role`` and ``sample`` attributes may be present for attributes that have
a special semantics (recognized by GDAL). The value of `sample` should be
a integer value between 0 and number_of_samples - 1.
* Scale and offset to convert integer raw values to floating point values
may be expressed with XML `Item` elements whose name attribute is respectively
``SCALE`` and ``OFFSET``, and their ``role`` attribute is respectively ``scale``
and ``offset``. The decoded value will be: {offset} + {scale} * raw_value_from_geotiff_file
For a offset value of 1 and scaling of 2, the following payload should be
stored:
.. code-block:: xml
<GDALMetadata>
<Item name="OFFSET" sample="0" role="offset">1</Item>
<Item name="SCALE" sample="0" role="scale">2</Item>
</GDALMetadata>
* The type of the grid must be specified with a `Item` whose ``name`` is set
to ``TYPE``.
Values recognized by PROJ currently are:
- ``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.
Corresponds to PROJ ``hgridshift`` method.
- ``VERTICAL_OFFSET_GEOGRAPHIC_TO_VERTICAL``: implies the presence of at least one sample.
The first sample must contain the vertical adjustment. Must be used when
the source/interpolation CRS is a Geographic CRS and the target CRS a Vertical CRS.
Corresponds to PROJ ``vgridshift`` method.
- ``VERTICAL_OFFSET_VERTICAL_TO_VERTICAL``: implies the presence of at least one sample.
The first sample must contain the vertical adjustment. Must be used when
the source and target CRS are Vertical CRS.
Corresponds to PROJ ``vgridshift`` method.
- ``GEOCENTRIC_TRANSLATION``: implies the presence of at least 3 samples.
The first 3 samples must be respectively the geocentric adjustments along
the X, Y and Z axis. Must be used when the source and target CRS are
geocentric CRS. The interpolation CRS must be a geographic CRS.
Corresponds to PROJ ``xyzgridshift`` method.
- ``VELOCITY``: implies the presence of at least 3 samples.
The first 3 samples must be respectively the velocities along
the E(ast), N(orth), U(p) axis in the local topocentric coordinate system.
Corresponds to PROJ ``deformation`` method.
For example:
.. code-block:: xml
<Item name="TYPE">HORIZONTAL_OFFSET</Item>
* The description of each sample must be specified with a Item whose ``name``
attribute is set to ``DESCRIPTION`` and ``role`` attribute to ``description``.
Values recognized by PROJ for this Item are currently:
+ ``latitude_offset``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the value to add a latitude expressed in the CRS encoded in the GeoKeys
to obtain a latitude value expressed in the target CRS.
+ ``longitude_offset``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the value to add a longitude expressed in the CRS encoded in the GeoKeys
to obtain a longitude value expressed in the target CRS.
+ ``geoid_undulation``: valid for TYPE=VERTICAL_OFFSET_GEOGRAPHIC_TO_VERTICAL.
For a source CRS being a geographic CRS and a target CRS being a vertical CRS,
sample values should be the value to add to a geoid-related height (that
is expressed in the target CRS) to
get an ellipsoidal height (that is expressed in the source CRS), also
called the geoid undulation.
Note the possible confusion related to what is the source CRS and target CRS and
the semantics of the value stored (to convert from the source to the target,
one must subtract the value contained in the grid). This is the convention
used by the `EPSG:9665 <https://www.epsg-registry.org/export.htm?gml=urn:ogc:def:method:EPSG::9665>`_
operation method.
+ ``vertical_offset``: valid for TYPE=VERTICAL_OFFSET_VERTICAL_TO_VERTICAL.
For a source and target CRS being vertical CRS,
sample values should be the value to add to an elevation expressed in the
source CRS to obtain a longitude value expressed in the target CRS.
+ ``x_translation`` / ``y_translation`` / ``z_translation``: valid for
TYPE=GEOCENTRIC_TRANSLATION.
Sample values should be the value to add to the input geocentric coordinates
expressed in the source CRS to geocentric coordinates expressed in the target CRS.
+ ``east_velocity`` / ``north_velocity`` / ``up_velocity``: valid for
TYPE=VELOCITY.
Sample values should be the velocity in a linear/time unit in a ENU local
topocentric coordinate system.
For example:
.. code-block:: xml
<Item name="DESCRIPTION" sample="0" role="description">latitude_offset</Item>
<Item name="DESCRIPTION" sample="1" role="description">longitude_offset</Item>
Other values may be used (not used by PROJ):
+ ``latitude_offset_accuracy``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the accuracy of corresponding latitude_offset samples. Generally in metre (if converted from NTv2)
+ ``longitude_offset_accuracy``: valid for TYPE=HORIZONTAL_OFFSET. Sample values should be
the accuracy of corresponding longitude_offset samples. Generally in metre (if converted from NTv2)
* The sign convention for the values of the ``longitude_offset`` channel
should be indicated with an Item named ``positive_value`` whose value
can be ``west`` or ``east``. NTv2 products originally use a ``west``
convention, but when converting from them to GeoTIFF, the sign of those
samples will be inverted so they use a more natural ``east`` convention.
If this item is absent, the default value is ``east``.
* The unit of the values stored in the grid must be specified for each
sample through an Item of name ``UNITTYPE`` and role ``unittype``
Valid values should be the name of entries from the EPSG ``unitofmeasure``
table. To maximize interoperability, writers are strongly encouraged to
limit themselves to the following values:
For linear units:
- ``metre`` (default value assumed if absent for vertical shift grid files, and value used for files stored on PROJ CDN)
- ``US survey foot``
For angular units:
- ``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)
For velocity units:
- ``millimetres per year``
The longitude and latitude offset samples should use the same unit.
The geocentric translation samples should use the same unit.
The velocity samples should use the same unit.
Example:
.. code-block:: xml
<Item name="UNITTYPE" sample="0" role="unittype">arc-second</Item>
<Item name="UNITTYPE" sample="1" role="unittype">arc-second</Item>
* The ``target_crs_epsg_code`` metadata item should be present.
For a horizontal shift grid, this is the EPSG
code of the target geographic CRS. For a vertical shift grid, this is the
EPSG code of a the target vertical CRS.
If the target CRS has no associated EPSG code, ``target_crs_wkt`` must be
used.
Ignored by PROJ currently.
* The ``target_crs_wkt`` metadata item must be present if the
``target_crs_epsg_code`` cannot be used.
Its value should be a valid WKT string according to
`WKT:2015 <http://docs.opengeospatial.org/is/12-063r5/12-063r5.html>`_
or `WKT:2019 <hhttp://docs.opengeospatial.org/is/18-010r7/18-010r7.html>`_
Ignored by PROJ currently.
* The ``source_crs_epsg_code`` metadata item must be present if the source
and interpolation CRS are not the same (typical use case is vertical CRS to vertical CRS
transformation), because the GeoKeys encode the interpolation CRS and not the source CRS.
If the source CRS has no associated EPSG code, ``source_crs_wkt`` must be
used.
Ignored by PROJ currently.
* The ``source_crs_wkt`` metadata item must be present if the
``source_crs_epsg_code`` cannot be used.
Its value should be a valid WKT string according to WKT:2015 or WKT:2019.
Ignored by PROJ currently.
* The ``interpolation_crs_wkt`` metadata item may be present if the GeoKeys
cannot be used to express reliably the interpolation CRS.
Its value should be a valid WKT string according to WKT:2015 or WKT:2019.
Ignored by PROJ currently.
* The ``recommended_interpolation_method`` metadata item may be present to
describe the method to use to interpolation values at locations not
coincident with nodes stored in the grid file. Potential values: ``bilinear``,
``bicubic``.
Ignored by PROJ currently.
* The ``area_of_use`` metadata item can be used to indicate plain text information
about the area of use of the grid (like "USA - Wisconsin"). In case of multiple
subgrids, it should be set only on the first one, but applies to the whole
set of grids, not just the first one.
* The ``grid_name`` metadata item should be present if there are
subgrids for this grid (that is grids whose extent is contained in the extent
of this grid), or if this is a subgrid.
It is intended to be a relatively short identifier
Will be ignored by PROJ (this information can be inferred by the grids extent)
* The ``parent_grid_name`` metadata item should be present if this is a
subgrid and its value should be equal to the paren's ``grid_name``
Will be ignored by PROJ (this information can be inferred by the grids extent)
* The ``number_of_nested_grids`` metadata item should be present if there are
subgrids for this grid (that is grids whose extent is contained in the extent
of this grid).
Will be ignored by PROJ (this information can be inferred by the grids extent)
Example
+++++++
https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntf_r93.tif has
been converted from https://github.com/OSGeo/proj-datumgrid/blob/master/ntf_r93.gsb
with https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntv2_to_gtiff.py
::
$ tiffinfo ntf_r93.tif
TIFF Directory at offset 0x4e (78)
Image Width: 156 Image Length: 111
Bits/Sample: 32
Sample Format: IEEE floating point
Compression Scheme: AdobeDeflate
Photometric Interpretation: min-is-black
Extra Samples: 3<unspecified, unspecified, unspecified>
Samples/Pixel: 4
Rows/Strip: 111
Planar Configuration: separate image planes
ImageDescription: NTF (EPSG:4275) to RGF93 (EPSG:4171). Converted from ntf_r93.gsb (version IGN07_01, last updated on 2007-10-31)
DateTime: 2019:12:09 00:00:00
Copyright: Derived from work by IGN France. Open License https://www.etalab.gouv.fr/wp-content/uploads/2014/05/Open_Licence.pdf
Tag 33550: 0.100000,0.100000,0.000000
Tag 33922: 0.000000,0.000000,0.000000,-5.500000,52.000000,0.000000
Tag 34735: 1,1,1,3,1024,0,1,2,1025,0,1,2,2048,0,1,4275
Tag 42112: <GDALMetadata>
<Item name="grid_name">FRANCE</Item>
<Item name="target_crs_epsg_code">4171</Item>
<Item name="TYPE">HORIZONTAL_OFFSET</Item>
<Item name="UNITTYPE" sample="0" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="0" role="description">latitude_offset</Item>
<Item name="positive_value" sample="1">east</Item>
<Item name="UNITTYPE" sample="1" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="1" role="description">longitude_offset</Item>
<Item name="UNITTYPE" sample="2" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="2" role="description">latitude_offset_accuracy</Item>
<Item name="UNITTYPE" sample="3" role="unittype">arc-second</Item>
<Item name="DESCRIPTION" sample="3" role="description">longitude_offset_accuracy</Item>
</GDALMetadata>
Predictor: floating point predictor 3 (0x3)
::
$ listgeo ntf_r93.tif
Geotiff_Information:
Version: 1
Key_Revision: 1.1
Tagged_Information:
ModelTiepointTag (2,3):
0 0 0
-5.5 52 0
ModelPixelScaleTag (1,3):
0.1 0.1 0
End_Of_Tags.
Keyed_Information:
GTModelTypeGeoKey (Short,1): ModelTypeGeographic
GTRasterTypeGeoKey (Short,1): RasterPixelIsPoint
GeodeticCRSGeoKey (Short,1): Code-4275 (NTF)
End_Of_Keys.
End_Of_Geotiff.
GCS: 4275/NTF
Datum: 6275/Nouvelle Triangulation Francaise
Ellipsoid: 7011/Clarke 1880 (IGN) (6378249.20,6356515.00)
Prime Meridian: 8901/Greenwich (0.000000/ 0d 0' 0.00"E)
Projection Linear Units: User-Defined (1.000000m)
Corner Coordinates:
Upper Left ( 5d30' 0.00"W, 52d 0' 0.00"N)
Lower Left ( 5d30' 0.00"W, 40d54' 0.00"N)
Upper Right ( 10d 6' 0.00"E, 52d 0' 0.00"N)
Lower Right ( 10d 6' 0.00"E, 40d54' 0.00"N)
Center ( 2d18' 0.00"E, 46d27' 0.00"N)
::
$ gdalinfo ntf_r93.tif
Driver: GTiff/GeoTIFF
Files: ntf_r93.tif
Size is 156, 111
Coordinate System is:
GEOGCRS["NTF",
DATUM["Nouvelle Triangulation Francaise",
ELLIPSOID["Clarke 1880 (IGN)",6378249.2,293.466021293627,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
CS[ellipsoidal,2],
AXIS["geodetic latitude (Lat)",north,
ORDER[1],
ANGLEUNIT["degree",0.0174532925199433]],
AXIS["geodetic longitude (Lon)",east,
ORDER[2],
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4275]]
Data axis to CRS axis mapping: 2,1
Origin = (-5.550000000000000,52.049999999999997)
Pixel Size = (0.100000000000000,-0.100000000000000)
Metadata:
AREA_OR_POINT=Point
grid_name=FRANCE
target_crs_epsg_code=4171
TIFFTAG_DATETIME=2019:12:09 00:00:00
TIFFTAG_IMAGEDESCRIPTION=NTF (EPSG:4275) to RGF93 (EPSG:4171). Converted from ntf_r93.gsb (version IGN07_01, last updated on 2007-10-31)
TYPE=HORIZONTAL_OFFSET
Image Structure Metadata:
COMPRESSION=DEFLATE
INTERLEAVE=BAND
Corner Coordinates:
Upper Left ( -5.5500000, 52.0500000) ( 5d33' 0.00"W, 52d 3' 0.00"N)
Lower Left ( -5.5500000, 40.9500000) ( 5d33' 0.00"W, 40d57' 0.00"N)
Upper Right ( 10.0500000, 52.0500000) ( 10d 3' 0.00"E, 52d 3' 0.00"N)
Lower Right ( 10.0500000, 40.9500000) ( 10d 3' 0.00"E, 40d57' 0.00"N)
Center ( 2.2500000, 46.5000000) ( 2d15' 0.00"E, 46d30' 0.00"N)
Band 1 Block=156x111 Type=Float32, ColorInterp=Gray
Description = latitude_offset
Unit Type: arc-second
Band 2 Block=156x111 Type=Float32, ColorInterp=Undefined
Description = longitude_offset
Unit Type: arc-second
Metadata:
positive_value=east
Band 3 Block=156x111 Type=Float32, ColorInterp=Undefined
Description = latitude_offset_accuracy
Unit Type: arc-second
Band 4 Block=156x111 Type=Float32, ColorInterp=Undefined
Description = longitude_offset_accuracy
Unit Type: arc-second
Multi-grid storage
++++++++++++++++++
Formats like NTv2 can contain multiple subgrids. This can be transposed to
TIFF by using several IFD chained together with the last 4 bytes (or 8 bytes
for BigTIFF) of an IFD pointing to the offset of the next one.
The first IFD should have a full description according to the
:ref:`General description <gtg_general_description>`.
Subsequent IFD might have a more compact description, omitting for example, CRS
information if it is identical to the main IFD (which should be the case for
the currently envisionned use cases), or Copyright / ImageDescription metadata
items.
Each IFD will have its
`NewSubfileType <https://www.awaresystems.be/imaging/tiff/tifftags/newsubfiletype.html>`_
tag set to 0.
If a low-resolution grid is available, it should be put before subgrids of
higher-resolution in the chain of IFD linking. On reading, PROJ will use the
value from the highest-resoluted grid that contains the point of interest.
For efficient reading from the network, files hosted on the CDN will use
a layout similar to the one described in the `low level paragraph of the Cloud Optimized GeoTIFF
GDAL driver page <https://gdal.org/drivers/raster/cog.html#low-level>`_
The layout for a file converted from NTv2 will for example be:
- TIFF/BigTIFF header/signature and pointer to first IFD (Image File Directory)
- "ghost area" indicating the generated process
- IFD of the first grid, followed by TIFF tags values, excluding the TileOffsets and TileByteCounts arrays
- ...
- IFD of the last grid, followed by TIFF tags values, excluding the GDAL_METADATA tag, TileOffsets and TileByteCounts arrays
- TileOffsets and TileByteCounts arrays for first IFD
- ...
- TileOffsets and TileByteCounts arrays for last IFD
- Value of GDAL_METADATA tag for IFDs following the first IFD
- First IFD: Data corresponding to latitude offset of Block_0_0
- First IFD: Data corresponding to longitude offset of Block_0_0
- First IFD: Data corresponding to latitude offset of Block_0_1
- First IFD: Data corresponding to longitude offset of Block_0_1
- ...
- First IFD: Data corresponding to latitude offset of Block_n_m
- First IFD: Data corresponding to longitude offset of Block_n_m
- ...
- Last IFD: Data corresponding to latitude offset of Block_0_0
- Last IFD: Data corresponding to longitude offset of Block_0_0
- Last IFD: Data corresponding to latitude offset of Block_0_1
- Last IFD: Data corresponding to longitude offset of Block_0_1
- ...
- Last IFD: Data corresponding to latitude offset of Block_n_m
- Last IFD: Data corresponding to longitude offset of Block_n_m
If longitude_offset_accuracy and latitude_offset_accuracy are present, this
will be followed by:
- First IFD: Data corresponding to latitude offset accuracy of Block_0_0
- First IFD: Data corresponding to longitude offset accuracy of Block_0_0
- ...
- First IFD: Data corresponding to latitude offset accuracy of Block_n_m
- First IFD: Data corresponding to longitude offset accuracy of Block_n_m
- ...
- Last IFD: Data corresponding to latitude offset accuracy of Block_0_0
- Last IFD: Data corresponding to longitude offset accuracy of Block_0_0
- ...
- Last IFD: Data corresponding to latitude offset accuracy of Block_n_m
- Last IFD: Data corresponding to longitude offset accuracy of Block_n_m
.. note::
TIFF has another mechanism to link IFDs, the SubIFD tag. This potentially
enables to define a hiearchy of IFDs (similar to HDF5 groups). There is no
support for that in most TIFF-using software, notably GDAL, and no compelling
need to have a nested hiearchy, so "flat" organization with the standard IFD chaining
mechanism is adopted.
Examples of multi-grid dataset
++++++++++++++++++++++++++++++
https://github.com/rouault/sample_proj_gtiff_grids/blob/master/GDA94_GDA2020_conformal.tif has
been converted from https://github.com/OSGeo/proj-datumgrid/blob/master/oceania/GDA94_GDA2020_conformal.gsb
with https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntv2_to_gtiff.py
It contains 5 subgrids. All essential metadata to list the subgrids and their
georeferencing is contained within the first 3 KB of the file.
The file size is 4.8 MB using DEFLATE compression and floating-point predictor.
To be compared with the 83 MB of the original .gsb file.
https://github.com/rouault/sample_proj_gtiff_grids/blob/master/ntv2_0.tif has
been converted from https://github.com/OSGeo/proj-datumgrid/blob/master/north-america/ntv2_0.gsb
It contains 114 subgrids. All essential metadata to list the subgrids and their
georeferencing is contained within the first 40 KB of the file.
+14
View File
@@ -0,0 +1,14 @@
.. _specifications:
================================================================================
Specifications
================================================================================
PROJ implements a number of extensions to standards, that are described below
for the sake of broader interoperability.
.. toctree::
:maxdepth: 1
projjson
geodetictiffgrids
+6
View File
@@ -139,3 +139,9 @@ cs2cs
Removed ``-ld`` option from application, since it promoted use of deprecated
paramters like ``+towgs`` and ``+datum``.
UTF-8 adoption
--------------
The value of all path, filenames passed to PROJ through function calls, PROJ
strings or environment variables should be encoded in UTF-8.
+18
View File
@@ -56,3 +56,21 @@ done by setting the variable with no content::
Set the debug level of PROJ. The default debug level is zero, which results
in no debug output when using PROJ. A number from 1-3, whit 3 being the most
verbose setting.
.. envvar:: PROJ_NETWORK
.. versionadded:: 7.0.0
If set to ON, enable the capability to use remote grids stored on CDN
(Content Delivery Network) storage, when grids are not available locally.
Alternatively, the :c:func:`proj_context_set_enable_network` function can
be used.
.. envvar:: PROJ_NETWORK_ENDPOINT
.. versionadded:: 7.0.0
Define the endpoint of the CDN storage. Normally defined through the proj.ini
configuration file locale in :envvar:`PROJ_LIB`.
Alternatively, the :c:func:`proj_context_set_url_endpoint` function can
be used.
+1 -2
View File
@@ -17,5 +17,4 @@ command line applications or the C API that is a part of the software package.
transformation
environmentvars
differences
projjson
network
+102
View File
@@ -0,0 +1,102 @@
.. _network:
================================================================================
Network capabilities
================================================================================
.. versionadded:: 7.0
PROJ 7.0 has introduced, per :ref:`rfc4`, the capability to work with grid files
that are not installed on the local machine where PROJ is executed.
This enables to transparently download the parts of grids that are needed to
perform a coordinate transformation.
.. _cdn_grids:
CDN of GeoTIFF grids
--------------------
Files are accessed by default through a CDN (Content Delivery Network),
accessible through https://cdn.proj.org, that contains :ref:`geodetictiffgrids`
datasets which are mirrored and managed by the
https://github.com/OSGeo/proj-datumgrid-geotiff/ GitHub project.
Files in the CDN are designed to be used by PROJ 7 or later, but any software
project wishing to use the CDN for shifting support are encouraged to
participate in the project and leverage the CDN.
How to enable network capabilities ?
------------------------------------
This capability assumes that PROJ has been build against `libcurl`, and that
the user authorizes network access.
Authorizing network access can be done in multiple ways:
- enabling / uncommenting the ``network = on`` line of :ref:`proj-ini`
- definiting the :envvar:`PROJ_NETWORK` environment variable to ON
- or using the :cpp:func:`proj_context_set_enable_network` with a
``enabled`` = TRUE value.
.. note::
Instead of using the `libcurl` implementation, an application using the PROJ
API can supply its own network implementation through C function callbacks
with :cpp:func:`proj_context_set_network_callbacks`. Enabling network use
must still be done with one of the above mentionned method.
Setting endpoint
----------------
When this is enabled, and a grid is not found in the various locations where
:ref:`resource files are looked for <resource_file_paths>`, PROJ will then
attempt at loading the file from a remote server, which defaults to
https://cdn.proj.org in :ref:`proj-ini`. This location can be changed with
the :envvar:`PROJ_NETWORK_ENDPOINT` environment variable or with
:cpp:func:`proj_context_set_url_endpoint`.
Caching
-------
To avoid repeated access to network, a local cache of downloaded chunks of grids
is implemented as SQLite3 database, ``cache.db``, stored in the
:ref:`PROJ user writable directory <user_writable_directory>`.
This local caching is enabled by default (can be changed in :ref:`proj-ini` or
with :cpp:func:`proj_grid_cache_set_enable`). The default maximum size of the
cache is 300 MB, which is more than half of the total size of grids available,
at time of writing. This size can also be customized in :ref:`proj-ini` or
with :cpp:func:`proj_grid_cache_set_max_size`
Download API
------------
When on-demand loading of grid is not desirable, the PROJ API also offers the
capability to download whole grids in the
:ref:`PROJ user writable directory <user_writable_directory>` by using the
:cpp:func:`proj_is_download_needed` and :cpp:func:`proj_download_file` functions.
Mirroring
---------
If you are able, you are encouraged to mirror the grids via AWS S3 command line:
::
aws s3 sync s3://cdn.proj.org .
If direct S3 access is not possible, you can also use wget to locally mirror the
data:
::
wget --mirror https://cdn.proj.org/
Acknowledgments
---------------
The s3://cdn.proj.org bucket is hosted by the
`Amazon Public Datasets program <https://aws.amazon.com/opendata/public-datasets/>`_.
CDN services are provided by the AWS Public Dataset team via
`CloudFront <https://aws.amazon.com/cloudfront/>`_
+14 -4
View File
@@ -144,10 +144,12 @@ class PROJ_GCC_DLL CoordinateOperation : public common::ObjectUsage,
/** \brief Return grids needed by an operation. */
PROJ_DLL virtual std::set<GridDescription>
gridsNeeded(const io::DatabaseContextPtr &databaseContext) const = 0;
gridsNeeded(const io::DatabaseContextPtr &databaseContext,
bool considerKnownGridsAsAvailable) const = 0;
PROJ_DLL bool
isPROJInstantiable(const io::DatabaseContextPtr &databaseContext) const;
isPROJInstantiable(const io::DatabaseContextPtr &databaseContext,
bool considerKnownGridsAsAvailable) const;
PROJ_DLL bool hasBallparkTransformation() const;
@@ -601,7 +603,8 @@ class PROJ_GCC_DLL SingleOperation : virtual public CoordinateOperation {
std::vector<metadata::PositionalAccuracyNNPtr>());
PROJ_DLL std::set<GridDescription>
gridsNeeded(const io::DatabaseContextPtr &databaseContext) const override;
gridsNeeded(const io::DatabaseContextPtr &databaseContext,
bool considerKnownGridsAsAvailable) const override;
PROJ_DLL std::list<std::string> validateParameters() const;
@@ -1680,7 +1683,8 @@ class PROJ_GCC_DLL ConcatenatedOperation final : public CoordinateOperation {
bool checkExtent); // throw InvalidOperation
PROJ_DLL std::set<GridDescription>
gridsNeeded(const io::DatabaseContextPtr &databaseContext) const override;
gridsNeeded(const io::DatabaseContextPtr &databaseContext,
bool considerKnownGridsAsAvailable) const override;
PROJ_PRIVATE :
@@ -1810,6 +1814,12 @@ class PROJ_GCC_DLL CoordinateOperationContext {
/** Ignore grid availability at all. Results will be presented as if
* all grids were available. */
IGNORE_GRID_AVAILABILITY,
/** Results will be presented as if grids known to PROJ (that is
* registered in the grid_alternatives table of its database) were
* available. Used typically when networking is enabled.
*/
KNOWN_AVAILABLE,
};
PROJ_DLL void setGridAvailabilityUse(GridAvailabilityUse use);
@@ -180,8 +180,10 @@ class InverseConversion : public Conversion, public InverseCoordinateOperation {
// 'osgeo::proj::operation::SingleOperation::osgeo::proj::operation::SingleOperation::gridsNeeded'
// via dominance
std::set<GridDescription>
gridsNeeded(const io::DatabaseContextPtr &databaseContext) const override {
return SingleOperation::gridsNeeded(databaseContext);
gridsNeeded(const io::DatabaseContextPtr &databaseContext,
bool considerKnownGridsAsAvailable) const override {
return SingleOperation::gridsNeeded(databaseContext,
considerKnownGridsAsAvailable);
}
#endif
@@ -232,8 +234,10 @@ class InverseTransformation : public Transformation,
// 'osgeo::proj::operation::SingleOperation::osgeo::proj::operation::SingleOperation::gridsNeeded'
// via dominance
std::set<GridDescription>
gridsNeeded(const io::DatabaseContextPtr &databaseContext) const override {
return SingleOperation::gridsNeeded(databaseContext);
gridsNeeded(const io::DatabaseContextPtr &databaseContext,
bool considerKnownGridsAsAvailable) const override {
return SingleOperation::gridsNeeded(databaseContext,
considerKnownGridsAsAvailable);
}
#endif
@@ -274,7 +278,8 @@ class PROJBasedOperation : public SingleOperation {
bool hasRoughTransformation);
std::set<GridDescription>
gridsNeeded(const io::DatabaseContextPtr &databaseContext) const override;
gridsNeeded(const io::DatabaseContextPtr &databaseContext,
bool considerKnownGridsAsAvailable) const override;
protected:
PROJBasedOperation(const PROJBasedOperation &) = default;
+5 -3
View File
@@ -832,6 +832,7 @@ class PROJ_GCC_DLL DatabaseContext {
bool &inverse) const;
PROJ_DLL bool lookForGridInfo(const std::string &projFilename,
bool considerKnownGridsAsAvailable,
std::string &fullFilename,
std::string &packageName, std::string &url,
bool &directDownload, bool &openLicense,
@@ -1055,7 +1056,8 @@ class PROJ_GCC_DLL AuthorityFactory {
const std::string &sourceCRSAuthName, const std::string &sourceCRSCode,
const std::string &targetCRSAuthName, const std::string &targetCRSCode,
bool usePROJAlternativeGridNames, bool discardIfMissingGrid,
bool discardSuperseded, bool tryReverseOrder = false,
bool considerKnownGridsAsAvailable, bool discardSuperseded,
bool tryReverseOrder = false,
bool reportOnlyIntersectingTransformations = false,
const metadata::ExtentPtr &intersectingExtent1 = nullptr,
const metadata::ExtentPtr &intersectingExtent2 = nullptr) const;
@@ -1065,7 +1067,7 @@ class PROJ_GCC_DLL AuthorityFactory {
const std::string &sourceCRSAuthName, const std::string &sourceCRSCode,
const std::string &targetCRSAuthName, const std::string &targetCRSCode,
bool usePROJAlternativeGridNames, bool discardIfMissingGrid,
bool discardSuperseded,
bool considerKnownGridsAsAvailable, bool discardSuperseded,
const std::vector<std::pair<std::string, std::string>>
&intermediateCRSAuthCodes,
ObjectType allowedIntermediateObjectType = ObjectType::CRS,
@@ -1131,7 +1133,7 @@ class PROJ_GCC_DLL AuthorityFactory {
const std::string &sourceCRSCode, const crs::CRSNNPtr &targetCRS,
const std::string &targetCRSAuthName, const std::string &targetCRSCode,
bool usePROJAlternativeGridNames, bool discardIfMissingGrid,
bool discardSuperseded,
bool considerKnownGridsAsAvailable, bool discardSuperseded,
const std::vector<std::string> &allowedAuthorities,
const metadata::ExtentPtr &intersectingExtent1,
const metadata::ExtentPtr &intersectingExtent2) const;
+9 -1
View File
@@ -34,7 +34,11 @@ fi
mkdir -p docs/build/tmp_breathe
python scripts/generate_breathe_friendly_general_doc.py
rm -rf docs/build/xml/
(cat Doxyfile; printf "GENERATE_HTML=NO\nGENERATE_XML=YES\nINPUT= src/iso19111 include/proj src/proj.h docs/build/tmp_breathe/general_doc.dox.reworked.h") | doxygen - > docs/build/tmp_breathe/docs_log.txt 2>&1
# Ugly hack to workaround a bug of Doxygen 1.8.17 that erroneously detect proj_network_get_header_value_cbk_type/ as a variable
sed "s/const char\* (\*proj_network_get_header_value_cbk_type/CONST_CHAR\* (\*proj_network_get_header_value_cbk_type/" < src/proj.h > docs/build/tmp_breathe/proj.h
(cat Doxyfile; printf "GENERATE_HTML=NO\nGENERATE_XML=YES\nINPUT= src/iso19111 include/proj docs/build/tmp_breathe/proj.h src/filemanager.cpp src/networkfilemanager.cpp docs/build/tmp_breathe/general_doc.dox.reworked.h") | doxygen - > docs/build/tmp_breathe/docs_log.txt 2>&1
if grep -i warning docs/build/tmp_breathe/docs_log.txt; then
echo "Doxygen warnings found" && cat docs/build/tmp_breathe/docs_log.txt && /bin/false;
else
@@ -56,5 +60,9 @@ done
sed "s/Convention/Convention_/g" < ${TOPDIR}/docs/build/xml/classosgeo_1_1proj_1_1io_1_1WKTFormatter.xml | sed "s/WKT2_2018/_WKT2_2018/g" | sed "s/WKT2_2019/_WKT2_2019/g" | sed "s/WKT2_2015/_WKT2_2015/g" | sed "s/WKT1_GDAL/_WKT1_GDAL/g" | sed "s/WKT1_ESRI/_WKT1_ESRI/g" > ${TOPDIR}/docs/build/xml/classosgeo_1_1proj_1_1io_1_1WKTFormatter.xml.tmp
mv ${TOPDIR}/docs/build/xml/classosgeo_1_1proj_1_1io_1_1WKTFormatter.xml.tmp ${TOPDIR}/docs/build/xml/classosgeo_1_1proj_1_1io_1_1WKTFormatter.xml
# Ugly hack to workaround a bug of Doxygen 1.8.17 that erroneously detect proj_network_get_header_value_cbk_type/ as a variable
sed "s/CONST_CHAR/const char/" < ${TOPDIR}/docs/build/xml/proj_8h.xml > ${TOPDIR}/docs/build/xml/proj_8h.xml.tmp
mv ${TOPDIR}/docs/build/xml/proj_8h.xml.tmp ${TOPDIR}/docs/build/xml/proj_8h.xml
popd > /dev/null || exit
+50 -6
View File
@@ -281,6 +281,26 @@ osgeo::proj::datum::TemporalDatum::temporalOrigin() const
osgeo::proj::datum::VerticalReferenceFrame::create(osgeo::proj::util::PropertyMap const&, osgeo::proj::util::optional<std::string> const&, osgeo::proj::util::optional<osgeo::proj::datum::RealizationMethod> const&)
osgeo::proj::datum::VerticalReferenceFrame::realizationMethod() const
osgeo::proj::datum::VerticalReferenceFrame::~VerticalReferenceFrame()
osgeo::proj::GenericShiftGrid::~GenericShiftGrid()
osgeo::proj::GenericShiftGrid::GenericShiftGrid(std::string const&, int, int, osgeo::proj::ExtentAndRes const&)
osgeo::proj::GenericShiftGrid::gridAt(double, double) const
osgeo::proj::GenericShiftGridSet::~GenericShiftGridSet()
osgeo::proj::GenericShiftGridSet::GenericShiftGridSet()
osgeo::proj::GenericShiftGridSet::gridAt(double, double) const
osgeo::proj::GenericShiftGridSet::open(projCtx_t*, std::string const&)
osgeo::proj::GenericShiftGridSet::reassign_context(projCtx_t*)
osgeo::proj::GenericShiftGridSet::reopen(projCtx_t*)
osgeo::proj::Grid::~Grid()
osgeo::proj::Grid::Grid(std::string const&, int, int, osgeo::proj::ExtentAndRes const&)
osgeo::proj::HorizontalShiftGrid::gridAt(double, double) const
osgeo::proj::HorizontalShiftGrid::~HorizontalShiftGrid()
osgeo::proj::HorizontalShiftGrid::HorizontalShiftGrid(std::string const&, int, int, osgeo::proj::ExtentAndRes const&)
osgeo::proj::HorizontalShiftGridSet::gridAt(double, double) const
osgeo::proj::HorizontalShiftGridSet::~HorizontalShiftGridSet()
osgeo::proj::HorizontalShiftGridSet::HorizontalShiftGridSet()
osgeo::proj::HorizontalShiftGridSet::open(projCtx_t*, std::string const&)
osgeo::proj::HorizontalShiftGridSet::reassign_context(projCtx_t*)
osgeo::proj::HorizontalShiftGridSet::reopen(projCtx_t*)
osgeo::proj::internal::ci_equal(std::string const&, char const*)
osgeo::proj::internal::ci_equal(std::string const&, std::string const&)
osgeo::proj::internal::ci_find(std::string const&, char const*)
@@ -301,8 +321,8 @@ osgeo::proj::io::AuthorityFactory::create(dropbox::oxygen::nn<std::shared_ptr<os
osgeo::proj::io::AuthorityFactory::createEllipsoid(std::string const&) const
osgeo::proj::io::AuthorityFactory::createExtent(std::string const&) const
osgeo::proj::io::AuthorityFactory::createFromCoordinateReferenceSystemCodes(std::string const&, std::string const&) const
osgeo::proj::io::AuthorityFactory::createFromCoordinateReferenceSystemCodes(std::string const&, std::string const&, std::string const&, std::string const&, bool, bool, bool, bool, bool, std::shared_ptr<osgeo::proj::metadata::Extent> const&, std::shared_ptr<osgeo::proj::metadata::Extent> const&) const
osgeo::proj::io::AuthorityFactory::createFromCRSCodesWithIntermediates(std::string const&, std::string const&, std::string const&, std::string const&, bool, bool, bool, std::vector<std::pair<std::string, std::string>, std::allocator<std::pair<std::string, std::string> > > const&, osgeo::proj::io::AuthorityFactory::ObjectType, std::vector<std::string, std::allocator<std::string> > const&, std::shared_ptr<osgeo::proj::metadata::Extent> const&, std::shared_ptr<osgeo::proj::metadata::Extent> const&) const
osgeo::proj::io::AuthorityFactory::createFromCoordinateReferenceSystemCodes(std::string const&, std::string const&, std::string const&, std::string const&, bool, bool, bool, bool, bool, bool, std::shared_ptr<osgeo::proj::metadata::Extent> const&, std::shared_ptr<osgeo::proj::metadata::Extent> const&) const
osgeo::proj::io::AuthorityFactory::createFromCRSCodesWithIntermediates(std::string const&, std::string const&, std::string const&, std::string const&, bool, bool, bool, bool, std::vector<std::pair<std::string, std::string>, std::allocator<std::pair<std::string, std::string> > > const&, osgeo::proj::io::AuthorityFactory::ObjectType, std::vector<std::string, std::allocator<std::string> > const&, std::shared_ptr<osgeo::proj::metadata::Extent> const&, std::shared_ptr<osgeo::proj::metadata::Extent> const&) const
osgeo::proj::io::AuthorityFactory::createGeodeticCRS(std::string const&) const
osgeo::proj::io::AuthorityFactory::createGeodeticDatum(std::string const&) const
osgeo::proj::io::AuthorityFactory::createGeographicCRS(std::string const&) const
@@ -332,7 +352,7 @@ osgeo::proj::io::DatabaseContext::getDatabaseStructure() const
osgeo::proj::io::DatabaseContext::getMetadata(char const*) const
osgeo::proj::io::DatabaseContext::getPath() const
osgeo::proj::io::DatabaseContext::getSqliteHandle() const
osgeo::proj::io::DatabaseContext::lookForGridInfo(std::string const&, std::string&, std::string&, std::string&, bool&, bool&, bool&) const
osgeo::proj::io::DatabaseContext::lookForGridInfo(std::string const&, bool, std::string&, std::string&, std::string&, bool&, bool&, bool&) const
osgeo::proj::io::FactoryException::~FactoryException()
osgeo::proj::io::FactoryException::FactoryException(char const*)
osgeo::proj::io::FactoryException::FactoryException(osgeo::proj::io::FactoryException const&)
@@ -467,7 +487,7 @@ osgeo::proj::metadata::VerticalExtent::~VerticalExtent()
osgeo::proj::operation::ConcatenatedOperation::~ConcatenatedOperation()
osgeo::proj::operation::ConcatenatedOperation::createComputeMetadata(std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::CoordinateOperation> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::CoordinateOperation> > > > const&, bool)
osgeo::proj::operation::ConcatenatedOperation::create(osgeo::proj::util::PropertyMap const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::CoordinateOperation> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::CoordinateOperation> > > > const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
osgeo::proj::operation::ConcatenatedOperation::gridsNeeded(std::shared_ptr<osgeo::proj::io::DatabaseContext> const&) const
osgeo::proj::operation::ConcatenatedOperation::gridsNeeded(std::shared_ptr<osgeo::proj::io::DatabaseContext> const&, bool) const
osgeo::proj::operation::ConcatenatedOperation::inverse() const
osgeo::proj::operation::ConcatenatedOperation::operations() const
osgeo::proj::operation::Conversion::~Conversion()
@@ -577,7 +597,7 @@ osgeo::proj::operation::CoordinateOperationFactory::createOperation(dropbox::oxy
osgeo::proj::operation::CoordinateOperationFactory::createOperations(dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::unique_ptr<osgeo::proj::operation::CoordinateOperationContext, std::default_delete<osgeo::proj::operation::CoordinateOperationContext> > > const&) const
osgeo::proj::operation::CoordinateOperation::hasBallparkTransformation() const
osgeo::proj::operation::CoordinateOperation::interpolationCRS() const
osgeo::proj::operation::CoordinateOperation::isPROJInstantiable(std::shared_ptr<osgeo::proj::io::DatabaseContext> const&) const
osgeo::proj::operation::CoordinateOperation::isPROJInstantiable(std::shared_ptr<osgeo::proj::io::DatabaseContext> const&, bool) const
osgeo::proj::operation::CoordinateOperation::normalizeForVisualization() const
osgeo::proj::operation::CoordinateOperation::operationVersion() const
osgeo::proj::operation::CoordinateOperation::shallowClone() const
@@ -623,7 +643,7 @@ osgeo::proj::operation::ParameterValue::value() const
osgeo::proj::operation::ParameterValue::valueFile() const
osgeo::proj::operation::PointMotionOperation::~PointMotionOperation()
osgeo::proj::operation::SingleOperation::createPROJBased(osgeo::proj::util::PropertyMap const&, std::string const&, std::shared_ptr<osgeo::proj::crs::CRS> const&, std::shared_ptr<osgeo::proj::crs::CRS> const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
osgeo::proj::operation::SingleOperation::gridsNeeded(std::shared_ptr<osgeo::proj::io::DatabaseContext> const&) const
osgeo::proj::operation::SingleOperation::gridsNeeded(std::shared_ptr<osgeo::proj::io::DatabaseContext> const&, bool) const
osgeo::proj::operation::SingleOperation::method() const
osgeo::proj::operation::SingleOperation::parameterValue(int) const
osgeo::proj::operation::SingleOperation::parameterValueMeasure(int) const
@@ -698,6 +718,15 @@ osgeo::proj::util::PropertyMap::set(std::string const&, std::string const&)
osgeo::proj::util::PropertyMap::set(std::string const&, std::vector<std::string, std::allocator<std::string> > const&)
osgeo::proj::util::UnsupportedOperationException::~UnsupportedOperationException()
osgeo::proj::util::UnsupportedOperationException::UnsupportedOperationException(osgeo::proj::util::UnsupportedOperationException const&)
osgeo::proj::VerticalShiftGrid::gridAt(double, double) const
osgeo::proj::VerticalShiftGridSet::gridAt(double, double) const
osgeo::proj::VerticalShiftGridSet::open(projCtx_t*, std::string const&)
osgeo::proj::VerticalShiftGridSet::reassign_context(projCtx_t*)
osgeo::proj::VerticalShiftGridSet::reopen(projCtx_t*)
osgeo::proj::VerticalShiftGridSet::~VerticalShiftGridSet()
osgeo::proj::VerticalShiftGridSet::VerticalShiftGridSet()
osgeo::proj::VerticalShiftGrid::~VerticalShiftGrid()
osgeo::proj::VerticalShiftGrid::VerticalShiftGrid(std::string const&, int, int, osgeo::proj::ExtentAndRes const&)
pj_acquire_lock
pj_add_type_crs_if_needed(std::string const&)
pj_apply_gridshift
@@ -709,6 +738,9 @@ pj_chomp(char*)
pj_cleanup_lock
pj_clear_initcache
pj_compare_datums
pj_context_get_grid_cache_filename(projCtx_t*)
pj_context_get_user_writable_directory(projCtx_t*, bool)
pj_context_is_network_enabled(projCtx_t*)
pj_ctx_alloc
pj_ctx_fclose
pj_ctx_fgets
@@ -796,9 +828,14 @@ proj_context_get_use_proj4_init_rules
proj_context_guess_wkt_dialect
proj_context_set_autoclose_database
proj_context_set_database_path
proj_context_set_enable_network
proj_context_set_fileapi
proj_context_set_file_finder
proj_context_set_network_callbacks
proj_context_set(PJconsts*, projCtx_t*)
proj_context_set_search_paths
proj_context_set_sqlite3_vfs_name
proj_context_set_url_endpoint
proj_context_use_proj4_init_rules
proj_convert_conversion_to_other_method
proj_coord
@@ -928,6 +965,7 @@ proj_cs_get_axis_info
proj_cs_get_type
proj_destroy
proj_dmstor
proj_download_file
proj_ellipsoid_get_parameters
proj_errno
proj_errno_reset
@@ -953,6 +991,11 @@ proj_get_scope
proj_get_source_crs
proj_get_target_crs
proj_get_type
proj_grid_cache_clear
proj_grid_cache_set_enable
proj_grid_cache_set_filename
proj_grid_cache_set_max_size
proj_grid_cache_set_ttl
proj_grid_get_info_from_database
proj_grid_info
proj_identify
@@ -962,6 +1005,7 @@ proj_int_list_destroy
proj_is_crs
proj_is_deprecated
proj_is_derived_crs
proj_is_download_needed
proj_is_equivalent_to
proj_is_equivalent_to_with_ctx
proj_list_angular_units
+5 -1
View File
@@ -15,7 +15,11 @@ esac
TOPDIR="$SCRIPT_DIR/.."
for i in "$TOPDIR"/include/proj/*.hpp "$TOPDIR"/include/proj/internal/*.hpp "$TOPDIR"/src/iso19111/*.cpp "$TOPDIR"/test/unit/*.cpp "$TOPDIR"/src/apps/projinfo.cpp "$TOPDIR"/src/tracing.cpp; do
for i in "$TOPDIR"/include/proj/*.hpp "$TOPDIR"/include/proj/internal/*.hpp \
"$TOPDIR"/src/iso19111/*.cpp "$TOPDIR"/test/unit/*.cpp "$TOPDIR"/src/apps/projinfo.cpp \
"$TOPDIR"/src/tracing.cpp "$TOPDIR"/src/grids.hpp "$TOPDIR"/src/grids.cpp \
"$TOPDIR"/src/filemanager.hpp "$TOPDIR"/src/filemanager.cpp \
"$TOPDIR"/src/sqlite3_utils.hpp "$TOPDIR"/src/sqlite3_utils.cpp ; do
if ! echo "$i" | grep -q "lru_cache.hpp"; then
"$SCRIPT_DIR"/reformat.sh "$i";
fi
+79 -38
View File
@@ -47,6 +47,8 @@
#include "proj_internal.h"
#include <math.h>
#include "geodesic.h"
#include "grids.hpp"
#include "filemanager.hpp"
#include "proj/common.hpp"
#include "proj/coordinateoperation.hpp"
@@ -262,6 +264,9 @@ similarly, but prefers the 2D resp. 3D interfaces if available.
}
PJ_COORD res = direction == PJ_FWD ?
pj_fwd4d( coord, alt.pj ) : pj_inv4d( coord, alt.pj );
if( proj_errno(alt.pj) == PJD_ERR_NETWORK_ERROR ) {
return proj_coord_error ();
}
if( res.xyzt.x != HUGE_VAL ) {
return res;
}
@@ -290,7 +295,7 @@ similarly, but prefers the 2D resp. 3D interfaces if available.
auto coordOperation = dynamic_cast<
NS_PROJ::operation::CoordinateOperation*>(alt.pj->iso_obj.get());
if( coordOperation ) {
if( coordOperation->gridsNeeded(dbContext).empty() ) {
if( coordOperation->gridsNeeded(dbContext, true).empty() ) {
if( P->iCurCoordOp != i ) {
if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) {
std::string msg("Using coordinate operation ");
@@ -1146,7 +1151,10 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons
proj_operation_factory_context_set_spatial_criterion(
ctx, operation_ctx, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
proj_operation_factory_context_set_grid_availability_use(
ctx, operation_ctx, PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID);
ctx, operation_ctx,
pj_context_is_network_enabled(ctx) ?
PROJ_GRID_AVAILABILITY_KNOWN_AVAILABLE:
PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID);
auto op_list = proj_create_operations(ctx, source_crs, target_crs, operation_ctx);
@@ -1476,10 +1484,20 @@ PJ_INFO proj_info (void) {
/* build search path string */
auto ctx = pj_get_default_ctx();
if (!ctx || ctx->search_paths.empty()) {
const char *envPROJ_LIB = getenv("PROJ_LIB");
buf = path_append(buf, envPROJ_LIB, &buf_size);
// Env var mostly for testing purposes and being independent from
// an existing installation
const char* ignoreUserWritableDirectory =
getenv("PROJ_SKIP_READ_USER_WRITABLE_DIRECTORY");
if( ignoreUserWritableDirectory == nullptr ||
ignoreUserWritableDirectory[0] == '\0' ) {
buf = path_append(buf,
pj_context_get_user_writable_directory(ctx, false).c_str(),
&buf_size);
}
const std::string envPROJ_LIB = NS_PROJ::FileManager::getProjLibEnvVar(ctx);
buf = path_append(buf, envPROJ_LIB.empty() ? nullptr : envPROJ_LIB.c_str(), &buf_size);
#ifdef PROJ_LIB
if (envPROJ_LIB == nullptr) {
if (envPROJ_LIB.empty()) {
buf = path_append(buf, PROJ_LIB, &buf_size);
}
#endif
@@ -1583,43 +1601,65 @@ PJ_GRID_INFO proj_grid_info(const char *gridname) {
/*PJ_CONTEXT *ctx = proj_context_create(); */
PJ_CONTEXT *ctx = pj_get_default_ctx();
PJ_GRIDINFO *gridinfo = pj_gridinfo_init(ctx, gridname);
memset(&grinfo, 0, sizeof(PJ_GRID_INFO));
/* in case the grid wasn't found */
if (gridinfo->filename == nullptr || gridinfo->ct == nullptr) {
pj_gridinfo_free(ctx, gridinfo);
strcpy(grinfo.format, "missing");
return grinfo;
const auto fillGridInfo = [&grinfo, ctx, gridname]
(const NS_PROJ::Grid& grid, const std::string& format)
{
const auto& extent = grid.extentAndRes();
/* name of grid */
strncpy (grinfo.gridname, gridname, sizeof(grinfo.gridname) - 1);
/* full path of grid */
pj_find_file(ctx, gridname, grinfo.filename, sizeof(grinfo.filename) - 1);
/* grid format */
strncpy (grinfo.format, format.c_str(), sizeof(grinfo.format) - 1);
/* grid size */
grinfo.n_lon = grid.width();
grinfo.n_lat = grid.height();
/* cell size */
grinfo.cs_lon = extent.resLon;
grinfo.cs_lat = extent.resLat;
/* bounds of grid */
grinfo.lowerleft.lam = extent.westLon;
grinfo.lowerleft.phi = extent.southLat;
grinfo.upperright.lam = extent.eastLon;
grinfo.upperright.phi = extent.northLat;
};
{
const auto gridSet = NS_PROJ::VerticalShiftGridSet::open(ctx, gridname);
if( gridSet )
{
const auto& grids = gridSet->grids();
if( !grids.empty() )
{
const auto& grid = grids.front();
fillGridInfo(*grid, gridSet->format());
return grinfo;
}
}
}
/* The string copies below are automatically null-terminated due to */
/* the memset above, so strncpy is safe */
/* name of grid */
strncpy (grinfo.gridname, gridname, sizeof(grinfo.gridname) - 1);
/* full path of grid */
pj_find_file(ctx, gridname, grinfo.filename, sizeof(grinfo.filename) - 1);
/* grid format */
strncpy (grinfo.format, gridinfo->format, sizeof(grinfo.format) - 1);
/* grid size */
grinfo.n_lon = gridinfo->ct->lim.lam;
grinfo.n_lat = gridinfo->ct->lim.phi;
/* cell size */
grinfo.cs_lon = gridinfo->ct->del.lam;
grinfo.cs_lat = gridinfo->ct->del.phi;
/* bounds of grid */
grinfo.lowerleft = gridinfo->ct->ll;
grinfo.upperright.lam = grinfo.lowerleft.lam + grinfo.n_lon*grinfo.cs_lon;
grinfo.upperright.phi = grinfo.lowerleft.phi + grinfo.n_lat*grinfo.cs_lat;
pj_gridinfo_free(ctx, gridinfo);
{
const auto gridSet = NS_PROJ::HorizontalShiftGridSet::open(ctx, gridname);
if( gridSet )
{
const auto& grids = gridSet->grids();
if( !grids.empty() )
{
const auto& grid = grids.front();
fillGridInfo(*grid, gridSet->format());
return grinfo;
}
}
}
strcpy(grinfo.format, "missing");
return grinfo;
}
@@ -1763,3 +1803,4 @@ PJ_FACTORS proj_factors(PJ *P, PJ_COORD lp) {
return factors;
}
+16 -9
View File
@@ -7,7 +7,7 @@ TESTS = geodtest
check_PROGRAMS = geodtest
AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \
-DMUTEX_@MUTEX_SETTING@ -I$(top_srcdir)/include @SQLITE3_CFLAGS@
-DMUTEX_@MUTEX_SETTING@ -I$(top_srcdir)/include @SQLITE3_CFLAGS@ @TIFF_CFLAGS@ @TIFF_ENABLED_FLAGS@ @CURL_CFLAGS@ @CURL_ENABLED_FLAGS@
AM_CXXFLAGS = @CXX_WFLAGS@ @FLTO_FLAG@
include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesic.h \
@@ -43,7 +43,7 @@ geodtest_LDADD = libproj.la
lib_LTLIBRARIES = libproj.la
libproj_la_LDFLAGS = -no-undefined -version-info 18:0:3
libproj_la_LIBADD = @SQLITE3_LIBS@
libproj_la_LIBADD = @SQLITE3_LIBS@ @TIFF_LIBS@ @CURL_LIBS@
libproj_la_SOURCES = \
pj_list.h proj_internal.h \
@@ -183,23 +183,22 @@ libproj_la_SOURCES = \
transformations/horner.cpp \
transformations/molodensky.cpp \
transformations/vgridshift.cpp \
transformations/xyzgridshift.cpp \
\
aasincos.cpp adjlon.cpp \
dmstor.cpp auth.cpp \
deriv.cpp ell_set.cpp ellps.cpp errno.cpp \
factors.cpp fwd.cpp init.cpp inv.cpp \
list.cpp malloc.cpp mlfn.cpp msfn.cpp proj_mdist.cpp \
open_lib.cpp param.cpp phi2.cpp pr_list.cpp \
param.cpp phi2.cpp pr_list.cpp \
qsfn.cpp strerrno.cpp \
tsfn.cpp units.cpp ctx.cpp log.cpp zpoly1.cpp rtodms.cpp \
release.cpp gauss.cpp \
fileapi.cpp \
\
gc_reader.cpp gridcatalog.cpp \
nad_cvt.cpp nad_init.cpp nad_intr.cpp \
apply_gridshift.cpp datums.cpp datum_set.cpp transform.cpp \
geocent.cpp geocent.h utils.cpp gridinfo.cpp gridlist.cpp \
mutex.cpp initcache.cpp apply_vgridshift.cpp geodesic.c \
datums.cpp datum_set.cpp transform.cpp \
geocent.cpp geocent.h utils.cpp \
mutex.cpp initcache.cpp geodesic.c \
strtod.cpp \
\
4D_api.cpp pipeline.cpp \
@@ -213,7 +212,15 @@ libproj_la_SOURCES = \
proj_json_streaming_writer.hpp \
proj_json_streaming_writer.cpp \
\
tracing.cpp
tracing.cpp \
\
grids.hpp \
grids.cpp \
filemanager.hpp \
filemanager.cpp \
networkfilemanager.cpp \
sqlite3_utils.hpp \
sqlite3_utils.cpp
# The sed hack is to please MSVC
-366
View File
@@ -1,366 +0,0 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Apply datum shifts based on grid shift files (normally NAD27 to
* NAD83 or the reverse). This module is responsible for keeping
* a list of loaded grids, and calling with each one that is
* allowed for a given datum (expressed as the nadgrids= parameter).
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2000, Frank Warmerdam <warmerdam@pobox.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#define PJ_LIB__
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "proj.h"
#include "proj_internal.h"
/************************************************************************/
/* pj_apply_gridshift() */
/* */
/* This is the externally callable interface - part of the */
/* public API - though it is not used internally any more and I */
/* doubt it is used by any other applications. But we preserve */
/* it to honour our public api. */
/************************************************************************/
int pj_apply_gridshift( projCtx ctx, const char *nadgrids, int inverse,
long point_count, int point_offset,
double *x, double *y, double *z )
{
PJ_GRIDINFO **gridlist;
int grid_count;
int ret;
gridlist = pj_gridlist_from_nadgrids( ctx, nadgrids, &grid_count );
if( gridlist == nullptr || grid_count == 0 )
{
pj_dalloc( gridlist );
return ctx->last_errno;
}
ret = pj_apply_gridshift_3( ctx, gridlist, grid_count, inverse,
point_count, point_offset, x, y, z );
/*
** Note this frees the array of grid list pointers, but not the grids
** which is as intended. The grids themselves live on.
*/
pj_dalloc( gridlist );
return ret;
}
/************************************************************************/
/* pj_apply_gridshift_2() */
/* */
/* This implementation uses the gridlist from a coordinate */
/* system definition. If the gridlist has not yet been */
/* populated in the coordinate system definition we set it up */
/* now. */
/************************************************************************/
int pj_apply_gridshift_2( PJ *defn, int inverse,
long point_count, int point_offset,
double *x, double *y, double *z )
{
if( defn->catalog_name != nullptr )
return pj_gc_apply_gridshift( defn, inverse, point_count, point_offset,
x, y, z );
if( defn->gridlist == nullptr )
{
defn->gridlist =
pj_gridlist_from_nadgrids( pj_get_ctx( defn ),
pj_param(defn->ctx, defn->params,"snadgrids").s,
&(defn->gridlist_count) );
if( defn->gridlist == nullptr || defn->gridlist_count == 0 )
return defn->ctx->last_errno;
}
return pj_apply_gridshift_3( pj_get_ctx( defn ),
defn->gridlist, defn->gridlist_count, inverse,
point_count, point_offset, x, y, z );
}
/************************************************************************/
/* find_ctable() */
/* */
/* Determine which grid is the correct given an input coordinate. */
/************************************************************************/
struct CTABLE* find_ctable(projCtx ctx, PJ_LP input, int grid_count, PJ_GRIDINFO **tables) {
int itable;
/* keep trying till we find a table that works */
for( itable = 0; itable < grid_count; itable++ )
{
PJ_GRIDINFO *gi = tables[itable];
struct CTABLE *ct = gi->ct;
double epsilon = (fabs(ct->del.phi)+fabs(ct->del.lam))/10000.0;
/* skip tables that don't match our point at all. */
if ( ct->ll.phi - epsilon > input.phi
|| ct->ll.lam - epsilon > input.lam
|| (ct->ll.phi + (ct->lim.phi-1) * ct->del.phi + epsilon < input.phi)
|| (ct->ll.lam + (ct->lim.lam-1) * ct->del.lam + epsilon < input.lam) ) {
continue;
}
/* If we have child nodes, check to see if any of them apply. */
while( gi->child )
{
PJ_GRIDINFO *child;
for( child = gi->child; child != nullptr; child = child->next )
{
struct CTABLE *ct1 = child->ct;
epsilon = (fabs(ct1->del.phi)+fabs(ct1->del.lam))/10000.0;
if( ct1->ll.phi - epsilon > input.phi
|| ct1->ll.lam - epsilon > input.lam
|| (ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi + epsilon < input.phi)
|| (ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam + epsilon < input.lam) ) {
continue;
}
break;
}
/* If we didn't find a child then nothing more to do */
if( child == nullptr ) break;
/* Otherwise use the child, first checking it's children */
gi = child;
ct = child->ct;
}
/* load the grid shift info if we don't have it. */
if( ct->cvs == nullptr) {
if (!pj_gridinfo_load( ctx, gi ) ) {
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return nullptr;
}
}
/* if we get this far we have found a suitable grid */
return ct;
}
return nullptr;
}
/************************************************************************/
/* pj_apply_gridshift_3() */
/* */
/* This is the real workhorse, given a gridlist. */
/************************************************************************/
int pj_apply_gridshift_3( projCtx ctx, PJ_GRIDINFO **gridlist, int gridlist_count,
int inverse, long point_count, int point_offset,
double *x, double *y, double *z )
{
int i;
struct CTABLE *ct;
static int debug_count = 0;
(void) z;
if( gridlist== nullptr || gridlist_count == 0 )
{
pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID);
return PJD_ERR_FAILED_TO_LOAD_GRID;
}
ctx->last_errno = 0;
for( i = 0; i < point_count; i++ )
{
long io = i * point_offset;
PJ_LP input, output;
int itable;
input.phi = y[io];
input.lam = x[io];
output.phi = HUGE_VAL;
output.lam = HUGE_VAL;
ct = find_ctable(ctx, input, gridlist_count, gridlist);
if( ct != nullptr )
{
output = nad_cvt( ctx, input, inverse, ct, gridlist_count, gridlist);
if ( output.lam != HUGE_VAL && debug_count++ < 20 )
pj_log( ctx, PJ_LOG_DEBUG_MINOR, "pj_apply_gridshift(): used %s", ct->id );
}
if ( output.lam == HUGE_VAL )
{
if( ctx->debug_level >= PJ_LOG_DEBUG_MAJOR )
{
pj_log( ctx, PJ_LOG_DEBUG_MAJOR,
"pj_apply_gridshift(): failed to find a grid shift table for\n"
" location (%.7fdW,%.7fdN)",
x[io] * RAD_TO_DEG,
y[io] * RAD_TO_DEG );
for( itable = 0; itable < gridlist_count; itable++ )
{
PJ_GRIDINFO *gi = gridlist[itable];
if( itable == 0 )
pj_log( ctx, PJ_LOG_DEBUG_MAJOR, " tried: %s", gi->gridname );
else
pj_log( ctx, PJ_LOG_DEBUG_MAJOR, ",%s", gi->gridname );
}
}
/*
* We don't actually have any machinery currently to set the
* following macro, so this is mostly kept here to make it clear
* how we ought to operate if we wanted to make it super clear
* that an error has occurred when points are outside our available
* datum shift areas. But if this is on, we will find that "low
* value" points on the fringes of some datasets will completely
* fail causing lots of problems when it is more or less ok to
* just not apply a datum shift. So rather than deal with
* that we just fallback to no shift. (see also bug #45).
*/
#ifdef ERR_GRID_AREA_TRANSIENT_SEVERE
y[io] = HUGE_VAL;
x[io] = HUGE_VAL;
#else
/* leave x/y unshifted. */
#endif
}
else
{
y[io] = output.phi;
x[io] = output.lam;
}
}
return 0;
}
/**********************************************/
int proj_hgrid_init(PJ* P, const char *grids) {
/**********************************************
Initizalize and populate list of horizontal
grids.
Takes a PJ-object and the plus-parameter
name that is used in the proj-string to
specify the grids to load, e.g. "+grids".
The + should be left out here.
Returns the number of loaded grids.
***********************************************/
/* prepend "s" to the "grids" string to allow usage with pj_param */
char *sgrids = (char *) pj_malloc( (strlen(grids)+1+1) *sizeof(char) );
sprintf(sgrids, "%s%s", "s", grids);
if (P->gridlist == nullptr) {
P->gridlist = pj_gridlist_from_nadgrids(
P->ctx,
pj_param(P->ctx, P->params, sgrids).s,
&(P->gridlist_count)
);
if( P->gridlist == nullptr || P->gridlist_count == 0 ) {
pj_dealloc(sgrids);
return 0;
}
}
if (P->gridlist_count == 0) {
proj_errno_set(P, PJD_ERR_FAILED_TO_LOAD_GRID);
}
pj_dealloc(sgrids);
return P->gridlist_count;
}
/********************************************/
/* proj_hgrid_value() */
/* */
/* Return coordinate offset in grid */
/********************************************/
PJ_LP proj_hgrid_value(PJ *P, PJ_LP lp) {
struct CTABLE *ct;
PJ_LP out = proj_coord_error().lp;
ct = find_ctable(P->ctx, lp, P->gridlist_count, P->gridlist);
if (ct == nullptr) {
pj_ctx_set_errno( P->ctx, PJD_ERR_GRID_AREA);
return out;
}
/* normalize input to ll origin */
lp.lam -= ct->ll.lam;
lp.phi -= ct->ll.phi;
lp.lam = adjlon(lp.lam - M_PI) + M_PI;
out = nad_intr(lp, ct);
if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) {
pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA);
}
return out;
}
PJ_LP proj_hgrid_apply(PJ *P, PJ_LP lp, PJ_DIRECTION direction) {
struct CTABLE *ct;
int inverse;
PJ_LP out;
out.lam = HUGE_VAL; out.phi = HUGE_VAL;
ct = find_ctable(P->ctx, lp, P->gridlist_count, P->gridlist);
if (ct == nullptr || ct->cvs == nullptr) {
if( P->gridlist_count == 1 &&
strcmp(P->gridlist[0]->gridname, "null") == 0) {
// TODO: remove this particular case that is put there just to be
// able to handle longitudes outside of -180,180
out = lp;
} else {
pj_ctx_set_errno( P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
}
return out;
}
inverse = direction == PJ_FWD ? 0 : 1;
out = nad_cvt(P->ctx, lp, inverse, ct, P->gridlist_count, P->gridlist);
if (out.lam == HUGE_VAL || out.phi == HUGE_VAL)
pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA);
return out;
}
-361
View File
@@ -1,361 +0,0 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Apply vertical datum shifts based on grid shift files, normally
* geoid grids mapping WGS84 to NAVD88 or something similar.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#define PJ_LIB__
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "proj_internal.h"
static int is_nodata(float value, double vmultiplier)
{
/* nodata? */
/* GTX official nodata value if -88.88880f, but some grids also */
/* use other big values for nodata (e.g naptrans2008.gtx has */
/* nodata values like -2147479936), so test them too */
return value * vmultiplier > 1000 || value * vmultiplier < -1000 || value == -88.88880f;
}
static double read_vgrid_value( PJ *defn, PJ_LP input, double vmultiplier, int *gridlist_count_p, PJ_GRIDINFO **tables, struct CTABLE *ct) {
int itable = 0;
double value = HUGE_VAL;
double grid_x, grid_y;
long grid_ix, grid_iy;
long grid_ix2, grid_iy2;
float *cvs;
/* do not deal with NaN coordinates */
/* cppcheck-suppress duplicateExpression */
if( isnan(input.phi) || isnan(input.lam) )
itable = *gridlist_count_p;
/* keep trying till we find a table that works */
for ( ; itable < *gridlist_count_p; itable++ )
{
PJ_GRIDINFO *gi = tables[itable];
ct = gi->ct;
/* skip tables that don't match our point at all (latitude check). */
if( ct->ll.phi > input.phi
|| ct->ll.phi + (ct->lim.phi-1) * ct->del.phi < input.phi )
continue;
bool fullWorldLongExtent = false;
if( fabs(ct->lim.lam * ct->del.lam - 2 * M_PI) < 1e-10 )
{
fullWorldLongExtent = true;
}
/* skip tables that don't match our point at all (longitude check). */
else if( ct->ll.lam > input.lam
|| ct->ll.lam + (ct->lim.lam-1) * ct->del.lam < input.lam )
continue;
/* If we have child nodes, check to see if any of them apply. */
while( gi->child != nullptr )
{
PJ_GRIDINFO *child;
for( child = gi->child; child != nullptr; child = child->next )
{
struct CTABLE *ct1 = child->ct;
fullWorldLongExtent = false;
if( ct1->ll.phi > input.phi
|| ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi < input.phi)
continue;
if( fabs(ct1->lim.lam * ct1->del.lam - 2 * M_PI) < 1e-10 )
{
fullWorldLongExtent = true;
}
else if( ct1->ll.lam > input.lam
|| ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam < input.lam)
continue;
break;
}
/* we didn't find a more refined child node to use, so go with current grid */
if( child == nullptr )
{
break;
}
/* Otherwise let's try for childrens children .. */
gi = child;
ct = child->ct;
}
/* load the grid shift info if we don't have it. */
if( ct->cvs == nullptr )
{
pj_gridinfo_load( pj_get_ctx(defn), gi );
}
if( ct->cvs == nullptr )
{
pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return PJD_ERR_FAILED_TO_LOAD_GRID;
}
/* Interpolation a location within the grid */
grid_x = (input.lam - ct->ll.lam) / ct->del.lam;
if( fullWorldLongExtent ) {
// The first fmod goes to ]-lim, lim[ range
// So we add lim again to be in ]0, 2*lim[ and fmod again
grid_x = fmod(
fmod(grid_x + ct->lim.lam, ct->lim.lam) + ct->lim.lam,
ct->lim.lam);
}
grid_y = (input.phi - ct->ll.phi) / ct->del.phi;
grid_ix = lround(floor(grid_x));
assert(grid_ix >= 0 && grid_ix < ct->lim.lam);
grid_iy = lround(floor(grid_y));
assert(grid_iy >= 0 && grid_iy < ct->lim.phi);
grid_x -= grid_ix;
grid_y -= grid_iy;
grid_ix2 = grid_ix + 1;
if( grid_ix2 >= ct->lim.lam ) {
if( fullWorldLongExtent ) {
grid_ix2 = 0;
} else {
grid_ix2 = ct->lim.lam - 1;
}
}
grid_iy2 = grid_iy + 1;
if( grid_iy2 >= ct->lim.phi )
grid_iy2 = ct->lim.phi - 1;
cvs = (float *) ct->cvs;
{
float value_a = cvs[grid_ix + grid_iy * ct->lim.lam];
float value_b = cvs[grid_ix2 + grid_iy * ct->lim.lam];
float value_c = cvs[grid_ix + grid_iy2 * ct->lim.lam];
float value_d = cvs[grid_ix2 + grid_iy2 * ct->lim.lam];
double total_weight = 0.0;
int n_weights = 0;
value = 0.0f;
if( !is_nodata(value_a, vmultiplier) )
{
double weight = (1.0-grid_x) * (1.0-grid_y);
value += value_a * weight;
total_weight += weight;
n_weights ++;
}
if( !is_nodata(value_b, vmultiplier) )
{
double weight = (grid_x) * (1.0-grid_y);
value += value_b * weight;
total_weight += weight;
n_weights ++;
}
if( !is_nodata(value_c, vmultiplier) )
{
double weight = (1.0-grid_x) * (grid_y);
value += value_c * weight;
total_weight += weight;
n_weights ++;
}
if( !is_nodata(value_d, vmultiplier) )
{
double weight = (grid_x) * (grid_y);
value += value_d * weight;
total_weight += weight;
n_weights ++;
}
if( n_weights == 0 )
value = HUGE_VAL;
else if( n_weights != 4 )
value /= total_weight;
}
}
return value * vmultiplier;
}
/************************************************************************/
/* pj_apply_vgridshift() */
/* */
/* This implementation takes uses the gridlist from a coordinate */
/* system definition. If the gridlist has not yet been */
/* populated in the coordinate system definition we set it up */
/* now. */
/************************************************************************/
int pj_apply_vgridshift( PJ *defn, const char *listname,
PJ_GRIDINFO ***gridlist_p,
int *gridlist_count_p,
int inverse,
long point_count, int point_offset,
double *x, double *y, double *z )
{
int i;
static int debug_count = 0;
PJ_GRIDINFO **tables;
struct CTABLE ct;
if( *gridlist_p == nullptr )
{
*gridlist_p =
pj_gridlist_from_nadgrids( pj_get_ctx(defn),
pj_param(defn->ctx,defn->params,listname).s,
gridlist_count_p );
if( *gridlist_p == nullptr || *gridlist_count_p == 0 )
return defn->ctx->last_errno;
}
if( *gridlist_count_p == 0 )
{
pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID);
return PJD_ERR_FAILED_TO_LOAD_GRID;
}
tables = *gridlist_p;
defn->ctx->last_errno = 0;
for( i = 0; i < point_count; i++ )
{
double value;
long io = i * point_offset;
PJ_LP input;
input.phi = y[io];
input.lam = x[io];
value = read_vgrid_value(defn, input, 1.0, gridlist_count_p, tables, &ct);
if( inverse )
z[io] -= value;
else
z[io] += value;
if( value != HUGE_VAL )
{
if( debug_count++ < 20 ) {
proj_log_trace(defn, "pj_apply_gridshift(): used %s", ct.id);
break;
}
}
if( value == HUGE_VAL )
{
int itable;
std::string gridlist;
proj_log_debug(defn,
"pj_apply_vgridshift(): failed to find a grid shift table for\n"
" location (%.7fdW,%.7fdN)",
x[io] * RAD_TO_DEG,
y[io] * RAD_TO_DEG );
for( itable = 0; itable < *gridlist_count_p; itable++ )
{
PJ_GRIDINFO *gi = tables[itable];
if( itable == 0 )
gridlist += " tried: ";
else
gridlist += ',';
gridlist += gi->gridname;
}
proj_log_debug(defn, "%s", gridlist.c_str());
pj_ctx_set_errno( defn->ctx, PJD_ERR_GRID_AREA );
return PJD_ERR_GRID_AREA;
}
}
return 0;
}
/**********************************************/
int proj_vgrid_init(PJ* P, const char *grids) {
/**********************************************
Initizalize and populate gridlist.
Takes a PJ-object and the plus-parameter
name that is used in the proj-string to
specify the grids to load, e.g. "+grids".
The + should be left out here.
Returns the number of loaded grids.
***********************************************/
/* prepend "s" to the "grids" string to allow usage with pj_param */
char *sgrids = (char *) pj_malloc( (strlen(grids)+1+1) *sizeof(char) );
sprintf(sgrids, "%s%s", "s", grids);
if (P->vgridlist_geoid == nullptr) {
P->vgridlist_geoid = pj_gridlist_from_nadgrids(
P->ctx,
pj_param(P->ctx, P->params, sgrids).s,
&(P->vgridlist_geoid_count)
);
if( P->vgridlist_geoid == nullptr || P->vgridlist_geoid_count == 0 ) {
pj_dealloc(sgrids);
return 0;
}
}
if (P->vgridlist_geoid_count == 0) {
proj_errno_set(P, PJD_ERR_FAILED_TO_LOAD_GRID);
}
pj_dealloc(sgrids);
return P->vgridlist_geoid_count;
}
/***********************************************/
double proj_vgrid_value(PJ *P, PJ_LP lp, double vmultiplier){
/***********************************************
Read grid value at position lp in grids loaded
with proj_grid_init.
Returns the grid value of the given coordinate.
************************************************/
struct CTABLE used_grid;
double value;
memset(&used_grid, 0, sizeof(struct CTABLE));
value = read_vgrid_value(P, lp, vmultiplier, &(P->vgridlist_geoid_count), P->vgridlist_geoid, &used_grid);
proj_log_trace(P, "proj_vgrid_value: (%f, %f) = %f", lp.lam*RAD_TO_DEG, lp.phi*RAD_TO_DEG, value);
return value;
}
+1
View File
@@ -1153,6 +1153,7 @@ static const struct errno_vs_err_const lookup[] = {
{"pjd_err_inconsistent_unit" , -59},
{"pjd_err_mutually_exclusive_args" , -60},
{"pjd_err_generic_error" , -61},
{"pjd_err_network_error" , -62},
{"pjd_err_dont_skip" , 5555},
{"pjd_err_unknown" , 9999},
{"pjd_err_enomem" , ENOMEM},
+22 -8
View File
@@ -87,7 +87,8 @@ static void usage() {
<< " [--spatial-test contains|intersects]" << std::endl
<< " [--crs-extent-use none|both|intersection|smallest]"
<< std::endl
<< " [--grid-check none|discard_missing|sort] "
<< " [--grid-check "
"none|discard_missing|sort|known_available] "
"[--show-superseded]"
<< std::endl
<< " [--pivot-crs always|if_no_direct_transformation|"
@@ -554,7 +555,7 @@ static void outputObject(
auto op = dynamic_cast<CoordinateOperation *>(obj.get());
if (op && dbContext && getenv("PROJINFO_NO_GRID_CHECK") == nullptr) {
try {
auto setGrids = op->gridsNeeded(dbContext);
auto setGrids = op->gridsNeeded(dbContext, false);
bool firstWarning = true;
for (const auto &grid : setGrids) {
if (!grid.available) {
@@ -570,6 +571,7 @@ static void outputObject(
if (!grid.url.empty()) {
std::cout << " at " << grid.url;
}
std::cout << ", or on CDN";
} else if (!grid.url.empty()) {
std::cout << " Can be obtained at " << grid.url;
}
@@ -584,8 +586,9 @@ static void outputObject(
// ---------------------------------------------------------------------------
static void outputOperationSummary(const CoordinateOperationNNPtr &op,
const DatabaseContextPtr &dbContext) {
static void outputOperationSummary(
const CoordinateOperationNNPtr &op, const DatabaseContextPtr &dbContext,
CoordinateOperationContext::GridAvailabilityUse gridAvailabilityUse) {
auto ids = op->identifiers();
if (!ids.empty()) {
std::cout << *(ids[0]->codeSpace()) << ":" << ids[0]->code();
@@ -631,10 +634,16 @@ static void outputOperationSummary(const CoordinateOperationNNPtr &op,
if (dbContext && getenv("PROJINFO_NO_GRID_CHECK") == nullptr) {
try {
auto setGrids = op->gridsNeeded(dbContext);
auto setGrids = op->gridsNeeded(dbContext, false);
for (const auto &grid : setGrids) {
if (!grid.available) {
std::cout << ", at least one grid missing";
if (gridAvailabilityUse ==
CoordinateOperationContext::GridAvailabilityUse::
KNOWN_AVAILABLE &&
!grid.packageName.empty()) {
std::cout << " on the system, but available on CDN";
}
break;
}
}
@@ -731,7 +740,7 @@ static void outputOperations(
}
if (summary) {
for (const auto &op : list) {
outputOperationSummary(op, dbContext);
outputOperationSummary(op, dbContext, gridAvailabilityUse);
}
} else {
bool first = true;
@@ -744,7 +753,7 @@ static void outputOperations(
std::cout << "-------------------------------------" << std::endl;
std::cout << "Operation No. " << (i + 1) << ":" << std::endl
<< std::endl;
outputOperationSummary(op, dbContext);
outputOperationSummary(op, dbContext, gridAvailabilityUse);
std::cout << std::endl;
outputObject(dbContext, op, allowUseIntermediateCRS, outputOpt);
}
@@ -777,7 +786,9 @@ int main(int argc, char **argv) {
CoordinateOperationContext::SourceTargetCRSExtentUse::SMALLEST;
bool buildBoundCRSToWGS84 = false;
CoordinateOperationContext::GridAvailabilityUse gridAvailabilityUse =
CoordinateOperationContext::GridAvailabilityUse::USE_FOR_SORTING;
pj_context_is_network_enabled(nullptr)
? CoordinateOperationContext::GridAvailabilityUse::KNOWN_AVAILABLE
: CoordinateOperationContext::GridAvailabilityUse::USE_FOR_SORTING;
CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS =
CoordinateOperationContext::IntermediateCRSUse::
IF_NO_DIRECT_TRANSFORMATION;
@@ -992,6 +1003,9 @@ int main(int argc, char **argv) {
} else if (ci_equal(value, "sort")) {
gridAvailabilityUse = CoordinateOperationContext::
GridAvailabilityUse::USE_FOR_SORTING;
} else if (ci_equal(value, "known_available")) {
gridAvailabilityUse = CoordinateOperationContext::
GridAvailabilityUse::KNOWN_AVAILABLE;
} else {
std::cerr << "Unrecognized value for option --grid-check: "
<< value << std::endl;
+7 -29
View File
@@ -33,6 +33,7 @@
#include "proj_experimental.h"
#include "proj_internal.h"
#include "filemanager.hpp"
/************************************************************************/
/* pj_get_ctx() */
@@ -60,9 +61,9 @@ void pj_set_ctx( projPJ pj, projCtx ctx )
if (pj==nullptr)
return;
pj->ctx = ctx;
if( pj->is_pipeline )
if( pj->reassign_context )
{
pj_pipeline_assign_context_to_steps(pj, ctx);
pj->reassign_context(pj, ctx);
}
for( const auto &alt: pj->alternativeCoordinateOperations )
{
@@ -95,7 +96,8 @@ projCtx_t projCtx_t::createDefault()
projCtx_t ctx;
ctx.debug_level = PJ_LOG_NONE;
ctx.logger = pj_stderr_logger;
ctx.fileapi = pj_get_default_fileapi();
ctx.fileapi_legacy = pj_get_default_fileapi();
NS_PROJ::FileManager::fillDefaultNetworkInterface(&ctx);
if( getenv("PROJ_DEBUG") != nullptr )
{
@@ -133,12 +135,13 @@ projCtx_t::projCtx_t(const projCtx_t& other)
debug_level = other.debug_level;
logger = other.logger;
logger_app_data = other.logger_app_data;
fileapi = other.fileapi;
fileapi_legacy = other.fileapi_legacy;
epsg_file_exists = other.epsg_file_exists;
set_search_paths(other.search_paths);
file_finder = other.file_finder;
file_finder_legacy = other.file_finder_legacy;
file_finder_user_data = other.file_finder_user_data;
networking = other.networking;
}
/************************************************************************/
@@ -258,28 +261,3 @@ void *pj_ctx_get_app_data( projCtx ctx )
return nullptr;
return ctx->logger_app_data;
}
/************************************************************************/
/* pj_ctx_set_fileapi() */
/************************************************************************/
void pj_ctx_set_fileapi( projCtx ctx, projFileAPI *fileapi )
{
if (nullptr==ctx)
return;
ctx->fileapi = fileapi;
}
/************************************************************************/
/* pj_ctx_get_fileapi() */
/************************************************************************/
projFileAPI *pj_ctx_get_fileapi( projCtx ctx )
{
if (nullptr==ctx)
return nullptr;
return ctx->fileapi;
}
+1 -20
View File
@@ -41,7 +41,7 @@
int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef)
{
const char *name, *towgs84, *nadgrids, *catalog;
const char *name, *towgs84, *nadgrids;
projdef->datum_type = PJD_UNKNOWN;
@@ -117,25 +117,6 @@ int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef)
projdef->datum_type = PJD_GRIDSHIFT;
}
/* -------------------------------------------------------------------- */
/* Check for grid catalog parameter, and optional date. */
/* -------------------------------------------------------------------- */
else if( (catalog = pj_param(ctx, pl,"scatalog").s) != nullptr )
{
const char *date;
projdef->datum_type = PJD_GRIDSHIFT;
projdef->catalog_name = pj_strdup(catalog);
if (!projdef->catalog_name) {
pj_ctx_set_errno(ctx, ENOMEM);
return 1;
}
date = pj_param(ctx, pl, "sdate").s;
if( date != nullptr)
projdef->datum_date = pj_gc_parsedate( ctx, date);
}
/* -------------------------------------------------------------------- */
/* Check for towgs84 parameter. */
/* -------------------------------------------------------------------- */
+31 -5
View File
@@ -34,6 +34,7 @@
#include "proj.h"
#include "proj_internal.h"
#include "filemanager.hpp"
static PAFile stdio_fopen(projCtx ctx, const char *filename,
const char *access);
@@ -141,7 +142,7 @@ static void stdio_fclose(PAFile file)
PAFile pj_ctx_fopen(projCtx ctx, const char *filename, const char *access)
{
return ctx->fileapi->FOpen(ctx, filename, access);
return ctx->fileapi_legacy->FOpen(ctx, filename, access);
}
/************************************************************************/
@@ -149,7 +150,7 @@ PAFile pj_ctx_fopen(projCtx ctx, const char *filename, const char *access)
/************************************************************************/
size_t pj_ctx_fread(projCtx ctx, void *buffer, size_t size, size_t nmemb, PAFile file)
{
return ctx->fileapi->FRead(buffer, size, nmemb, file);
return ctx->fileapi_legacy->FRead(buffer, size, nmemb, file);
}
/************************************************************************/
@@ -157,7 +158,7 @@ size_t pj_ctx_fread(projCtx ctx, void *buffer, size_t size, size_t nmemb, PAFile
/************************************************************************/
int pj_ctx_fseek(projCtx ctx, PAFile file, long offset, int whence)
{
return ctx->fileapi->FSeek(file, offset, whence);
return ctx->fileapi_legacy->FSeek(file, offset, whence);
}
/************************************************************************/
@@ -165,7 +166,7 @@ int pj_ctx_fseek(projCtx ctx, PAFile file, long offset, int whence)
/************************************************************************/
long pj_ctx_ftell(projCtx ctx, PAFile file)
{
return ctx->fileapi->FTell(file);
return ctx->fileapi_legacy->FTell(file);
}
/************************************************************************/
@@ -173,7 +174,7 @@ long pj_ctx_ftell(projCtx ctx, PAFile file)
/************************************************************************/
void pj_ctx_fclose(projCtx ctx, PAFile file)
{
ctx->fileapi->FClose(file);
ctx->fileapi_legacy->FClose(file);
}
/************************************************************************/
@@ -212,3 +213,28 @@ char *pj_ctx_fgets(projCtx ctx, char *line, int size, PAFile file)
}
return line;
}
/************************************************************************/
/* pj_ctx_set_fileapi() */
/************************************************************************/
void pj_ctx_set_fileapi( projCtx ctx, projFileAPI *fileapi )
{
if (nullptr==ctx)
return;
ctx->fileapi_legacy = fileapi;
}
/************************************************************************/
/* pj_ctx_get_fileapi() */
/************************************************************************/
projFileAPI *pj_ctx_get_fileapi( projCtx ctx )
{
if (nullptr==ctx)
return nullptr;
return ctx->fileapi_legacy;
}
+1733
View File
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
/******************************************************************************
* Project: PROJ
* Purpose: File manager
* Author: Even Rouault, <even.rouault at spatialys.com>
*
******************************************************************************
* Copyright (c) 2019, Even Rouault, <even.rouault at spatialys.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#ifndef FILEMANAGER_HPP_INCLUDED
#define FILEMANAGER_HPP_INCLUDED
#include <memory>
#include "proj.h"
#include "proj/util.hpp"
//! @cond Doxygen_Suppress
NS_PROJ_START
class File;
enum class FileAccess {
READ_ONLY, // "rb"
READ_UPDATE, // "r+b"
CREATE, // "w+b"
};
class FileManager {
private:
FileManager() = delete;
public:
// "Low-level" interface.
static std::unique_ptr<File> open(PJ_CONTEXT *ctx, const char *filename,
FileAccess access);
static bool exists(PJ_CONTEXT *ctx, const char *filename);
static bool mkdir(PJ_CONTEXT *ctx, const char *filename);
static bool unlink(PJ_CONTEXT *ctx, const char *filename);
static bool rename(PJ_CONTEXT *ctx, const char *oldPath,
const char *newPath);
static std::string getProjLibEnvVar(PJ_CONTEXT *ctx);
// "High-level" interface, honoring PROJ_LIB and the like.
static std::unique_ptr<File> open_resource_file(PJ_CONTEXT *ctx,
const char *name);
static void fillDefaultNetworkInterface(PJ_CONTEXT *ctx);
static void clearMemoryCache();
};
// ---------------------------------------------------------------------------
class File {
protected:
std::string name_;
explicit File(const std::string &name);
public:
virtual ~File();
virtual size_t read(void *buffer, size_t sizeBytes) = 0;
virtual size_t write(const void *buffer, size_t sizeBytes) = 0;
virtual bool seek(unsigned long long offset, int whence = SEEK_SET) = 0;
virtual unsigned long long tell() = 0;
virtual void reassign_context(PJ_CONTEXT *ctx) = 0;
virtual bool hasChanged() const = 0;
const std::string &name() const { return name_; }
};
// ---------------------------------------------------------------------------
std::unique_ptr<File> pj_network_file_open(PJ_CONTEXT *ctx,
const char *filename);
NS_PROJ_END
//! @endcond Doxygen_Suppress
#endif // FILEMANAGER_HPP_INCLUDED
-248
View File
@@ -1,248 +0,0 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Code to read a grid catalog from a .cvs file.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2012, Frank Warmerdam <warmerdam@pobox.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#define PJ_LIB__
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "proj.h"
#include "proj_internal.h"
static int gc_readentry(projCtx ctx, PAFile fid, PJ_GridCatalogEntry *entry);
/************************************************************************/
/* pj_gc_readcatalog() */
/* */
/* Read a grid catalog from a .csv file. */
/************************************************************************/
PJ_GridCatalog *pj_gc_readcatalog( projCtx ctx, const char *catalog_name )
{
PAFile fid;
PJ_GridCatalog *catalog;
int entry_max;
char line[302];
fid = pj_open_lib( ctx, catalog_name, "r" );
if (fid == nullptr)
return nullptr;
/* discard title line */
pj_ctx_fgets(ctx, line, sizeof(line)-1, fid);
catalog = (PJ_GridCatalog *) calloc(1,sizeof(PJ_GridCatalog));
if( !catalog )
{
pj_ctx_set_errno(ctx, ENOMEM);
pj_ctx_fclose(ctx, fid);
return nullptr;
}
catalog->catalog_name = pj_strdup(catalog_name);
if (!catalog->catalog_name) {
pj_ctx_set_errno(ctx, ENOMEM);
free(catalog);
pj_ctx_fclose(ctx, fid);
return nullptr;
}
entry_max = 10;
catalog->entries = (PJ_GridCatalogEntry *)
malloc(entry_max * sizeof(PJ_GridCatalogEntry));
if (!catalog->entries) {
pj_ctx_set_errno(ctx, ENOMEM);
free(catalog->catalog_name);
free(catalog);
pj_ctx_fclose(ctx, fid);
return nullptr;
}
while( gc_readentry( ctx, fid,
catalog->entries+catalog->entry_count) == 0)
{
catalog->entry_count++;
if( catalog->entry_count == entry_max )
{
PJ_GridCatalogEntry* new_entries;
entry_max = entry_max * 2;
new_entries = (PJ_GridCatalogEntry *)
realloc(catalog->entries,
entry_max * sizeof(PJ_GridCatalogEntry));
if (new_entries == nullptr )
{
int i;
for( i = 0; i < catalog->entry_count; i++ )
free( catalog->entries[i].definition );
free( catalog->entries );
free( catalog->catalog_name );
free( catalog );
pj_ctx_fclose(ctx, fid);
return nullptr;
}
catalog->entries = new_entries;
}
}
pj_ctx_fclose(ctx, fid);
return catalog;
}
/************************************************************************/
/* gc_read_csv_line() */
/* */
/* Simple csv line splitter with fixed maximum line size and */
/* token count. */
/************************************************************************/
static int gc_read_csv_line( projCtx ctx, PAFile fid,
char **tokens, int max_tokens )
{
char line[302];
while( pj_ctx_fgets(ctx, line, sizeof(line)-1, fid) != nullptr )
{
char *next = line;
int token_count = 0;
while( isspace(*next) )
next++;
/* skip blank and comment lines */
if( next[0] == '#' || next[0] == '\0' )
continue;
while( token_count < max_tokens && *next != '\0' )
{
const char *start = next;
char* token;
while( *next != '\0' && *next != ',' )
next++;
if( *next == ',' )
{
*next = '\0';
next++;
}
token = pj_strdup(start);
if (!token) {
while (token_count > 0)
free(tokens[--token_count]);
pj_ctx_set_errno(ctx, ENOMEM);
return 0;
}
tokens[token_count++] = token;
}
return token_count;
}
return 0;
}
/************************************************************************/
/* pj_gc_parsedate() */
/* */
/* Parse a date into a floating point year value. Acceptable */
/* values are "yyyy.fraction" and "yyyy-mm-dd". Anything else */
/* returns 0.0. */
/************************************************************************/
double pj_gc_parsedate( projCtx ctx, const char *date_string )
{
(void) ctx;
if( strlen(date_string) == 10
&& date_string[4] == '-' && date_string[7] == '-' )
{
int year = atoi(date_string);
int month = atoi(date_string+5);
int day = atoi(date_string+8);
/* simplified calculation so we don't need to know all about months */
return year + ((month-1) * 31 + (day-1)) / 372.0;
}
else
{
return pj_atof(date_string);
}
}
/************************************************************************/
/* gc_readentry() */
/* */
/* Read one catalog entry from the file */
/* */
/* Format: */
/* gridname,ll_long,ll_lat,ur_long,ur_lat,priority,date */
/************************************************************************/
static int gc_readentry(projCtx ctx, PAFile fid, PJ_GridCatalogEntry *entry)
{
#define MAX_TOKENS 30
char *tokens[MAX_TOKENS];
int token_count, i;
int error = 0;
memset( entry, 0, sizeof(PJ_GridCatalogEntry) );
token_count = gc_read_csv_line( ctx, fid, tokens, MAX_TOKENS );
if( token_count < 5 )
{
error = 1; /* TODO: need real error codes */
if( token_count != 0 )
pj_log( ctx, PJ_LOG_ERROR, "Short line in grid catalog." );
}
else
{
entry->definition = tokens[0];
tokens[0] = nullptr; /* We take ownership of tokens[0] */
entry->region.ll_long = dmstor_ctx( ctx, tokens[1], nullptr );
entry->region.ll_lat = dmstor_ctx( ctx, tokens[2], nullptr );
entry->region.ur_long = dmstor_ctx( ctx, tokens[3], nullptr );
entry->region.ur_lat = dmstor_ctx( ctx, tokens[4], nullptr );
if( token_count > 5 )
entry->priority = atoi( tokens[5] ); /* defaults to zero */
if( token_count > 6 )
entry->date = pj_gc_parsedate( ctx, tokens[6] );
}
for( i = 0; i < token_count; i++ )
free( tokens[i] );
return error;
}
-306
View File
@@ -1,306 +0,0 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Code in support of grid catalogs
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2012, Frank Warmerdam <warmerdam@pobox.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#define PJ_LIB__
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "proj.h"
#include "proj_internal.h"
static PJ_GridCatalog *grid_catalog_list = nullptr;
static
PJ_GRIDINFO *pj_gc_findgrid( projCtx_t *ctx,
PJ_GridCatalog *catalog, int after,
PJ_LP location, double date,
PJ_Region *optional_region,
double *grid_date );
/************************************************************************/
/* pj_gc_unloadall() */
/* */
/* Deallocate all the grid catalogs (but not the referenced */
/* grids). */
/************************************************************************/
void pj_gc_unloadall( projCtx ctx )
{
(void) ctx;
while( grid_catalog_list != nullptr )
{
int i;
PJ_GridCatalog *catalog = grid_catalog_list;
grid_catalog_list = grid_catalog_list->next;
for( i = 0; i < catalog->entry_count; i++ )
{
/* we don't own gridinfo - do not free here */
free( catalog->entries[i].definition );
}
free( catalog->entries );
free( catalog->catalog_name );
free( catalog );
}
}
/************************************************************************/
/* pj_gc_findcatalog() */
/************************************************************************/
PJ_GridCatalog *pj_gc_findcatalog( projCtx ctx, const char *name )
{
PJ_GridCatalog *catalog;
pj_acquire_lock();
for( catalog=grid_catalog_list; catalog != nullptr; catalog = catalog->next )
{
if( strcmp(catalog->catalog_name, name) == 0 )
{
pj_release_lock();
return catalog;
}
}
pj_release_lock();
catalog = pj_gc_readcatalog( ctx, name );
if( catalog == nullptr )
return nullptr;
pj_acquire_lock();
catalog->next = grid_catalog_list;
grid_catalog_list = catalog;
pj_release_lock();
return catalog;
}
/************************************************************************/
/* pj_gc_apply_gridshift() */
/************************************************************************/
int pj_gc_apply_gridshift( PJ *defn, int inverse,
long point_count, int point_offset,
double *x, double *y, double *z )
{
int i;
(void) z;
if( defn->catalog == nullptr )
{
defn->catalog = pj_gc_findcatalog( defn->ctx, defn->catalog_name );
if( defn->catalog == nullptr )
return defn->ctx->last_errno;
}
defn->ctx->last_errno = 0;
for( i = 0; i < point_count; i++ )
{
long io = i * point_offset;
PJ_LP input, output_after, output_before;
double mix_ratio;
PJ_GRIDINFO *gi;
input.phi = y[io];
input.lam = x[io];
/* make sure we have appropriate "after" shift file available */
if( defn->last_after_grid == nullptr
|| input.lam < defn->last_after_region.ll_long
|| input.lam > defn->last_after_region.ur_long
|| input.phi < defn->last_after_region.ll_lat
|| input.phi > defn->last_after_region.ll_lat ) {
defn->last_after_grid =
pj_gc_findgrid( defn->ctx, defn->catalog,
1, input, defn->datum_date,
&(defn->last_after_region),
&(defn->last_after_date));
if( defn->last_after_grid == nullptr )
{
pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return PJD_ERR_FAILED_TO_LOAD_GRID;
}
}
gi = defn->last_after_grid;
assert( gi->child == nullptr );
/* load the grid shift info if we don't have it. */
if( gi->ct->cvs == nullptr && !pj_gridinfo_load( defn->ctx, gi ) )
{
pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return PJD_ERR_FAILED_TO_LOAD_GRID;
}
output_after = nad_cvt( defn->ctx, input, inverse, gi->ct, 0, nullptr );
if( output_after.lam == HUGE_VAL )
{
if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR )
{
pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR,
"pj_apply_gridshift(): failed to find a grid shift table for\n"
" location (%.7fdW,%.7fdN)",
x[io] * RAD_TO_DEG,
y[io] * RAD_TO_DEG );
}
continue;
}
if( defn->datum_date == 0.0 )
{
y[io] = output_after.phi;
x[io] = output_after.lam;
continue;
}
/* make sure we have appropriate "before" shift file available */
if( defn->last_before_grid == nullptr
|| input.lam < defn->last_before_region.ll_long
|| input.lam > defn->last_before_region.ur_long
|| input.phi < defn->last_before_region.ll_lat
|| input.phi > defn->last_before_region.ll_lat ) {
defn->last_before_grid =
pj_gc_findgrid( defn->ctx, defn->catalog,
0, input, defn->datum_date,
&(defn->last_before_region),
&(defn->last_before_date));
if( defn->last_before_grid == nullptr )
{
pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return PJD_ERR_FAILED_TO_LOAD_GRID;
}
}
gi = defn->last_before_grid;
assert( gi->child == nullptr );
/* load the grid shift info if we don't have it. */
if( gi->ct->cvs == nullptr && !pj_gridinfo_load( defn->ctx, gi ) )
{
pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return PJD_ERR_FAILED_TO_LOAD_GRID;
}
output_before = nad_cvt( defn->ctx, input, inverse, gi->ct, 0, nullptr );
if( output_before.lam == HUGE_VAL )
{
if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR )
{
pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR,
"pj_apply_gridshift(): failed to find a grid shift table for\n"
" location (%.7fdW,%.7fdN)",
x[io] * RAD_TO_DEG,
y[io] * RAD_TO_DEG );
}
continue;
}
mix_ratio = (defn->datum_date - defn->last_before_date)
/ (defn->last_after_date - defn->last_before_date);
y[io] = mix_ratio * output_after.phi
+ (1.0-mix_ratio) * output_before.phi;
x[io] = mix_ratio * output_after.lam
+ (1.0-mix_ratio) * output_before.lam;
}
return 0;
}
/************************************************************************/
/* pj_c_findgrid() */
/************************************************************************/
static
PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx, PJ_GridCatalog *catalog, int after,
PJ_LP location, double date,
PJ_Region *optional_region,
double *grid_date )
{
int iEntry;
PJ_GridCatalogEntry *entry = nullptr;
for( iEntry = 0; iEntry < catalog->entry_count; iEntry++ )
{
entry = catalog->entries + iEntry;
if( (after && entry->date < date)
|| (!after && entry->date > date) )
continue;
if( location.lam < entry->region.ll_long
|| location.lam > entry->region.ur_long
|| location.phi < entry->region.ll_lat
|| location.phi > entry->region.ur_lat )
continue;
if( entry->available == -1 )
continue;
break;
}
if( entry == nullptr )
{
if( grid_date )
*grid_date = 0.0;
if( optional_region != nullptr )
memset( optional_region, 0, sizeof(PJ_Region));
return nullptr;
}
if( grid_date )
*grid_date = entry->date;
if( optional_region )
{
}
if( entry->gridinfo == nullptr )
{
PJ_GRIDINFO **gridlist = nullptr;
int grid_count = 0;
gridlist = pj_gridlist_from_nadgrids( ctx, entry->definition,
&grid_count);
// FIXME: this leaks gridlist itself, and memory ownership of
// entry->gridinfo is also confusing. Coverity CID 193539
if( grid_count == 1 )
entry->gridinfo = gridlist[0];
}
return entry->gridinfo;
}
-988
View File
@@ -1,988 +0,0 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Functions for handling individual PJ_GRIDINFO's. Includes
* loaders for all formats but CTABLE (in nad_init.c).
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2000, Frank Warmerdam <warmerdam@pobox.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#define PJ_LIB__
#include <errno.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "proj_internal.h"
/************************************************************************/
/* swap_words() */
/* */
/* Convert the byte order of the given word(s) in place. */
/************************************************************************/
static const int byte_order_test = 1;
#define IS_LSB (1 == ((const unsigned char *) (&byte_order_test))[0])
static void swap_words( unsigned char *data, int word_size, int word_count )
{
int word;
for( word = 0; word < word_count; word++ )
{
int i;
for( i = 0; i < word_size/2; i++ )
{
unsigned char t;
t = data[i];
data[i] = data[word_size-i-1];
data[word_size-i-1] = t;
}
data += word_size;
}
}
/************************************************************************/
/* to_double() */
/* */
/* Returns a double from the pointed data. */
/************************************************************************/
static double to_double( unsigned char* data )
{
double d;
memcpy(&d, data, sizeof(d));
return d;
}
/************************************************************************/
/* pj_gridinfo_free() */
/************************************************************************/
void pj_gridinfo_free( projCtx ctx, PJ_GRIDINFO *gi )
{
if( gi == nullptr )
return;
if( gi->child != nullptr )
{
PJ_GRIDINFO *child, *next;
for( child = gi->child; child != nullptr; child=next)
{
next=child->next;
pj_gridinfo_free( ctx, child );
}
}
if( gi->ct != nullptr )
nad_free( gi->ct );
free( gi->gridname );
if( gi->filename != nullptr )
free( gi->filename );
pj_dalloc( gi );
}
/************************************************************************/
/* pj_gridinfo_load() */
/* */
/* This function is intended to implement delayed loading of */
/* the data contents of a grid file. The header and related */
/* stuff are loaded by pj_gridinfo_init(). */
/************************************************************************/
int pj_gridinfo_load( projCtx_t* ctx, PJ_GRIDINFO *gi )
{
struct CTABLE ct_tmp;
if( gi == nullptr || gi->ct == nullptr )
return 0;
pj_acquire_lock();
if( gi->ct->cvs != nullptr )
{
pj_release_lock();
return 1;
}
memcpy(&ct_tmp, gi->ct, sizeof(struct CTABLE));
/* -------------------------------------------------------------------- */
/* Original platform specific CTable format. */
/* -------------------------------------------------------------------- */
if( strcmp(gi->format,"ctable") == 0 )
{
PAFile fid;
int result;
fid = pj_open_lib( ctx, gi->filename, "rb" );
if( fid == nullptr )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
result = nad_ctable_load( ctx, &ct_tmp, (struct projFileAPI_t*)fid );
pj_ctx_fclose( ctx, fid );
gi->ct->cvs = ct_tmp.cvs;
pj_release_lock();
return result;
}
/* -------------------------------------------------------------------- */
/* CTable2 format. */
/* -------------------------------------------------------------------- */
else if( strcmp(gi->format,"ctable2") == 0 )
{
PAFile fid;
int result;
fid = pj_open_lib( ctx, gi->filename, "rb" );
if( fid == nullptr )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
result = nad_ctable2_load( ctx, &ct_tmp, (struct projFileAPI_t*)fid );
pj_ctx_fclose( ctx, fid );
gi->ct->cvs = ct_tmp.cvs;
pj_release_lock();
return result;
}
/* -------------------------------------------------------------------- */
/* NTv1 format. */
/* We process one line at a time. Note that the array storage */
/* direction (e-w) is different in the NTv1 file and what */
/* the CTABLE is supposed to have. The phi/lam are also */
/* reversed, and we have to be aware of byte swapping. */
/* -------------------------------------------------------------------- */
else if( strcmp(gi->format,"ntv1") == 0 )
{
double *row_buf;
int row;
PAFile fid;
fid = pj_open_lib( ctx, gi->filename, "rb" );
if( fid == nullptr )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET );
row_buf = (double *) pj_malloc(gi->ct->lim.lam * sizeof(double) * 2);
ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP));
if( row_buf == nullptr || ct_tmp.cvs == nullptr )
{
pj_dalloc( row_buf );
pj_dalloc( ct_tmp.cvs );
pj_ctx_set_errno( ctx, ENOMEM );
pj_release_lock();
return 0;
}
for( row = 0; row < gi->ct->lim.phi; row++ )
{
int i;
FLP *cvs;
double *diff_seconds;
if( pj_ctx_fread( ctx, row_buf,
sizeof(double), gi->ct->lim.lam * 2, fid )
!= (size_t)( 2 * gi->ct->lim.lam ) )
{
pj_dalloc( row_buf );
pj_dalloc( ct_tmp.cvs );
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
if( IS_LSB )
swap_words( (unsigned char *) row_buf, 8, gi->ct->lim.lam*2 );
/* convert seconds to radians */
diff_seconds = row_buf;
for( i = 0; i < gi->ct->lim.lam; i++ )
{
cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam
+ (gi->ct->lim.lam - i - 1);
cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0));
cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0));
}
}
pj_dalloc( row_buf );
pj_ctx_fclose( ctx, fid );
gi->ct->cvs = ct_tmp.cvs;
pj_release_lock();
return 1;
}
/* -------------------------------------------------------------------- */
/* NTv2 format. */
/* We process one line at a time. Note that the array storage */
/* direction (e-w) is different in the NTv2 file and what */
/* the CTABLE is supposed to have. The phi/lam are also */
/* reversed, and we have to be aware of byte swapping. */
/* -------------------------------------------------------------------- */
else if( strcmp(gi->format,"ntv2") == 0 )
{
float *row_buf;
int row;
PAFile fid;
pj_log( ctx, PJ_LOG_DEBUG_MINOR,
"NTv2 - loading grid %s", gi->ct->id );
fid = pj_open_lib( ctx, gi->filename, "rb" );
if( fid == nullptr )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET );
row_buf = (float *) pj_malloc(gi->ct->lim.lam * sizeof(float) * 4);
ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP));
if( row_buf == nullptr || ct_tmp.cvs == nullptr )
{
pj_dalloc( row_buf );
pj_dalloc( ct_tmp.cvs );
pj_ctx_set_errno( ctx, ENOMEM );
pj_release_lock();
return 0;
}
for( row = 0; row < gi->ct->lim.phi; row++ )
{
int i;
FLP *cvs;
float *diff_seconds;
if( pj_ctx_fread( ctx, row_buf, sizeof(float),
gi->ct->lim.lam*4, fid )
!= (size_t)( 4 * gi->ct->lim.lam ) )
{
pj_dalloc( row_buf );
pj_dalloc( ct_tmp.cvs );
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
if( gi->must_swap )
swap_words( (unsigned char *) row_buf, 4,
gi->ct->lim.lam*4 );
/* convert seconds to radians */
diff_seconds = row_buf;
for( i = 0; i < gi->ct->lim.lam; i++ )
{
cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam
+ (gi->ct->lim.lam - i - 1);
cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0));
cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0));
diff_seconds += 2; /* skip accuracy values */
}
}
pj_dalloc( row_buf );
pj_ctx_fclose( ctx, fid );
gi->ct->cvs = ct_tmp.cvs;
pj_release_lock();
return 1;
}
/* -------------------------------------------------------------------- */
/* GTX format. */
/* -------------------------------------------------------------------- */
else if( strcmp(gi->format,"gtx") == 0 )
{
int words = gi->ct->lim.lam * gi->ct->lim.phi;
PAFile fid;
fid = pj_open_lib( ctx, gi->filename, "rb" );
if( fid == nullptr )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET );
ct_tmp.cvs = (FLP *) pj_malloc(words*sizeof(float));
if( ct_tmp.cvs == nullptr )
{
pj_ctx_set_errno( ctx, ENOMEM );
pj_release_lock();
return 0;
}
if( pj_ctx_fread( ctx, ct_tmp.cvs, sizeof(float), words, fid )
!= (size_t)words )
{
pj_dalloc( ct_tmp.cvs );
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return 0;
}
if( IS_LSB )
swap_words( (unsigned char *) ct_tmp.cvs, 4, words );
pj_ctx_fclose( ctx, fid );
gi->ct->cvs = ct_tmp.cvs;
pj_release_lock();
return 1;
}
else
{
pj_release_lock();
return 0;
}
}
/************************************************************************/
/* gridinfo_parent() */
/* */
/* Seek a parent grid file by name from a grid list */
/************************************************************************/
static PJ_GRIDINFO* gridinfo_parent( PJ_GRIDINFO *gilist,
const char *name, int length )
{
while( gilist )
{
if( strncmp(gilist->ct->id,name,length) == 0 ) return gilist;
if( gilist->child )
{
PJ_GRIDINFO *parent=gridinfo_parent( gilist->child, name, length );
if( parent ) return parent;
}
gilist=gilist->next;
}
return gilist;
}
/************************************************************************/
/* pj_gridinfo_init_ntv2() */
/* */
/* Load a ntv2 (.gsb) file. */
/************************************************************************/
static int pj_gridinfo_init_ntv2( projCtx ctx, PAFile fid, PJ_GRIDINFO *gilist )
{
unsigned char header[11*16];
int num_subfiles, subfile;
int must_swap;
/* cppcheck-suppress sizeofCalculation */
STATIC_ASSERT( sizeof(pj_int32) == 4 );
/* cppcheck-suppress sizeofCalculation */
STATIC_ASSERT( sizeof(double) == 8 );
/* -------------------------------------------------------------------- */
/* Read the overview header. */
/* -------------------------------------------------------------------- */
if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
if( header[8] == 11 )
must_swap = !IS_LSB;
else
must_swap = IS_LSB;
/* -------------------------------------------------------------------- */
/* Byte swap interesting fields if needed. */
/* -------------------------------------------------------------------- */
if( must_swap )
{
swap_words( header+8, 4, 1 );
swap_words( header+8+16, 4, 1 );
swap_words( header+8+32, 4, 1 );
swap_words( header+8+7*16, 8, 1 );
swap_words( header+8+8*16, 8, 1 );
swap_words( header+8+9*16, 8, 1 );
swap_words( header+8+10*16, 8, 1 );
}
/* -------------------------------------------------------------------- */
/* Get the subfile count out ... all we really use for now. */
/* -------------------------------------------------------------------- */
memcpy( &num_subfiles, header+8+32, 4 );
/* ==================================================================== */
/* Step through the subfiles, creating a PJ_GRIDINFO for each. */
/* ==================================================================== */
for( subfile = 0; subfile < num_subfiles; subfile++ )
{
struct CTABLE *ct;
PJ_LP ur;
int gs_count;
PJ_GRIDINFO *gi;
/* -------------------------------------------------------------------- */
/* Read header. */
/* -------------------------------------------------------------------- */
if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
if( strncmp((const char *) header,"SUB_NAME",8) != 0 )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
/* -------------------------------------------------------------------- */
/* Byte swap interesting fields if needed. */
/* -------------------------------------------------------------------- */
if( must_swap )
{
swap_words( header+8+16*4, 8, 1 );
swap_words( header+8+16*5, 8, 1 );
swap_words( header+8+16*6, 8, 1 );
swap_words( header+8+16*7, 8, 1 );
swap_words( header+8+16*8, 8, 1 );
swap_words( header+8+16*9, 8, 1 );
swap_words( header+8+16*10, 4, 1 );
}
/* -------------------------------------------------------------------- */
/* Initialize a corresponding "ct" structure. */
/* -------------------------------------------------------------------- */
ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE));
if (!ct) {
pj_ctx_set_errno(ctx, ENOMEM);
return 0;
}
strncpy( ct->id, (const char *) header + 8, 8 );
ct->id[8] = '\0';
ct->ll.lam = - to_double(header+7*16+8); /* W_LONG */
ct->ll.phi = to_double(header+4*16+8); /* S_LAT */
ur.lam = - to_double(header+6*16+8); /* E_LONG */
ur.phi = to_double(header+5*16+8); /* N_LAT */
ct->del.lam = to_double(header+9*16+8);
ct->del.phi = to_double(header+8*16+8);
ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1;
ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1;
pj_log( ctx, PJ_LOG_DEBUG_MINOR,
"NTv2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)",
ct->id,
ct->lim.lam, ct->lim.phi,
ct->ll.lam/3600.0, ct->ll.phi/3600.0,
ur.lam/3600.0, ur.phi/3600.0 );
ct->ll.lam *= DEG_TO_RAD/3600.0;
ct->ll.phi *= DEG_TO_RAD/3600.0;
ct->del.lam *= DEG_TO_RAD/3600.0;
ct->del.phi *= DEG_TO_RAD/3600.0;
memcpy( &gs_count, header + 8 + 16*10, 4 );
if( gs_count != ct->lim.lam * ct->lim.phi )
{
pj_log( ctx, PJ_LOG_ERROR,
"GS_COUNT(%d) does not match expected cells (%dx%d=%d)",
gs_count, ct->lim.lam, ct->lim.phi,
ct->lim.lam * ct->lim.phi );
pj_dalloc(ct);
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
ct->cvs = nullptr;
/* -------------------------------------------------------------------- */
/* Create a new gridinfo for this if we aren't processing the */
/* 1st subfile, and initialize our grid info. */
/* -------------------------------------------------------------------- */
if( subfile == 0 )
gi = gilist;
else
{
gi = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO));
if (!gi) {
pj_dalloc(ct);
pj_gridinfo_free(ctx, gilist);
pj_ctx_set_errno(ctx, ENOMEM);
return 0;
}
gi->gridname = pj_strdup( gilist->gridname );
gi->filename = pj_strdup( gilist->filename );
if (!gi->gridname || !gi->filename) {
pj_gridinfo_free(ctx, gi);
pj_dalloc(ct);
pj_gridinfo_free(ctx, gilist);
pj_ctx_set_errno(ctx, ENOMEM);
return 0;
}
gi->next = nullptr;
}
gi->must_swap = must_swap;
gi->ct = ct;
gi->format = "ntv2";
gi->grid_offset = pj_ctx_ftell( ctx, fid );
/* -------------------------------------------------------------------- */
/* Attach to the correct list or sublist. */
/* -------------------------------------------------------------------- */
if( strncmp((const char *)header+24,"NONE",4) == 0 )
{
if( gi != gilist )
{
PJ_GRIDINFO *lnk;
for( lnk = gilist; lnk->next != nullptr; lnk = lnk->next ) {}
lnk->next = gi;
}
}
else
{
PJ_GRIDINFO *lnk;
PJ_GRIDINFO *gp = gridinfo_parent(gilist,
(const char*)header+24,8);
if( gp == nullptr )
{
pj_log( ctx, PJ_LOG_ERROR,
"pj_gridinfo_init_ntv2(): "
"failed to find parent %8.8s for %s.",
(const char *) header+24, gi->ct->id );
for( lnk = gilist; lnk->next != nullptr; lnk = lnk->next ) {}
lnk->next = gi;
}
else
{
if( gp->child == nullptr )
{
gp->child = gi;
}
else
{
for( lnk = gp->child; lnk->next != nullptr; lnk = lnk->next ) {}
lnk->next = gi;
}
}
}
/* -------------------------------------------------------------------- */
/* Seek past the data. */
/* -------------------------------------------------------------------- */
pj_ctx_fseek( ctx, fid, gs_count * 16, SEEK_CUR );
}
return 1;
}
/************************************************************************/
/* pj_gridinfo_init_ntv1() */
/* */
/* Load an NTv1 style Canadian grid shift file. */
/************************************************************************/
static int pj_gridinfo_init_ntv1( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi )
{
unsigned char header[192]; /* 12 records of 16 bytes */
struct CTABLE *ct;
PJ_LP ur;
/* cppcheck-suppress sizeofCalculation */
STATIC_ASSERT( sizeof(pj_int32) == 4 );
/* cppcheck-suppress sizeofCalculation */
STATIC_ASSERT( sizeof(double) == 8 );
/* -------------------------------------------------------------------- */
/* Read the header. */
/* -------------------------------------------------------------------- */
if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
/* -------------------------------------------------------------------- */
/* Regularize fields of interest. */
/* -------------------------------------------------------------------- */
if( IS_LSB )
{
swap_words( header+8, 4, 1 );
swap_words( header+24, 8, 1 );
swap_words( header+40, 8, 1 );
swap_words( header+56, 8, 1 );
swap_words( header+72, 8, 1 );
swap_words( header+88, 8, 1 );
swap_words( header+104, 8, 1 );
}
if( *((int *) (header+8)) != 12 )
{
pj_log( ctx, PJ_LOG_ERROR,
"NTv1 grid shift file has wrong record count, corrupt?" );
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
/* -------------------------------------------------------------------- */
/* Fill in CTABLE structure. */
/* -------------------------------------------------------------------- */
ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE));
if (!ct) {
pj_ctx_set_errno(ctx, ENOMEM);
return 0;
}
strcpy( ct->id, "NTv1 Grid Shift File" );
ct->ll.lam = - to_double(header+72);
ct->ll.phi = to_double(header+24);
ur.lam = - to_double(header+56);
ur.phi = to_double(header+40);
ct->del.lam = to_double(header+104);
ct->del.phi = to_double(header+88);
ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1;
ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1;
pj_log( ctx, PJ_LOG_DEBUG_MINOR,
"NTv1 %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)",
ct->lim.lam, ct->lim.phi,
ct->ll.lam, ct->ll.phi, ur.lam, ur.phi );
ct->ll.lam *= DEG_TO_RAD;
ct->ll.phi *= DEG_TO_RAD;
ct->del.lam *= DEG_TO_RAD;
ct->del.phi *= DEG_TO_RAD;
ct->cvs = nullptr;
gi->ct = ct;
gi->grid_offset = (long) sizeof(header);
gi->format = "ntv1";
return 1;
}
/************************************************************************/
/* pj_gridinfo_init_gtx() */
/* */
/* Load a NOAA .gtx vertical datum shift file. */
/************************************************************************/
static int pj_gridinfo_init_gtx( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi )
{
unsigned char header[40];
struct CTABLE *ct;
double xorigin,yorigin,xstep,ystep;
int rows, columns;
/* cppcheck-suppress sizeofCalculation */
STATIC_ASSERT( sizeof(pj_int32) == 4 );
/* cppcheck-suppress sizeofCalculation */
STATIC_ASSERT( sizeof(double) == 8 );
/* -------------------------------------------------------------------- */
/* Read the header. */
/* -------------------------------------------------------------------- */
if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 )
{
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
/* -------------------------------------------------------------------- */
/* Regularize fields of interest and extract. */
/* -------------------------------------------------------------------- */
if( IS_LSB )
{
swap_words( header+0, 8, 4 );
swap_words( header+32, 4, 2 );
}
memcpy( &yorigin, header+0, 8 );
memcpy( &xorigin, header+8, 8 );
memcpy( &ystep, header+16, 8 );
memcpy( &xstep, header+24, 8 );
memcpy( &rows, header+32, 4 );
memcpy( &columns, header+36, 4 );
if( xorigin < -360 || xorigin > 360
|| yorigin < -90 || yorigin > 90 )
{
pj_log( ctx, PJ_LOG_ERROR,
"gtx file header has invalid extents, corrupt?");
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
return 0;
}
/* -------------------------------------------------------------------- */
/* Fill in CTABLE structure. */
/* -------------------------------------------------------------------- */
ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE));
if (!ct) {
pj_ctx_set_errno(ctx, ENOMEM);
return 0;
}
strcpy( ct->id, "GTX Vertical Grid Shift File" );
ct->ll.lam = xorigin;
ct->ll.phi = yorigin;
ct->del.lam = xstep;
ct->del.phi = ystep;
ct->lim.lam = columns;
ct->lim.phi = rows;
/* some GTX files come in 0-360 and we shift them back into the
expected -180 to 180 range if possible. This does not solve
problems with grids spanning the dateline. */
if( ct->ll.lam >= 180.0 )
ct->ll.lam -= 360.0;
if( ct->ll.lam >= 0.0 && ct->ll.lam + ct->del.lam * ct->lim.lam > 180.0 )
{
pj_log( ctx, PJ_LOG_DEBUG_MAJOR,
"This GTX spans the dateline! This will cause problems." );
}
pj_log( ctx, PJ_LOG_DEBUG_MINOR,
"GTX %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)",
ct->lim.lam, ct->lim.phi,
ct->ll.lam, ct->ll.phi,
ct->ll.lam + (columns-1)*xstep, ct->ll.phi + (rows-1)*ystep);
ct->ll.lam *= DEG_TO_RAD;
ct->ll.phi *= DEG_TO_RAD;
ct->del.lam *= DEG_TO_RAD;
ct->del.phi *= DEG_TO_RAD;
ct->cvs = nullptr;
gi->ct = ct;
gi->grid_offset = 40;
gi->format = "gtx";
return 1;
}
/************************************************************************/
/* pj_gridinfo_init() */
/* */
/* Open and parse header details from a datum gridshift file */
/* returning a list of PJ_GRIDINFOs for the grids in that */
/* file. This superceeds use of nad_init() for modern */
/* applications. */
/************************************************************************/
PJ_GRIDINFO *pj_gridinfo_init( projCtx ctx, const char *gridname )
{
PJ_GRIDINFO *gilist;
PAFile fp;
char header[160];
size_t header_size = 0;
errno = pj_errno = 0;
ctx->last_errno = 0;
/* -------------------------------------------------------------------- */
/* Initialize a GRIDINFO with stub info we would use if it */
/* cannot be loaded. */
/* -------------------------------------------------------------------- */
gilist = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO));
if (!gilist) {
pj_ctx_set_errno(ctx, ENOMEM);
return nullptr;
}
gilist->gridname = pj_strdup( gridname );
if (!gilist->gridname) {
pj_dalloc(gilist);
pj_ctx_set_errno(ctx, ENOMEM);
return nullptr;
}
gilist->filename = nullptr;
gilist->format = "missing";
gilist->grid_offset = 0;
gilist->ct = nullptr;
gilist->next = nullptr;
/* -------------------------------------------------------------------- */
/* Open the file using the usual search rules. */
/* -------------------------------------------------------------------- */
if (!(fp = pj_open_lib(ctx, gridname, "rb"))) {
ctx->last_errno = 0; /* don't treat as a persistent error */
return gilist;
}
gilist->filename = pj_strdup(gridname);
if (!gilist->filename) {
pj_dalloc(gilist->gridname);
pj_dalloc(gilist);
pj_ctx_set_errno(ctx, ENOMEM);
return nullptr;
}
/* -------------------------------------------------------------------- */
/* Load a header, to determine the file type. */
/* -------------------------------------------------------------------- */
if( (header_size = pj_ctx_fread( ctx, header, 1,
sizeof(header), fp ) ) != sizeof(header) )
{
/* some files may be smaller that sizeof(header), eg 160, so */
ctx->last_errno = 0; /* don't treat as a persistent error */
pj_log( ctx, PJ_LOG_DEBUG_MAJOR,
"pj_gridinfo_init: short header read of %d bytes",
(int)header_size );
}
pj_ctx_fseek( ctx, fp, SEEK_SET, 0 );
/* -------------------------------------------------------------------- */
/* Determine file type. */
/* -------------------------------------------------------------------- */
if( header_size >= 144 + 16
&& strncmp(header + 0, "HEADER", 6) == 0
&& strncmp(header + 96, "W GRID", 6) == 0
&& strncmp(header + 144, "TO NAD83 ", 16) == 0 )
{
pj_gridinfo_init_ntv1( ctx, fp, gilist );
}
else if( header_size >= 48 + 7
&& strncmp(header + 0, "NUM_OREC", 8) == 0
&& strncmp(header + 48, "GS_TYPE", 7) == 0 )
{
pj_gridinfo_init_ntv2( ctx, fp, gilist );
}
else if( strlen(gridname) > 4
&& (strcmp(gridname+strlen(gridname)-3,"gtx") == 0
|| strcmp(gridname+strlen(gridname)-3,"GTX") == 0) )
{
pj_gridinfo_init_gtx( ctx, fp, gilist );
}
else if( header_size >= 9 && strncmp(header + 0,"CTABLE V2",9) == 0 )
{
struct CTABLE *ct = nad_ctable2_init( ctx, (struct projFileAPI_t*)fp );
gilist->format = "ctable2";
gilist->ct = ct;
if (ct == nullptr)
{
pj_log( ctx, PJ_LOG_DEBUG_MAJOR,
"CTABLE V2 ct is NULL.");
}
else
{
pj_log( ctx, PJ_LOG_DEBUG_MAJOR,
"Ctable2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)",
ct->id,
ct->lim.lam, ct->lim.phi,
ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG,
(ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG,
(ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG );
}
}
else
{
struct CTABLE *ct = nad_ctable_init( ctx, (struct projFileAPI_t*)fp );
if (ct == nullptr)
{
pj_log( ctx, PJ_LOG_DEBUG_MAJOR,
"CTABLE ct is NULL.");
} else
{
gilist->format = "ctable";
gilist->ct = ct;
pj_log( ctx, PJ_LOG_DEBUG_MAJOR,
"Ctable %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)",
ct->id,
ct->lim.lam, ct->lim.phi,
ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG,
(ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG,
(ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG );
}
}
pj_ctx_fclose(ctx, fp);
return gilist;
}
-220
View File
@@ -1,220 +0,0 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Code to manage the list of currently loaded (cached) PJ_GRIDINFOs
* See pj_gridinfo.c for details of loading individual grids.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2000, Frank Warmerdam <warmerdam@pobox.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#define PJ_LIB__
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include "proj.h"
#include "proj_internal.h"
static PJ_GRIDINFO *grid_list = nullptr;
#define PJ_MAX_PATH_LENGTH 1024
/************************************************************************/
/* pj_deallocate_grids() */
/* */
/* Deallocate all loaded grids. */
/************************************************************************/
void pj_deallocate_grids()
{
while( grid_list != nullptr )
{
PJ_GRIDINFO *item = grid_list;
grid_list = grid_list->next;
item->next = nullptr;
pj_gridinfo_free( pj_get_default_ctx(), item );
}
}
/************************************************************************/
/* pj_gridlist_merge_grid() */
/* */
/* Find/load the named gridfile and merge it into the */
/* last_nadgrids_list. */
/************************************************************************/
static int pj_gridlist_merge_gridfile( projCtx ctx,
const char *gridname,
PJ_GRIDINFO ***p_gridlist,
int *p_gridcount,
int *p_gridmax )
{
int got_match=0;
PJ_GRIDINFO *this_grid, *tail = nullptr;
/* -------------------------------------------------------------------- */
/* Try to find in the existing list of loaded grids. Add all */
/* matching grids as with NTv2 we can get many grids from one */
/* file (one shared gridname). */
/* -------------------------------------------------------------------- */
for( this_grid = grid_list; this_grid != nullptr; this_grid = this_grid->next)
{
if( strcmp(this_grid->gridname,gridname) == 0 )
{
got_match = 1;
/* don't add to the list if it is invalid. */
if( this_grid->ct == nullptr )
return 0;
/* do we need to grow the list? */
if( *p_gridcount >= *p_gridmax - 2 )
{
PJ_GRIDINFO **new_list;
int new_max = *p_gridmax + 20;
new_list = (PJ_GRIDINFO **) pj_calloc(new_max, sizeof(void *));
if (!new_list) {
pj_ctx_set_errno( ctx, ENOMEM );
return 0;
}
if( *p_gridlist != nullptr )
{
memcpy( new_list, *p_gridlist,
sizeof(void *) * (*p_gridmax) );
pj_dalloc( *p_gridlist );
}
*p_gridlist = new_list;
*p_gridmax = new_max;
}
/* add to the list */
(*p_gridlist)[(*p_gridcount)++] = this_grid;
(*p_gridlist)[*p_gridcount] = nullptr;
}
tail = this_grid;
}
if( got_match )
return 1;
/* -------------------------------------------------------------------- */
/* Try to load the named grid. */
/* -------------------------------------------------------------------- */
this_grid = pj_gridinfo_init( ctx, gridname );
if( this_grid == nullptr )
{
return 0;
}
if( tail != nullptr )
tail->next = this_grid;
else
grid_list = this_grid;
/* -------------------------------------------------------------------- */
/* Recurse to add the grid now that it is loaded. */
/* -------------------------------------------------------------------- */
return pj_gridlist_merge_gridfile( ctx, gridname, p_gridlist,
p_gridcount, p_gridmax );
}
/************************************************************************/
/* pj_gridlist_from_nadgrids() */
/* */
/* This functions loads the list of grids corresponding to a */
/* particular nadgrids string into a list, and returns it. The */
/* list is kept around till a request is made with a different */
/* string in order to cut down on the string parsing cost, and */
/* the cost of building the list of tables each time. */
/************************************************************************/
PJ_GRIDINFO **pj_gridlist_from_nadgrids( projCtx ctx, const char *nadgrids,
int *grid_count)
{
const char *s;
PJ_GRIDINFO **gridlist = nullptr;
int grid_max = 0;
pj_errno = 0;
*grid_count = 0;
pj_acquire_lock();
/* -------------------------------------------------------------------- */
/* Loop processing names out of nadgrids one at a time. */
/* -------------------------------------------------------------------- */
for( s = nadgrids; *s != '\0'; )
{
size_t end_char;
int required = 1;
char name[PJ_MAX_PATH_LENGTH];
if( *s == '@' )
{
required = 0;
s++;
}
for( end_char = 0;
s[end_char] != '\0' && s[end_char] != ',';
end_char++ ) {}
if( end_char >= sizeof(name) )
{
pj_dalloc( gridlist );
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return nullptr;
}
strncpy( name, s, end_char );
name[end_char] = '\0';
s += end_char;
if( *s == ',' )
s++;
if( !pj_gridlist_merge_gridfile( ctx, name, &gridlist, grid_count,
&grid_max)
&& required )
{
pj_dalloc( gridlist );
pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID );
pj_release_lock();
return nullptr;
}
else
pj_errno = 0;
}
pj_release_lock();
return gridlist;
}

Some files were not shown because too many files have changed in this diff Show More