diff --git a/.github/workflows/android_cmake.yml b/.github/workflows/android_cmake.yml index d81b50ff90dd..0200112eeaf1 100644 --- a/.github/workflows/android_cmake.yml +++ b/.github/workflows/android_cmake.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Cache uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 diff --git a/.github/workflows/clang_static_analyzer.yml b/.github/workflows/clang_static_analyzer.yml index f1cddfbfb00f..452a8cd3c392 100644 --- a/.github/workflows/clang_static_analyzer.yml +++ b/.github/workflows/clang_static_analyzer.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Run run: docker run --rm -v $PWD:$PWD ubuntu:22.04 sh -c "cd $PWD && apt update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends sudo software-properties-common && DEBIAN_FRONTEND=noninteractive sh ./ci/travis/csa_common/before_install.sh && sh ./ci/travis/csa_common/install.sh && sh ./ci/travis/csa_common/script.sh" diff --git a/.github/workflows/cmake_builds.yml b/.github/workflows/cmake_builds.yml index 825ec91eaa3a..cb32503760f0 100644 --- a/.github/workflows/cmake_builds.yml +++ b/.github/workflows/cmake_builds.yml @@ -9,6 +9,7 @@ on: branches-ignore: - 'backport**' - 'dependabot**' + - 'i18n**' pull_request: paths-ignore: - 'doc/**' @@ -32,7 +33,7 @@ jobs: cache-name: cmake-ubuntu-focal steps: - name: Checkout GDAL - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup cache uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 id: cache @@ -312,7 +313,7 @@ jobs: run: | git config --global core.autocrlf false - name: Checkout GDAL - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install development packages uses: msys2/setup-msys2@d0e80f58dffbc64f6a3a1f43527d469b4fc7b6c8 # v2.23.0 with: @@ -405,7 +406,7 @@ jobs: run: | git config --global core.autocrlf false - name: Checkout GDAL - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - name: populate JAVA_HOME shell: pwsh @@ -466,30 +467,25 @@ jobs: shell: bash -l {0} run: | cmake --build $GITHUB_WORKSPACE/build --config Release --target quicktest - # FIXME !! Disabled because of actions/runner-images#10004 - #- name: test (with ctest) - # shell: bash -l {0} - # run: | - # ctest --test-dir $GITHUB_WORKSPACE/build -C Release -V -j 3 - # env: - # SKIP_OGR_GMLAS_HUGE_PROCESSING_TIME: YES - # SKIP_OGR_GMLAS_HTTP_RELATED: YES - # SKIP_GDAL_HTTP_SSL_VERIFYSTATUS: YES - # BUILD_NAME: "build-windows-conda" + - name: test (with ctest) + shell: bash -l {0} + run: | + ctest --test-dir $GITHUB_WORKSPACE/build -C Release -V -j 3 + env: + SKIP_OGR_GMLAS_HUGE_PROCESSING_TIME: YES + SKIP_OGR_GMLAS_HTTP_RELATED: YES + SKIP_GDAL_HTTP_SSL_VERIFYSTATUS: YES + BUILD_NAME: "build-windows-conda" - name: Install shell: bash -l {0} run: | cmake --build $GITHUB_WORKSPACE/build --config Release --target install - # FIXME !! Disabled because of actions/runner-images#10004 - #- name: Test install - # shell: bash -l {0} - # run: | - # export PATH=$GITHUB_WORKSPACE/install-gdal/bin:$PATH - # gdalinfo --version - # python -VV - # PYTHONPATH=$GITHUB_WORKSPACE/install-gdal/lib/site-packages python -c "from osgeo import gdal;print(gdal.VersionInfo(None))" - # export PATH=$GITHUB_WORKSPACE/install-gdal/Scripts:$PATH - # PYTHONPATH=$GITHUB_WORKSPACE/install-gdal/lib/site-packages gdal_edit --version + export PATH=$GITHUB_WORKSPACE/install-gdal/bin:$PATH + gdalinfo --version + python -VV + PYTHONPATH=$GITHUB_WORKSPACE/install-gdal/lib/site-packages python -c "from osgeo import gdal;print(gdal.VersionInfo(None))" + export PATH=$GITHUB_WORKSPACE/install-gdal/Scripts:$PATH + PYTHONPATH=$GITHUB_WORKSPACE/install-gdal/lib/site-packages gdal_edit --version - name: Show gdal.pc shell: bash -l {0} run: cat $GITHUB_WORKSPACE/build/gdal.pc @@ -512,7 +508,7 @@ jobs: run: | git config --global core.autocrlf false - name: Checkout GDAL - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4 with: activate-environment: gdalenv @@ -589,7 +585,7 @@ jobs: with: xcode-version: 14.3 - name: Checkout GDAL - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup cache uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 id: cache @@ -669,7 +665,7 @@ jobs: run: | git config --global core.autocrlf false - name: Checkout GDAL - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4 with: activate-environment: gdalenv diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml index 321cd50a897e..b8b80337434e 100644 --- a/.github/workflows/code_checks.yml +++ b/.github/workflows/code_checks.yml @@ -7,6 +7,7 @@ on: branches-ignore: - 'backport**' - 'dependabot**' + - 'i18n**' pull_request: paths-ignore: - 'doc/**' @@ -24,7 +25,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install Requirements run: | @@ -47,7 +48,7 @@ jobs: container: ubuntu:24.04 steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install Requirements run: | @@ -69,7 +70,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Detect tabulations run: ./scripts/detect_tabulations.sh @@ -104,7 +105,7 @@ jobs: linting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 @@ -113,7 +114,7 @@ jobs: container: ghcr.io/osgeo/proj-docs steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Run doxygen run: | @@ -124,7 +125,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install Requirements run: | @@ -143,7 +144,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Python uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: @@ -159,7 +160,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install requirements run: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bdac6681fb81..f492c7c9cb0c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -44,7 +44,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install dependencies run: | @@ -107,7 +107,7 @@ jobs: # We do that after running CMake to avoid CodeQL to trigger during CMake time, # in particular during HDF5 detection which is terribly slow (https://github.com/OSGeo/gdal/issues/9549) - name: Initialize CodeQL - uses: github/codeql-action/init@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7 + uses: github/codeql-action/init@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -127,6 +127,6 @@ jobs: cmake --build build -j$(nproc) - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7 + uses: github/codeql-action/analyze@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index eaba06ddd159..fdb2624f3949 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -37,7 +37,7 @@ jobs: CACHE_NUMBER: 0 steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Support longpaths run: git config --system core.longpaths true diff --git a/.github/workflows/coverity_scan.yml b/.github/workflows/coverity_scan.yml index 7b560539f657..746b7864a198 100644 --- a/.github/workflows/coverity_scan.yml +++ b/.github/workflows/coverity_scan.yml @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Login to GHCR if: env.CONTAINER_REGISTRY == 'ghcr.io' diff --git a/.github/workflows/doc_build.yml b/.github/workflows/doc_build.yml index ee75f953b0c0..91f6db8b444b 100644 --- a/.github/workflows/doc_build.yml +++ b/.github/workflows/doc_build.yml @@ -24,7 +24,7 @@ jobs: container: ghcr.io/osgeo/proj-docs steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup environment shell: bash -l {0} run: | diff --git a/.github/workflows/linux_build.yml b/.github/workflows/linux_build.yml index 1ec856e4e5c5..ef1eb6501999 100644 --- a/.github/workflows/linux_build.yml +++ b/.github/workflows/linux_build.yml @@ -174,7 +174,7 @@ jobs: sudo sysctl vm.mmap_rnd_bits=28 - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Login to Docker Hub if: env.CONTAINER_REGISTRY == 'docker.io' diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 715058dfc41a..c9f17e32971d 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -7,6 +7,7 @@ on: branches-ignore: - 'backport**' - 'dependabot**' + - 'i18n**' pull_request: paths-ignore: - 'doc/**' @@ -25,7 +26,7 @@ jobs: runs-on: macos-14 steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4 with: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index d5727d248b87..425bc372a745 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -36,7 +36,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7 + uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 with: sarif_file: results.sarif diff --git a/.github/workflows/slow_tests.yml b/.github/workflows/slow_tests.yml index c7fc3b084495..f7cec9357de0 100644 --- a/.github/workflows/slow_tests.yml +++ b/.github/workflows/slow_tests.yml @@ -47,7 +47,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Login to GHCR if: env.CONTAINER_REGISTRY == 'ghcr.io' diff --git a/.github/workflows/ubuntu_20.04/Dockerfile.ci b/.github/workflows/ubuntu_20.04/Dockerfile.ci index 50aa2c17d8a5..89424ca0a80e 100644 --- a/.github/workflows/ubuntu_20.04/Dockerfile.ci +++ b/.github/workflows/ubuntu_20.04/Dockerfile.ci @@ -37,6 +37,7 @@ RUN apt-get update -y \ libfreexl-dev \ libfyba-dev \ libgeos-dev \ + libgeotiff-dev \ libgif-dev \ libhdf4-alt-dev \ libhdf5-serial-dev \ @@ -75,7 +76,7 @@ RUN apt-get update -y \ numactl \ ocl-icd-opencl-dev \ opencl-c-headers \ - openjdk-8-jdk \ + openjdk-8-jdk-headless \ pkg-config \ python3-dev \ python3-numpy \ diff --git a/.github/workflows/ubuntu_20.04/build.sh b/.github/workflows/ubuntu_20.04/build.sh index 510a463b79cf..e2a8cdde3517 100755 --- a/.github/workflows/ubuntu_20.04/build.sh +++ b/.github/workflows/ubuntu_20.04/build.sh @@ -5,12 +5,12 @@ set -eu export CXXFLAGS="-march=native -O2 -Wodr -flto-odr-type-merging -Werror" export CFLAGS="-O2 -march=native -Werror" -cmake ${GDAL_SOURCE_DIR:=..} \ +cmake "${GDAL_SOURCE_DIR:=..}" \ -DUSE_CCACHE=ON \ -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DGDAL_USE_TIFF_INTERNAL=ON \ - -DGDAL_USE_GEOTIFF_INTERNAL=ON \ + -DCMAKE_INSTALL_PREFIX=/tmp/install-gdal \ + -DGDAL_USE_TIFF_INTERNAL=OFF \ + -DGDAL_USE_GEOTIFF_INTERNAL=OFF \ -DECW_ROOT=/opt/libecwj2-3.3 \ -DMRSID_ROOT=/usr/local \ -DFileGDB_ROOT=/usr/local/FileGDB_API \ @@ -20,5 +20,25 @@ cmake ${GDAL_SOURCE_DIR:=..} \ unset CXXFLAGS unset CFLAGS -make -j$(nproc) -make -j$(nproc) install DESTDIR=/tmp/install-gdal +make "-j$(nproc)" +make "-j$(nproc)" install + +# Test building MrSID driver in standalone mode +mkdir build_mrsid +cd build_mrsid +cmake -S ${GDAL_SOURCE_DIR:=..}/frmts/mrsid -DMRSID_ROOT=/usr/local -DCMAKE_PREFIX_PATH=/tmp/install-gdal +cmake --build . "-j$(nproc)" +test -f gdal_MrSID.so +cd .. + +# Test building OCI driver in standalone mode +mkdir build_oci +cd build_oci +wget https://download.oracle.com/otn_software/linux/instantclient/1923000/instantclient-basic-linux.x64-19.23.0.0.0dbru.zip +wget https://download.oracle.com/otn_software/linux/instantclient/1923000/instantclient-sdk-linux.x64-19.23.0.0.0dbru.zip +unzip -o instantclient-basic-linux.x64-19.23.0.0.0dbru.zip +unzip -o instantclient-sdk-linux.x64-19.23.0.0.0dbru.zip +cmake -S "${GDAL_SOURCE_DIR:=..}/ogr/ogrsf_frmts/oci" "-DOracle_ROOT=$PWD/instantclient_19_23" -DCMAKE_PREFIX_PATH=/tmp/install-gdal +cmake --build . "-j$(nproc)" +test -f ogr_OCI.so +cd .. diff --git a/.github/workflows/ubuntu_22.04/Dockerfile.ci b/.github/workflows/ubuntu_22.04/Dockerfile.ci index 84d95dbe3c60..711cb293cf15 100644 --- a/.github/workflows/ubuntu_22.04/Dockerfile.ci +++ b/.github/workflows/ubuntu_22.04/Dockerfile.ci @@ -58,7 +58,7 @@ RUN apt-get update && \ locales \ mysql-client-core-8.0 \ netcdf-bin \ - openjdk-8-jdk \ + openjdk-8-jdk-headless \ poppler-utils \ postgis \ postgresql-client \ @@ -104,7 +104,7 @@ RUN mkdir mongocxx \ && make install \ && cd ../.. \ && rm -rf mongocxx - + # Build libOpenDRIVE ARG OPENDRIVE_VERSION=0.5.0-gdal RUN if test "${OPENDRIVE_VERSION}" != ""; then ( \ diff --git a/.github/workflows/ubuntu_24.04/Dockerfile.ci b/.github/workflows/ubuntu_24.04/Dockerfile.ci index 9de48391106c..b9465fc6c8fb 100644 --- a/.github/workflows/ubuntu_24.04/Dockerfile.ci +++ b/.github/workflows/ubuntu_24.04/Dockerfile.ci @@ -59,7 +59,7 @@ RUN apt-get update && \ locales \ mysql-client-core-8.0 \ netcdf-bin \ - openjdk-8-jdk \ + openjdk-8-jdk-headless \ poppler-utils \ postgis \ postgresql-client \ diff --git a/.github/workflows/windows_build.yml b/.github/workflows/windows_build.yml index a75a70f5878c..475510c9fedf 100644 --- a/.github/workflows/windows_build.yml +++ b/.github/workflows/windows_build.yml @@ -56,7 +56,7 @@ jobs: git config --global core.autocrlf false - name: Checkout - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set environment shell: pwsh diff --git a/CMakeLists.txt b/CMakeLists.txt index f6f81c1c929d..32b0011b45d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,24 +35,8 @@ define_property( PROPERTY PLUGIN_OUTPUT_DIR BRIEF_DOCS "Plugin modules build directories" FULL_DOCS "Plugin modules build directories") -# -# check compiler and set preferences. -if (NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) - set(CMAKE_CXX_STANDARD_REQUIRED ON) -endif() - -if (NOT CMAKE_C_STANDARD) - set(CMAKE_C_STANDARD 99) - set(CMAKE_C_STANDARD_REQUIRED ON) -endif() -# -if (MSVC) - add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) - add_definitions(-DNOMINMAX) -endif () -# +include(GdalCAndCXXStandards) include(CheckCompilerMachineOption) include(CheckCompilerSIMDFeature) include(Ccache) diff --git a/alg/gdalchecksum.cpp b/alg/gdalchecksum.cpp index e0f0dcafacf8..e1f5e38f1b1d 100644 --- a/alg/gdalchecksum.cpp +++ b/alg/gdalchecksum.cpp @@ -80,12 +80,9 @@ int CPL_STDCALL GDALChecksumImage(GDALRasterBandH hBand, int nXOff, int nYOff, const auto IntFromDouble = [](double dfVal) { int nVal; - if (CPLIsNan(dfVal) || CPLIsInf(dfVal)) + if (!std::isfinite(dfVal)) { - // Most compilers seem to cast NaN or Inf to 0x80000000. - // but VC7 is an exception. So we force the result - // of such a cast. - nVal = 0x80000000; + nVal = INT_MIN; } else { @@ -371,5 +368,6 @@ int CPL_STDCALL GDALChecksumImage(GDALRasterBandH hBand, int nXOff, int nYOff, CPLFree(panLineData); } + // coverity[return_overflow] return nChecksum; } diff --git a/alg/gdalrasterize.cpp b/alg/gdalrasterize.cpp index 16be0bac7c55..6aa6efc998e3 100644 --- a/alg/gdalrasterize.cpp +++ b/alg/gdalrasterize.cpp @@ -1559,11 +1559,8 @@ CPLErr GDALRasterizeLayers(GDALDatasetH hDS, int nBandCount, int *panBandList, if (!(pszYChunkSize && ((nYChunkSize = atoi(pszYChunkSize))) != 0)) { const GIntBig nYChunkSize64 = GDALGetCacheMax64() / nScanlineBytes; - const int knIntMax = std::numeric_limits::max(); - if (nYChunkSize64 > knIntMax) - nYChunkSize = knIntMax; - else - nYChunkSize = static_cast(nYChunkSize64); + nYChunkSize = static_cast( + std::min(nYChunkSize64, std::numeric_limits::max())); } if (nYChunkSize < 1) diff --git a/alg/gdalwarpkernel.cpp b/alg/gdalwarpkernel.cpp index 98b1555c4a1b..51361a45d12c 100644 --- a/alg/gdalwarpkernel.cpp +++ b/alg/gdalwarpkernel.cpp @@ -513,6 +513,7 @@ static CPLErr GWKRun(GDALWarpKernel *poWK, const char *pszFuncName, job.pfnFunc = pfnFunc; } + bool bStopFlag; { std::unique_lock lock(psThreadData->mutex); @@ -550,6 +551,8 @@ static CPLErr GWKRun(GDALWarpKernel *poWK, const char *pszFuncName, } } } + + bStopFlag = psThreadData->stopFlag; } /* -------------------------------------------------------------------- */ @@ -557,7 +560,7 @@ static CPLErr GWKRun(GDALWarpKernel *poWK, const char *pszFuncName, /* -------------------------------------------------------------------- */ psThreadData->poJobQueue->WaitCompletion(); - return psThreadData->stopFlag ? CE_Failure : CE_None; + return bStopFlag ? CE_Failure : CE_None; } /************************************************************************/ diff --git a/alg/internal_libqhull/poly_r.c b/alg/internal_libqhull/poly_r.c index c68596a12bf9..b7e09b54fc8d 100644 --- a/alg/internal_libqhull/poly_r.c +++ b/alg/internal_libqhull/poly_r.c @@ -1137,10 +1137,13 @@ ridgeT *qh_newridge(qhT *qh) { qh_memalloc_(qh, (int)sizeof(ridgeT), freelistp, ridge, ridgeT); memset((char *)ridge, (size_t)0, sizeof(ridgeT)); zinc_(Ztotridges); + ridge->id= qh->ridge_id; if (qh->ridge_id == UINT_MAX) { qh_fprintf(qh, qh->ferr, 7074, "qhull warning: more than 2^32 ridges. Qhull results are OK. Since the ridge ID wraps around to 0, two ridges may have the same identifier.\n"); + qh->ridge_id = 0; + } else { + qh->ridge_id++; } - ridge->id= qh->ridge_id++; trace4((qh, qh->ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id)); return(ridge); } /* newridge */ @@ -1176,10 +1179,14 @@ int qh_pointid(qhT *qh, pointT *point) { offset= (ptr_intT)(point - qh->first_point); /* coverity[divide_arg] */ id= offset / qh->hull_dim; - }else if ((id= qh_setindex(qh->other_points, point)) != -1) - id += qh->num_points; - else - return qh_IDunknown; + } else { + id = qh_setindex(qh->other_points, point); + if (id >= 0) { + id += qh->num_points; + } else { + return qh_IDunknown; + } + } return (int)id; } /* pointid */ diff --git a/alg/viewshed.cpp b/alg/viewshed.cpp index 18af2999a9eb..6fb84ad6f736 100644 --- a/alg/viewshed.cpp +++ b/alg/viewshed.cpp @@ -282,19 +282,9 @@ bool Viewshed::calcOutputExtent(int nX, int nY) oOutExtent.xStop = GDALGetRasterBandXSize(pSrcBand); oOutExtent.yStop = GDALGetRasterBandYSize(pSrcBand); - if (!oOutExtent.containsY(nY)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Observer position above or below the raster " - "not currently supported"); - return false; - } if (!oOutExtent.contains(nX, nY)) - { CPLError(CE_Warning, CPLE_AppDefined, "NOTE: The observer location falls outside of the DEM area"); - //ABELL - Make sure observer Z is specified. - } constexpr double EPSILON = 1e-8; if (oOpts.maxDistance > 0) @@ -419,7 +409,8 @@ bool Viewshed::emitProgress(double fraction) /// @param nX X location of the observer. /// @param vThisLineVal Line height data. /// @return [left, right) Leftmost and one past the rightmost cell in the line within -/// the max distance +/// the max distance. Indices are limited to the raster extent (right may be just +/// outside the raster). std::pair Viewshed::adjustHeight(int nYOffset, int nX, std::vector &vThisLineVal) { @@ -799,15 +790,15 @@ void Viewshed::setOutput(double &dfResult, double &dfCellVal, double dfZ) /// /// @param nX X location of the observer /// @param nY Y location of the observer -/// @param nLine Line number being processed (should always be the same as nY) /// @param vLastLineVal Vector in which to store the read line. Becomes the last line /// in further processing. /// @return True on success, false otherwise. -bool Viewshed::processFirstLine(int nX, int nY, int nLine, +bool Viewshed::processFirstLine(int nX, int nY, std::vector &vLastLineVal) { + int nLine = oOutExtent.clampY(nY); int nYOffset = nLine - nY; - assert(nYOffset == 0); + std::vector vResult(oOutExtent.xSize()); std::vector vThisLineVal(oOutExtent.xSize()); @@ -832,21 +823,30 @@ bool Viewshed::processFirstLine(int nX, int nY, int nLine, // iLeft and iRight are the processing limits for the line. const auto [iLeft, iRight] = adjustHeight(nYOffset, nX, vThisLineVal); - auto t1 = std::async( - std::launch::async, [&, left = iLeft]() - { processFirstLineLeft(nX, nX - 1, left - 1, vResult, vThisLineVal); }); - - auto t2 = std::async( - std::launch::async, [&, right = iRight]() - { processFirstLineRight(nX, nX + 1, right, vResult, vThisLineVal); }); - t1.wait(); - t2.wait(); + if (!oCurExtent.containsY(nY)) + processFirstLineTopOrBottom(iLeft, iRight, vResult, vThisLineVal); + else + { + auto t1 = std::async(std::launch::async, + [&, left = iLeft]() { + processFirstLineLeft(nX, nX - 1, left - 1, + vResult, vThisLineVal); + }); + + auto t2 = std::async(std::launch::async, + [&, right = iRight]() { + processFirstLineRight(nX, nX + 1, right, + vResult, vThisLineVal); + }); + t1.wait(); + t2.wait(); + } // Make the current line the last line. vLastLineVal = std::move(vThisLineVal); // Create the output writer. - if (!writeLine(nY, vResult)) + if (!writeLine(nLine, vResult)) return false; if (!lineProgress()) @@ -854,6 +854,30 @@ bool Viewshed::processFirstLine(int nX, int nY, int nLine, return true; } +// If the observer is above or below the raster, set all cells in the first line near the +// observer as observable provided they're in range. Mark cells out of range as such. +/// @param iLeft Leftmost observable raster position in range of the target line. +/// @param iRight One past the rightmost observable raster position of the target line. +/// @param vResult Result line. +/// @param vThisLineVal Heights of the cells in the target line +void Viewshed::processFirstLineTopOrBottom(int iLeft, int iRight, + std::vector &vResult, + std::vector &vThisLineVal) +{ + double *pResult = vResult.data() + iLeft; + double *pThis = vThisLineVal.data() + iLeft; + for (int iPixel = iLeft; iPixel < iRight; ++iPixel, ++pResult, pThis++) + { + if (oOpts.outputMode == OutputMode::Normal) + *pResult = oOpts.visibleVal; + else + setOutput(*pResult, *pThis, *pThis); + } + std::fill(vResult.begin(), vResult.begin() + iLeft, oOpts.outOfRangeVal); + std::fill(vResult.begin() + iRight, vResult.begin() + oCurExtent.xStop, + oOpts.outOfRangeVal); +} + /// Process a line above or below the observer. /// /// @param nX X location of the observer @@ -989,7 +1013,7 @@ bool Viewshed::run(GDALRasterBandH band, GDALProgressFunc pfnProgress, std::vector vFirstLineVal(oCurExtent.xSize()); - if (!processFirstLine(nX, nY, nY, vFirstLineVal)) + if (!processFirstLine(nX, nY, vFirstLineVal)) return false; if (oOpts.cellMode == CellMode::Edge) @@ -1002,29 +1026,31 @@ bool Viewshed::run(GDALRasterBandH band, GDALProgressFunc pfnProgress, oZcalc = doMax; // scan upwards + int yStart = oCurExtent.clampY(nY); std::atomic err(false); auto tUp = std::async(std::launch::async, [&]() { std::vector vLastLineVal = vFirstLineVal; - for (int nLine = nY - 1; + for (int nLine = yStart - 1; nLine >= oCurExtent.yStart && !err; nLine--) if (!processLine(nX, nY, nLine, vLastLineVal)) err = true; }); // scan downwards - auto tDown = std::async( - std::launch::async, - [&]() - { - std::vector vLastLineVal = vFirstLineVal; + auto tDown = + std::async(std::launch::async, + [&]() + { + std::vector vLastLineVal = vFirstLineVal; - for (int nLine = nY + 1; nLine < oCurExtent.yStop && !err; nLine++) - if (!processLine(nX, nY, nLine, vLastLineVal)) - err = true; - }); + for (int nLine = yStart + 1; + nLine < oCurExtent.yStop && !err; nLine++) + if (!processLine(nX, nY, nLine, vLastLineVal)) + err = true; + }); tUp.wait(); tDown.wait(); diff --git a/alg/viewshed.h b/alg/viewshed.h index 349ccc8e6ba3..13a1ab558091 100644 --- a/alg/viewshed.h +++ b/alg/viewshed.h @@ -132,6 +132,14 @@ class Viewshed return xSize() ? std::clamp(nX, xStart, xStop - 1) : xStart; } + /// \brief Clamp the argument to be in the window in the Y dimension. + /// \param nY Value to clamp. + /// \return Clamped value. + int clampY(int nY) const + { + return ySize() ? std::clamp(nY, yStart, yStop - 1) : yStart; + } + /// \brief Shift the X dimension by nShift. /// \param nShift Amount to shift void shiftX(int nShift) @@ -225,14 +233,16 @@ class Viewshed bool writeLine(int nLine, std::vector &vResult); bool processLine(int nX, int nY, int nLine, std::vector &vLastLineVal); - bool processFirstLine(int nX, int nY, int nLine, - std::vector &vLastLineVal); + bool processFirstLine(int nX, int nY, std::vector &vLastLineVal); void processFirstLineLeft(int nX, int iStart, int iEnd, std::vector &vResult, std::vector &vThisLineVal); void processFirstLineRight(int nX, int iStart, int iEnd, std::vector &vResult, std::vector &vThisLineVal); + void processFirstLineTopOrBottom(int iLeft, int iRight, + std::vector &vResult, + std::vector &vThisLineVal); void processLineLeft(int nX, int nYOffset, int iStart, int iEnd, std::vector &vResult, std::vector &vThisLineVal, diff --git a/apps/argparse/argparse.hpp b/apps/argparse/argparse.hpp index a29c120e00ab..a52142848192 100644 --- a/apps/argparse/argparse.hpp +++ b/apps/argparse/argparse.hpp @@ -1411,6 +1411,10 @@ class Argument { * '+' '-' */ static bool is_decimal_literal(std::string_view s) { + if (s == "inf") { + return true; + } + auto is_digit = [](auto c) constexpr { switch (c) { case '0': @@ -2041,8 +2045,10 @@ class ArgumentParser { } stream << std::setw(2) << " "; - stream << std::setw(static_cast(longest_arg_length - 2)) - << command; + if (longest_arg_length >= 2) { + stream << std::setw(static_cast(longest_arg_length - 2)) + << command; + } stream << " " << subparser->get().m_description << "\n"; } } diff --git a/apps/data/gdalinfo_output.schema.json b/apps/data/gdalinfo_output.schema.json index 166a490d9e26..a4c50c780e66 100644 --- a/apps/data/gdalinfo_output.schema.json +++ b/apps/data/gdalinfo_output.schema.json @@ -277,7 +277,7 @@ }, "stac": { - "$comment": "Derived from https://raw.githubusercontent.com/stac-extensions/projection/main/json-schema/schema.json#/definitions/fields, https://raw.githubusercontent.com/stac-extensions/eo/main/json-schema/schema.json#/definitions/bands and https://raw.githubusercontent.com/stac-extensions/eo/main/json-schema/schema.json#/definitions/bands", + "$comment": "Derived from https://raw.githubusercontent.com/stac-extensions/projection/main/json-schema/schema.json#/definitions/fields, https://raw.githubusercontent.com/stac-extensions/eo/v1.1.0/json-schema/schema.json#/definitions/bands and https://raw.githubusercontent.com/stac-extensions/eo/v1.1.0/json-schema/schema.json#/definitions/bands", "type": "object", "properties": { "proj:epsg": { @@ -334,10 +334,10 @@ } }, "eo:bands": { - "$ref": "https://raw.githubusercontent.com/stac-extensions/eo/main/json-schema/schema.json#/definitions/bands" + "$ref": "https://raw.githubusercontent.com/stac-extensions/eo/v1.1.0/json-schema/schema.json#/definitions/bands" }, "raster:bands": { - "$ref": "https://raw.githubusercontent.com/stac-extensions/eo/main/json-schema/schema.json#/definitions/bands" + "$ref": "https://raw.githubusercontent.com/stac-extensions/eo/v1.1.0/json-schema/schema.json#/definitions/bands" } }, "additionalProperties": false diff --git a/apps/gdal_rasterize_lib.cpp b/apps/gdal_rasterize_lib.cpp index 39913ad306cb..493922ee1068 100644 --- a/apps/gdal_rasterize_lib.cpp +++ b/apps/gdal_rasterize_lib.cpp @@ -482,7 +482,7 @@ static GDALDatasetH CreateOutputDataset( OGREnvelope sEnvelop, GDALDriverH hDriver, const char *pszDest, int nXSize, int nYSize, double dfXRes, double dfYRes, bool bTargetAlignedPixels, int nBandCount, GDALDataType eOutputType, char **papszCreationOptions, - const std::vector &adfInitVals, int bNoDataSet, double dfNoData) + const std::vector &adfInitVals, const char *pszNoData) { bool bFirstLayer = true; char *pszWKT = nullptr; @@ -598,12 +598,16 @@ static GDALDatasetH CreateOutputDataset( } }*/ - if (bNoDataSet) + if (pszNoData) { for (int iBand = 0; iBand < nBandCount; iBand++) { GDALRasterBandH hBand = GDALGetRasterBand(hDstDS, iBand + 1); - GDALSetRasterNoDataValue(hBand, dfNoData); + if (GDALGetRasterDataType(hBand) == GDT_Int64) + GDALSetRasterNoDataValueAsInt64(hBand, + CPLAtoGIntBig(pszNoData)); + else + GDALSetRasterNoDataValue(hBand, CPLAtof(pszNoData)); } } @@ -649,8 +653,7 @@ struct GDALRasterizeOptions char **papszCreationOptions; GDALDataType eOutputType; std::vector adfInitVals; - int bNoDataSet; - double dfNoData; + char *pszNoData; OGREnvelope sEnvelop; int nXSize, nYSize; OGRSpatialReferenceH hSRS; @@ -790,6 +793,36 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS, } } + const auto GetOutputDataType = [&](OGRLayerH hLayer) + { + CPLAssert(bCreateOutput); + CPLAssert(hDriver); + GDALDataType eOutputType = psOptions->eOutputType; + if (eOutputType == GDT_Unknown && + psOptions->pszBurnAttribute != nullptr) + { + OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn(hLayer); + const int iBurnField = + OGR_FD_GetFieldIndex(hLayerDefn, psOptions->pszBurnAttribute); + if (iBurnField >= 0 && OGR_Fld_GetType(OGR_FD_GetFieldDefn( + hLayerDefn, iBurnField)) == OFTInteger64) + { + const char *pszMD = GDALGetMetadataItem( + hDriver, GDAL_DMD_CREATIONDATATYPES, nullptr); + if (pszMD && CPLStringList(CSLTokenizeString2(pszMD, " ", 0)) + .FindString("Int64") >= 0) + { + eOutputType = GDT_Int64; + } + } + } + if (eOutputType == GDT_Unknown) + { + eOutputType = GDT_Float64; + } + return eOutputType; + }; + /* -------------------------------------------------------------------- */ /* Process SQL request. */ /* -------------------------------------------------------------------- */ @@ -806,25 +839,7 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS, std::vector ahLayers; ahLayers.push_back(hLayer); - GDALDataType eOutputType = psOptions->eOutputType; - if (eOutputType == GDT_Unknown && - psOptions->pszBurnAttribute != nullptr) - { - OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn(hLayer); - int iBurnField = OGR_FD_GetFieldIndex( - hLayerDefn, psOptions->pszBurnAttribute); - if (iBurnField >= 0 && - OGR_Fld_GetType(OGR_FD_GetFieldDefn( - hLayerDefn, iBurnField)) == OFTInteger64) - { - eOutputType = GDT_Int64; - } - } - if (eOutputType == GDT_Unknown) - { - eOutputType = GDT_Float64; - } - + const GDALDataType eOutputType = GetOutputDataType(hLayer); hDstDS = CreateOutputDataset( ahLayers, psOptions->hSRS, psOptions->sEnvelop, hDriver, pszDest, psOptions->nXSize, psOptions->nYSize, @@ -832,7 +847,7 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS, psOptions->bTargetAlignedPixels, static_cast(psOptions->anBandList.size()), eOutputType, psOptions->papszCreationOptions, psOptions->adfInitVals, - psOptions->bNoDataSet, psOptions->dfNoData); + psOptions->pszNoData); if (hDstDS == nullptr) { GDALDatasetReleaseResultSet(hSrcDataset, hLayer); @@ -882,18 +897,10 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS, GDALRasterizeOptionsFree(psOptionsToFree); return nullptr; } - if (eOutputType == GDT_Unknown && - psOptions->pszBurnAttribute != nullptr) + if (eOutputType == GDT_Unknown) { - OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn(hLayer); - int iBurnField = OGR_FD_GetFieldIndex( - hLayerDefn, psOptions->pszBurnAttribute); - if (iBurnField >= 0 && - OGR_Fld_GetType(OGR_FD_GetFieldDefn( - hLayerDefn, iBurnField)) == OFTInteger64) - { + if (GetOutputDataType(hLayer) == GDT_Int64) eOutputType = GDT_Int64; - } } ahLayers.push_back(hLayer); @@ -910,7 +917,7 @@ GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS, psOptions->dfYRes, psOptions->bTargetAlignedPixels, static_cast(psOptions->anBandList.size()), eOutputType, psOptions->papszCreationOptions, psOptions->adfInitVals, - psOptions->bNoDataSet, psOptions->dfNoData); + psOptions->pszNoData); if (hDstDS == nullptr) { GDALRasterizeOptionsFree(psOptionsToFree); @@ -1020,8 +1027,7 @@ GDALRasterizeOptionsNew(char **papszArgv, psOptions->dfXRes = 0; psOptions->dfYRes = 0; psOptions->eOutputType = GDT_Unknown; - psOptions->bNoDataSet = FALSE; - psOptions->dfNoData = 0; + psOptions->pszNoData = nullptr; psOptions->nXSize = 0; psOptions->nYSize = 0; psOptions->hSRS = nullptr; @@ -1195,8 +1201,8 @@ GDALRasterizeOptionsNew(char **papszArgv, } else if (i < argc - 1 && EQUAL(papszArgv[i], "-a_nodata")) { - psOptions->dfNoData = CPLAtof(papszArgv[i + 1]); - psOptions->bNoDataSet = TRUE; + CPLFree(psOptions->pszNoData); + psOptions->pszNoData = CPLStrdup(papszArgv[i + 1]); i += 1; psOptions->bCreateOutput = true; } @@ -1472,6 +1478,7 @@ void GDALRasterizeOptionsFree(GDALRasterizeOptions *psOptions) CPLFree(psOptions->pszDialect); CPLFree(psOptions->pszBurnAttribute); CPLFree(psOptions->pszWHERE); + CPLFree(psOptions->pszNoData); OSRDestroySpatialReference(psOptions->hSRS); delete psOptions; diff --git a/apps/gdal_translate_lib.cpp b/apps/gdal_translate_lib.cpp index 0dbbd9193253..79f1e4895551 100644 --- a/apps/gdal_translate_lib.cpp +++ b/apps/gdal_translate_lib.cpp @@ -3032,19 +3032,6 @@ GDALTranslateOptionsGetParser(GDALTranslateOptions *psOptions, argParser->add_argument("-a_nodata") .metavar("|none") - .action( - [psOptions](const std::string &s) - { - if (EQUAL(s.c_str(), "none")) - { - psOptions->bUnsetNoData = true; - } - else - { - psOptions->bSetNoData = true; - psOptions->osNoData = s; - } - }) .help(_("Assign a specified nodata value to output bands.")); argParser->add_argument("-a_gt") @@ -3383,6 +3370,23 @@ GDALTranslateOptionsNew(char **papszArgv, psOptions->anColorInterp[nIndex] = GetColorInterp(papszArgv[i]); } + // argparser will be confused if the value of a string argument + // starts with a negative sign. + else if (EQUAL(papszArgv[i], "-a_nodata") && papszArgv[i + 1]) + { + ++i; + const std::string s = papszArgv[i]; + if (EQUAL(s.c_str(), "none")) + { + psOptions->bUnsetNoData = true; + } + else + { + psOptions->bSetNoData = true; + psOptions->osNoData = s; + } + } + else { aosArgv.AddString(papszArgv[i]); diff --git a/apps/gdalargumentparser.cpp b/apps/gdalargumentparser.cpp index c70a939be599..f9992cea7317 100644 --- a/apps/gdalargumentparser.cpp +++ b/apps/gdalargumentparser.cpp @@ -50,10 +50,10 @@ GDALArgumentParser::GDALArgumentParser(const std::string &program_name, add_argument("-h", "--help") .flag() .action( - [this, program_name](const auto &) + [this](const auto &) { std::cout << usage() << std::endl << std::endl; - std::cout << _("Note: ") << program_name + std::cout << _("Note: ") << m_program_name << _(" --long-usage for full help.") << std::endl; std::exit(0); }) @@ -77,11 +77,11 @@ GDALArgumentParser::GDALArgumentParser(const std::string &program_name, .flag() .hidden() .action( - [program_name](const auto &) + [this](const auto &) { printf("%s was compiled against GDAL %s and " "is running against GDAL %s\n", - program_name.c_str(), GDAL_RELEASE_NAME, + m_program_name.c_str(), GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME")); std::exit(0); }) diff --git a/apps/gdalbuildvrt_lib.cpp b/apps/gdalbuildvrt_lib.cpp index ae642786f383..31e720fcc866 100644 --- a/apps/gdalbuildvrt_lib.cpp +++ b/apps/gdalbuildvrt_lib.cpp @@ -2268,6 +2268,21 @@ GDALBuildVRTOptionsNew(char **papszArgv, psOptionsForBinary->osDstFilename = papszArgv[i + 1]; ++i; } + // argparser will be confused if the value of a string argument + // starts with a negative sign. + else if (EQUAL(papszArgv[i], "-srcnodata") && i + 1 < nArgc) + { + ++i; + psOptions->osSrcNoData = papszArgv[i]; + } + // argparser will be confused if the value of a string argument + // starts with a negative sign. + else if (EQUAL(papszArgv[i], "-vrtnodata") && i + 1 < nArgc) + { + ++i; + psOptions->osVRTNoData = papszArgv[i]; + } + else { aosArgv.AddString(papszArgv[i]); diff --git a/apps/gdallocationinfo.cpp b/apps/gdallocationinfo.cpp index d317e2599b5c..72599f0ef1d2 100644 --- a/apps/gdallocationinfo.cpp +++ b/apps/gdallocationinfo.cpp @@ -432,7 +432,12 @@ MAIN_START(argc, argv) osXML += "Location is off this file! No further details " "to report."; else if (bValOnly) - printf("\n"); + { + for (int i = 1; i < static_cast(anBandList.size()); i++) + { + printf("%s", osFieldSep.c_str()); + } + } else if (!bQuiet) printf("\nLocation is off this file! No further details to " "report.\n"); diff --git a/apps/gdalwarp_lib.cpp b/apps/gdalwarp_lib.cpp index 6fb54762fc6a..b79dbf15b75f 100644 --- a/apps/gdalwarp_lib.cpp +++ b/apps/gdalwarp_lib.cpp @@ -5747,12 +5747,12 @@ GDALWarpAppOptionsGetParser(GDALWarpAppOptions *psOptions, .help(_("Set max warp memory.")); argParser->add_argument("-srcnodata") - .metavar("[ ...]") + .metavar("\"[ ]...\"") .store_into(psOptions->osSrcNodata) .help(_("Nodata masking values for input bands.")); argParser->add_argument("-dstnodata") - .metavar("[ ...]") + .metavar("\"[ ]...\"") .store_into(psOptions->osDstNodata) .help(_("Nodata masking values for output bands.")); @@ -6126,6 +6126,20 @@ GDALWarpAppOptionsNew(char **papszArgv, } psOptions->bCreateOutput = true; } + // argparser will be confused if the value of a string argument + // starts with a negative sign. + else if (EQUAL(papszArgv[i], "-srcnodata") && i + 1 < nArgc) + { + ++i; + psOptions->osSrcNodata = papszArgv[i]; + } + // argparser will be confused if the value of a string argument + // starts with a negative sign. + else if (EQUAL(papszArgv[i], "-dstnodata") && i + 1 < nArgc) + { + ++i; + psOptions->osDstNodata = papszArgv[i]; + } else { aosArgv.AddString(papszArgv[i]); diff --git a/apps/ogr2ogr_lib.cpp b/apps/ogr2ogr_lib.cpp index 0d24991f801d..e42155fdfa49 100644 --- a/apps/ogr2ogr_lib.cpp +++ b/apps/ogr2ogr_lib.cpp @@ -270,6 +270,9 @@ struct GDALVectorTranslateOptions /*! Whether to run MakeValid */ bool bMakeValid = false; + /*! Whether to run OGRGeometry::IsValid */ + bool bSkipInvalidGeom = false; + /*! list of field types to convert to a field of type string in the destination layer. Valid types are: Integer, Integer64, Real, String, Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList, @@ -575,17 +578,23 @@ class LayerTranslator int m_eGType = -1; GeomTypeConversion m_eGeomTypeConversion = GTC_DEFAULT; bool m_bMakeValid = false; + bool m_bSkipInvalidGeom = false; int m_nCoordDim = 0; GeomOperation m_eGeomOp = GEOMOP_NONE; double m_dfGeomOpParam = 0; + OGRGeometry *m_poClipSrcOri = nullptr; bool m_bWarnedClipSrcSRS = false; std::unique_ptr m_poClipSrcReprojectedToSrcSRS; const OGRSpatialReference *m_poClipSrcReprojectedToSrcSRS_SRS = nullptr; + OGREnvelope m_oClipSrcEnv{}; + OGRGeometry *m_poClipDstOri = nullptr; bool m_bWarnedClipDstSRS = false; std::unique_ptr m_poClipDstReprojectedToDstSRS; const OGRSpatialReference *m_poClipDstReprojectedToDstSRS_SRS = nullptr; + OGREnvelope m_oClipDstEnv{}; + bool m_bExplodeCollections = false; bool m_bNativeData = false; GIntBig m_nLimit = -1; @@ -598,8 +607,10 @@ class LayerTranslator const GDALVectorTranslateOptions *psOptions); private: - const OGRGeometry *GetDstClipGeom(const OGRSpatialReference *poGeomSRS); - const OGRGeometry *GetSrcClipGeom(const OGRSpatialReference *poGeomSRS); + std::pair + GetDstClipGeom(const OGRSpatialReference *poGeomSRS); + std::pair + GetSrcClipGeom(const OGRSpatialReference *poGeomSRS); }; static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS, @@ -733,7 +744,8 @@ class OGRSplitListFieldLayer : public OGRLayer int nListFieldCount; int nMaxSplitListSubFields; - OGRFeature *TranslateFeature(OGRFeature *poSrcFeature); + std::unique_ptr + TranslateFeature(std::unique_ptr poSrcFeature); public: OGRSplitListFieldLayer(OGRLayer *poSrcLayer, int nMaxSplitListSubFields); @@ -988,14 +1000,15 @@ bool OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress, /* TranslateFeature() */ /************************************************************************/ -OGRFeature *OGRSplitListFieldLayer::TranslateFeature(OGRFeature *poSrcFeature) +std::unique_ptr OGRSplitListFieldLayer::TranslateFeature( + std::unique_ptr poSrcFeature) { if (poSrcFeature == nullptr) return nullptr; if (poFeatureDefn == nullptr) return poSrcFeature; - OGRFeature *poFeature = OGRFeature::CreateFeature(poFeatureDefn); + auto poFeature = std::make_unique(poFeatureDefn); poFeature->SetFID(poSrcFeature->GetFID()); for (int i = 0; i < poFeature->GetGeomFieldCount(); i++) { @@ -1068,8 +1081,6 @@ OGRFeature *OGRSplitListFieldLayer::TranslateFeature(OGRFeature *poSrcFeature) } } - OGRFeature::DestroyFeature(poSrcFeature); - return poFeature; } @@ -1079,7 +1090,9 @@ OGRFeature *OGRSplitListFieldLayer::TranslateFeature(OGRFeature *poSrcFeature) OGRFeature *OGRSplitListFieldLayer::GetNextFeature() { - return TranslateFeature(poSrcLayer->GetNextFeature()); + return TranslateFeature( + std::unique_ptr(poSrcLayer->GetNextFeature())) + .release(); } /************************************************************************/ @@ -1088,7 +1101,9 @@ OGRFeature *OGRSplitListFieldLayer::GetNextFeature() OGRFeature *OGRSplitListFieldLayer::GetFeature(GIntBig nFID) { - return TranslateFeature(poSrcLayer->GetFeature(nFID)); + return TranslateFeature( + std::unique_ptr(poSrcLayer->GetFeature(nFID))) + .release(); } /************************************************************************/ @@ -1472,20 +1487,19 @@ static bool IsFieldType(const char *pszArg) class GDALVectorTranslateWrappedDataset : public GDALDataset { - GDALDataset *m_poBase; - OGRSpatialReference *m_poOutputSRS; - bool m_bTransform; + std::unique_ptr m_poDriverToFree{}; + GDALDataset *m_poBase = nullptr; + OGRSpatialReference *m_poOutputSRS = nullptr; + bool m_bTransform = false; - std::vector m_apoLayers; - std::vector m_apoHiddenLayers; + std::vector> m_apoLayers{}; + std::vector> m_apoHiddenLayers; GDALVectorTranslateWrappedDataset(GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform); public: - virtual ~GDALVectorTranslateWrappedDataset(); - virtual int GetLayerCount() override { return static_cast(m_apoLayers.size()); @@ -1499,17 +1513,18 @@ class GDALVectorTranslateWrappedDataset : public GDALDataset const char *pszDialect) override; virtual void ReleaseResultSet(OGRLayer *poResultsSet) override; - static GDALVectorTranslateWrappedDataset * + static std::unique_ptr New(GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform); }; class GDALVectorTranslateWrappedLayer : public OGRLayerDecorator { - std::vector m_apoCT; - OGRFeatureDefn *m_poFDefn; + std::vector> m_apoCT{}; + OGRFeatureDefn *m_poFDefn = nullptr; GDALVectorTranslateWrappedLayer(OGRLayer *poBaseLayer, bool bOwnBaseLayer); - OGRFeature *TranslateFeature(OGRFeature *poSrcFeat); + std::unique_ptr + TranslateFeature(std::unique_ptr poSrcFeat); public: virtual ~GDALVectorTranslateWrappedLayer(); @@ -1522,7 +1537,7 @@ class GDALVectorTranslateWrappedLayer : public OGRLayerDecorator virtual OGRFeature *GetNextFeature() override; virtual OGRFeature *GetFeature(GIntBig nFID) override; - static GDALVectorTranslateWrappedLayer * + static std::unique_ptr New(OGRLayer *poBaseLayer, bool bOwnBaseLayer, OGRSpatialReference *poOutputSRS, bool bTransform); }; @@ -1530,19 +1545,17 @@ class GDALVectorTranslateWrappedLayer : public OGRLayerDecorator GDALVectorTranslateWrappedLayer::GDALVectorTranslateWrappedLayer( OGRLayer *poBaseLayer, bool bOwnBaseLayer) : OGRLayerDecorator(poBaseLayer, bOwnBaseLayer), - m_apoCT(poBaseLayer->GetLayerDefn()->GetGeomFieldCount(), - static_cast(nullptr)), - m_poFDefn(nullptr) + m_apoCT(poBaseLayer->GetLayerDefn()->GetGeomFieldCount()) { } -GDALVectorTranslateWrappedLayer * +std::unique_ptr GDALVectorTranslateWrappedLayer::New(OGRLayer *poBaseLayer, bool bOwnBaseLayer, OGRSpatialReference *poOutputSRS, bool bTransform) { - GDALVectorTranslateWrappedLayer *poNew = - new GDALVectorTranslateWrappedLayer(poBaseLayer, bOwnBaseLayer); + auto poNew = std::unique_ptr( + new GDALVectorTranslateWrappedLayer(poBaseLayer, bOwnBaseLayer)); poNew->m_poFDefn = poBaseLayer->GetLayerDefn()->Clone(); poNew->m_poFDefn->Reference(); if (!poOutputSRS) @@ -1563,13 +1576,14 @@ GDALVectorTranslateWrappedLayer::New(OGRLayer *poBaseLayer, bool bOwnBaseLayer, poBaseLayer->GetLayerDefn() ->GetGeomFieldDefn(i) ->GetNameRef()); - delete poNew; return nullptr; } else { poNew->m_apoCT[i] = - OGRCreateCoordinateTransformation(poSourceSRS, poOutputSRS); + std::unique_ptr( + OGRCreateCoordinateTransformation(poSourceSRS, + poOutputSRS)); if (poNew->m_apoCT[i] == nullptr) { CPLError(CE_Failure, CPLE_AppDefined, @@ -1590,7 +1604,6 @@ GDALVectorTranslateWrappedLayer::New(OGRLayer *poBaseLayer, bool bOwnBaseLayer, pszWKT); CPLFree(pszWKT); - delete poNew; return nullptr; } } @@ -1605,27 +1618,29 @@ GDALVectorTranslateWrappedLayer::~GDALVectorTranslateWrappedLayer() { if (m_poFDefn) m_poFDefn->Release(); - for (size_t i = 0; i < m_apoCT.size(); ++i) - delete m_apoCT[i]; } OGRFeature *GDALVectorTranslateWrappedLayer::GetNextFeature() { - return TranslateFeature(OGRLayerDecorator::GetNextFeature()); + return TranslateFeature( + std::unique_ptr(OGRLayerDecorator::GetNextFeature())) + .release(); } OGRFeature *GDALVectorTranslateWrappedLayer::GetFeature(GIntBig nFID) { - return TranslateFeature(OGRLayerDecorator::GetFeature(nFID)); + return TranslateFeature( + std::unique_ptr(OGRLayerDecorator::GetFeature(nFID))) + .release(); } -OGRFeature * -GDALVectorTranslateWrappedLayer::TranslateFeature(OGRFeature *poSrcFeat) +std::unique_ptr GDALVectorTranslateWrappedLayer::TranslateFeature( + std::unique_ptr poSrcFeat) { if (poSrcFeat == nullptr) return nullptr; - OGRFeature *poNewFeat = new OGRFeature(m_poFDefn); - poNewFeat->SetFrom(poSrcFeat); + auto poNewFeat = std::make_unique(m_poFDefn); + poNewFeat->SetFrom(poSrcFeat.get()); poNewFeat->SetFID(poSrcFeat->GetFID()); for (int i = 0; i < poNewFeat->GetGeomFieldCount(); i++) { @@ -1633,12 +1648,11 @@ GDALVectorTranslateWrappedLayer::TranslateFeature(OGRFeature *poSrcFeat) if (poGeom) { if (m_apoCT[i]) - poGeom->transform(m_apoCT[i]); + poGeom->transform(m_apoCT[i].get()); poGeom->assignSpatialReference( m_poFDefn->GetGeomFieldDefn(i)->GetSpatialRef()); } } - delete poSrcFeat; return poNewFeat; } @@ -1651,77 +1665,68 @@ GDALVectorTranslateWrappedDataset::GDALVectorTranslateWrappedDataset( { poDriver = new GDALDriver(); poDriver->SetDescription(poBase->GetDriver()->GetDescription()); + m_poDriverToFree.reset(poDriver); } } -GDALVectorTranslateWrappedDataset *GDALVectorTranslateWrappedDataset::New( - GDALDataset *poBase, OGRSpatialReference *poOutputSRS, bool bTransform) +std::unique_ptr +GDALVectorTranslateWrappedDataset::New(GDALDataset *poBase, + OGRSpatialReference *poOutputSRS, + bool bTransform) { - GDALVectorTranslateWrappedDataset *poNew = - new GDALVectorTranslateWrappedDataset(poBase, poOutputSRS, bTransform); + auto poNew = std::unique_ptr( + new GDALVectorTranslateWrappedDataset(poBase, poOutputSRS, bTransform)); for (int i = 0; i < poBase->GetLayerCount(); i++) { - OGRLayer *poLayer = GDALVectorTranslateWrappedLayer::New( - poBase->GetLayer(i), false, poOutputSRS, bTransform); + auto poLayer = GDALVectorTranslateWrappedLayer::New( + poBase->GetLayer(i), /* bOwnBaseLayer = */ false, poOutputSRS, + bTransform); if (poLayer == nullptr) { - delete poNew; return nullptr; } - poNew->m_apoLayers.push_back(poLayer); + poNew->m_apoLayers.push_back(std::move(poLayer)); } return poNew; } -GDALVectorTranslateWrappedDataset::~GDALVectorTranslateWrappedDataset() -{ - delete poDriver; - for (size_t i = 0; i < m_apoLayers.size(); i++) - { - delete m_apoLayers[i]; - } - for (size_t i = 0; i < m_apoHiddenLayers.size(); i++) - { - delete m_apoHiddenLayers[i]; - } -} - OGRLayer *GDALVectorTranslateWrappedDataset::GetLayer(int i) { if (i < 0 || i >= static_cast(m_apoLayers.size())) return nullptr; - return m_apoLayers[i]; + return m_apoLayers[i].get(); } OGRLayer *GDALVectorTranslateWrappedDataset::GetLayerByName(const char *pszName) { - for (size_t i = 0; i < m_apoLayers.size(); i++) + for (const auto &poLayer : m_apoLayers) { - if (strcmp(m_apoLayers[i]->GetName(), pszName) == 0) - return m_apoLayers[i]; + if (strcmp(poLayer->GetName(), pszName) == 0) + return poLayer.get(); } - for (size_t i = 0; i < m_apoHiddenLayers.size(); i++) + for (const auto &poLayer : m_apoHiddenLayers) { - if (strcmp(m_apoHiddenLayers[i]->GetName(), pszName) == 0) - return m_apoHiddenLayers[i]; + if (strcmp(poLayer->GetName(), pszName) == 0) + return poLayer.get(); } - for (size_t i = 0; i < m_apoLayers.size(); i++) + for (const auto &poLayer : m_apoLayers) { - if (EQUAL(m_apoLayers[i]->GetName(), pszName)) - return m_apoLayers[i]; + if (EQUAL(poLayer->GetName(), pszName)) + return poLayer.get(); } - for (size_t i = 0; i < m_apoHiddenLayers.size(); i++) + for (const auto &poLayer : m_apoHiddenLayers) { - if (EQUAL(m_apoHiddenLayers[i]->GetName(), pszName)) - return m_apoHiddenLayers[i]; + if (EQUAL(poLayer->GetName(), pszName)) + return poLayer.get(); } OGRLayer *poLayer = m_poBase->GetLayerByName(pszName); if (poLayer == nullptr) return nullptr; - poLayer = GDALVectorTranslateWrappedLayer::New(poLayer, false, - m_poOutputSRS, m_bTransform); - if (poLayer == nullptr) + + auto poNewLayer = GDALVectorTranslateWrappedLayer::New( + poLayer, /* bOwnBaseLayer = */ false, m_poOutputSRS, m_bTransform); + if (poNewLayer == nullptr) return nullptr; // Replicate source dataset behavior: if the fact of calling @@ -1732,12 +1737,12 @@ OGRLayer *GDALVectorTranslateWrappedDataset::GetLayerByName(const char *pszName) { if (m_poBase->GetLayer(i) == poLayer) { - m_apoLayers.push_back(poLayer); - return poLayer; + m_apoLayers.push_back(std::move(poNewLayer)); + return m_apoLayers.back().get(); } } - m_apoHiddenLayers.push_back(poLayer); - return poLayer; + m_apoHiddenLayers.push_back(std::move(poNewLayer)); + return m_apoHiddenLayers.back().get(); } OGRLayer * @@ -1749,8 +1754,9 @@ GDALVectorTranslateWrappedDataset::ExecuteSQL(const char *pszStatement, m_poBase->ExecuteSQL(pszStatement, poSpatialFilter, pszDialect); if (poLayer == nullptr) return nullptr; - return GDALVectorTranslateWrappedLayer::New(poLayer, true, m_poOutputSRS, - m_bTransform); + return GDALVectorTranslateWrappedLayer::New( + poLayer, /* bOwnBaseLayer = */ true, m_poOutputSRS, m_bTransform) + .release(); } void GDALVectorTranslateWrappedDataset::ReleaseResultSet(OGRLayer *poResultsSet) @@ -2002,6 +2008,7 @@ GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest, } GDALDataset *poWrkSrcDS = poDS; + std::unique_ptr poWrkSrcDSToFree; OGR2OGRSpatialReferenceHolder oOutputSRSHolder; if (!psOptions->osOutputSRSDef.empty()) @@ -2020,10 +2027,11 @@ GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest, oOutputSRSHolder.get()->SetCoordinateEpoch( psOptions->dfOutputCoordinateEpoch); - poWrkSrcDS = GDALVectorTranslateWrappedDataset::New( + poWrkSrcDSToFree = GDALVectorTranslateWrappedDataset::New( poDS, oOutputSRSHolder.get(), psOptions->bTransform); - if (poWrkSrcDS == nullptr) + if (poWrkSrcDSToFree == nullptr) return nullptr; + poWrkSrcDS = poWrkSrcDSToFree.get(); } if (!psOptions->osWHERE.empty()) @@ -2036,8 +2044,6 @@ GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest, CPLError(CE_Failure, CPLE_NotSupported, "-where not supported by this output driver " "without explicit layer name(s)"); - if (poWrkSrcDS != poDS) - delete poWrkSrcDS; return nullptr; } else @@ -2056,8 +2062,6 @@ GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest, else { CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "-where"); - if (poWrkSrcDS != poDS) - delete poWrkSrcDS; return nullptr; } } @@ -2115,8 +2119,6 @@ GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest, { CPLError(CE_Failure, CPLE_NotSupported, szErrorMsg, "Specifying layers"); - if (poWrkSrcDS != poDS) - delete poWrkSrcDS; return nullptr; } } @@ -2140,9 +2142,6 @@ GDALVectorTranslateCreateCopy(GDALDriver *poDriver, const char *pszDest, poDriver->CreateCopy(pszDest, poWrkSrcDS, FALSE, aosDSCO.List(), psOptions->pfnProgress, psOptions->pProgressData); - if (poWrkSrcDS != poDS) - delete poWrkSrcDS; - return poOut; } @@ -2880,6 +2879,7 @@ GDALDatasetH GDALVectorTranslate(const char *pszDest, GDALDatasetH hDstDS, oTranslator.m_eGType = psOptions->eGType; oTranslator.m_eGeomTypeConversion = psOptions->eGeomTypeConversion; oTranslator.m_bMakeValid = psOptions->bMakeValid; + oTranslator.m_bSkipInvalidGeom = psOptions->bSkipInvalidGeom; oTranslator.m_nCoordDim = psOptions->nCoordDim; oTranslator.m_eGeomOp = psOptions->eGeomOp; oTranslator.m_dfGeomOpParam = psOptions->dfGeomOpParam; @@ -3916,7 +3916,7 @@ bool SetupTargetLayer::CanUseWriteArrowBatch( m_bExactFieldNameMatch && !m_bForceNullable && !m_bResolveDomains && !m_bUnsetDefault && psOptions->nFIDToFetch == OGRNullFID && psOptions->dfXYRes == OGRGeomCoordinatePrecision::UNKNOWN && - !psOptions->bMakeValid) + !psOptions->bMakeValid && !psOptions->bSkipInvalidGeom) { struct ArrowArrayStream streamSrc; const char *const apszOptions[] = {"SILENCE_GET_SCHEMA_ERROR=YES", @@ -6002,13 +6002,22 @@ bool LayerTranslator::Translate( if (nDstGeomFieldCount == 0 && poStolenGeometry && m_poClipSrcOri) { - const OGRGeometry *poClipGeom = + if (poStolenGeometry->IsEmpty()) + goto end_loop; + + const auto [poClipGeom, poClipGeomEnvelope] = GetSrcClipGeom(poStolenGeometry->getSpatialReference()); - if (poClipGeom != nullptr && - !poClipGeom->Intersects(poStolenGeometry.get())) + if (poClipGeom && poClipGeomEnvelope) { - goto end_loop; + OGREnvelope oEnv; + poStolenGeometry->getEnvelope(&oEnv); + if (!poClipGeomEnvelope->Contains(oEnv) && + !(poClipGeomEnvelope->Intersects(oEnv) && + poClipGeom->Intersects(poStolenGeometry.get()))) + { + goto end_loop; + } } } @@ -6207,49 +6216,51 @@ bool LayerTranslator::Translate( if (m_poClipSrcOri) { + if (poDstGeometry->IsEmpty()) + goto end_loop; - const OGRGeometry *poClipGeom = + const auto [poClipGeom, poClipGeomEnvelope] = GetSrcClipGeom(poDstGeometry->getSpatialReference()); - std::unique_ptr poClipped; - if (poClipGeom != nullptr) - { - OGREnvelope oClipEnv; - OGREnvelope oDstEnv; + if (!(poClipGeom && poClipGeomEnvelope)) + goto end_loop; - poClipGeom->getEnvelope(&oClipEnv); - poDstGeometry->getEnvelope(&oDstEnv); + OGREnvelope oDstEnv; + poDstGeometry->getEnvelope(&oDstEnv); - if (oClipEnv.Intersects(oDstEnv)) + if (!poClipGeomEnvelope->Contains(oDstEnv)) + { + std::unique_ptr poClipped; + if (poClipGeomEnvelope->Intersects(oDstEnv)) { poClipped.reset( poClipGeom->Intersection(poDstGeometry.get())); } - } + if (poClipped == nullptr || poClipped->IsEmpty()) + { + goto end_loop; + } - if (poClipped == nullptr || poClipped->IsEmpty()) - { - goto end_loop; - } + const int nDim = poDstGeometry->getDimension(); + if (poClipped->getDimension() < nDim && + wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom) + ->GetType()) != wkbUnknown) + { + CPLDebug( + "OGR2OGR", + "Discarding feature " CPL_FRMT_GIB + " of layer %s, " + "as its intersection with -clipsrc is a %s " + "whereas the input is a %s", + nSrcFID, poSrcLayer->GetName(), + OGRToOGCGeomType(poClipped->getGeometryType()), + OGRToOGCGeomType( + poDstGeometry->getGeometryType())); + goto end_loop; + } - const int nDim = poDstGeometry->getDimension(); - if (poClipped->getDimension() < nDim && - wkbFlatten( - poDstFDefn->GetGeomFieldDefn(iGeom)->GetType()) != - wkbUnknown) - { - CPLDebug( - "OGR2OGR", - "Discarding feature " CPL_FRMT_GIB " of layer %s, " - "as its intersection with -clipsrc is a %s " - "whereas the input is a %s", - nSrcFID, poSrcLayer->GetName(), - OGRToOGCGeomType(poClipped->getGeometryType()), - OGRToOGCGeomType(poDstGeometry->getGeometryType())); - goto end_loop; + poDstGeometry = std::move(poClipped); } - - poDstGeometry = std::move(poClipped); } OGRCoordinateTransformation *const poCT = @@ -6387,51 +6398,54 @@ bool LayerTranslator::Translate( { if (m_poClipDstOri) { - const OGRGeometry *poClipGeom = GetDstClipGeom( + if (poDstGeometry->IsEmpty()) + goto end_loop; + + auto [poClipGeom, poClipGeomEnvelope] = GetDstClipGeom( poDstGeometry->getSpatialReference()); - if (poClipGeom == nullptr) + if (!poClipGeom || !poClipGeomEnvelope) { goto end_loop; } - std::unique_ptr poClipped; - - OGREnvelope oClipEnv; OGREnvelope oDstEnv; - - poClipGeom->getEnvelope(&oClipEnv); poDstGeometry->getEnvelope(&oDstEnv); - if (oClipEnv.Intersects(oDstEnv)) + if (!poClipGeomEnvelope->Contains(oDstEnv)) { - poClipped.reset( - poClipGeom->Intersection(poDstGeometry.get())); - } + std::unique_ptr poClipped; + if (poClipGeomEnvelope->Intersects(oDstEnv)) + { + poClipped.reset(poClipGeom->Intersection( + poDstGeometry.get())); + } - if (poClipped == nullptr || poClipped->IsEmpty()) - { - goto end_loop; - } + if (poClipped == nullptr || poClipped->IsEmpty()) + { + goto end_loop; + } - const int nDim = poDstGeometry->getDimension(); - if (poClipped->getDimension() < nDim && - wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom) - ->GetType()) != wkbUnknown) - { - CPLDebug( - "OGR2OGR", - "Discarding feature " CPL_FRMT_GIB - " of layer %s, " - "as its intersection with -clipdst is a %s " - "whereas the input is a %s", - nSrcFID, poSrcLayer->GetName(), - OGRToOGCGeomType(poClipped->getGeometryType()), - OGRToOGCGeomType( - poDstGeometry->getGeometryType())); - goto end_loop; - } + const int nDim = poDstGeometry->getDimension(); + if (poClipped->getDimension() < nDim && + wkbFlatten(poDstFDefn->GetGeomFieldDefn(iGeom) + ->GetType()) != wkbUnknown) + { + CPLDebug( + "OGR2OGR", + "Discarding feature " CPL_FRMT_GIB + " of layer %s, " + "as its intersection with -clipdst is a %s " + "whereas the input is a %s", + nSrcFID, poSrcLayer->GetName(), + OGRToOGCGeomType( + poClipped->getGeometryType()), + OGRToOGCGeomType( + poDstGeometry->getGeometryType())); + goto end_loop; + } - poDstGeometry = std::move(poClipped); + poDstGeometry = std::move(poClipped); + } } if (psOptions->dfXYRes != @@ -6480,6 +6494,9 @@ bool LayerTranslator::Translate( } } + if (m_bSkipInvalidGeom && !poDstGeometry->IsValid()) + goto end_loop; + if (m_eGeomTypeConversion != GTC_DEFAULT) { OGRwkbGeometryType eTargetType = @@ -6603,7 +6620,13 @@ bool LayerTranslator::Translate( /* LayerTranslator::GetDstClipGeom() */ /************************************************************************/ -const OGRGeometry * +/** Returns the destination clip geometry and its envelope + * + * @param poGeomSRS The SRS into which the destination clip geometry should be + * expressed. + * @return the destination clip geometry and its envelope, or (nullptr, nullptr) + */ +std::pair LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS) { if (m_poClipDstReprojectedToDstSRS_SRS != poGeomSRS) @@ -6616,7 +6639,7 @@ LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS) if (m_poClipDstReprojectedToDstSRS->transformTo(poGeomSRS) != OGRERR_NONE) { - return nullptr; + return std::make_pair(nullptr, nullptr); } m_poClipDstReprojectedToDstSRS_SRS = poGeomSRS; } @@ -6633,17 +6656,30 @@ LayerTranslator::GetDstClipGeom(const OGRSpatialReference *poGeomSRS) "same as the feature's geometry"); } } + m_oClipDstEnv = OGREnvelope(); } - return m_poClipDstReprojectedToDstSRS ? m_poClipDstReprojectedToDstSRS.get() - : m_poClipDstOri; + const auto poGeom = m_poClipDstReprojectedToDstSRS + ? m_poClipDstReprojectedToDstSRS.get() + : m_poClipDstOri; + if (poGeom && !m_oClipDstEnv.IsInit()) + { + poGeom->getEnvelope(&m_oClipDstEnv); + } + return std::make_pair(poGeom, poGeom ? &m_oClipDstEnv : nullptr); } /************************************************************************/ /* LayerTranslator::GetSrcClipGeom() */ /************************************************************************/ -const OGRGeometry * +/** Returns the source clip geometry and its envelope + * + * @param poGeomSRS The SRS into which the source clip geometry should be + * expressed. + * @return the source clip geometry and its envelope, or (nullptr, nullptr) + */ +std::pair LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS) { if (m_poClipSrcReprojectedToSrcSRS_SRS != poGeomSRS) @@ -6656,7 +6692,7 @@ LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS) if (m_poClipSrcReprojectedToSrcSRS->transformTo(poGeomSRS) != OGRERR_NONE) { - return nullptr; + return std::make_pair(nullptr, nullptr); } m_poClipSrcReprojectedToSrcSRS_SRS = poGeomSRS; } @@ -6672,10 +6708,17 @@ LayerTranslator::GetSrcClipGeom(const OGRSpatialReference *poGeomSRS) "same as the feature's geometry"); } } + m_oClipSrcEnv = OGREnvelope(); } - return m_poClipSrcReprojectedToSrcSRS ? m_poClipSrcReprojectedToSrcSRS.get() - : m_poClipSrcOri; + const auto poGeom = m_poClipSrcReprojectedToSrcSRS + ? m_poClipSrcReprojectedToSrcSRS.get() + : m_poClipSrcOri; + if (poGeom && !m_oClipSrcEnv.IsInit()) + { + poGeom->getEnvelope(&m_oClipSrcEnv); + } + return std::make_pair(poGeom, poGeom ? &m_oClipSrcEnv : nullptr); } /************************************************************************/ @@ -7246,6 +7289,21 @@ static std::unique_ptr GDALVectorTranslateOptionsGetParser( .help(_("Fix geometries to be valid regarding the rules of the Simple " "Features specification.")); + argParser->add_argument("-skipinvalid") + .flag() + .action( + [psOptions](const std::string &) + { + if (!OGRGeometryFactory::haveGEOS()) + { + throw std::invalid_argument( + "-skipinvalid only supported for builds against GEOS"); + } + psOptions->bSkipInvalidGeom = true; + }) + .help(_("Whether to skip features with invalid geometries regarding the" + "rules of the Simple Features specification.")); + argParser->add_argument("-wrapdateline") .store_into(psOptions->bWrapDateline) .help(_("Split geometries crossing the dateline meridian.")); diff --git a/autotest/alg/polygonize.py b/autotest/alg/polygonize.py index cd2bafdeab9d..7ef5c39b0069 100755 --- a/autotest/alg/polygonize.py +++ b/autotest/alg/polygonize.py @@ -82,8 +82,6 @@ def test_polygonize_1(is_int_polygonize): "POLYGON ((440720 3751200,440720 3751020,440900 3751020,440900 3751200,440720 3751200),(440780 3751140,440840 3751140,440840 3751080,440780 3751080,440780 3751140))", ) - feat_read.Destroy() - ############################################################################### # Test a simple case without masking. @@ -173,8 +171,6 @@ def test_polygonize_3(): "POLYGON ((6 -3,6 -40,19 -40,19 -39,25 -39,25 -38,27 -38,27 -37,28 -37,28 -36,29 -36,29 -35,30 -35,30 -34,31 -34,31 -25,30 -25,30 -24,29 -24,29 -23,28 -23,28 -22,27 -22,27 -21,24 -21,24 -20,23 -20,23 -19,26 -19,26 -18,27 -18,27 -17,28 -17,28 -16,29 -16,29 -8,28 -8,28 -7,27 -7,27 -6,26 -6,26 -5,24 -5,24 -4,18 -4,18 -3,6 -3),(11 -7,23 -7,23 -8,24 -8,24 -9,25 -9,25 -16,24 -16,24 -17,23 -17,23 -18,11 -18,11 -7),(11 -22,24 -22,24 -23,26 -23,26 -25,27 -25,27 -33,26 -33,26 -35,24 -35,24 -36,11 -36,11 -22))", ) - feat_read.Destroy() - ############################################################################### # Test a simple case without masking but with 8-connectedness. diff --git a/autotest/cpp/test_gdal.cpp b/autotest/cpp/test_gdal.cpp index 459105bdb9ec..8e8af2c85dd3 100644 --- a/autotest/cpp/test_gdal.cpp +++ b/autotest/cpp/test_gdal.cpp @@ -3413,7 +3413,7 @@ TEST_F(test_gdal, gtiff_ReadCompressedData) CE_None); EXPECT_EQ(nGotSize, nNeededSize); EXPECT_NE(pBuffer, nullptr); - if (pBuffer != nullptr && nGotSize == nNeededSize) + if (pBuffer != nullptr && nGotSize == nNeededSize && nNeededSize >= 2) { const GByte *pabyBuffer = static_cast(pBuffer); EXPECT_EQ(pabyBuffer[0], 0xFF); diff --git a/autotest/cpp/test_gdal_gtiff.cpp b/autotest/cpp/test_gdal_gtiff.cpp index 1ea518295fb6..b9a24c5a59b3 100644 --- a/autotest/cpp/test_gdal_gtiff.cpp +++ b/autotest/cpp/test_gdal_gtiff.cpp @@ -240,4 +240,32 @@ TEST_F(test_gdal_gtiff, raster_min_max) GDALClose(ds); } +// Test setting a nodata value with SetNoDataValue(double) on a int64 dataset +TEST_F(test_gdal_gtiff, set_nodata_value_on_int64) +{ + std::string osTmpFile = "/vsimem/temp.tif"; + auto poDS = + std::unique_ptr(GDALDriver::FromHandle(drv_)->Create( + osTmpFile.c_str(), 1, 1, 1, GDT_Int64, nullptr)); + EXPECT_EQ(poDS->GetRasterBand(1)->SetNoDataValue(1), CE_None); + { + int bGotNoData = false; + EXPECT_EQ(poDS->GetRasterBand(1)->GetNoDataValue(&bGotNoData), 1.0); + EXPECT_TRUE(bGotNoData); + } + { + int bGotNoData = false; + EXPECT_EQ(poDS->GetRasterBand(1)->GetNoDataValueAsInt64(&bGotNoData), + 1.0); + EXPECT_TRUE(bGotNoData); + } + int64_t nVal = 0; + EXPECT_EQ(poDS->GetRasterBand(1)->RasterIO(GF_Read, 0, 0, 1, 1, &nVal, 1, 1, + GDT_Int64, 0, 0, nullptr), + CE_None); + EXPECT_EQ(nVal, 1); + poDS.reset(); + VSIUnlink(osTmpFile.c_str()); +} + } // namespace diff --git a/autotest/cpp/test_ogr.cpp b/autotest/cpp/test_ogr.cpp index 90806d2e0da7..498ba17f627f 100644 --- a/autotest/cpp/test_ogr.cpp +++ b/autotest/cpp/test_ogr.cpp @@ -4175,4 +4175,29 @@ TEST_F(test_ogr, OGRGeometry_removeEmptyParts) } } +// Test OGRCurve::reversePoints() +TEST_F(test_ogr, OGRCurve_reversePoints) +{ + { + OGRGeometry *poGeom = nullptr; + OGRGeometryFactory::createFromWkt( + "COMPOUNDCURVE ZM (CIRCULARSTRING ZM (0 0 10 20,1 1 11 21,2 0 12 " + "22),(2 0 12 22,3 0 13 2))", + nullptr, &poGeom); + ASSERT_NE(poGeom, nullptr); + poGeom->toCurve()->reversePoints(); + char *pszWKT = nullptr; + poGeom->exportToWkt(&pszWKT, wkbVariantIso); + EXPECT_TRUE(pszWKT != nullptr); + if (pszWKT) + { + EXPECT_STREQ( + pszWKT, "COMPOUNDCURVE ZM ((3 0 13 2,2 0 12 22),CIRCULARSTRING " + "ZM (2 0 12 22,1 1 11 21,0 0 10 20))"); + } + CPLFree(pszWKT); + delete poGeom; + } +} + } // namespace diff --git a/autotest/cpp/test_ogr_swq.cpp b/autotest/cpp/test_ogr_swq.cpp index 520a5846ba86..73074b9e13c6 100644 --- a/autotest/cpp/test_ogr_swq.cpp +++ b/autotest/cpp/test_ogr_swq.cpp @@ -216,7 +216,8 @@ TEST_F(test_ogr_swq, select_unparse) swq_select select; const char *pszSQL = "SELECT DISTINCT a, \"a b\" AS renamed, AVG(x.a) AS avg, MIN(a), " - "MAX(\"a b\"), SUM(a), AVG(a), COUNT(a), COUNT(DISTINCT a) " + "MAX(\"a b\"), SUM(a), AVG(a), COUNT(a), COUNT(DISTINCT a), " + "STDDEV_POP(a), STDDEV_SAMP(a) " "FROM 'foo'.\"FOO BAR\" AS x " "JOIN 'bar'.BAR AS y ON FOO.x = BAR.y " "WHERE 1 ORDER BY a, \"a b\" DESC " diff --git a/autotest/cpp/test_viewshed.cpp b/autotest/cpp/test_viewshed.cpp index 7311265cb834..95382ba0a814 100644 --- a/autotest/cpp/test_viewshed.cpp +++ b/autotest/cpp/test_viewshed.cpp @@ -308,7 +308,7 @@ TEST(Viewshed, oor_right) } } -// Test an observer to the right of the raster. +// Test an observer to the left of the raster. TEST(Viewshed, oor_left) { // clang-format off @@ -369,4 +369,128 @@ TEST(Viewshed, oor_left) } } +// Test an observer above the raster +TEST(Viewshed, oor_above) +{ + // clang-format off + const int xlen = 5; + const int ylen = 3; + std::array in + { + 1, 2, 0, 4, 1, + 0, 0, 2, 1, 0, + 1, 0, 0, 3, 3 + }; + // clang-format on + + { + Viewshed::Options opts = stdOptions(2, -2); + opts.outputMode = Viewshed::OutputMode::DEM; + DatasetPtr ds = runViewshed(in.data(), xlen, ylen, opts); + GDALRasterBand *band = ds->GetRasterBand(1); + std::array out; + CPLErr err = band->RasterIO(GF_Read, 0, 0, xlen, ylen, out.data(), xlen, + ylen, GDT_Float64, 0, 0, nullptr); + + EXPECT_EQ(err, CE_None); + + // clang-format off + std::array expected + { + 1, 2, 0, 4, 1, + 2.5, 2, 0, 4, 4.5, + 3, 8 / 3.0, 8 / 3.0, 14 / 3.0, 17 / 3.0 + }; + // clang-format on + + for (size_t i = 0; i < out.size(); ++i) + EXPECT_DOUBLE_EQ(out[i], expected[i]); + } + + { + Viewshed::Options opts = stdOptions(-2, -2); + opts.outputMode = Viewshed::OutputMode::DEM; + DatasetPtr ds = runViewshed(in.data(), xlen, ylen, opts); + GDALRasterBand *band = ds->GetRasterBand(1); + std::array out; + CPLErr err = band->RasterIO(GF_Read, 0, 0, xlen, ylen, out.data(), xlen, + ylen, GDT_Float64, 0, 0, nullptr); + EXPECT_EQ(err, CE_None); + + // clang-format off + std::array expected + { + 1, 2, 0, 4, 1, + 0, 1.5, 2.5, 1.25, 3.15, + 1, 0.5, 2, 3, 2.2 + }; + // clang-format on + + for (size_t i = 0; i < out.size(); ++i) + EXPECT_DOUBLE_EQ(out[i], expected[i]); + } +} + +// Test an observer below the raster +TEST(Viewshed, oor_below) +{ + // clang-format off + const int xlen = 5; + const int ylen = 3; + std::array in + { + 1, 2, 0, 4, 1, + 0, 0, 2, 1, 0, + 1, 0, 0, 3, 3 + }; + // clang-format on + + { + Viewshed::Options opts = stdOptions(2, 4); + opts.outputMode = Viewshed::OutputMode::DEM; + DatasetPtr ds = runViewshed(in.data(), xlen, ylen, opts); + GDALRasterBand *band = ds->GetRasterBand(1); + std::array out; + CPLErr err = band->RasterIO(GF_Read, 0, 0, xlen, ylen, out.data(), xlen, + ylen, GDT_Float64, 0, 0, nullptr); + + EXPECT_EQ(err, CE_None); + + // clang-format off + std::array expected + { + 1 / 3.0, 2 / 3.0, 8 / 3.0, 11 / 3.0, 5, + 0.5, 0, 0, 3, 4.5, + 1, 0, 0, 3, 3 + }; + // clang-format on + + for (size_t i = 0; i < out.size(); ++i) + EXPECT_DOUBLE_EQ(out[i], expected[i]); + } + + { + Viewshed::Options opts = stdOptions(6, 4); + opts.outputMode = Viewshed::OutputMode::DEM; + DatasetPtr ds = runViewshed(in.data(), xlen, ylen, opts); + GDALRasterBand *band = ds->GetRasterBand(1); + std::array out; + CPLErr err = band->RasterIO(GF_Read, 0, 0, xlen, ylen, out.data(), xlen, + ylen, GDT_Float64, 0, 0, nullptr); + EXPECT_EQ(err, CE_None); + + // clang-format off + std::array expected + { + 4.2, 6, 6, 1.5, 1, + 1.35, 2.25, 4.5, 4.5, 0, + 1, 0, 0, 3, 3 + }; + // clang-format on + + for (size_t i = 0; i < out.size(); ++i) + EXPECT_DOUBLE_EQ(out[i], expected[i]); + } +} + } // namespace gdal diff --git a/autotest/gcore/basic_test.py b/autotest/gcore/basic_test.py index 2d2e2a91eb61..2719fc963dcc 100755 --- a/autotest/gcore/basic_test.py +++ b/autotest/gcore/basic_test.py @@ -68,6 +68,15 @@ def test_basic_test_1(): pytest.fail("did not get expected error message, got %s" % gdal.GetLastErrorMsg()) +def test_basic_test_invalid_open_flag(): + with pytest.raises(Exception, match="invalid value for GDALAccess"): + gdal.Open("data/byte.tif", "invalid") + + assert gdal.OF_RASTER not in (gdal.GA_ReadOnly, gdal.GA_Update) + with pytest.raises(Exception, match="invalid value for GDALAccess"): + gdal.Open("data/byte.tif", gdal.OF_RASTER) + + @pytest.mark.skipif(sys.platform != "linux", reason="Incorrect platform") def test_basic_test_strace_non_existing_file(): diff --git a/autotest/gcore/tiff_ovr.py b/autotest/gcore/tiff_ovr.py index 43577d218158..ba49b4b3fb45 100755 --- a/autotest/gcore/tiff_ovr.py +++ b/autotest/gcore/tiff_ovr.py @@ -1602,6 +1602,34 @@ def test_tiff_ovr_42(tmp_path, both_endian): ds = None +############################################################################### +# Test (failed) attempt at creating JPEG external overviews on dataset with color table + + +@pytest.mark.require_creation_option("GTiff", "JPEG") +@gdaltest.enable_exceptions() +def test_tiff_ovr_jpeg_on_color_table(tmp_path): + + tif_fname = str(tmp_path / "test_tiff_ovr_jpeg_on_color_table.tif") + + ct_data = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255)] + + ct = gdal.ColorTable() + for i, data in enumerate(ct_data): + ct.SetColorEntry(i, data) + + ds = gdal.GetDriverByName("GTiff").Create(tif_fname, 1, 1) + ds.GetRasterBand(1).SetRasterColorTable(ct) + ds = None + + with gdal.Open(tif_fname) as ds: + with pytest.raises( + Exception, + match="Cannot create JPEG compressed overviews on a raster with a color table", + ): + ds.BuildOverviews("NEAREST", overviewlist=[2], options=["COMPRESS=JPEG"]) + + ############################################################################### # Make sure that 16bit overviews with JPEG compression are handled using 12-bit # jpeg-in-tiff (#3539) diff --git a/autotest/gcore/tiff_srs.py b/autotest/gcore/tiff_srs.py index 71a922ad89f6..a4d9d6c9c9a1 100755 --- a/autotest/gcore/tiff_srs.py +++ b/autotest/gcore/tiff_srs.py @@ -621,7 +621,7 @@ def test_tiff_srs_proj4(proj4): def _create_geotiff1_1_from_copy_and_compare(srcfilename, options=[]): if int(gdal.GetDriverByName("GTiff").GetMetadataItem("LIBGEOTIFF")) < 1600: - pytest.skip() + pytest.skip("libgeotiff >= 1.6.0 required") src_ds = gdal.Open(srcfilename) tmpfile = "/vsimem/tmp.tif" @@ -1250,9 +1250,11 @@ def test_tiff_srs_projected_GTCitationGeoKey_with_underscore_and_GeogTOWGS84GeoK def test_tiff_srs_write_compound_with_non_epsg_vert_crs(): - """Test bugfix for https://github.com/OSGeo/gdal/issues/7833""" + if int(gdal.GetDriverByName("GTiff").GetMetadataItem("LIBGEOTIFF")) < 1600: + pytest.skip("libgeotiff >= 1.6.0 required") + filename = "/vsimem/test_tiff_srs_write_compound_with_non_epsg_vert_crs.tif" srs = osr.SpatialReference() srs.SetFromUserInput( @@ -1349,6 +1351,9 @@ def test_tiff_srs_read_compound_without_EPSG_code(): """Test case where identification of code for CompoundCRS (added for bugfix of https://github.com/OSGeo/gdal/issues/7982) doesn't trigger""" + if int(gdal.GetDriverByName("GTiff").GetMetadataItem("LIBGEOTIFF")) < 1600: + pytest.skip("libgeotiff >= 1.6.0 required") + filename = "/vsimem/test_tiff_srs_read_compound_without_EPSG_code.tif" srs = osr.SpatialReference() # WGS 84 + NAP height, unlikely to have a EPSG code ever diff --git a/autotest/gcore/tiff_write.py b/autotest/gcore/tiff_write.py index 11a2dc8e3e0b..d2195a60a845 100755 --- a/autotest/gcore/tiff_write.py +++ b/autotest/gcore/tiff_write.py @@ -1068,6 +1068,7 @@ def test_tiff_write_26(): ct.SetColorEntry(1, (255, 255, 0, 255)) ct.SetColorEntry(2, (255, 0, 255, 255)) ct.SetColorEntry(3, (0, 255, 255, 255)) + ct.SetColorEntry(3, (0, 255, 255, 255)) ds.GetRasterBand(1).SetRasterColorTable(ct) @@ -1088,8 +1089,6 @@ def test_tiff_write_26(): ct = None ds = None - gdaltest.tiff_drv.Delete("tmp/ct8.tif") - ############################################################################### # Test color table in a 16 bit image @@ -11559,3 +11558,41 @@ def test_tiff_write_too_many_gcps(tmp_vsimem, with_initial_gcps): ds = gdal.Open(filename) assert ds.GetGCPCount() == 0 ds = None + + +############################################################################### +# Test writing/reading a TIFF color map using 256 as the multiplication factor +# https://github.com/OSGeo/gdal/issues/10310 + + +def test_tiff_write_colormap_256_mult_factor(tmp_vsimem): + + filename = str(tmp_vsimem / "test.tif") + ds = gdal.GetDriverByName("GTiff").Create( + filename, 1, 1, 1, gdal.GDT_Byte, ["COLOR_TABLE_MULTIPLIER=256"] + ) + ds.GetRasterBand(1).SetRasterColorInterpretation(gdal.GCI_PaletteIndex) + ct = gdal.ColorTable() + ct.SetColorEntry(0, (0, 0, 0, 255)) + ct.SetColorEntry(1, (1, 2, 3, 255)) + ct.SetColorEntry(2, (255, 255, 255, 255)) + ds.GetRasterBand(1).SetRasterColorTable(ct) + ds = None + + # Check we auto-guess correctly the 256 multiplication factor + ds = gdal.Open(filename) + ct = ds.GetRasterBand(1).GetRasterColorTable() + assert ( + ct.GetColorEntry(0) == (0, 0, 0, 255) + and ct.GetColorEntry(1) == (1, 2, 3, 255) + and ct.GetColorEntry(2) == (255, 255, 255, 255) + ), "Wrong color table entry." + + # Check we get wrong values when not specifying the appropriate multiplier + ds = gdal.OpenEx(filename, open_options=["COLOR_TABLE_MULTIPLIER=257"]) + ct = ds.GetRasterBand(1).GetRasterColorTable() + assert ( + ct.GetColorEntry(0) == (0, 0, 0, 255) + and ct.GetColorEntry(1) == (0, 1, 2, 255) + and ct.GetColorEntry(2) == (254, 254, 254, 255) + ), "Wrong color table entry." diff --git a/autotest/gdrivers/data/netcdf/fake_EMIT_L2A_with_good_wavelengths.nc b/autotest/gdrivers/data/netcdf/fake_EMIT_L2A_with_good_wavelengths.nc new file mode 100644 index 000000000000..bddcb696313b Binary files /dev/null and b/autotest/gdrivers/data/netcdf/fake_EMIT_L2A_with_good_wavelengths.nc differ diff --git a/autotest/gdrivers/data/wmts/clip_WGS84BoundingBox_with_tilematrix.xml b/autotest/gdrivers/data/wmts/clip_WGS84BoundingBox_with_tilematrix.xml new file mode 100644 index 000000000000..bdf9dc4d910d --- /dev/null +++ b/autotest/gdrivers/data/wmts/clip_WGS84BoundingBox_with_tilematrix.xml @@ -0,0 +1,152 @@ + + + + + title + + 0.10594674240568917 45.2375427360256 + 20.448891294525627 56.84787345153812 + + de_basemapde_web_raster_grau + + image/png + + DE_EPSG_25832_ADV + + + + + DE_EPSG_25832_ADV + EPSG:25832 + + 00 + 17471320.750897426 + -46133.17 6301219.54 + 256 + 256 + 1 + 1 + + + 01 + 8735660.375448713 + -46133.17 6301219.54 + 256 + 256 + 2 + 2 + + + 02 + 4367830.187724357 + -46133.17 6301219.54 + 256 + 256 + 4 + 4 + + + 03 + 2183915.0938621783 + -46133.17 6301219.54 + 256 + 256 + 8 + 8 + + + 04 + 1091957.5469310891 + -46133.17 6301219.54 + 256 + 256 + 16 + 16 + + + 05 + 545978.7734655463 + -46133.17 6301219.54 + 256 + 256 + 32 + 32 + + + 06 + 272989.38673277246 + -46133.17 6301219.54 + 256 + 256 + 64 + 64 + + + 07 + 136494.69336638605 + -46133.17 6301219.54 + 256 + 256 + 128 + 128 + + + 08 + 68247.3466831932 + -46133.17 6301219.54 + 256 + 256 + 256 + 256 + + + 09 + 34123.673341596535 + -46133.17 6301219.54 + 256 + 256 + 512 + 512 + + + 10 + 17061.836670798286 + -46133.17 6301219.54 + 256 + 256 + 1024 + 1024 + + + 11 + 8530.918335399143 + -46133.17 6301219.54 + 256 + 256 + 2048 + 2048 + + + 12 + 4265.4591676995715 + -46133.17 6301219.54 + 256 + 256 + 4096 + 4096 + + + 13 + 2132.729583849782 + -46133.17 6301219.54 + 256 + 256 + 8192 + 8192 + + + + diff --git a/autotest/gdrivers/netcdf_multidim.py b/autotest/gdrivers/netcdf_multidim.py index 7fd4616b1f85..bc9ea089c208 100755 --- a/autotest/gdrivers/netcdf_multidim.py +++ b/autotest/gdrivers/netcdf_multidim.py @@ -3762,6 +3762,88 @@ def test_netcdf_multidim_getresampled_with_geoloc_EMIT_L2A(): ) +def test_netcdf_multidim_getresampled_with_geoloc_EMIT_L2A_with_good_wavelengths(): + + ds = gdal.OpenEx( + "data/netcdf/fake_EMIT_L2A_with_good_wavelengths.nc", gdal.OF_MULTIDIM_RASTER + ) + rg = ds.GetRootGroup() + + ar = rg.OpenMDArray("reflectance") + + # Use glt_x and glt_y arrays, and good_wavelengths variable + resampled_ar = ar.GetResampled( + [None, None, None], gdal.GRIORA_NearestNeighbour, None + ) + assert resampled_ar is not None + + # Read one band that is valid according to good_wavelengths variable + assert struct.unpack( + "f" * (3 * 3), resampled_ar.Read(array_start_idx=[0, 0, 1], count=[3, 3, 1]) + ) == ( + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + ) + + # Read one band that is invalid according to good_wavelengths variable + assert struct.unpack( + "f" * (3 * 3), resampled_ar.Read(array_start_idx=[0, 0, 0], count=[3, 3, 1]) + ) == ( + -9999.0, + -9999.0, + -9999.0, + -9999.0, + 30.0, + 40.0, + -9999.0, + 10.0, + 20.0, + ) + + # Read all bands + assert struct.unpack("f" * (3 * 3 * 2), resampled_ar.Read()) == ( + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + -9999.0, + 30.0, + -9999.0, + 40.0, + -9999.0, + -9999.0, + -9999.0, + 10.0, + -9999.0, + 20.0, + -9999.0, + ) + + # Test *not* using good_wavelengths variable + resampled_ar = ar.GetResampled( + [None, None, None], + gdal.GRIORA_NearestNeighbour, + None, + ["USE_GOOD_WAVELENGTHS=NO"], + ) + assert resampled_ar is not None + + # Read one band that is valid according to good_wavelengths variable + assert struct.unpack( + "f" * (3 * 3), resampled_ar.Read(array_start_idx=[0, 0, 1], count=[3, 3, 1]) + ) == (-9999.0, -9999.0, -9999.0, -9999.0, -30.0, -40.0, -9999.0, -10.0, -20.0) + + def test_netcdf_multidim_getresampled_with_geoloc_EMIT_L2B_MIN(): ds = gdal.OpenEx("data/netcdf/fake_EMIT_L2B_MIN.nc", gdal.OF_MULTIDIM_RASTER) diff --git a/autotest/gdrivers/wmts.py b/autotest/gdrivers/wmts.py index e941167ad9ee..93e117939475 100755 --- a/autotest/gdrivers/wmts.py +++ b/autotest/gdrivers/wmts.py @@ -1871,6 +1871,18 @@ def test_wmts_check_no_overflow_zoom_level(): gdal.Unlink(inputXml) +############################################################################### +# Test fix for https://github.com/OSGeo/gdal/issues/10348 + + +def test_wmts_clip_extent_with_union_of_tile_matrix_extent(): + + ds = gdal.Open("data/wmts/clip_WGS84BoundingBox_with_tilematrix.xml") + assert ds.GetGeoTransform() == pytest.approx( + (-46133.17, 0.5971642834779389, 0.0, 6301219.54, 0.0, -0.5971642834779389) + ) + + ############################################################################### # Test when local wmts tiles are missing diff --git a/autotest/ogr/data/csv/inf_nan.csv b/autotest/ogr/data/csv/inf_nan.csv new file mode 100644 index 000000000000..7ab5a1f7cd1e --- /dev/null +++ b/autotest/ogr/data/csv/inf_nan.csv @@ -0,0 +1,5 @@ +id,v +1,10 +2,inf +3,-inf +4,NaN diff --git a/autotest/ogr/ogr_csv.py b/autotest/ogr/ogr_csv.py index 22d9111f4cc7..2c315d484bf5 100755 --- a/autotest/ogr/ogr_csv.py +++ b/autotest/ogr/ogr_csv.py @@ -27,6 +27,7 @@ # Boston, MA 02111-1307, USA. ############################################################################### +import math import pathlib import sys @@ -3133,6 +3134,26 @@ def test_ogr_csv_force_opening(tmp_vsimem): assert ds.GetDriver().GetDescription() == "CSV" +############################################################################### +# Test opening a CSV file with inf/nan numeric values + + +@gdaltest.enable_exceptions() +def test_ogr_csv_inf_nan(): + + ds = gdal.OpenEx("data/csv/inf_nan.csv", open_options=["AUTODETECT_TYPE=YES"]) + lyr = ds.GetLayer(0) + assert lyr.GetLayerDefn().GetFieldDefn(1).GetType() == ogr.OFTReal + f = lyr.GetNextFeature() + assert f["v"] == 10.0 + f = lyr.GetNextFeature() + assert f["v"] == float("inf") + f = lyr.GetNextFeature() + assert f["v"] == float("-inf") + f = lyr.GetNextFeature() + assert math.isnan(f["v"]) + + ############################################################################### diff --git a/autotest/ogr/ogr_db2_hack.py b/autotest/ogr/ogr_db2_hack.py index 9878ad6d6be4..154a1cab5030 100755 --- a/autotest/ogr/ogr_db2_hack.py +++ b/autotest/ogr/ogr_db2_hack.py @@ -44,14 +44,12 @@ def test_ogr_db2_hack_1(): # XDR Case. geom = ogr.CreateGeometryFromWkt("POINT(10 20)") wkb = geom.ExportToWkb(byte_order=ogr.wkbXDR).decode("latin1") - geom.Destroy() assert wkb[0] == "0", "WKB wkbXDR point geometry has wrong byte order" # NDR Case. geom = ogr.CreateGeometryFromWkt("POINT(10 20)") wkb = geom.ExportToWkb(byte_order=ogr.wkbNDR).decode("latin1") - geom.Destroy() assert wkb[0] == "1", "WKB wkbNDR point geometry has wrong byte order" @@ -65,14 +63,12 @@ def test_ogr_db2_hack_1(): # XDR Case. geom = ogr.CreateGeometryFromWkt("POINT(10 20)") wkb = geom.ExportToWkb(byte_order=ogr.wkbXDR).decode("latin1") - geom.Destroy() assert wkb[0] == chr(0), "WKB wkbXDR point geometry has wrong byte order" # NDR Case. geom = ogr.CreateGeometryFromWkt("POINT(10 20)") wkb = geom.ExportToWkb(byte_order=ogr.wkbNDR).decode("latin1") - geom.Destroy() assert wkb[0] == chr(1), "WKB wkbNDR point geometry has wrong byte order" @@ -90,7 +86,6 @@ def test_ogr_db2_hack_3(): geom = ogr.CreateGeometryFromWkt(wkt) wkb = geom.ExportToWkb() - geom.Destroy() # Check primary byte order value. assert ( @@ -107,6 +102,4 @@ def test_ogr_db2_hack_3(): "Conversion to/from DB2 format seems to have " "corrupted geometry." ) - geom.Destroy() - ogr.SetGenerate_DB2_V72_BYTE_ORDER(0) diff --git a/autotest/ogr/ogr_dxf.py b/autotest/ogr/ogr_dxf.py index 21b283e779e9..d2ecbd72d34d 100644 --- a/autotest/ogr/ogr_dxf.py +++ b/autotest/ogr/ogr_dxf.py @@ -3890,12 +3890,21 @@ def test_ogr_dxf_54(): # Test hidden objects in blocks -def test_ogr_dxf_55(): - - with gdaltest.config_option("DXF_MERGE_BLOCK_GEOMETRIES", "FALSE"): - ds = ogr.Open("data/dxf/block-hidden-entities.dxf") +@pytest.mark.parametrize("use_config_option", [True, False]) +def test_ogr_dxf_55(use_config_option): + + if use_config_option: + with gdaltest.config_option("DXF_MERGE_BLOCK_GEOMETRIES", "FALSE"): + ds = ogr.Open("data/dxf/block-hidden-entities.dxf") + else: + ds = gdal.OpenEx( + "data/dxf/block-hidden-entities.dxf", + open_options={"MERGE_BLOCK_GEOMETRIES": False}, + ) lyr = ds.GetLayer(0) + assert lyr.GetFeatureCount() == 6 + # Red features should be hidden, black features should be visible for number, f in enumerate(lyr): assert "#ff000000)" in f.GetStyleString() or "#000000)" in f.GetStyleString(), ( @@ -4011,3 +4020,12 @@ def test_ogr_dxf_read_closed_polyline_with_bulge(): g.ExportToWkt() == "LINESTRING (40585366.7065058 3433935.53809098,40585329.9256486 3433998.44081707,40585329.9256486 3433998.44081707,40585328.5387678 3434000.63680805,40585327.0051198 3434002.73293274,40585325.3318693 3434004.71939884,40585323.526833 3434006.58692634,40585321.5984435 3434008.32679087,40585319.5557093 3434009.93086443,40585317.4081735 3434011.39165342,40585315.1658683 3434012.70233358,40585312.8392691 3434013.85678191,40585310.4392448 3434014.84960528,40585307.9770074 3434015.67616559,40585305.4640596 3434016.33260146,40585302.9121409 3434016.81584629,40585300.3331728 3434017.12364253,40585297.7392033 3434017.25455227,40585271.1313178 3434017.68678191,40585252.1698149 3433885.99037548,40585256.74147 3433885.9161116,40585256.74147 3433885.9161116,40585266.2920614 3433886.0916242,40585275.8076317 3433886.92740148,40585285.2425893 3433888.41943902,40585294.551729 3433890.56058809,40585303.6904483 3433893.34058991,40585312.6149614 3433896.74612477,40585321.2825086 3433900.76087591,40585329.6515615 3433905.36560764,40585364.2483736 3433925.99220872,40585364.2483736 3433925.99220872,40585364.6481964 3433926.24937651,40585365.0296424 3433926.53308859,40585365.3909523 3433926.84203644,40585365.7304596 3433927.17479516,40585366.0465985 3433927.52983003,40585366.337911 3433927.90550359,40585366.6030535 3433928.30008319,40585366.840803 3433928.71174899,40585367.0500632 3433929.13860232,40585367.2298688 3433929.5786745,40585367.3793906 3433930.02993587,40585367.4979389 3433930.49030515,40585367.5849671 3433930.95765907,40585367.6400736 3433931.42984214,40585367.6630045 3433931.9046766,40585367.6536538 3433932.37997246,40585367.6120647 3433932.85353759,40585367.5384291 3433933.32318787,40585367.4330866 3433933.7867572,40585367.2965229 3433934.24210757,40585367.129368 3433934.68713883,40585366.9323928 3433935.11979846,40585366.7065058 3433935.53809098)" ) + + ds = gdal.OpenEx( + "data/dxf/closed_polyline_with_bulge.dxf", + open_options=["CLOSED_LINE_AS_POLYGON=YES"], + ) + lyr = ds.GetLayer(0) + f = lyr.GetNextFeature() + g = f.GetGeometryRef() + assert g.GetGeometryType() == ogr.wkbPolygon diff --git a/autotest/ogr/ogr_gml.py b/autotest/ogr/ogr_gml.py index eadda1826340..fc70d74f1766 100755 --- a/autotest/ogr/ogr_gml.py +++ b/autotest/ogr/ogr_gml.py @@ -4356,3 +4356,95 @@ def test_ogr_gml_geom_link_to_immediate_child(): "data/gml/link_to_immediate_child.gml", open_options=["WRITE_GFS=NO"] ) assert ds + + +############################################################################### +# Test scenario of https://github.com/OSGeo/gdal/issues/10332 + + +@pytest.mark.parametrize("use_create_geom_field", [False, True]) +@pytest.mark.parametrize("has_srs", [False, True]) +def test_ogr_gml_ogr2ogr_from_layer_with_name_geom_field( + tmp_vsimem, use_create_geom_field, has_srs +): + + ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0, gdal.GDT_Unknown) + if has_srs: + srs = osr.SpatialReference() + srs.ImportFromEPSG(4326) + srs.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER) + else: + srs = None + if use_create_geom_field: + lyr = ds.CreateLayer("test", geom_type=ogr.wkbNone) + my_geom_field = ogr.GeomFieldDefn("my_geom", ogr.wkbUnknown) + my_geom_field.SetSpatialRef(srs) + lyr.CreateGeomField(my_geom_field) + else: + lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown, srs=srs) + f = ogr.Feature(lyr.GetLayerDefn()) + f.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(2 49)")) + lyr.CreateFeature(f) + f = ogr.Feature(lyr.GetLayerDefn()) + f.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(3 50)")) + lyr.CreateFeature(f) + + out_filename = str(tmp_vsimem / "out.gml") + gdal.VectorTranslate(out_filename, ds, format="GML") + + f = gdal.VSIFOpenL(out_filename, "rb") + assert f + try: + data = gdal.VSIFReadL(1, 10000, f) + finally: + gdal.VSIFCloseL(f) + + if has_srs: + assert ( + b'49 250 3' + in data + ) + else: + assert ( + b"2 493 50" + in data + ) + + +############################################################################### + + +@pytest.mark.parametrize("first_layer_has_srs", [False, True]) +def test_ogr_gml_ogr2ogr_from_layers_with_inconsistent_srs( + tmp_vsimem, first_layer_has_srs +): + + ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0, gdal.GDT_Unknown) + srs = osr.SpatialReference() + srs.ImportFromEPSG(4326) + srs.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER) + lyr = ds.CreateLayer( + "test", geom_type=ogr.wkbUnknown, srs=(srs if first_layer_has_srs else None) + ) + f = ogr.Feature(lyr.GetLayerDefn()) + f.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(2 49)")) + lyr.CreateFeature(f) + + lyr = ds.CreateLayer( + "test2", geom_type=ogr.wkbUnknown, srs=(None if first_layer_has_srs else srs) + ) + f = ogr.Feature(lyr.GetLayerDefn()) + f.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(3 50)")) + lyr.CreateFeature(f) + + out_filename = str(tmp_vsimem / "out.gml") + gdal.VectorTranslate(out_filename, ds, format="GML") + + f = gdal.VSIFOpenL(out_filename, "rb") + assert f + try: + data = gdal.VSIFReadL(1, 10000, f) + finally: + gdal.VSIFCloseL(f) + + assert b"" in data diff --git a/autotest/ogr/ogr_gml_geom.py b/autotest/ogr/ogr_gml_geom.py index 46ddda5f0e60..2343e8f7bf3b 100755 --- a/autotest/ogr/ogr_gml_geom.py +++ b/autotest/ogr/ogr_gml_geom.py @@ -1579,6 +1579,17 @@ def test_gml_invalid_geoms(): '0 0 4 0 4 4 0 4 0 0', "POLYGON ((0 0,4 0,4 4,0 4,0 0))", ), + ("", None), + ("", None), + ("", None), + ( + "", + None, + ), + ( + "0 0", + None, + ), ("", None), ("", None), ("", None), @@ -3003,3 +3014,22 @@ def test_gml_read_gml_ArcByCenterPoint_projected_crs_northing_easting(): """ ) assert g is not None + + +############################################################################### +# Test reading an OrientableCurve + + +def test_gml_OrientableCurve(): + + g = ogr.CreateGeometryFromGML( + """ 0 1 2 3 """ + ) + assert g is not None + assert g.ExportToWkt() == "LINESTRING (0 1,2 3)" + + g = ogr.CreateGeometryFromGML( + """ 0 1 2 3 """ + ) + assert g is not None + assert g.ExportToWkt() == "LINESTRING (2 3,0 1)" diff --git a/autotest/ogr/ogr_hana.py b/autotest/ogr/ogr_hana.py index d6a6266f9c28..fb17c2898167 100644 --- a/autotest/ogr/ogr_hana.py +++ b/autotest/ogr/ogr_hana.py @@ -424,7 +424,7 @@ def test_ogr_hana_18(): feat_new = ogr.Feature(feature_def=layer.GetLayerDefn()) feat_new.SetField("PRFEDEA", "9999") layer.CreateFeature(feat_new) - feat_new.Destroy() + feat_new = None layer.SetAttributeFilter("PRFEDEA = '9999'") feat = layer.GetNextFeature() @@ -438,7 +438,7 @@ def test_ogr_hana_18(): assert layer.SetFeature(feat) == 0, "SetFeature() method failed." fid = feat.GetFID() - feat.Destroy() + feat = None feat = layer.GetFeature(fid) assert feat is not None, "GetFeature(%d) failed." % fid diff --git a/autotest/ogr/ogr_mssqlspatial.py b/autotest/ogr/ogr_mssqlspatial.py index 9a42741cd9f4..949ec06299ab 100755 --- a/autotest/ogr/ogr_mssqlspatial.py +++ b/autotest/ogr/ogr_mssqlspatial.py @@ -260,9 +260,6 @@ def test_ogr_mssqlspatial_4(mssql_ds, mssql_has_z_m): ogrtest.check_feature_geometry(feat_read, geom) - feat_read.Destroy() - - dst_feat.Destroy() mssqlspatial_lyr.ResetReading() # to close implicit transaction diff --git a/autotest/ogr/ogr_mysql.py b/autotest/ogr/ogr_mysql.py index 04e08ed29880..d490c69b736c 100755 --- a/autotest/ogr/ogr_mysql.py +++ b/autotest/ogr/ogr_mysql.py @@ -350,8 +350,6 @@ def test_ogr_mysql_6(mysql_ds): max_error=1e-3, ) - feat_read.Destroy() - sql_lyr.ResetReading() with ogrtest.spatial_filter(sql_lyr, "LINESTRING(-10 -10,0 0)"): @@ -556,7 +554,6 @@ def test_ogr_mysql_20(mysql_ds): # We are obliged to create a fake geometry dst_feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(0 1)")) layer.CreateFeature(dst_feat) - dst_feat.Destroy() layer = mysql_ds.GetLayerByName("select") layer.ResetReading() @@ -602,8 +599,6 @@ def test_ogr_mysql_22(mysql_ds): layer.CreateFeature(dst_feat) - dst_feat.Destroy() - layer.ResetReading() feat = layer.GetNextFeature() assert feat is not None diff --git a/autotest/ogr/ogr_oci.py b/autotest/ogr/ogr_oci.py index a8ad569222fe..7952d947633a 100755 --- a/autotest/ogr/ogr_oci.py +++ b/autotest/ogr/ogr_oci.py @@ -98,26 +98,20 @@ def test_ogr_oci_2(): ###################################################### # Copy in poly.shp - dst_feat = ogr.Feature(feature_def=gdaltest.oci_lyr.GetLayerDefn()) - shp_ds = ogr.Open("data/poly.shp") gdaltest.shp_ds = shp_ds shp_lyr = shp_ds.GetLayer(0) - feat = shp_lyr.GetNextFeature() gdaltest.poly_feat = [] - while feat is not None: + for feat in shp_lyr: gdaltest.poly_feat.append(feat) + dst_feat = ogr.Feature(feature_def=gdaltest.oci_lyr.GetLayerDefn()) dst_feat.SetFrom(feat) gdaltest.oci_lyr.CreateFeature(dst_feat) - feat = shp_lyr.GetNextFeature() - - dst_feat.Destroy() - # Test updating non-existing feature shp_lyr.ResetReading() feat = shp_lyr.GetNextFeature() @@ -213,10 +207,6 @@ def test_ogr_oci_4(): geom.SetCoordinateDimension(3) ogrtest.check_feature_geometry(geom_ref, geom) - feat_read.Destroy() - - dst_feat.Destroy() - ############################################################################### # Test ExecuteSQL() results layers without geometry. @@ -271,7 +261,6 @@ def test_ogr_oci_7(): geom = ogr.CreateGeometryFromWkt("LINESTRING(479505 4763195,480526 4762819)") gdaltest.oci_lyr.SetSpatialFilter(geom) - geom.Destroy() tr = ogrtest.check_features_against_list(gdaltest.oci_lyr, "eas_id", [158]) @@ -398,17 +387,15 @@ def test_ogr_oci_10(): """ ) - sql_lyr = gdaltest.oci_ds.ExecuteSQL("select * from geom_test where ora_fid = 1") + with gdaltest.oci_ds.ExecuteSQL( + "select * from geom_test where ora_fid = 1" + ) as sql_lyr: - feat_read = sql_lyr.GetNextFeature() + feat_read = sql_lyr.GetNextFeature() - expected_wkt = "POLYGON ((1 1 0,5 1 0,5 7 0,1 7 0,1 1 0))" + expected_wkt = "POLYGON ((1 1 0,5 1 0,5 7 0,1 7 0,1 1 0))" - try: ogrtest.check_feature_geometry(feat_read, expected_wkt) - finally: - feat_read.Destroy() - gdaltest.oci_ds.ReleaseResultSet(sql_lyr) ############################################################################### @@ -433,17 +420,15 @@ def test_ogr_oci_11(): """ ) - sql_lyr = gdaltest.oci_ds.ExecuteSQL("select * from geom_test where ora_fid = 4") + expected_wkt = "POLYGON ((10 9,9.989043790736547 9.209056926535308,9.956295201467611 9.415823381635519,9.902113032590307 9.618033988749895,9.827090915285202 9.8134732861516,9.732050807568877 10.0,9.618033988749895 10.175570504584947,9.486289650954788 10.338261212717716,9.338261212717717 10.486289650954788,9.175570504584947 10.618033988749895,9.0 10.732050807568877,8.8134732861516 10.827090915285202,8.618033988749895 10.902113032590307,8.415823381635519 10.956295201467611,8.209056926535308 10.989043790736547,8 11,7.790943073464693 10.989043790736547,7.584176618364482 10.956295201467611,7.381966011250105 10.902113032590307,7.1865267138484 10.827090915285202,7.0 10.732050807568877,6.824429495415054 10.618033988749895,6.661738787282284 10.486289650954788,6.513710349045212 10.338261212717716,6.381966011250105 10.175570504584947,6.267949192431122 10.0,6.172909084714799 9.8134732861516,6.097886967409693 9.618033988749895,6.043704798532389 9.415823381635519,6.010956209263453 9.209056926535308,6 9,6.010956209263453 8.790943073464694,6.043704798532389 8.584176618364483,6.097886967409693 8.381966011250105,6.172909084714798 8.1865267138484,6.267949192431123 8.0,6.381966011250105 7.824429495415054,6.513710349045212 7.661738787282284,6.661738787282284 7.513710349045212,6.824429495415053 7.381966011250105,7 7.267949192431123,7.1865267138484 7.172909084714798,7.381966011250105 7.097886967409693,7.584176618364481 7.043704798532389,7.790943073464693 7.010956209263453,8 7,8.209056926535306 7.010956209263453,8.415823381635518 7.043704798532389,8.618033988749895 7.097886967409693,8.8134732861516 7.172909084714799,9.0 7.267949192431123,9.175570504584947 7.381966011250105,9.338261212717715 7.513710349045211,9.486289650954788 7.661738787282284,9.618033988749895 7.824429495415053,9.732050807568877 8,9.827090915285202 8.1865267138484,9.902113032590307 8.381966011250105,9.956295201467611 8.584176618364481,9.989043790736547 8.790943073464693,10 9))" - feat_read = sql_lyr.GetNextFeature() + with gdaltest.oci_ds.ExecuteSQL( + "select * from geom_test where ora_fid = 4" + ) as sql_lyr: - expected_wkt = "POLYGON ((10 9,9.989043790736547 9.209056926535308,9.956295201467611 9.415823381635519,9.902113032590307 9.618033988749895,9.827090915285202 9.8134732861516,9.732050807568877 10.0,9.618033988749895 10.175570504584947,9.486289650954788 10.338261212717716,9.338261212717717 10.486289650954788,9.175570504584947 10.618033988749895,9.0 10.732050807568877,8.8134732861516 10.827090915285202,8.618033988749895 10.902113032590307,8.415823381635519 10.956295201467611,8.209056926535308 10.989043790736547,8 11,7.790943073464693 10.989043790736547,7.584176618364482 10.956295201467611,7.381966011250105 10.902113032590307,7.1865267138484 10.827090915285202,7.0 10.732050807568877,6.824429495415054 10.618033988749895,6.661738787282284 10.486289650954788,6.513710349045212 10.338261212717716,6.381966011250105 10.175570504584947,6.267949192431122 10.0,6.172909084714799 9.8134732861516,6.097886967409693 9.618033988749895,6.043704798532389 9.415823381635519,6.010956209263453 9.209056926535308,6 9,6.010956209263453 8.790943073464694,6.043704798532389 8.584176618364483,6.097886967409693 8.381966011250105,6.172909084714798 8.1865267138484,6.267949192431123 8.0,6.381966011250105 7.824429495415054,6.513710349045212 7.661738787282284,6.661738787282284 7.513710349045212,6.824429495415053 7.381966011250105,7 7.267949192431123,7.1865267138484 7.172909084714798,7.381966011250105 7.097886967409693,7.584176618364481 7.043704798532389,7.790943073464693 7.010956209263453,8 7,8.209056926535306 7.010956209263453,8.415823381635518 7.043704798532389,8.618033988749895 7.097886967409693,8.8134732861516 7.172909084714799,9.0 7.267949192431123,9.175570504584947 7.381966011250105,9.338261212717715 7.513710349045211,9.486289650954788 7.661738787282284,9.618033988749895 7.824429495415053,9.732050807568877 8,9.827090915285202 8.1865267138484,9.902113032590307 8.381966011250105,9.956295201467611 8.584176618364481,9.989043790736547 8.790943073464693,10 9))" + feat_read = sql_lyr.GetNextFeature() - try: ogrtest.check_feature_geometry(feat_read, expected_wkt) - finally: - feat_read.Destroy() - gdaltest.oci_ds.ReleaseResultSet(sql_lyr) ############################################################################### @@ -468,17 +453,15 @@ def test_ogr_oci_12(): """ ) - sql_lyr = gdaltest.oci_ds.ExecuteSQL("select * from geom_test where ora_fid = 12") + expected_wkt = "LINESTRING (0.0 0.0,0.104528463267653 0.005478104631727,0.207911690817759 0.021852399266194,0.309016994374947 0.048943483704846,0.4067366430758 0.086454542357399,0.5 0.133974596215561,0.587785252292473 0.190983005625053,0.669130606358858 0.256855174522606,0.743144825477394 0.330869393641142,0.809016994374947 0.412214747707527,0.866025403784439 0.5,0.913545457642601 0.5932633569242,0.951056516295154 0.690983005625053,0.978147600733806 0.792088309182241,0.994521895368273 0.895471536732347,1 1,0.994521895368273 1.104528463267654,0.978147600733806 1.207911690817759,0.951056516295154 1.309016994374948,0.913545457642601 1.4067366430758,0.866025403784439 1.5,0.809016994374947 1.587785252292473,0.743144825477394 1.669130606358858,0.669130606358858 1.743144825477394,0.587785252292473 1.809016994374948,0.5 1.866025403784439,0.4067366430758 1.913545457642601,0.309016994374947 1.951056516295154,0.207911690817759 1.978147600733806,0.104528463267653 1.994521895368273,0 2,-0.104528463267653 2.005478104631727,-0.207911690817759 2.021852399266194,-0.309016994374947 2.048943483704846,-0.4067366430758 2.086454542357399,-0.5 2.133974596215561,-0.587785252292473 2.190983005625053,-0.669130606358858 2.256855174522606,-0.743144825477394 2.330869393641142,-0.809016994374947 2.412214747707527,-0.866025403784439 2.5,-0.913545457642601 2.593263356924199,-0.951056516295154 2.690983005625053,-0.978147600733806 2.792088309182241,-0.994521895368273 2.895471536732346,-1 3,-0.994521895368273 3.104528463267653,-0.978147600733806 3.207911690817759,-0.951056516295154 3.309016994374948,-0.913545457642601 3.4067366430758,-0.866025403784439 3.5,-0.809016994374948 3.587785252292473,-0.743144825477394 3.669130606358858,-0.669130606358858 3.743144825477394,-0.587785252292473 3.809016994374948,-0.5 3.866025403784438,-0.4067366430758 3.913545457642601,-0.309016994374948 3.951056516295154,-0.20791169081776 3.978147600733806,-0.104528463267653 3.994521895368274,0 4,0.209056926535307 3.989043790736547,0.415823381635519 3.956295201467611,0.618033988749895 3.902113032590307,0.8134732861516 3.827090915285202,1.0 3.732050807568877,1.175570504584946 3.618033988749895,1.338261212717717 3.486289650954788,1.486289650954789 3.338261212717717,1.618033988749895 3.175570504584946,1.732050807568877 3.0,1.827090915285202 2.8134732861516,1.902113032590307 2.618033988749895,1.956295201467611 2.415823381635519,1.989043790736547 2.209056926535307,2 2,1.989043790736547 1.790943073464693,1.956295201467611 1.584176618364481,1.902113032590307 1.381966011250105,1.827090915285202 1.1865267138484,1.732050807568877 1.0,1.618033988749895 0.824429495415054,1.486289650954789 0.661738787282284,1.338261212717717 0.513710349045212,1.175570504584946 0.381966011250105,1.0 0.267949192431123,0.8134732861516 0.172909084714798,0.618033988749895 0.097886967409693,0.415823381635519 0.043704798532389,0.209056926535307 0.010956209263453,0.0 0.0)" - feat_read = sql_lyr.GetNextFeature() + with gdaltest.oci_ds.ExecuteSQL( + "select * from geom_test where ora_fid = 12" + ) as sql_lyr: - expected_wkt = "LINESTRING (0.0 0.0,0.104528463267653 0.005478104631727,0.207911690817759 0.021852399266194,0.309016994374947 0.048943483704846,0.4067366430758 0.086454542357399,0.5 0.133974596215561,0.587785252292473 0.190983005625053,0.669130606358858 0.256855174522606,0.743144825477394 0.330869393641142,0.809016994374947 0.412214747707527,0.866025403784439 0.5,0.913545457642601 0.5932633569242,0.951056516295154 0.690983005625053,0.978147600733806 0.792088309182241,0.994521895368273 0.895471536732347,1 1,0.994521895368273 1.104528463267654,0.978147600733806 1.207911690817759,0.951056516295154 1.309016994374948,0.913545457642601 1.4067366430758,0.866025403784439 1.5,0.809016994374947 1.587785252292473,0.743144825477394 1.669130606358858,0.669130606358858 1.743144825477394,0.587785252292473 1.809016994374948,0.5 1.866025403784439,0.4067366430758 1.913545457642601,0.309016994374947 1.951056516295154,0.207911690817759 1.978147600733806,0.104528463267653 1.994521895368273,0 2,-0.104528463267653 2.005478104631727,-0.207911690817759 2.021852399266194,-0.309016994374947 2.048943483704846,-0.4067366430758 2.086454542357399,-0.5 2.133974596215561,-0.587785252292473 2.190983005625053,-0.669130606358858 2.256855174522606,-0.743144825477394 2.330869393641142,-0.809016994374947 2.412214747707527,-0.866025403784439 2.5,-0.913545457642601 2.593263356924199,-0.951056516295154 2.690983005625053,-0.978147600733806 2.792088309182241,-0.994521895368273 2.895471536732346,-1 3,-0.994521895368273 3.104528463267653,-0.978147600733806 3.207911690817759,-0.951056516295154 3.309016994374948,-0.913545457642601 3.4067366430758,-0.866025403784439 3.5,-0.809016994374948 3.587785252292473,-0.743144825477394 3.669130606358858,-0.669130606358858 3.743144825477394,-0.587785252292473 3.809016994374948,-0.5 3.866025403784438,-0.4067366430758 3.913545457642601,-0.309016994374948 3.951056516295154,-0.20791169081776 3.978147600733806,-0.104528463267653 3.994521895368274,0 4,0.209056926535307 3.989043790736547,0.415823381635519 3.956295201467611,0.618033988749895 3.902113032590307,0.8134732861516 3.827090915285202,1.0 3.732050807568877,1.175570504584946 3.618033988749895,1.338261212717717 3.486289650954788,1.486289650954789 3.338261212717717,1.618033988749895 3.175570504584946,1.732050807568877 3.0,1.827090915285202 2.8134732861516,1.902113032590307 2.618033988749895,1.956295201467611 2.415823381635519,1.989043790736547 2.209056926535307,2 2,1.989043790736547 1.790943073464693,1.956295201467611 1.584176618364481,1.902113032590307 1.381966011250105,1.827090915285202 1.1865267138484,1.732050807568877 1.0,1.618033988749895 0.824429495415054,1.486289650954789 0.661738787282284,1.338261212717717 0.513710349045212,1.175570504584946 0.381966011250105,1.0 0.267949192431123,0.8134732861516 0.172909084714798,0.618033988749895 0.097886967409693,0.415823381635519 0.043704798532389,0.209056926535307 0.010956209263453,0.0 0.0)" + feat_read = sql_lyr.GetNextFeature() - try: ogrtest.check_feature_geometry(feat_read, expected_wkt) - finally: - feat_read.Destroy() - gdaltest.oci_ds.ReleaseResultSet(sql_lyr) ############################################################################### @@ -503,17 +486,15 @@ def test_ogr_oci_13(): """ ) - sql_lyr = gdaltest.oci_ds.ExecuteSQL("select * from geom_test where ora_fid = 13") + expected_wkt = "POLYGON ((0.0 0.0,0.104528463267653 0.005478104631727,0.207911690817759 0.021852399266194,0.309016994374947 0.048943483704846,0.4067366430758 0.086454542357399,0.5 0.133974596215561,0.587785252292473 0.190983005625053,0.669130606358858 0.256855174522606,0.743144825477394 0.330869393641142,0.809016994374947 0.412214747707527,0.866025403784439 0.5,0.913545457642601 0.5932633569242,0.951056516295154 0.690983005625053,0.978147600733806 0.792088309182241,0.994521895368273 0.895471536732347,1 1,0.994521895368273 1.104528463267654,0.978147600733806 1.207911690817759,0.951056516295154 1.309016994374948,0.913545457642601 1.4067366430758,0.866025403784439 1.5,0.809016994374947 1.587785252292473,0.743144825477394 1.669130606358858,0.669130606358858 1.743144825477394,0.587785252292473 1.809016994374948,0.5 1.866025403784439,0.4067366430758 1.913545457642601,0.309016994374947 1.951056516295154,0.207911690817759 1.978147600733806,0.104528463267653 1.994521895368273,0 2,-0.104528463267653 2.005478104631727,-0.207911690817759 2.021852399266194,-0.309016994374947 2.048943483704846,-0.4067366430758 2.086454542357399,-0.5 2.133974596215561,-0.587785252292473 2.190983005625053,-0.669130606358858 2.256855174522606,-0.743144825477394 2.330869393641142,-0.809016994374947 2.412214747707527,-0.866025403784439 2.5,-0.913545457642601 2.593263356924199,-0.951056516295154 2.690983005625053,-0.978147600733806 2.792088309182241,-0.994521895368273 2.895471536732346,-1 3,-0.994521895368273 3.104528463267653,-0.978147600733806 3.207911690817759,-0.951056516295154 3.309016994374948,-0.913545457642601 3.4067366430758,-0.866025403784439 3.5,-0.809016994374948 3.587785252292473,-0.743144825477394 3.669130606358858,-0.669130606358858 3.743144825477394,-0.587785252292473 3.809016994374948,-0.5 3.866025403784438,-0.4067366430758 3.913545457642601,-0.309016994374948 3.951056516295154,-0.20791169081776 3.978147600733806,-0.104528463267653 3.994521895368274,0 4,0.209056926535307 3.989043790736547,0.415823381635519 3.956295201467611,0.618033988749895 3.902113032590307,0.8134732861516 3.827090915285202,1.0 3.732050807568877,1.175570504584946 3.618033988749895,1.338261212717717 3.486289650954788,1.486289650954789 3.338261212717717,1.618033988749895 3.175570504584946,1.732050807568877 3.0,1.827090915285202 2.8134732861516,1.902113032590307 2.618033988749895,1.956295201467611 2.415823381635519,1.989043790736547 2.209056926535307,2 2,1.989043790736547 1.790943073464693,1.956295201467611 1.584176618364481,1.902113032590307 1.381966011250105,1.827090915285202 1.1865267138484,1.732050807568877 1.0,1.618033988749895 0.824429495415054,1.486289650954789 0.661738787282284,1.338261212717717 0.513710349045212,1.175570504584946 0.381966011250105,1.0 0.267949192431123,0.8134732861516 0.172909084714798,0.618033988749895 0.097886967409693,0.415823381635519 0.043704798532389,0.209056926535307 0.010956209263453,0.0 0.0))" - feat_read = sql_lyr.GetNextFeature() + with gdaltest.oci_ds.ExecuteSQL( + "select * from geom_test where ora_fid = 13" + ) as sql_lyr: - expected_wkt = "POLYGON ((0.0 0.0,0.104528463267653 0.005478104631727,0.207911690817759 0.021852399266194,0.309016994374947 0.048943483704846,0.4067366430758 0.086454542357399,0.5 0.133974596215561,0.587785252292473 0.190983005625053,0.669130606358858 0.256855174522606,0.743144825477394 0.330869393641142,0.809016994374947 0.412214747707527,0.866025403784439 0.5,0.913545457642601 0.5932633569242,0.951056516295154 0.690983005625053,0.978147600733806 0.792088309182241,0.994521895368273 0.895471536732347,1 1,0.994521895368273 1.104528463267654,0.978147600733806 1.207911690817759,0.951056516295154 1.309016994374948,0.913545457642601 1.4067366430758,0.866025403784439 1.5,0.809016994374947 1.587785252292473,0.743144825477394 1.669130606358858,0.669130606358858 1.743144825477394,0.587785252292473 1.809016994374948,0.5 1.866025403784439,0.4067366430758 1.913545457642601,0.309016994374947 1.951056516295154,0.207911690817759 1.978147600733806,0.104528463267653 1.994521895368273,0 2,-0.104528463267653 2.005478104631727,-0.207911690817759 2.021852399266194,-0.309016994374947 2.048943483704846,-0.4067366430758 2.086454542357399,-0.5 2.133974596215561,-0.587785252292473 2.190983005625053,-0.669130606358858 2.256855174522606,-0.743144825477394 2.330869393641142,-0.809016994374947 2.412214747707527,-0.866025403784439 2.5,-0.913545457642601 2.593263356924199,-0.951056516295154 2.690983005625053,-0.978147600733806 2.792088309182241,-0.994521895368273 2.895471536732346,-1 3,-0.994521895368273 3.104528463267653,-0.978147600733806 3.207911690817759,-0.951056516295154 3.309016994374948,-0.913545457642601 3.4067366430758,-0.866025403784439 3.5,-0.809016994374948 3.587785252292473,-0.743144825477394 3.669130606358858,-0.669130606358858 3.743144825477394,-0.587785252292473 3.809016994374948,-0.5 3.866025403784438,-0.4067366430758 3.913545457642601,-0.309016994374948 3.951056516295154,-0.20791169081776 3.978147600733806,-0.104528463267653 3.994521895368274,0 4,0.209056926535307 3.989043790736547,0.415823381635519 3.956295201467611,0.618033988749895 3.902113032590307,0.8134732861516 3.827090915285202,1.0 3.732050807568877,1.175570504584946 3.618033988749895,1.338261212717717 3.486289650954788,1.486289650954789 3.338261212717717,1.618033988749895 3.175570504584946,1.732050807568877 3.0,1.827090915285202 2.8134732861516,1.902113032590307 2.618033988749895,1.956295201467611 2.415823381635519,1.989043790736547 2.209056926535307,2 2,1.989043790736547 1.790943073464693,1.956295201467611 1.584176618364481,1.902113032590307 1.381966011250105,1.827090915285202 1.1865267138484,1.732050807568877 1.0,1.618033988749895 0.824429495415054,1.486289650954789 0.661738787282284,1.338261212717717 0.513710349045212,1.175570504584946 0.381966011250105,1.0 0.267949192431123,0.8134732861516 0.172909084714798,0.618033988749895 0.097886967409693,0.415823381635519 0.043704798532389,0.209056926535307 0.010956209263453,0.0 0.0))" + feat_read = sql_lyr.GetNextFeature() - try: ogrtest.check_feature_geometry(feat_read, expected_wkt) - finally: - feat_read.Destroy() - gdaltest.oci_ds.ReleaseResultSet(sql_lyr) ############################################################################### @@ -538,17 +519,15 @@ def test_ogr_oci_14(): """ ) - sql_lyr = gdaltest.oci_ds.ExecuteSQL("select * from geom_test where ora_fid = 11") + expected_wkt = "LINESTRING (10 10,10 14,9.58188614692939 13.9780875814731,9.16835323672896 13.9125904029352,8.76393202250021 13.8042260651806,8.3730534276968 13.6541818305704,8.0 13.4641016151378,7.64885899083011 13.2360679774998,7.32347757456457 12.9725793019096,7.02742069809042 12.6765224254354,6.76393202250021 12.3511410091699,6.53589838486224 12.0,6.3458181694296 11.6269465723032,6.19577393481939 11.2360679774998,6.08740959706478 10.831646763271,6.02191241852691 10.4181138530706,6 10,6.02191241852691 9.58188614692939,6.08740959706478 9.16835323672896,6.19577393481939 8.76393202250021,6.3458181694296 8.3730534276968,6.53589838486225 8.0,6.76393202250021 7.64885899083011,7.02742069809042 7.32347757456457,7.32347757456457 7.02742069809042,7.64885899083011 6.76393202250021,8.0 6.53589838486225,8.3730534276968 6.3458181694296,8.76393202250021 6.19577393481939,9.16835323672896 6.08740959706478,9.58188614692939 6.02191241852691,10 6,10.4181138530706 6.02191241852691,10.831646763271 6.08740959706478,11.2360679774998 6.19577393481939,11.6269465723032 6.3458181694296,12.0 6.53589838486225,12.3511410091699 6.76393202250021,12.6765224254354 7.02742069809042,12.9725793019096 7.32347757456457,13.2360679774998 7.64885899083011,13.4641016151378 8.0,13.6541818305704 8.3730534276968,13.8042260651806 8.76393202250021,13.9125904029352 9.16835323672896,13.9780875814731 9.58188614692939,14 10)" - feat_read = sql_lyr.GetNextFeature() + with gdaltest.oci_ds.ExecuteSQL( + "select * from geom_test where ora_fid = 11" + ) as sql_lyr: - expected_wkt = "LINESTRING (10 10,10 14,9.58188614692939 13.9780875814731,9.16835323672896 13.9125904029352,8.76393202250021 13.8042260651806,8.3730534276968 13.6541818305704,8.0 13.4641016151378,7.64885899083011 13.2360679774998,7.32347757456457 12.9725793019096,7.02742069809042 12.6765224254354,6.76393202250021 12.3511410091699,6.53589838486224 12.0,6.3458181694296 11.6269465723032,6.19577393481939 11.2360679774998,6.08740959706478 10.831646763271,6.02191241852691 10.4181138530706,6 10,6.02191241852691 9.58188614692939,6.08740959706478 9.16835323672896,6.19577393481939 8.76393202250021,6.3458181694296 8.3730534276968,6.53589838486225 8.0,6.76393202250021 7.64885899083011,7.02742069809042 7.32347757456457,7.32347757456457 7.02742069809042,7.64885899083011 6.76393202250021,8.0 6.53589838486225,8.3730534276968 6.3458181694296,8.76393202250021 6.19577393481939,9.16835323672896 6.08740959706478,9.58188614692939 6.02191241852691,10 6,10.4181138530706 6.02191241852691,10.831646763271 6.08740959706478,11.2360679774998 6.19577393481939,11.6269465723032 6.3458181694296,12.0 6.53589838486225,12.3511410091699 6.76393202250021,12.6765224254354 7.02742069809042,12.9725793019096 7.32347757456457,13.2360679774998 7.64885899083011,13.4641016151378 8.0,13.6541818305704 8.3730534276968,13.8042260651806 8.76393202250021,13.9125904029352 9.16835323672896,13.9780875814731 9.58188614692939,14 10)" + feat_read = sql_lyr.GetNextFeature() - try: ogrtest.check_feature_geometry(feat_read, expected_wkt) - finally: - feat_read.Destroy() - gdaltest.oci_ds.ReleaseResultSet(sql_lyr) ############################################################################### @@ -573,17 +552,15 @@ def test_ogr_oci_15(): """ ) - sql_lyr = gdaltest.oci_ds.ExecuteSQL("select * from geom_test where ora_fid = 21") + expected_wkt = "POLYGON ((-10 10,10 10,9.94521895368273 8.95471536732347,9.78147600733806 7.92088309182241,9.51056516295153 6.90983005625053,9.13545457642601 5.932633569242,8.66025403784439 5.0,8.09016994374947 4.12214747707527,7.43144825477394 3.30869393641142,6.69130606358858 2.56855174522606,5.87785252292473 1.90983005625053,5.0 1.33974596215561,4.067366430758 0.864545423573992,3.09016994374947 0.489434837048465,2.07911690817759 0.218523992661945,1.04528463267653 0.054781046317267,0.0 0.0,-1.04528463267653 0.054781046317267,-2.07911690817759 0.218523992661943,-3.09016994374947 0.489434837048464,-4.067366430758 0.86454542357399,-5 1.33974596215561,-5.87785252292473 1.90983005625053,-6.69130606358858 2.56855174522606,-7.43144825477394 3.30869393641142,-8.09016994374947 4.12214747707527,-8.66025403784439 5.0,-9.13545457642601 5.932633569242,-9.51056516295153 6.90983005625053,-9.78147600733806 7.92088309182241,-9.94521895368273 8.95471536732346,-10 10))" - feat_read = sql_lyr.GetNextFeature() + with gdaltest.oci_ds.ExecuteSQL( + "select * from geom_test where ora_fid = 21" + ) as sql_lyr: - expected_wkt = "POLYGON ((-10 10,10 10,9.94521895368273 8.95471536732347,9.78147600733806 7.92088309182241,9.51056516295153 6.90983005625053,9.13545457642601 5.932633569242,8.66025403784439 5.0,8.09016994374947 4.12214747707527,7.43144825477394 3.30869393641142,6.69130606358858 2.56855174522606,5.87785252292473 1.90983005625053,5.0 1.33974596215561,4.067366430758 0.864545423573992,3.09016994374947 0.489434837048465,2.07911690817759 0.218523992661945,1.04528463267653 0.054781046317267,0.0 0.0,-1.04528463267653 0.054781046317267,-2.07911690817759 0.218523992661943,-3.09016994374947 0.489434837048464,-4.067366430758 0.86454542357399,-5 1.33974596215561,-5.87785252292473 1.90983005625053,-6.69130606358858 2.56855174522606,-7.43144825477394 3.30869393641142,-8.09016994374947 4.12214747707527,-8.66025403784439 5.0,-9.13545457642601 5.932633569242,-9.51056516295153 6.90983005625053,-9.78147600733806 7.92088309182241,-9.94521895368273 8.95471536732346,-10 10))" + feat_read = sql_lyr.GetNextFeature() - try: ogrtest.check_feature_geometry(feat_read, expected_wkt) - finally: - feat_read.Destroy() - gdaltest.oci_ds.ReleaseResultSet(sql_lyr) ############################################################################### @@ -634,26 +611,20 @@ def test_ogr_oci_17(): ###################################################### # Copy in poly.shp - dst_feat = ogr.Feature(feature_def=gdaltest.oci_lyr.GetLayerDefn()) - shp_ds = ogr.Open("data/poly.shp") gdaltest.shp_ds = shp_ds shp_lyr = shp_ds.GetLayer(0) - feat = shp_lyr.GetNextFeature() gdaltest.poly_feat = [] - while feat is not None: + for feat in shp_lyr: gdaltest.poly_feat.append(feat) + dst_feat = ogr.Feature(feature_def=gdaltest.oci_lyr.GetLayerDefn()) dst_feat.SetFrom(feat) gdaltest.oci_lyr.CreateFeature(dst_feat) - feat = shp_lyr.GetNextFeature() - - dst_feat.Destroy() - ###################################################### # Create a distinct connection to the same database to monitor the # metadata table. diff --git a/autotest/ogr/ogr_openfilegdb.py b/autotest/ogr/ogr_openfilegdb.py index 3ea017d1f425..7d3f41f63591 100755 --- a/autotest/ogr/ogr_openfilegdb.py +++ b/autotest/ogr/ogr_openfilegdb.py @@ -810,6 +810,9 @@ def test_ogr_openfilegdb_4(): ("str IN ('aaa ')", [], IDX_USED), ("str IN ('aaaX')", [], IDX_USED), ("str IN ('aaaXX')", [], IDX_USED), + ("str ILIKE 'a'", [1], IDX_NOT_USED), + ("str ILIKE 'a%'", [1, 2, 3], IDX_NOT_USED), + ("str ILIKE 'aaa '", [], IDX_NOT_USED), ], ) def test_ogr_openfilegdb_str_indexed_truncated( @@ -832,6 +835,24 @@ def test_ogr_openfilegdb_str_indexed_truncated( assert [f.GetFID() for f in lyr] == fids, (where_clause, fids) +def test_ogr_openfilegdb_ilike(): + + ds = ogr.Open("data/filegdb/Domains.gdb/a00000001.gdbtable") + lyr = ds.GetLayer(0) + + lyr.SetAttributeFilter("Name = 'Roads'") + assert lyr.GetFeatureCount() == 1 + + lyr.SetAttributeFilter("Name ILIKE 'Roads'") + assert lyr.GetFeatureCount() == 1 + + lyr.SetAttributeFilter("Name = 'Roadsx'") + assert lyr.GetFeatureCount() == 0 + + lyr.SetAttributeFilter("Name ILIKE 'Roadsx'") + assert lyr.GetFeatureCount() == 0 + + ############################################################################### # Test opening an unzipped dataset diff --git a/autotest/ogr/ogr_osm.py b/autotest/ogr/ogr_osm.py index f50d66b04a68..09666b00edbd 100755 --- a/autotest/ogr/ogr_osm.py +++ b/autotest/ogr/ogr_osm.py @@ -929,3 +929,21 @@ def test_ogr_osm_tags_json_special_characters(): assert lyr_defn.GetFieldDefn(other_tags_idx).GetSubType() == ogr.OFSTJSON f = lyr.GetNextFeature() assert f["other_tags"] == """{"foo":"x'\\\\\\"\\t\\n\\ry"}""" + + +############################################################################### +# Test that osmconf.ini can be parsed with Python's configparser + + +def test_ogr_osmconf_ini(): + + import configparser + + with ogr.Open("data/osm/test_json.pbf") as ds: + with ds.ExecuteSQL("SHOW config_file_path") as sql_lyr: + f = sql_lyr.GetNextFeature() + osmconf_ini_filename = f.GetField(0) + config = configparser.ConfigParser() + config.read_file(open(osmconf_ini_filename)) + assert "general" in config + assert "closed_ways_are_polygons" in config["general"] diff --git a/autotest/ogr/ogr_pg.py b/autotest/ogr/ogr_pg.py index 8a8ad9a75357..ea9c514e3a77 100755 --- a/autotest/ogr/ogr_pg.py +++ b/autotest/ogr/ogr_pg.py @@ -681,9 +681,6 @@ def test_ogr_pg_4(pg_ds): ogrtest.check_feature_geometry(feat_read, geom) - feat_read.Destroy() - - dst_feat.Destroy() pg_lyr.ResetReading() # to close implicit transaction @@ -915,7 +912,6 @@ def test_ogr_pg_10(pg_ds): pg_lyr.SetAttributeFilter(None) fid = feat.GetFID() - feat.Destroy() assert pg_lyr.DeleteFeature(fid) == 0, "DeleteFeature() method failed." @@ -1173,7 +1169,6 @@ def test_ogr_pg_20(pg_ds): geom = feat.GetGeometryRef() assert geom is not None, "did not get geometry, expected %s" % geoms[1] wkt = geom.ExportToIsoWkt() - feat.Destroy() feat = None assert wkt == geoms[1], "WKT do not match: expected %s, got %s" % ( @@ -1195,23 +1190,17 @@ def test_ogr_pg_21(pg_ds): layer = pg_ds.ExecuteSQL("SELECT wkb_geometry FROM testgeom") assert layer is not None, "did not get testgeom layer" - feat = layer.GetNextFeature() - while feat is not None: + for feat in layer: geom = feat.GetGeometryRef() if ( ogr.GT_HasZ(geom.GetGeometryType()) == 0 or ogr.GT_HasM(geom.GetGeometryType()) == 0 ): - feat.Destroy() feat = None pg_ds.ReleaseResultSet(layer) layer = None pytest.fail("expected feature with type >3000") - feat.Destroy() - feat = layer.GetNextFeature() - - feat = None pg_ds.ReleaseResultSet(layer) layer = None @@ -1259,7 +1248,6 @@ def test_ogr_pg_21_subgeoms(pg_ds): ), "did not get the expected subgeometry, expected %s" % ( subgeom_TIN[j] ) - feat.Destroy() feat = None @@ -1772,7 +1760,6 @@ def test_ogr_pg_33(pg_ds): # eacute in UTF8 : 0xc3 0xa9 dst_feat.SetField("SHORTNAME", "\xc3\xa9") pg_lyr.CreateFeature(dst_feat) - dst_feat.Destroy() ############################################################################### @@ -2412,7 +2399,6 @@ def test_ogr_pg_47(pg_ds, pg_postgis_version, pg_postgis_schema): ) field_defn = ogr.FieldDefn("test_string", ogr.OFTString) lyr.CreateField(field_defn) - field_defn.Destroy() feature_defn = lyr.GetLayerDefn() @@ -6121,3 +6107,38 @@ def test_ogr_pg_skip_conflicts(pg_ds): feat["beginnt"] = "2020-07-10T04:48:14Z" assert lyr.CreateFeature(feat) == ogr.OGRERR_NONE assert lyr.GetFeatureCount() == 2 + + +############################################################################### +# Test scenario of https://github.com/OSGeo/gdal/issues/10311 + + +@only_without_postgis +@gdaltest.enable_exceptions() +def test_ogr_pg_ogr2ogr_with_multiple_dotted_table_name(pg_ds): + + tmp_schema = "tmp_schema_issue_10311" + pg_ds.ExecuteSQL(f'CREATE SCHEMA "{tmp_schema}"') + try: + src_ds = gdal.GetDriverByName("Memory").Create("", 0, 0, 0, gdal.GDT_Unknown) + lyr = src_ds.CreateLayer(tmp_schema + ".table1", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("str")) + f = ogr.Feature(lyr.GetLayerDefn()) + f["str"] = "foo" + lyr.CreateFeature(f) + lyr = src_ds.CreateLayer(tmp_schema + ".table2", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("str")) + f = ogr.Feature(lyr.GetLayerDefn()) + f["str"] = "bar" + lyr.CreateFeature(f) + + gdal.VectorTranslate(pg_ds.GetDescription(), src_ds) + + pg_ds = reconnect(pg_ds) + lyr = pg_ds.GetLayerByName(tmp_schema + ".table1") + assert lyr.GetFeatureCount() == 1 + lyr = pg_ds.GetLayerByName(tmp_schema + ".table2") + assert lyr.GetFeatureCount() == 1 + + finally: + pg_ds.ExecuteSQL(f'DROP SCHEMA "{tmp_schema}" CASCADE') diff --git a/autotest/ogr/ogr_sql_rfc28.py b/autotest/ogr/ogr_sql_rfc28.py index d5aa09bdac81..6b54af821e2b 100755 --- a/autotest/ogr/ogr_sql_rfc28.py +++ b/autotest/ogr/ogr_sql_rfc28.py @@ -881,7 +881,7 @@ def test_ogr_rfc28_39(data_ds): ############################################################################### -# Test MIN(), MAX() and AVG() on a date (#5333) +# Test MIN(), MAX(), AVG(), STDDEV_POP(), STDDEV_SAMP() on a date (#5333) def test_ogr_rfc28_40(): @@ -896,15 +896,16 @@ def test_ogr_rfc28_40(): feat.SetField(0, "2013/01/01 00:00:00") lyr.CreateFeature(feat) - with ds.ExecuteSQL("SELECT MIN(DATE), MAX(DATE), AVG(DATE) from test") as lyr: + with ds.ExecuteSQL( + "SELECT MIN(DATE), MAX(DATE), AVG(DATE), STDDEV_POP(DATE), STDDEV_SAMP(DATE) from test" + ) as sql_lyr: - ogrtest.check_features_against_list(lyr, "MIN_DATE", ["2013/01/01 00:00:00"]) - lyr.ResetReading() - ogrtest.check_features_against_list(lyr, "MAX_DATE", ["2013/12/31 23:59:59"]) - lyr.ResetReading() - ogrtest.check_features_against_list( - lyr, "AVG_DATE", ["2013/07/02 11:59:59.500"] - ) + f = sql_lyr.GetNextFeature() + assert f["MIN_DATE"] == "2013/01/01 00:00:00" + assert f["MAX_DATE"] == "2013/12/31 23:59:59" + assert f["AVG_DATE"] == "2013/07/02 11:59:59.500" + assert f["STDDEV_POP_DATE"] == pytest.approx(15767999.5, rel=1e-15) + assert f["STDDEV_SAMP_DATE"] == pytest.approx(22299318.744392183, rel=1e-15) ############################################################################### diff --git a/autotest/ogr/ogr_sql_test.py b/autotest/ogr/ogr_sql_test.py index a328f8b36bda..a3041c326e81 100755 --- a/autotest/ogr/ogr_sql_test.py +++ b/autotest/ogr/ogr_sql_test.py @@ -27,6 +27,7 @@ # Boston, MA 02111-1307, USA. ############################################################################### +import math import os import shutil @@ -254,12 +255,14 @@ def test_ogr_sql_4(data_ds): def test_ogr_sql_5(data_ds): with data_ds.ExecuteSQL( - "select max(eas_id), min(eas_id), avg(eas_id), sum(eas_id), count(eas_id) from idlink" + "select max(eas_id), min(eas_id), avg(eas_id), STDDEV_POP(eas_id), STDDEV_SAMP(eas_id), sum(eas_id), count(eas_id) from idlink" ) as sql_lyr: feat = sql_lyr.GetNextFeature() assert feat["max_eas_id"] == 179 assert feat["min_eas_id"] == 158 assert feat["avg_eas_id"] == pytest.approx(168.142857142857, abs=1e-12) + assert feat["STDDEV_POP_eas_id"] == pytest.approx(5.9384599116647205, rel=1e-15) + assert feat["STDDEV_SAMP_eas_id"] == pytest.approx(6.414269805898183, rel=1e-15) assert feat["count_eas_id"] == 7 assert feat["sum_eas_id"] == 1177 @@ -714,6 +717,8 @@ def ds_for_invalid_statements(): "SELECT 1 - FROM my_layer", "SELECT 1 * FROM my_layer", "SELECT 1 % FROM my_layer", + "SELECT x.", + "SELECT x AS", "SELECT *", "SELECT * FROM", "SELECT * FROM foo", @@ -788,10 +793,15 @@ def ds_for_invalid_statements(): "SELECT MAX(foo) FROM my_layer", "SELECT SUM(foo) FROM my_layer", "SELECT AVG(foo) FROM my_layer", + "SELECT STDDEV_POP(foo) FROM my_layer", + "SELECT STDDEV_SAMP(foo) FROM my_layer", "SELECT SUM(strfield) FROM my_layer", "SELECT AVG(strfield) FROM my_layer", "SELECT AVG(intfield, intfield) FROM my_layer", + "SELECT STDDEV_POP(strfield) FROM my_layer", + "SELECT STDDEV_SAMP(strfield) FROM my_layer", "SELECT * FROM my_layer WHERE AVG(intfield) = 1", + "SELECT * FROM my_layer WHERE STDDEV_POP(intfield) = 1", "SELECT * FROM 'foo' foo", "SELECT * FROM my_layer WHERE strfield =", "SELECT * FROM my_layer WHERE strfield = foo", @@ -1100,10 +1110,11 @@ def test_ogr_sql_count_and_null(): assert feat.GetFieldAsInteger(2) == 4, fieldname with ds.ExecuteSQL( - "select avg(intfield) from layer where intfield is null" + "select avg(intfield), STDDEV_POP(intfield) from layer where intfield is null" ) as sql_lyr: feat = sql_lyr.GetNextFeature() assert feat.IsFieldSetAndNotNull(0) == 0 + assert feat.IsFieldSetAndNotNull(1) == 0 # Fix crash when first values is null (#4509) with ds.ExecuteSQL("select distinct strfield_first_null from layer") as sql_lyr: @@ -2102,3 +2113,32 @@ def test_ogr_sql_identifier_hidden(): with ds.ExecuteSQL("SELECT 'foo' AS hidden FROM hidden") as sql_lyr: f = sql_lyr.GetNextFeature() assert f["hidden"] == "foo" + + +@pytest.mark.parametrize( + "input,expected_output", + [ + [(1, 1e100, 1, -1e100), 2], + [(float("inf"), 1), float("inf")], + [(1, float("-inf")), float("-inf")], + [(1, float("nan")), float("nan")], + [(float("inf"), float("-inf")), float("nan")], + ], +) +def test_ogr_sql_kahan_babuska_eumaier_summation(input, expected_output): + """Test accurate SUM() implementation using Kahan-Babuska-Neumaier algorithm""" + + ds = ogr.GetDriverByName("Memory").CreateDataSource("") + lyr = ds.CreateLayer("test") + lyr.CreateField(ogr.FieldDefn("v", ogr.OFTReal)) + for v in input: + feat = ogr.Feature(lyr.GetLayerDefn()) + feat["v"] = v + lyr.CreateFeature(feat) + + with ds.ExecuteSQL("SELECT SUM(v) FROM test") as sql_lyr: + f = sql_lyr.GetNextFeature() + if math.isnan(expected_output): + assert math.isnan(f["SUM_v"]) + else: + assert f["SUM_v"] == expected_output diff --git a/autotest/ogr/ogr_sqlite.py b/autotest/ogr/ogr_sqlite.py index a85b64511b75..0cd69866f057 100755 --- a/autotest/ogr/ogr_sqlite.py +++ b/autotest/ogr/ogr_sqlite.py @@ -1457,7 +1457,7 @@ def test_ogr_spatialite_2(sqlite_test_db): dst_feat = ogr.Feature(feature_def=lyr.GetLayerDefn()) dst_feat.SetGeometry(geom) lyr.CreateFeature(dst_feat) - dst_feat.Destroy() + dst_feat = None lyr.CommitTransaction() @@ -1577,7 +1577,6 @@ def test_ogr_spatialite_2(sqlite_test_db): geom = ogr.CreateGeometryFromWkt("POLYGON((2 2,2 8,8 8,8 2,2 2))") lyr.SetSpatialFilter(geom) - geom.Destroy() assert lyr.TestCapability(ogr.OLCFastFeatureCount) is not True assert lyr.TestCapability(ogr.OLCFastSpatialFilter) is not True @@ -1638,7 +1637,6 @@ def test_ogr_spatialite_4(sqlite_test_db): feat = lyr.GetNextFeature() geom = feat.GetGeometryRef() assert geom is not None and geom.ExportToWkt() == "POINT (0 1)" - feat.Destroy() # Check that triggers and index are restored (#3474) with sqlite_test_db.ExecuteSQL("SELECT * FROM sqlite_master") as lyr: @@ -1656,7 +1654,6 @@ def test_ogr_spatialite_4(sqlite_test_db): feat = ogr.Feature(lyr.GetLayerDefn()) feat.SetGeometryDirectly(ogr.CreateGeometryFromWkt("POINT(100 -100)")) lyr.CreateFeature(feat) - feat.Destroy() # Check that the trigger is functional (#3474). with sqlite_test_db.ExecuteSQL("SELECT * FROM idx_geomspatialite_GEOMETRY") as lyr: @@ -4095,3 +4092,15 @@ def test_ogr_sql_ST_Area_on_ellipsoid(tmp_vsimem, require_spatialite): with ds.ExecuteSQL("SELECT ST_Area(null, 1) FROM my_layer") as sql_lyr: f = sql_lyr.GetNextFeature() assert f[0] is None + + +def test_ogr_sqlite_stddev(): + """Test STDDEV_POP() and STDDEV_SAMP""" + + ds = ogr.Open(":memory:", update=1) + ds.ExecuteSQL("CREATE TABLE test(v REAL)") + ds.ExecuteSQL("INSERT INTO test VALUES (4),(NULL),('invalid'),(5)") + with ds.ExecuteSQL("SELECT STDDEV_POP(v), STDDEV_SAMP(v) FROM test") as sql_lyr: + f = sql_lyr.GetNextFeature() + assert f.GetField(0) == pytest.approx(0.5, rel=1e-15) + assert f.GetField(1) == pytest.approx(0.5**0.5, rel=1e-15) diff --git a/autotest/ogr/ogr_wkbwkt_geom.py b/autotest/ogr/ogr_wkbwkt_geom.py index 6930da09fcfc..0033a03433b6 100755 --- a/autotest/ogr/ogr_wkbwkt_geom.py +++ b/autotest/ogr/ogr_wkbwkt_geom.py @@ -98,8 +98,6 @@ def test_wkbwkt_geom(filename): # print geom_wkt.ExportToWkt() # return 'fail' - geom_wkb.Destroy() - ###################################################################### # Convert geometry to WKB and back to verify that WKB encoding is # working smoothly. @@ -109,17 +107,11 @@ def test_wkbwkt_geom(filename): assert str(geom_wkb) == str(geom_wkt), "XDR WKB encoding/decoding failure." - geom_wkb.Destroy() - wkb_ndr = geom_wkt.ExportToWkb(ogr.wkbNDR) geom_wkb = ogr.CreateGeometryFromWkb(wkb_ndr) assert str(geom_wkb) == str(geom_wkt), "NDR WKB encoding/decoding failure." - geom_wkb.Destroy() - - geom_wkt.Destroy() - ############################################################################### # Test geometry with very large exponents of coordinate values. @@ -166,6 +158,7 @@ def test_ogr_wkbwkt_test_broken_geom(): "POINT Z(EMPTY)", "POINT Z(A)", "POINT Z(0 1", + "POINTZ M EMPTY", "LINESTRING", "LINESTRING UNKNOWN", "LINESTRING(", @@ -372,76 +365,79 @@ def test_ogr_wkbwkt_test_broken_geom(): # Test importing WKT SF1.2 -def test_ogr_wkbwkt_test_import_wkt_sf12(): - - list_wkt_tuples = [ +@pytest.mark.parametrize( + "input_wkt,expected_output_wkt", + [ ("POINT EMPTY", "POINT EMPTY"), - ("POINT Z EMPTY", "POINT EMPTY"), - ("POINT M EMPTY", "POINT EMPTY"), - ("POINT ZM EMPTY", "POINT EMPTY"), + ("POINT Z EMPTY", "POINT Z EMPTY"), + ("POINT M EMPTY", "POINT M EMPTY"), + ("POINT ZM EMPTY", "POINT ZM EMPTY"), ("POINT (0 1)", "POINT (0 1)"), - ("POINT Z (0 1 2)", "POINT (0 1 2)"), - ("POINT M (0 1 2)", "POINT (0 1)"), - ("POINT ZM (0 1 2 3)", "POINT (0 1 2)"), + ("POINT Z (0 1 2)", "POINT Z (0 1 2)"), + ("POINT M (0 1 2)", "POINT M (0 1 2)"), + ("POINT ZM (0 1 2 3)", "POINT ZM (0 1 2 3)"), ("LINESTRING EMPTY", "LINESTRING EMPTY"), - ("LINESTRING Z EMPTY", "LINESTRING EMPTY"), - ("LINESTRING M EMPTY", "LINESTRING EMPTY"), - ("LINESTRING ZM EMPTY", "LINESTRING EMPTY"), + ("LINESTRING Z EMPTY", "LINESTRING Z EMPTY"), + ("LINESTRING M EMPTY", "LINESTRING M EMPTY"), + ("LINESTRING ZM EMPTY", "LINESTRING ZM EMPTY"), ("LINESTRING (0 1,2 3)", "LINESTRING (0 1,2 3)"), - ("LINESTRING Z (0 1 2,3 4 5)", "LINESTRING (0 1 2,3 4 5)"), - ("LINESTRING M (0 1 2,3 4 5)", "LINESTRING (0 1,3 4)"), - ("LINESTRING ZM (0 1 2 3,4 5 6 7)", "LINESTRING (0 1 2,4 5 6)"), + ("LINESTRING Z (0 1 2,3 4 5)", "LINESTRING Z (0 1 2,3 4 5)"), + ("LINESTRING M (0 1 2,3 4 5)", "LINESTRING M (0 1 2,3 4 5)"), + ("LINESTRING ZM (0 1 2 3,4 5 6 7)", "LINESTRING ZM (0 1 2 3,4 5 6 7)"), ("POLYGON EMPTY", "POLYGON EMPTY"), ("POLYGON (EMPTY)", "POLYGON EMPTY"), - ("POLYGON Z EMPTY", "POLYGON EMPTY"), - ("POLYGON Z (EMPTY)", "POLYGON EMPTY"), - ("POLYGON M EMPTY", "POLYGON EMPTY"), - ("POLYGON ZM EMPTY", "POLYGON EMPTY"), + ("POLYGON Z EMPTY", "POLYGON Z EMPTY"), + ("POLYGON Z (EMPTY)", "POLYGON Z EMPTY"), + ("POLYGON M EMPTY", "POLYGON M EMPTY"), + ("POLYGON ZM EMPTY", "POLYGON ZM EMPTY"), ("POLYGON ((0 1,2 3,4 5,0 1))", "POLYGON ((0 1,2 3,4 5,0 1))"), ("POLYGON ((0 1,2 3,4 5,0 1),EMPTY)", "POLYGON ((0 1,2 3,4 5,0 1))"), ("POLYGON (EMPTY,(0 1,2 3,4 5,0 1))", "POLYGON EMPTY"), ("POLYGON (EMPTY,(0 1,2 3,4 5,0 1),EMPTY)", "POLYGON EMPTY"), ( "POLYGON Z ((0 1 10,2 3 20,4 5 30,0 1 10),(0 1 10,2 3 20,4 5 30,0 1 10))", - "POLYGON ((0 1 10,2 3 20,4 5 30,0 1 10),(0 1 10,2 3 20,4 5 30,0 1 10))", + "POLYGON Z ((0 1 10,2 3 20,4 5 30,0 1 10),(0 1 10,2 3 20,4 5 30,0 1 10))", + ), + ( + "POLYGON M ((0 1 10,2 3 20,4 5 30,0 1 10))", + "POLYGON M ((0 1 10,2 3 20,4 5 30,0 1 10))", ), - ("POLYGON M ((0 1 10,2 3 20,4 5 30,0 1 10))", "POLYGON ((0 1,2 3,4 5,0 1))"), ( "POLYGON ZM ((0 1 10 100,2 3 20 200,4 5 30 300,0 1 10 10))", - "POLYGON ((0 1 10,2 3 20,4 5 30,0 1 10))", + "POLYGON ZM ((0 1 10 100,2 3 20 200,4 5 30 300,0 1 10 10))", ), ("MULTIPOINT EMPTY", "MULTIPOINT EMPTY"), ("MULTIPOINT (EMPTY)", "MULTIPOINT EMPTY"), - ("MULTIPOINT Z EMPTY", "MULTIPOINT EMPTY"), - ("MULTIPOINT Z (EMPTY)", "MULTIPOINT EMPTY"), - ("MULTIPOINT M EMPTY", "MULTIPOINT EMPTY"), - ("MULTIPOINT ZM EMPTY", "MULTIPOINT EMPTY"), + ("MULTIPOINT Z EMPTY", "MULTIPOINT Z EMPTY"), + ("MULTIPOINT Z (EMPTY)", "MULTIPOINT Z EMPTY"), + ("MULTIPOINT M EMPTY", "MULTIPOINT M EMPTY"), + ("MULTIPOINT ZM EMPTY", "MULTIPOINT ZM EMPTY"), ( "MULTIPOINT (0 1,2 3)", - "MULTIPOINT (0 1,2 3)", + "MULTIPOINT ((0 1),(2 3))", ), # Not SF1.2 compliant but recognized - ("MULTIPOINT ((0 1),(2 3))", "MULTIPOINT (0 1,2 3)"), + ("MULTIPOINT ((0 1),(2 3))", "MULTIPOINT ((0 1),(2 3))"), ( "MULTIPOINT ((0 1),EMPTY)", - "MULTIPOINT (0 1)", + "MULTIPOINT ((0 1))", ), # We don't output empty points in multipoint ( "MULTIPOINT (EMPTY,(0 1))", - "MULTIPOINT (0 1)", + "MULTIPOINT ((0 1))", ), # We don't output empty points in multipoint ( "MULTIPOINT (EMPTY,(0 1),EMPTY)", - "MULTIPOINT (0 1)", + "MULTIPOINT ((0 1))", ), # We don't output empty points in multipoint - ("MULTIPOINT Z ((0 1 2),(3 4 5))", "MULTIPOINT (0 1 2,3 4 5)"), - ("MULTIPOINT M ((0 1 2),(3 4 5))", "MULTIPOINT (0 1,3 4)"), - ("MULTIPOINT ZM ((0 1 2 3),(4 5 6 7))", "MULTIPOINT (0 1 2,4 5 6)"), + ("MULTIPOINT Z ((0 1 2),(3 4 5))", "MULTIPOINT Z ((0 1 2),(3 4 5))"), + ("MULTIPOINT M ((0 1 2),(3 4 5))", "MULTIPOINT M ((0 1 2),(3 4 5))"), + ("MULTIPOINT ZM ((0 1 2 3),(4 5 6 7))", "MULTIPOINT ZM ((0 1 2 3),(4 5 6 7))"), ("MULTILINESTRING EMPTY", "MULTILINESTRING EMPTY"), ("MULTILINESTRING (EMPTY)", "MULTILINESTRING EMPTY"), - ("MULTILINESTRING Z EMPTY", "MULTILINESTRING EMPTY"), - ("MULTILINESTRING Z (EMPTY)", "MULTILINESTRING EMPTY"), - ("MULTILINESTRING M EMPTY", "MULTILINESTRING EMPTY"), - ("MULTILINESTRING ZM EMPTY", "MULTILINESTRING EMPTY"), + ("MULTILINESTRING Z EMPTY", "MULTILINESTRING Z EMPTY"), + ("MULTILINESTRING Z (EMPTY)", "MULTILINESTRING Z EMPTY"), + ("MULTILINESTRING M EMPTY", "MULTILINESTRING M EMPTY"), + ("MULTILINESTRING ZM EMPTY", "MULTILINESTRING ZM EMPTY"), ("MULTILINESTRING ((0 1,2 3,4 5,0 1))", "MULTILINESTRING ((0 1,2 3,4 5,0 1))"), ( "MULTILINESTRING ((0 1,2 3,4 5,0 1),EMPTY)", @@ -457,22 +453,22 @@ def test_ogr_wkbwkt_test_import_wkt_sf12(): ), ( "MULTILINESTRING Z ((0 1 10,2 3 20,4 5 30,0 1 10),(0 1 10,2 3 20,4 5 30,0 1 10))", - "MULTILINESTRING ((0 1 10,2 3 20,4 5 30,0 1 10),(0 1 10,2 3 20,4 5 30,0 1 10))", + "MULTILINESTRING Z ((0 1 10,2 3 20,4 5 30,0 1 10),(0 1 10,2 3 20,4 5 30,0 1 10))", ), ( "MULTILINESTRING M ((0 1 10,2 3 20,4 5 30,0 1 10))", - "MULTILINESTRING ((0 1,2 3,4 5,0 1))", + "MULTILINESTRING M ((0 1 10,2 3 20,4 5 30,0 1 10))", ), ( "MULTILINESTRING ZM ((0 1 10 100,2 3 20 200,4 5 30 300,0 1 10 10))", - "MULTILINESTRING ((0 1 10,2 3 20,4 5 30,0 1 10))", + "MULTILINESTRING ZM ((0 1 10 100,2 3 20 200,4 5 30 300,0 1 10 10))", ), ("MULTIPOLYGON EMPTY", "MULTIPOLYGON EMPTY"), ("MULTIPOLYGON (EMPTY)", "MULTIPOLYGON EMPTY"), - ("MULTIPOLYGON Z EMPTY", "MULTIPOLYGON EMPTY"), - ("MULTIPOLYGON Z (EMPTY)", "MULTIPOLYGON EMPTY"), - ("MULTIPOLYGON M EMPTY", "MULTIPOLYGON EMPTY"), - ("MULTIPOLYGON ZM EMPTY", "MULTIPOLYGON EMPTY"), + ("MULTIPOLYGON Z EMPTY", "MULTIPOLYGON Z EMPTY"), + ("MULTIPOLYGON Z (EMPTY)", "MULTIPOLYGON Z EMPTY"), + ("MULTIPOLYGON M EMPTY", "MULTIPOLYGON M EMPTY"), + ("MULTIPOLYGON ZM EMPTY", "MULTIPOLYGON ZM EMPTY"), ("MULTIPOLYGON ((EMPTY))", "MULTIPOLYGON EMPTY"), ("MULTIPOLYGON (((0 1,2 3,4 5,0 1)))", "MULTIPOLYGON (((0 1,2 3,4 5,0 1)))"), ( @@ -510,31 +506,31 @@ def test_ogr_wkbwkt_test_import_wkt_sf12(): ), ( "MULTIPOLYGON Z (((0 1 10,2 3 20,4 5 30,0 1 10)),((0 1 10,2 3 20,4 5 30,0 1 10)))", - "MULTIPOLYGON (((0 1 10,2 3 20,4 5 30,0 1 10)),((0 1 10,2 3 20,4 5 30,0 1 10)))", + "MULTIPOLYGON Z (((0 1 10,2 3 20,4 5 30,0 1 10)),((0 1 10,2 3 20,4 5 30,0 1 10)))", ), ( "MULTIPOLYGON M (((0 1 10,2 3 20,4 5 30,0 1 10)))", - "MULTIPOLYGON (((0 1,2 3,4 5,0 1)))", + "MULTIPOLYGON M (((0 1 10,2 3 20,4 5 30,0 1 10)))", ), ( "MULTIPOLYGON ZM (((0 1 10 100,2 3 20 200,4 5 30 300,0 1 10 10)))", - "MULTIPOLYGON (((0 1 10,2 3 20,4 5 30,0 1 10)))", + "MULTIPOLYGON ZM (((0 1 10 100,2 3 20 200,4 5 30 300,0 1 10 10)))", ), ("GEOMETRYCOLLECTION EMPTY", "GEOMETRYCOLLECTION EMPTY"), - ("GEOMETRYCOLLECTION Z EMPTY", "GEOMETRYCOLLECTION EMPTY"), - ("GEOMETRYCOLLECTION M EMPTY", "GEOMETRYCOLLECTION EMPTY"), - ("GEOMETRYCOLLECTION ZM EMPTY", "GEOMETRYCOLLECTION EMPTY"), + ("GEOMETRYCOLLECTION Z EMPTY", "GEOMETRYCOLLECTION Z EMPTY"), + ("GEOMETRYCOLLECTION M EMPTY", "GEOMETRYCOLLECTION M EMPTY"), + ("GEOMETRYCOLLECTION ZM EMPTY", "GEOMETRYCOLLECTION ZM EMPTY"), ( "GEOMETRYCOLLECTION Z (POINT Z (0 1 2),LINESTRING Z (0 1 2,3 4 5))", - "GEOMETRYCOLLECTION (POINT (0 1 2),LINESTRING (0 1 2,3 4 5))", + "GEOMETRYCOLLECTION Z (POINT Z (0 1 2),LINESTRING Z (0 1 2,3 4 5))", ), ( "GEOMETRYCOLLECTION M (POINT M (0 1 2),LINESTRING M (0 1 2,3 4 5))", - "GEOMETRYCOLLECTION (POINT (0 1),LINESTRING (0 1,3 4))", + "GEOMETRYCOLLECTION M (POINT M (0 1 2),LINESTRING M (0 1 2,3 4 5))", ), ( "GEOMETRYCOLLECTION ZM (POINT ZM (0 1 2 10),LINESTRING ZM (0 1 2 10,3 4 5 20))", - "GEOMETRYCOLLECTION (POINT (0 1 2),LINESTRING (0 1 2,3 4 5))", + "GEOMETRYCOLLECTION ZM (POINT ZM (0 1 2 10),LINESTRING ZM (0 1 2 10,3 4 5 20))", ), ( "GEOMETRYCOLLECTION (POINT EMPTY,LINESTRING EMPTY,POLYGON EMPTY,MULTIPOINT EMPTY,MULTILINESTRING EMPTY,MULTIPOLYGON EMPTY,GEOMETRYCOLLECTION EMPTY)", @@ -542,7 +538,7 @@ def test_ogr_wkbwkt_test_import_wkt_sf12(): ), ( "GEOMETRYCOLLECTION (POINT Z EMPTY,LINESTRING Z EMPTY,POLYGON Z EMPTY,MULTIPOINT Z EMPTY,MULTILINESTRING Z EMPTY,MULTIPOLYGON Z EMPTY,GEOMETRYCOLLECTION Z EMPTY)", - "GEOMETRYCOLLECTION (POINT EMPTY,LINESTRING EMPTY,POLYGON EMPTY,MULTIPOINT EMPTY,MULTILINESTRING EMPTY,MULTIPOLYGON EMPTY,GEOMETRYCOLLECTION EMPTY)", + "GEOMETRYCOLLECTION Z (POINT Z EMPTY,LINESTRING Z EMPTY,POLYGON Z EMPTY,MULTIPOINT Z EMPTY,MULTILINESTRING Z EMPTY,MULTIPOLYGON Z EMPTY,GEOMETRYCOLLECTION Z EMPTY)", ), # Not SF1.2 compliant but recognized ( @@ -555,17 +551,52 @@ def test_ogr_wkbwkt_test_import_wkt_sf12(): ("MULTICURVE (EMPTY)", "MULTICURVE EMPTY"), ("MULTISURFACE EMPTY", "MULTISURFACE EMPTY"), ("MULTISURFACE (EMPTY)", "MULTISURFACE EMPTY"), - ] + ], +) +def test_ogr_wkbwkt_test_import_wkt_sf12(input_wkt, expected_output_wkt): + + geom = ogr.CreateGeometryFromWkt(input_wkt) + assert geom is not None + out_wkt = geom.ExportToIsoWkt() + assert out_wkt == expected_output_wkt - for wkt_tuple in list_wkt_tuples: - geom = ogr.CreateGeometryFromWkt(wkt_tuple[0]) - assert geom is not None, "could not instantiate geometry %s" % wkt_tuple[0] - out_wkt = geom.ExportToWkt() - assert out_wkt == wkt_tuple[1], "in=%s, out=%s, expected=%s." % ( - wkt_tuple[0], - out_wkt, - wkt_tuple[1], - ) + # Test with input in lower case + geom = ogr.CreateGeometryFromWkt(input_wkt.lower()) + assert geom is not None + out_wkt = geom.ExportToIsoWkt() + assert out_wkt == expected_output_wkt + + +############################################################################### +# Test importing non-conformant WKT with Z/M modifier directly appended to +# geometry type name + + +@pytest.mark.parametrize( + "input_wkt,expected_output_wkt", + [ + ("POINTZ EMPTY", "POINT Z EMPTY"), + ("POINTM EMPTY", "POINT M EMPTY"), + ("POINTZM EMPTY", "POINT ZM EMPTY"), + ("POINTZ (0 1 2)", "POINT Z (0 1 2)"), + ("POINTM (0 1 2)", "POINT M (0 1 2)"), + ("POINTZM (0 1 2 3)", "POINT ZM (0 1 2 3)"), + ], +) +def test_ogr_wkbwkt_test_import_wkt_z_m_modifier_without_space( + input_wkt, expected_output_wkt +): + + geom = ogr.CreateGeometryFromWkt(input_wkt) + assert geom is not None + out_wkt = geom.ExportToIsoWkt() + assert out_wkt == expected_output_wkt + + # Test with input in lower case + geom = ogr.CreateGeometryFromWkt(input_wkt.lower()) + assert geom is not None + out_wkt = geom.ExportToIsoWkt() + assert out_wkt == expected_output_wkt ############################################################################### diff --git a/autotest/ogr/ogr_wktempty.py b/autotest/ogr/ogr_wktempty.py index 1b707500e3f3..3047cbd63b75 100755 --- a/autotest/ogr/ogr_wktempty.py +++ b/autotest/ogr/ogr_wktempty.py @@ -64,10 +64,7 @@ def test_empty_wkt(test_input, expected): except AttributeError: pytest.skip() - try: - assert geom.IsEmpty(), "IsEmpty returning false for an empty geometry" - finally: - geom.Destroy() + assert geom.IsEmpty(), "IsEmpty returning false for an empty geometry" def test_ogr_wktempty_test_partial_empty_geoms(): diff --git a/autotest/pyscripts/test_gdal2tiles.py b/autotest/pyscripts/test_gdal2tiles.py index a89e2ef4a952..b3da97a4de72 100755 --- a/autotest/pyscripts/test_gdal2tiles.py +++ b/autotest/pyscripts/test_gdal2tiles.py @@ -643,7 +643,7 @@ def test_gdal2tiles_nodata_values_pct_threshold(script_path, tmp_path): input_tif = str(tmp_path / "test_gdal2tiles_nodata_values_pct_threshold.tif") output_folder = str(tmp_path / "test_gdal2tiles_nodata_values_pct_threshold") - src_ds = gdal.GetDriverByName("GTiff").Create(input_tif, 256, 256, 1, gdal.GDT_Byte) + src_ds = gdal.GetDriverByName("GTiff").Create(input_tif, 256, 256, 3, gdal.GDT_Byte) src_ds.GetRasterBand(1).SetNoDataValue(20) src_ds.GetRasterBand(1).WriteRaster( 0, 0, 2, 2, struct.pack("B" * 4, 10, 20, 30, 40) @@ -665,7 +665,7 @@ def test_gdal2tiles_nodata_values_pct_threshold(script_path, tmp_path): ) ds = gdal.Open(f"{output_folder}/0/0/0.png") - assert struct.unpack("B" * 2, ds.ReadRaster(0, 0, 1, 1)) == ( + assert struct.unpack("B" * 2, ds.ReadRaster(0, 0, 1, 1, band_list=[1, 4])) == ( round((10 + 30 + 40) / 3), 255, ) @@ -677,7 +677,7 @@ def test_gdal2tiles_nodata_values_pct_threshold(script_path, tmp_path): ) ds = gdal.Open(f"{output_folder}/0/0/0.png") - assert struct.unpack("B" * 2, ds.ReadRaster(0, 0, 1, 1)) == ( + assert struct.unpack("B" * 2, ds.ReadRaster(0, 0, 1, 1, band_list=[1, 4])) == ( round((10 + 30 + 40) / 3), 255, ) @@ -689,7 +689,7 @@ def test_gdal2tiles_nodata_values_pct_threshold(script_path, tmp_path): ) ds = gdal.Open(f"{output_folder}/0/0/0.png") - assert struct.unpack("B" * 2, ds.ReadRaster(0, 0, 1, 1)) == (0, 0) + assert struct.unpack("B" * 2, ds.ReadRaster(0, 0, 1, 1, band_list=[1, 4])) == (0, 0) @pytest.mark.require_driver("JPEG") diff --git a/autotest/utilities/test_gdal_rasterize_lib.py b/autotest/utilities/test_gdal_rasterize_lib.py index b2669d966a87..67b2ba8d6d42 100755 --- a/autotest/utilities/test_gdal_rasterize_lib.py +++ b/autotest/utilities/test_gdal_rasterize_lib.py @@ -712,11 +712,13 @@ def test_gdal_rasterize_lib_int64_attribute(): feature["val"] = val layer.CreateFeature(feature) + noData = -(1 << 63) target_ds = gdal.Rasterize( - "", vector_ds, format="MEM", attribute="val", width=2, height=2 + "", vector_ds, format="MEM", attribute="val", width=2, height=2, noData=noData ) assert target_ds is not None assert target_ds.GetRasterBand(1).DataType == gdal.GDT_Int64 + assert target_ds.GetRasterBand(1).GetNoDataValue() == noData assert struct.unpack("Q" * 4, target_ds.ReadRaster())[0] == val diff --git a/autotest/utilities/test_gdal_translate_lib.py b/autotest/utilities/test_gdal_translate_lib.py index 8948856bd329..d3e32650feb0 100755 --- a/autotest/utilities/test_gdal_translate_lib.py +++ b/autotest/utilities/test_gdal_translate_lib.py @@ -292,6 +292,18 @@ def test_gdal_translate_lib_nodata_int64(): ds = None +############################################################################### +# Test nodata=-inf + + +def test_gdal_translate_lib_nodata_minus_inf(): + + ds = gdal.Translate( + "", "../gcore/data/float32.tif", format="MEM", noData=float("-inf") + ) + assert ds.GetRasterBand(1).GetNoDataValue() == float("-inf"), "Bad nodata value" + + ############################################################################### # Test srcWin option @@ -1142,6 +1154,20 @@ def test_gdal_translate_lib_scale_and_unscale_incompatible(): ) +############################################################################### +# Test -a_offset -inf (dummy example, but to prove -inf works as a value +# numeric value) + + +@gdaltest.enable_exceptions() +def test_gdal_translate_lib_assign_offset(): + + out_ds = gdal.Translate( + "", gdal.Open("../gcore/data/byte.tif"), options="-f MEM -a_offset -inf" + ) + assert out_ds.GetRasterBand(1).GetOffset() == float("-inf") + + ############################################################################### # Test option argument handling diff --git a/autotest/utilities/test_gdal_viewshed.py b/autotest/utilities/test_gdal_viewshed.py index 42dadb733cf8..ca572b803e66 100755 --- a/autotest/utilities/test_gdal_viewshed.py +++ b/autotest/utilities/test_gdal_viewshed.py @@ -369,17 +369,6 @@ def test_gdal_viewshed_invalid_band(gdal_viewshed_path, tmp_path): ############################################################################### -def test_gdal_viewshed_invalid_observer_point(gdal_viewshed_path, tmp_path): - - _, err = gdaltest.runexternal_out_and_err( - f"{gdal_viewshed_path} -ox 0 -oy 0 ../gdrivers/data/n43.tif {tmp_path}/tmp.tif" - ) - assert "Observer position above or below" in err - - -############################################################################### - - def test_gdal_viewshed_invalid_output_driver(gdal_viewshed_path, tmp_path): _, err = gdaltest.runexternal_out_and_err( diff --git a/autotest/utilities/test_gdalbuildvrt_lib.py b/autotest/utilities/test_gdalbuildvrt_lib.py index 94f449d1e282..74e41222ed6e 100755 --- a/autotest/utilities/test_gdalbuildvrt_lib.py +++ b/autotest/utilities/test_gdalbuildvrt_lib.py @@ -280,15 +280,15 @@ def test_gdalbuildvrt_lib_separate_nodata_2(tmp_vsimem): src2_ds.GetRasterBand(1).SetNoDataValue(2) gdal.BuildVRT( - tmp_vsimem / "out.vrt", [src1_ds, src2_ds], separate=True, srcNodata="3 4" + tmp_vsimem / "out.vrt", [src1_ds, src2_ds], separate=True, srcNodata="-3 4" ) f = gdal.VSIFOpenL(tmp_vsimem / "out.vrt", "rb") data = gdal.VSIFReadL(1, 10000, f) gdal.VSIFCloseL(f) - assert b"3" in data - assert b"3" in data + assert b"-3" in data + assert b"-3" in data assert b"4" in data assert b"4" in data @@ -309,14 +309,14 @@ def test_gdalbuildvrt_lib_separate_nodata_3(tmp_vsimem): [src1_ds, src2_ds], separate=True, srcNodata="3 4", - VRTNodata="5 6", + VRTNodata="-5 6", ) f = gdal.VSIFOpenL(tmp_vsimem / "out.vrt", "rb") data = gdal.VSIFReadL(1, 10000, f) gdal.VSIFCloseL(f) - assert b"5" in data + assert b"-5" in data assert b"3" in data assert b"6" in data assert b"4" in data diff --git a/autotest/utilities/test_gdallocationinfo.py b/autotest/utilities/test_gdallocationinfo.py index 2b8c80cd7a2e..0b64f4c19333 100755 --- a/autotest/utilities/test_gdallocationinfo.py +++ b/autotest/utilities/test_gdallocationinfo.py @@ -254,3 +254,48 @@ def test_gdallocationinfo_echo(gdallocationinfo_path): strin="1 2", ) assert "1,2,132" in ret + + +############################################################################### +# Test out of raster coordinates + + +def test_gdallocationinfo_out_of_raster_coordinates_valonly(gdallocationinfo_path): + + ret = gdaltest.runexternal( + gdallocationinfo_path + " -valonly ../gcore/data/byte.tif", + strin="1 2\n-1 -1\n1 2", + ) + + ret = ret.replace("\r\n", "\n") + assert "132\n\n132\n" in ret + + ret = gdaltest.runexternal( + gdallocationinfo_path + ' -E -valonly -field_sep "," ../gcore/data/byte.tif', + strin="1 2\n-1 -1\n1 2", + ) + + ret = ret.replace("\r\n", "\n") + assert "1,2,132\n-1,-1,\n1,2,132\n" in ret + + +def test_gdallocationinfo_out_of_raster_coordinates_valonly_multiband( + gdallocationinfo_path, +): + + ret = gdaltest.runexternal( + gdallocationinfo_path + " -valonly ../gcore/data/rgbsmall.tif", + strin="1 2\n-1 -1\n1 2", + ) + + ret = ret.replace("\r\n", "\n") + assert "0\n0\n0\n\n\n\n0\n0\n0\n" in ret + + ret = gdaltest.runexternal( + gdallocationinfo_path + + ' -E -valonly -field_sep "," ../gcore/data/rgbsmall.tif', + strin="1 2\n-1 -1\n1 2", + ) + + ret = ret.replace("\r\n", "\n") + assert "1,2,0,0,0\n-1,-1,,,\n1,2,0,0,0\n" in ret diff --git a/autotest/utilities/test_gdalwarp_lib.py b/autotest/utilities/test_gdalwarp_lib.py index a3f7b300a64d..7f641242e18b 100755 --- a/autotest/utilities/test_gdalwarp_lib.py +++ b/autotest/utilities/test_gdalwarp_lib.py @@ -1473,6 +1473,34 @@ def test_gdalwarp_lib_127(): assert ds.GetRasterBand(1).Checksum() == 4672, "bad checksum" +@pytest.mark.parametrize("srcNodata", [float("-inf"), -1]) +def test_gdalwarp_lib_srcnodata(srcNodata): + + ds = gdal.Warp( + "", + "../gcore/data/byte.tif", + format="MEM", + srcNodata=srcNodata, + outputType=gdal.GDT_Float32, + ) + assert ds.GetRasterBand(1).GetNoDataValue() == srcNodata, "bad nodata value" + assert ds.GetRasterBand(1).Checksum() == 4672, "bad checksum" + + +@pytest.mark.parametrize("dstNodata", [float("-inf"), -1]) +def test_gdalwarp_lib_dstnodata(dstNodata): + + ds = gdal.Warp( + "", + "../gcore/data/byte.tif", + format="MEM", + dstNodata=dstNodata, + outputType=gdal.GDT_Float32, + ) + assert ds.GetRasterBand(1).GetNoDataValue() == dstNodata, "bad nodata value" + assert ds.GetRasterBand(1).Checksum() == 4672, "bad checksum" + + ############################################################################### # Test automatic densification of cutline (#6375) diff --git a/autotest/utilities/test_ogr2ogr_lib.py b/autotest/utilities/test_ogr2ogr_lib.py index b94847000ba0..dbfec4cba68f 100755 --- a/autotest/utilities/test_ogr2ogr_lib.py +++ b/autotest/utilities/test_ogr2ogr_lib.py @@ -520,7 +520,6 @@ def test_ogr2ogr_lib_21(): gdal.VectorTranslate(ds, src_ds, accessMode="append", selectFields=["foo"]) ds = None - f.Destroy() src_ds = None @@ -2806,3 +2805,27 @@ def test_ogr2ogr_lib_two_gcps(): f = out_lyr.GetNextFeature() assert f.GetGeometryRef().GetX(0) == pytest.approx(250) assert f.GetGeometryRef().GetY(0) == pytest.approx(350) + + +############################################################################### +# Test -skipInvalid + + +@pytest.mark.require_geos +@gdaltest.enable_exceptions() +def test_ogr2ogr_lib_skip_invalid(tmp_vsimem): + + srcDS = gdal.GetDriverByName("Memory").Create("", 0, 0, 0, gdal.GDT_Unknown) + srcLayer = srcDS.CreateLayer("test") + f = ogr.Feature(srcLayer.GetLayerDefn()) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 2)")) + srcLayer.CreateFeature(f) + f = ogr.Feature(srcLayer.GetLayerDefn()) + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON((0 0,1 1,0 1,1 0,0 0))")) + srcLayer.CreateFeature(f) + + with gdal.quiet_errors(): + ds = gdal.VectorTranslate("", srcDS, format="Memory", skipInvalid=True) + lyr = ds.GetLayer(0) + assert lyr.GetFeatureCount() == 1 + ds = None diff --git a/cmake/helpers/CheckDependentLibraries.cmake b/cmake/helpers/CheckDependentLibraries.cmake index 7335af0e9751..856c4f52e963 100644 --- a/cmake/helpers/CheckDependentLibraries.cmake +++ b/cmake/helpers/CheckDependentLibraries.cmake @@ -8,275 +8,7 @@ Detect GDAL dependencies and set variable HAVE_* #]=======================================================================] -include(CheckFunctionExists) -include(CMakeDependentOption) -include(FeatureSummary) -include(DefineFindPackage2) -include(CheckSymbolExists) - -option( - GDAL_USE_EXTERNAL_LIBS - "Whether detected external libraries should be used by default. This should be set before CMakeCache.txt is created." - ON) - -set(GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES ON OFF WHEN_NO_EXTERNAL) -set( - GDAL_USE_INTERNAL_LIBS WHEN_NO_EXTERNAL - CACHE STRING "Control how internal libraries should be used by default. This should be set before CMakeCache.txt is created.") -set_property(CACHE GDAL_USE_INTERNAL_LIBS PROPERTY STRINGS ${GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES}) -if(NOT GDAL_USE_INTERNAL_LIBS IN_LIST GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES) - message(FATAL_ERROR "GDAL_USE_INTERNAL_LIBS must be one of ${GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES}") -endif() - -set(GDAL_IMPORT_DEPENDENCIES [[ -include(CMakeFindDependencyMacro) -include("${CMAKE_CURRENT_LIST_DIR}/DefineFindPackage2.cmake") -include("${CMAKE_CURRENT_LIST_DIR}/GdalFindModulePath.cmake") -]]) -if(TARGET Threads::Threads) - string(APPEND GDAL_IMPORT_DEPENDENCIES "find_dependency(Threads)\n") -endif() - -# Check that the configuration has a valid value for INTERFACE_INCLUDE_DIRECTORIES. This aimed at avoiding issues like -# https://github.com/OSGeo/gdal/issues/5324 -function (gdal_check_target_is_valid target res_var) - get_target_property(_interface_include_directories ${target} "INTERFACE_INCLUDE_DIRECTORIES") - if(_interface_include_directories) - foreach(_dir IN LISTS _interface_include_directories) - if(NOT EXISTS "${_dir}") - message(WARNING "Target ${target} references ${_dir} as a INTERFACE_INCLUDE_DIRECTORIES, but it does not exist. Ignoring that target.") - set(${res_var} FALSE PARENT_SCOPE) - return() - endif() - endforeach() - elseif("${target}" STREQUAL "geotiff_library" AND DEFINED GeoTIFF_INCLUDE_DIRS) - # geotiff-config.cmake of GeoTIFF 1.7.0 doesn't define a INTERFACE_INCLUDE_DIRECTORIES - # property, but a GeoTIFF_INCLUDE_DIRS variable. - set_target_properties(${target} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${GeoTIFF_INCLUDE_DIRS}") - else() - message(WARNING "Target ${target} has no INTERFACE_INCLUDE_DIRECTORIES property. Ignoring that target.") - set(${res_var} FALSE PARENT_SCOPE) - return() - endif() - set(${res_var} TRUE PARENT_SCOPE) -endfunction() - -# Package acceptance based on a candidate target list. -# If a matching target is found, sets ${name}_FOUND to TRUE, -# ${name}_INCLUDE_DIRS to "" and ${name}_LIBRARIES to the target name. -# If `REQUIRED` is used, ${name}_FOUND is set to FALSE if no target matches. -function(gdal_check_package_target name) - if("REQUIRED" IN_LIST ARGN) - list(REMOVE_ITEM ARGN "REQUIRED") - set(${name}_FOUND FALSE PARENT_SCOPE) - endif() - foreach(target IN LISTS ARGN) - if(TARGET ${target}) - gdal_check_target_is_valid(${target} _is_valid) - if (_is_valid) - set(${name}_TARGET "${target}" PARENT_SCOPE) - set(${name}_FOUND TRUE PARENT_SCOPE) - return() - endif() - endif() - endforeach() -endfunction() - -# Macro to declare a dependency on an external package. -# If not marked with the ALWAYS_ON_WHEN_FOUND option, dependencies can be -# marked for user control with either the CAN_DISABLE or DISABLED_BY_DEFAULT -# option. User control is done via a cache variable GDAL_USE_{name in upper case} -# with the default value ON for CAN_DISABLE or OFF for DISABLED_BY_DEFAULT. -# The RECOMMENDED option is used for the feature summary. -# The VERSION, CONFIG, MODULE, COMPONENTS and NAMES parameters are passed to find_package(). -# Using NAMES with find_package() implies config mode. However, gdal_check_package() -# attempts another find_package() without NAMES if the config mode attempt was not -# successful, allowing a fallback to Find modules. -# The TARGETS parameter can define a list of candidate targets. If given, a -# package will only be accepted if it defines one of the given targets. The matching -# target name will be saved in ${name}_TARGET. -# The NAMES and TARGETS map to GDAL_CHECK_PACKAGE_${name}_NAMES and -# GDAL_CHECK_PACKAGE_${name}_TARGETS cache variables which can be used to -# overwrite the default config and targets names. -# The required find_dependency() commands for exported config are appended to -# the GDAL_IMPORT_DEPENDENCIES string (when BUILD_SHARED_LIBS=OFF). -macro (gdal_check_package name purpose) - set(_options CONFIG MODULE CAN_DISABLE RECOMMENDED DISABLED_BY_DEFAULT ALWAYS_ON_WHEN_FOUND) - set(_oneValueArgs VERSION NAMES) - set(_multiValueArgs COMPONENTS TARGETS PATHS) - cmake_parse_arguments(_GCP "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - string(TOUPPER ${name} key) - set(_find_dependency "") - set(_find_dependency_args "") - if(FIND_PACKAGE2_${name}_ENABLED) - find_package2(${name} QUIET OUT_DEPENDENCY _find_dependency) - else() - set(_find_package_args) - # For some reason passing the HDF5 version requirement cause a linking error of the libkea driver on Conda Windows builds... - if (_GCP_VERSION AND NOT ("${name}" STREQUAL "TileDB") AND NOT ("${name}" STREQUAL "HDF5")) - list(APPEND _find_package_args ${_GCP_VERSION}) - endif () - if (_GCP_CONFIG) - list(APPEND _find_package_args CONFIG) - endif () - if (_GCP_MODULE) - list(APPEND _find_package_args MODULE) - endif () - if (_GCP_COMPONENTS) - list(APPEND _find_package_args COMPONENTS ${_GCP_COMPONENTS}) - endif () - if (_GCP_PATHS) - list(APPEND _find_package_args PATHS ${_GCP_PATHS}) - endif () - if (_GCP_NAMES) - set(GDAL_CHECK_PACKAGE_${name}_NAMES "${_GCP_NAMES}" CACHE STRING "Config file name for ${name}") - mark_as_advanced(GDAL_CHECK_PACKAGE_${name}_NAMES) - endif () - if (_GCP_TARGETS) - set(GDAL_CHECK_PACKAGE_${name}_TARGETS "${_GCP_TARGETS}" CACHE STRING "Target name candidates for ${name}") - mark_as_advanced(GDAL_CHECK_PACKAGE_${name}_TARGETS) - endif () - if (GDAL_CHECK_PACKAGE_${name}_NAMES) - find_package(${name} NAMES ${GDAL_CHECK_PACKAGE_${name}_NAMES} ${_find_package_args}) - gdal_check_package_target(${name} ${GDAL_CHECK_PACKAGE_${name}_TARGETS} REQUIRED) - if (${name}_FOUND) - get_filename_component(_find_dependency_args "${${name}_CONFIG}" NAME) - string(REPLACE ";" " " _find_dependency_args "${name} ${_find_package_args} NAMES ${GDAL_CHECK_PACKAGE_${name}_NAMES} CONFIGS ${_find_dependency_args}") - endif () - endif () - if (NOT ${name}_FOUND) - find_package(${name} ${_find_package_args}) - if (${name}_FOUND) - gdal_check_package_target(${name} ${GDAL_CHECK_PACKAGE_${name}_TARGETS}) - elseif (${key}_FOUND) # Some find modules do not set _FOUND - gdal_check_package_target(${key} ${GDAL_CHECK_PACKAGE_${name}_TARGETS}) - set(${name}_FOUND "${key}_FOUND") - endif () - if (${name}_FOUND) - string(REPLACE ";" " " _find_dependency_args "${name} ${_find_package_args}") - endif() - endif () - endif () - if (${key}_FOUND OR ${name}_FOUND) - if(_GCP_VERSION) - - if( "${name}" STREQUAL "TileDB" AND NOT DEFINED TileDB_VERSION) - get_property(_dirs TARGET TileDB::tiledb_shared PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - foreach(_dir IN LISTS _dirs) - set(TILEDB_VERSION_FILENAME "${_dir}/tiledb/tiledb_version.h") - if(EXISTS ${TILEDB_VERSION_FILENAME}) - file(READ ${TILEDB_VERSION_FILENAME} _tiledb_version_contents) - string(REGEX REPLACE "^.*TILEDB_VERSION_MAJOR +([0-9]+).*$" "\\1" TILEDB_VERSION_MAJOR "${_tiledb_version_contents}") - string(REGEX REPLACE "^.*TILEDB_VERSION_MINOR +([0-9]+).*$" "\\1" TILEDB_VERSION_MINOR "${_tiledb_version_contents}") - set(TileDB_VERSION "${TILEDB_VERSION_MAJOR}.${TILEDB_VERSION_MINOR}") - endif() - endforeach() - endif() - - if (DEFINED ${name}_VERSION_STRING AND NOT DEFINED ${name}_VERSION) - set(${name}_VERSION "${${name}_VERSION_STRING}") - endif() - - if( "${${name}_VERSION}" STREQUAL "") - message(WARNING "${name} has unknown version. Assuming it is at least matching the minimum version required of ${_GCP_VERSION}") - set(HAVE_${key} ON) - elseif( ${name}_VERSION VERSION_LESS ${_GCP_VERSION}) - message(WARNING "Ignoring ${name} because it is at version ${${name}_VERSION}, whereas the minimum version required is ${_GCP_VERSION}") - set(HAVE_${key} OFF) - else() - set(HAVE_${key} ON) - endif() - else() - set(HAVE_${key} ON) - endif() - else () - set(HAVE_${key} OFF) - endif () - if (purpose STREQUAL "") - - else () - if (_GCP_RECOMMENDED) - set_package_properties( - ${name} PROPERTIES - PURPOSE ${purpose} - TYPE RECOMMENDED) - else () - set_package_properties(${name} PROPERTIES PURPOSE ${purpose}) - endif () - endif () - - if (_GCP_CAN_DISABLE OR _GCP_DISABLED_BY_DEFAULT) - set(_gcpp_status ON) - if (GDAL_USE_${key}) - if (NOT HAVE_${key}) - message(FATAL_ERROR "Configured to use ${key}, but not found") - endif () - elseif (NOT GDAL_USE_EXTERNAL_LIBS) - set(_gcpp_status OFF) - if (HAVE_${key} AND NOT GDAL_USE_${key}) - message(STATUS - "${key} has been found, but is disabled due to GDAL_USE_EXTERNAL_LIBS=OFF. Enable it by setting GDAL_USE_${key}=ON" - ) - set(_find_dependency_args "") - endif () - endif () - if (_gcpp_status AND _GCP_DISABLED_BY_DEFAULT) - set(_gcpp_status OFF) - if (HAVE_${key} AND NOT GDAL_USE_${key}) - message(STATUS "${key} has been found, but is disabled by default. Enable it by setting GDAL_USE_${key}=ON") - set(_find_dependency_args "") - endif () - endif () - cmake_dependent_option(GDAL_USE_${key} "Set ON to use ${key}" ${_gcpp_status} "HAVE_${key}" OFF) - elseif (NOT _GCP_ALWAYS_ON_WHEN_FOUND) - message(FATAL_ERROR "Programming error: missing CAN_DISABLE or DISABLED_BY_DEFAULT option for component ${name}") - endif () - - if(_find_dependency_args) - string(REPLACE "\"" "\\\"" _find_dependency_args "${_find_dependency_args}") - set(_find_dependency "find_dependency(${_find_dependency_args})\n") - endif() - if(NOT BUILD_SHARED_LIBS AND GDAL_USE_${key} AND _find_dependency) - string(APPEND GDAL_IMPORT_DEPENDENCIES "${_find_dependency}") - endif() - unset(_find_dependency_args) - unset(_find_dependency) -endmacro () - -function (split_libpath _lib) - if (_lib) - # split lib_line into -L and -l linker options - get_filename_component(_path ${${_lib}} PATH) - get_filename_component(_name ${${_lib}} NAME_WE) - string(REGEX REPLACE "^lib" "" _name ${_name}) - set(${_lib} -L${_path} -l${_name}) - endif () -endfunction () - -function (gdal_internal_library libname) - set(_options REQUIRED) - set(_oneValueArgs) - set(_multiValueArgs) - cmake_parse_arguments(_GIL "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if ("${GDAL_USE_INTERNAL_LIBS}" STREQUAL "ON") - set(_default_value ON) - elseif ("${GDAL_USE_INTERNAL_LIBS}" STREQUAL "OFF") - set(_default_value OFF) - elseif( GDAL_USE_${libname} ) - set(_default_value OFF) - else() - set(_default_value ON) - endif() - set(GDAL_USE_${libname}_INTERNAL - ${_default_value} - CACHE BOOL "Use internal ${libname} copy (if set to ON, has precedence over GDAL_USE_${libname})") - if (_GIL_REQUIRED - AND (NOT GDAL_USE_${libname}) - AND (NOT GDAL_USE_${libname}_INTERNAL)) - message(FATAL_ERROR "GDAL_USE_${libname} or GDAL_USE_${libname}_INTERNAL must be set to ON") - endif () -endfunction () +include(CheckDependentLibrariesCommon) # Custom find_package definitions @@ -313,6 +45,7 @@ if (Iconv_FOUND) size_t ret = iconv(conv, &in, &ilen, &out, &olen); return (size_t)ret; }") + include(CheckCXXSourceCompiles) check_cxx_source_compiles("${ICONV_CONST_TEST_CODE}" _ICONV_SECOND_ARGUMENT_IS_NOT_CONST) if (_ICONV_SECOND_ARGUMENT_IS_NOT_CONST) set(ICONV_CPP_CONST "") @@ -430,11 +163,7 @@ gdal_check_package(ZSTD "ZSTD compression library" CAN_DISABLE ${ZSTD_NAMES_AND_ gdal_check_package(SFCGAL "gdal core supports ISO 19107:2013 and OGC Simple Features Access 1.2 for 3D operations" CAN_DISABLE) -gdal_check_package(GeoTIFF "libgeotiff library (external)" CAN_DISABLE RECOMMENDED - NAMES GeoTIFF - TARGETS geotiff_library GEOTIFF::GEOTIFF -) -gdal_internal_library(GEOTIFF REQUIRED) +include(CheckDependentLibrariesGeoTIFF) gdal_check_package(PNG "PNG compression library (external)" CAN_DISABLE RECOMMENDED VERSION "1.6") gdal_internal_library(PNG) @@ -615,7 +344,7 @@ gdal_check_package(FreeXL "Enable XLS driver" CAN_DISABLE) define_find_package2(GTA gta/gta.h gta PKGCONFIG_NAME gta) gdal_check_package(GTA "Enable GTA driver" CAN_DISABLE) -gdal_check_package(MRSID "MrSID raster SDK" CAN_DISABLE) +include(CheckDependentLibrariesMrSID) set(GDAL_USE_ARMADILLO_OLD ${GDAL_USE_ARMADILLO}) gdal_check_package(Armadillo "C++ library for linear algebra (used for TPS transformation)" CAN_DISABLE) @@ -790,7 +519,7 @@ option(GDAL_USE_PUBLICDECOMPWT "Set ON to build MSG driver and download external https://gitlab.eumetsat.int/open-source/PublicDecompWT" OFF) # proprietary libraries KAKADU -gdal_check_package(KDU "Enable KAKADU" CAN_DISABLE) +include(CheckDependentLibrariesKakadu) gdal_check_package(LURATECH "Enable JP2Lura driver" CAN_DISABLE) gdal_check_package(Arrow "Apache Arrow C++ library" CONFIG CAN_DISABLE) @@ -804,12 +533,14 @@ if (Arrow_FOUND) mark_as_advanced(ARROW_USE_STATIC_LIBRARIES) endif() -gdal_check_package(OpenDrive "Enable libOpenDRIVE" CAN_DISABLE) +gdal_check_package(OpenDrive "Enable libOpenDRIVE" CONFIG CAN_DISABLE) # bindings # finding python in top of project because of common for autotest and bindings +set(JAVA_AWT_LIBRARY NotNeeded) +set(JAVA_AWT_INCLUDE_PATH NotNeeded) find_package(JNI) find_package(Java COMPONENTS Runtime Development) find_program( diff --git a/cmake/helpers/CheckDependentLibrariesCommon.cmake b/cmake/helpers/CheckDependentLibrariesCommon.cmake new file mode 100644 index 000000000000..ebb353829fcb --- /dev/null +++ b/cmake/helpers/CheckDependentLibrariesCommon.cmake @@ -0,0 +1,281 @@ +# Distributed under the GDAL/OGR MIT style License. See accompanying file LICENSE.TXT. + +#[=======================================================================[.rst: +CheckDependentLibraries.cmake +----------------------------- + +Detect GDAL dependencies and set variable HAVE_* + +#]=======================================================================] + +include(CheckFunctionExists) +include(CMakeDependentOption) +include(FeatureSummary) +include(DefineFindPackage2) +include(CheckSymbolExists) + +option( + GDAL_USE_EXTERNAL_LIBS + "Whether detected external libraries should be used by default. This should be set before CMakeCache.txt is created." + ON) + +set(GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES ON OFF WHEN_NO_EXTERNAL) +set( + GDAL_USE_INTERNAL_LIBS WHEN_NO_EXTERNAL + CACHE STRING "Control how internal libraries should be used by default. This should be set before CMakeCache.txt is created.") +set_property(CACHE GDAL_USE_INTERNAL_LIBS PROPERTY STRINGS ${GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES}) +if(NOT GDAL_USE_INTERNAL_LIBS IN_LIST GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES) + message(FATAL_ERROR "GDAL_USE_INTERNAL_LIBS must be one of ${GDAL_USE_INTERNAL_LIBS_ALLOWED_VALUES}") +endif() + +set(GDAL_IMPORT_DEPENDENCIES [[ +include(CMakeFindDependencyMacro) +include("${CMAKE_CURRENT_LIST_DIR}/DefineFindPackage2.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/GdalFindModulePath.cmake") +]]) +if(TARGET Threads::Threads) + string(APPEND GDAL_IMPORT_DEPENDENCIES "find_dependency(Threads)\n") +endif() + +# Check that the configuration has a valid value for INTERFACE_INCLUDE_DIRECTORIES. This aimed at avoiding issues like +# https://github.com/OSGeo/gdal/issues/5324 +function (gdal_check_target_is_valid target res_var) + get_target_property(_interface_include_directories ${target} "INTERFACE_INCLUDE_DIRECTORIES") + if(_interface_include_directories) + foreach(_dir IN LISTS _interface_include_directories) + if(NOT EXISTS "${_dir}") + message(WARNING "Target ${target} references ${_dir} as a INTERFACE_INCLUDE_DIRECTORIES, but it does not exist. Ignoring that target.") + set(${res_var} FALSE PARENT_SCOPE) + return() + endif() + endforeach() + elseif("${target}" STREQUAL "geotiff_library" AND DEFINED GeoTIFF_INCLUDE_DIRS) + # geotiff-config.cmake of GeoTIFF 1.7.0 doesn't define a INTERFACE_INCLUDE_DIRECTORIES + # property, but a GeoTIFF_INCLUDE_DIRS variable. + set_target_properties(${target} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${GeoTIFF_INCLUDE_DIRS}") + else() + message(WARNING "Target ${target} has no INTERFACE_INCLUDE_DIRECTORIES property. Ignoring that target.") + set(${res_var} FALSE PARENT_SCOPE) + return() + endif() + set(${res_var} TRUE PARENT_SCOPE) +endfunction() + +# Package acceptance based on a candidate target list. +# If a matching target is found, sets ${name}_FOUND to TRUE, +# ${name}_INCLUDE_DIRS to "" and ${name}_LIBRARIES to the target name. +# If `REQUIRED` is used, ${name}_FOUND is set to FALSE if no target matches. +function(gdal_check_package_target name) + if("REQUIRED" IN_LIST ARGN) + list(REMOVE_ITEM ARGN "REQUIRED") + set(${name}_FOUND FALSE PARENT_SCOPE) + endif() + foreach(target IN LISTS ARGN) + if(TARGET ${target}) + gdal_check_target_is_valid(${target} _is_valid) + if (_is_valid) + set(${name}_TARGET "${target}" PARENT_SCOPE) + set(${name}_FOUND TRUE PARENT_SCOPE) + return() + endif() + endif() + endforeach() +endfunction() + +# Macro to declare a dependency on an external package. +# If not marked with the ALWAYS_ON_WHEN_FOUND option, dependencies can be +# marked for user control with either the CAN_DISABLE or DISABLED_BY_DEFAULT +# option. User control is done via a cache variable GDAL_USE_{name in upper case} +# with the default value ON for CAN_DISABLE or OFF for DISABLED_BY_DEFAULT. +# The RECOMMENDED option is used for the feature summary. +# The VERSION, CONFIG, MODULE, COMPONENTS and NAMES parameters are passed to find_package(). +# Using NAMES with find_package() implies config mode. However, gdal_check_package() +# attempts another find_package() without NAMES if the config mode attempt was not +# successful, allowing a fallback to Find modules. +# The TARGETS parameter can define a list of candidate targets. If given, a +# package will only be accepted if it defines one of the given targets. The matching +# target name will be saved in ${name}_TARGET. +# The NAMES and TARGETS map to GDAL_CHECK_PACKAGE_${name}_NAMES and +# GDAL_CHECK_PACKAGE_${name}_TARGETS cache variables which can be used to +# overwrite the default config and targets names. +# The required find_dependency() commands for exported config are appended to +# the GDAL_IMPORT_DEPENDENCIES string (when BUILD_SHARED_LIBS=OFF). +macro (gdal_check_package name purpose) + set(_options CONFIG MODULE CAN_DISABLE RECOMMENDED DISABLED_BY_DEFAULT ALWAYS_ON_WHEN_FOUND) + set(_oneValueArgs VERSION NAMES) + set(_multiValueArgs COMPONENTS TARGETS PATHS) + cmake_parse_arguments(_GCP "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + string(TOUPPER ${name} key) + set(_find_dependency "") + set(_find_dependency_args "") + if(FIND_PACKAGE2_${name}_ENABLED) + find_package2(${name} QUIET OUT_DEPENDENCY _find_dependency) + else() + set(_find_package_args) + # For some reason passing the HDF5 version requirement cause a linking error of the libkea driver on Conda Windows builds... + if (_GCP_VERSION AND NOT ("${name}" STREQUAL "TileDB") AND NOT ("${name}" STREQUAL "HDF5")) + list(APPEND _find_package_args ${_GCP_VERSION}) + endif () + if (_GCP_CONFIG) + list(APPEND _find_package_args CONFIG) + endif () + if (_GCP_MODULE) + list(APPEND _find_package_args MODULE) + endif () + if (_GCP_COMPONENTS) + list(APPEND _find_package_args COMPONENTS ${_GCP_COMPONENTS}) + endif () + if (_GCP_PATHS) + list(APPEND _find_package_args PATHS ${_GCP_PATHS}) + endif () + if (_GCP_NAMES) + set(GDAL_CHECK_PACKAGE_${name}_NAMES "${_GCP_NAMES}" CACHE STRING "Config file name for ${name}") + mark_as_advanced(GDAL_CHECK_PACKAGE_${name}_NAMES) + endif () + if (_GCP_TARGETS) + set(GDAL_CHECK_PACKAGE_${name}_TARGETS "${_GCP_TARGETS}" CACHE STRING "Target name candidates for ${name}") + mark_as_advanced(GDAL_CHECK_PACKAGE_${name}_TARGETS) + endif () + if (GDAL_CHECK_PACKAGE_${name}_NAMES) + find_package(${name} NAMES ${GDAL_CHECK_PACKAGE_${name}_NAMES} ${_find_package_args}) + gdal_check_package_target(${name} ${GDAL_CHECK_PACKAGE_${name}_TARGETS} REQUIRED) + if (${name}_FOUND) + get_filename_component(_find_dependency_args "${${name}_CONFIG}" NAME) + string(REPLACE ";" " " _find_dependency_args "${name} ${_find_package_args} NAMES ${GDAL_CHECK_PACKAGE_${name}_NAMES} CONFIGS ${_find_dependency_args}") + endif () + endif () + if (NOT ${name}_FOUND) + find_package(${name} ${_find_package_args}) + if (${name}_FOUND) + gdal_check_package_target(${name} ${GDAL_CHECK_PACKAGE_${name}_TARGETS}) + elseif (${key}_FOUND) # Some find modules do not set _FOUND + gdal_check_package_target(${key} ${GDAL_CHECK_PACKAGE_${name}_TARGETS}) + set(${name}_FOUND "${key}_FOUND") + endif () + if (${name}_FOUND) + string(REPLACE ";" " " _find_dependency_args "${name} ${_find_package_args}") + endif() + endif () + endif () + if (${key}_FOUND OR ${name}_FOUND) + if(_GCP_VERSION) + + if( "${name}" STREQUAL "TileDB" AND NOT DEFINED TileDB_VERSION) + get_property(_dirs TARGET TileDB::tiledb_shared PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + foreach(_dir IN LISTS _dirs) + set(TILEDB_VERSION_FILENAME "${_dir}/tiledb/tiledb_version.h") + if(EXISTS ${TILEDB_VERSION_FILENAME}) + file(READ ${TILEDB_VERSION_FILENAME} _tiledb_version_contents) + string(REGEX REPLACE "^.*TILEDB_VERSION_MAJOR +([0-9]+).*$" "\\1" TILEDB_VERSION_MAJOR "${_tiledb_version_contents}") + string(REGEX REPLACE "^.*TILEDB_VERSION_MINOR +([0-9]+).*$" "\\1" TILEDB_VERSION_MINOR "${_tiledb_version_contents}") + set(TileDB_VERSION "${TILEDB_VERSION_MAJOR}.${TILEDB_VERSION_MINOR}") + endif() + endforeach() + endif() + + if (DEFINED ${name}_VERSION_STRING AND NOT DEFINED ${name}_VERSION) + set(${name}_VERSION "${${name}_VERSION_STRING}") + endif() + + if( "${${name}_VERSION}" STREQUAL "") + message(WARNING "${name} has unknown version. Assuming it is at least matching the minimum version required of ${_GCP_VERSION}") + set(HAVE_${key} ON) + elseif( ${name}_VERSION VERSION_LESS ${_GCP_VERSION}) + message(WARNING "Ignoring ${name} because it is at version ${${name}_VERSION}, whereas the minimum version required is ${_GCP_VERSION}") + set(HAVE_${key} OFF) + else() + set(HAVE_${key} ON) + endif() + else() + set(HAVE_${key} ON) + endif() + else () + set(HAVE_${key} OFF) + endif () + if (purpose STREQUAL "") + + else () + if (_GCP_RECOMMENDED) + set_package_properties( + ${name} PROPERTIES + PURPOSE ${purpose} + TYPE RECOMMENDED) + else () + set_package_properties(${name} PROPERTIES PURPOSE ${purpose}) + endif () + endif () + + if (_GCP_CAN_DISABLE OR _GCP_DISABLED_BY_DEFAULT) + set(_gcpp_status ON) + if (GDAL_USE_${key}) + if (NOT HAVE_${key}) + message(FATAL_ERROR "Configured to use ${key}, but not found") + endif () + elseif (NOT GDAL_USE_EXTERNAL_LIBS) + set(_gcpp_status OFF) + if (HAVE_${key} AND NOT GDAL_USE_${key}) + message(STATUS + "${key} has been found, but is disabled due to GDAL_USE_EXTERNAL_LIBS=OFF. Enable it by setting GDAL_USE_${key}=ON" + ) + set(_find_dependency_args "") + endif () + endif () + if (_gcpp_status AND _GCP_DISABLED_BY_DEFAULT) + set(_gcpp_status OFF) + if (HAVE_${key} AND NOT GDAL_USE_${key}) + message(STATUS "${key} has been found, but is disabled by default. Enable it by setting GDAL_USE_${key}=ON") + set(_find_dependency_args "") + endif () + endif () + cmake_dependent_option(GDAL_USE_${key} "Set ON to use ${key}" ${_gcpp_status} "HAVE_${key}" OFF) + elseif (NOT _GCP_ALWAYS_ON_WHEN_FOUND) + message(FATAL_ERROR "Programming error: missing CAN_DISABLE or DISABLED_BY_DEFAULT option for component ${name}") + endif () + + if(_find_dependency_args) + string(REPLACE "\"" "\\\"" _find_dependency_args "${_find_dependency_args}") + set(_find_dependency "find_dependency(${_find_dependency_args})\n") + endif() + if(NOT BUILD_SHARED_LIBS AND GDAL_USE_${key} AND _find_dependency) + string(APPEND GDAL_IMPORT_DEPENDENCIES "${_find_dependency}") + endif() + unset(_find_dependency_args) + unset(_find_dependency) +endmacro () + +function (split_libpath _lib) + if (_lib) + # split lib_line into -L and -l linker options + get_filename_component(_path ${${_lib}} PATH) + get_filename_component(_name ${${_lib}} NAME_WE) + string(REGEX REPLACE "^lib" "" _name ${_name}) + set(${_lib} -L${_path} -l${_name}) + endif () +endfunction () + +function (gdal_internal_library libname) + set(_options REQUIRED) + set(_oneValueArgs) + set(_multiValueArgs) + cmake_parse_arguments(_GIL "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) + if ("${GDAL_USE_INTERNAL_LIBS}" STREQUAL "ON") + set(_default_value ON) + elseif ("${GDAL_USE_INTERNAL_LIBS}" STREQUAL "OFF") + set(_default_value OFF) + elseif( GDAL_USE_${libname} ) + set(_default_value OFF) + else() + set(_default_value ON) + endif() + set(GDAL_USE_${libname}_INTERNAL + ${_default_value} + CACHE BOOL "Use internal ${libname} copy (if set to ON, has precedence over GDAL_USE_${libname})") + if (_GIL_REQUIRED + AND (NOT GDAL_USE_${libname}) + AND (NOT GDAL_USE_${libname}_INTERNAL)) + message(FATAL_ERROR "GDAL_USE_${libname} or GDAL_USE_${libname}_INTERNAL must be set to ON") + endif () +endfunction () + +# vim: ts=4 sw=4 sts=4 et diff --git a/cmake/helpers/CheckDependentLibrariesGeoTIFF.cmake b/cmake/helpers/CheckDependentLibrariesGeoTIFF.cmake new file mode 100644 index 000000000000..82ea7cbc70fe --- /dev/null +++ b/cmake/helpers/CheckDependentLibrariesGeoTIFF.cmake @@ -0,0 +1,5 @@ +gdal_check_package(GeoTIFF "libgeotiff library (external)" CAN_DISABLE RECOMMENDED + NAMES GeoTIFF + TARGETS geotiff_library GEOTIFF::GEOTIFF +) +gdal_internal_library(GEOTIFF REQUIRED) diff --git a/cmake/helpers/CheckDependentLibrariesKakadu.cmake b/cmake/helpers/CheckDependentLibrariesKakadu.cmake new file mode 100644 index 000000000000..5ef1b0f4383d --- /dev/null +++ b/cmake/helpers/CheckDependentLibrariesKakadu.cmake @@ -0,0 +1 @@ +gdal_check_package(KDU "Enable KAKADU" CAN_DISABLE) diff --git a/cmake/helpers/CheckDependentLibrariesMrSID.cmake b/cmake/helpers/CheckDependentLibrariesMrSID.cmake new file mode 100644 index 000000000000..e2f37b39feae --- /dev/null +++ b/cmake/helpers/CheckDependentLibrariesMrSID.cmake @@ -0,0 +1 @@ +gdal_check_package(MRSID "MrSID raster SDK" CAN_DISABLE) diff --git a/cmake/helpers/CheckDependentLibrariesOCI.cmake b/cmake/helpers/CheckDependentLibrariesOCI.cmake new file mode 100644 index 000000000000..76d2644b1965 --- /dev/null +++ b/cmake/helpers/CheckDependentLibrariesOCI.cmake @@ -0,0 +1,2 @@ +set(Oracle_CAN_USE_CLNTSH_AS_MAIN_LIBRARY ON) +gdal_check_package(Oracle "Enable Oracle OCI driver" CAN_DISABLE) diff --git a/cmake/helpers/GdalCAndCXXStandards.cmake b/cmake/helpers/GdalCAndCXXStandards.cmake new file mode 100644 index 000000000000..6e2480cab02c --- /dev/null +++ b/cmake/helpers/GdalCAndCXXStandards.cmake @@ -0,0 +1,10 @@ + +if (NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +if (NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) + set(CMAKE_C_STANDARD_REQUIRED ON) +endif() diff --git a/cmake/helpers/GdalCompilationFlags.cmake b/cmake/helpers/GdalCompilationFlags.cmake new file mode 100644 index 000000000000..3501de613802 --- /dev/null +++ b/cmake/helpers/GdalCompilationFlags.cmake @@ -0,0 +1,219 @@ + +# ###################################################################################################################### +# Detect available warning flags + +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) + +# Do that check now, since we need the result of HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT for cpl_config.h + +set(GDAL_C_WARNING_FLAGS) +set(GDAL_CXX_WARNING_FLAGS) + +if (MSVC) + # 1. conditional expression is constant + # 2. 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' + # 3. non DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' + # 4. ?????????? + # 5. 'identifier' : unreferenced formal parameter + # 6. 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch + # 7. nonstandard extension used : translation unit is empty (only applies to C source code) + # 8. new behavior: elements of array 'array' will be default initialized (needed for + # https://trac.osgeo.org/gdal/changeset/35593) + # 9. interaction between '_setjmp' and C++ object destruction is non-portable + # + set(GDAL_C_WARNING_FLAGS + /W4 + /wd4127 + /wd4251 + /wd4275 + /wd4786 + /wd4100 + /wd4245 + /wd4206 + /wd4351 + /wd4611) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS}) + add_compile_options(/EHsc) + + # The following are extra disables that can be applied to external source not under our control that we wish to use + # less stringent warnings with. + set(GDAL_SOFTWARNFLAGS + /wd4244 + /wd4702 + /wd4701 + /wd4013 + /wd4706 + /wd4057 + /wd4210 + /wd4305) + +else () + + set(GDAL_SOFTWARNFLAGS "") + + macro (detect_and_set_c_warning_flag flag_name) + string(TOUPPER ${flag_name} flag_name_upper) + string(REPLACE "-" "_" flag_name_upper "${flag_name_upper}") + string(REPLACE "=" "_" flag_name_upper "${flag_name_upper}") + check_c_compiler_flag(-W${flag_name} "HAVE_WFLAG_${flag_name_upper}") + if (HAVE_WFLAG_${flag_name_upper}) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -W${flag_name}) + endif () + endmacro () + + macro (detect_and_set_cxx_warning_flag flag_name) + string(TOUPPER ${flag_name} flag_name_upper) + string(REPLACE "-" "_" flag_name_upper "${flag_name_upper}") + string(REPLACE "=" "_" flag_name_upper "${flag_name_upper}") + check_cxx_compiler_flag(-W${flag_name} "HAVE_WFLAG_${flag_name_upper}") + if (HAVE_WFLAG_${flag_name_upper}) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_CXX_WARNING_FLAGS} -W${flag_name}) + endif () + endmacro () + + macro (detect_and_set_c_and_cxx_warning_flag flag_name) + string(TOUPPER ${flag_name} flag_name_upper) + string(REPLACE "-" "_" flag_name_upper "${flag_name_upper}") + string(REPLACE "=" "_" flag_name_upper "${flag_name_upper}") + check_c_compiler_flag(-W${flag_name} "HAVE_WFLAG_${flag_name_upper}") + if (HAVE_WFLAG_${flag_name_upper}) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -W${flag_name}) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_CXX_WARNING_FLAGS} -W${flag_name}) + endif () + endmacro () + + detect_and_set_c_and_cxx_warning_flag(all) + detect_and_set_c_and_cxx_warning_flag(extra) + detect_and_set_c_and_cxx_warning_flag(init-self) + detect_and_set_c_and_cxx_warning_flag(unused-parameter) + detect_and_set_c_warning_flag(missing-prototypes) + detect_and_set_c_and_cxx_warning_flag(missing-declarations) + detect_and_set_c_and_cxx_warning_flag(shorten-64-to-32) + detect_and_set_c_and_cxx_warning_flag(logical-op) + detect_and_set_c_and_cxx_warning_flag(shadow) + detect_and_set_cxx_warning_flag(shadow-field) # CLang only for now + detect_and_set_c_and_cxx_warning_flag(missing-include-dirs) + check_c_compiler_flag("-Wformat -Werror=format-security -Wno-format-nonliteral" HAVE_WFLAG_FORMAT_SECURITY) + if (HAVE_WFLAG_FORMAT_SECURITY) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -Wformat -Werror=format-security -Wno-format-nonliteral) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_CXX_WARNING_FLAGS} -Wformat -Werror=format-security -Wno-format-nonliteral) + else () + detect_and_set_c_and_cxx_warning_flag(format) + endif () + detect_and_set_c_and_cxx_warning_flag(error=vla) + detect_and_set_c_and_cxx_warning_flag(no-clobbered) + detect_and_set_c_and_cxx_warning_flag(date-time) + detect_and_set_c_and_cxx_warning_flag(null-dereference) + detect_and_set_c_and_cxx_warning_flag(duplicate-cond) + detect_and_set_cxx_warning_flag(extra-semi) + detect_and_set_c_and_cxx_warning_flag(comma) + detect_and_set_c_and_cxx_warning_flag(float-conversion) + check_c_compiler_flag("-Wdocumentation -Wno-documentation-deprecated-sync" HAVE_WFLAG_DOCUMENTATION_AND_NO_DEPRECATED) + if (HAVE_WFLAG_DOCUMENTATION_AND_NO_DEPRECATED) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -Wdocumentation -Wno-documentation-deprecated-sync) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_CXX_WARNING_FLAGS} -Wdocumentation -Wno-documentation-deprecated-sync) + endif () + detect_and_set_cxx_warning_flag(unused-private-field) + detect_and_set_cxx_warning_flag(non-virtual-dtor) + detect_and_set_cxx_warning_flag(overloaded-virtual) + detect_and_set_cxx_warning_flag(suggest-override) + + check_cxx_compiler_flag(-fno-operator-names HAVE_FLAG_NO_OPERATOR_NAMES) + if (HAVE_FLAG_NO_OPERATOR_NAMES) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_CXX_WARNING_FLAGS} -fno-operator-names) + endif () + + check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT) + if (HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_CXX_WARNING_FLAGS} -Wzero-as-null-pointer-constant) + endif () + + # Detect -Wold-style-cast but do not add it by default, as not all targets support it + check_cxx_compiler_flag(-Wold-style-cast HAVE_WFLAG_OLD_STYLE_CAST) + if (HAVE_WFLAG_OLD_STYLE_CAST) + set(WFLAG_OLD_STYLE_CAST -Wold-style-cast) + endif () + + # Detect Weffc++ but do not add it by default, as not all targets support it + check_cxx_compiler_flag(-Weffc++ HAVE_WFLAG_EFFCXX) + if (HAVE_WFLAG_EFFCXX) + set(WFLAG_EFFCXX -Weffc++) + endif () + + if (CMAKE_BUILD_TYPE MATCHES Debug) + check_c_compiler_flag(-ftrapv HAVE_FTRAPV) + if (HAVE_FTRAPV) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -ftrapv) + set(GDAL_CXX_WARNING_FLAGS ${GDAL_CXX_WARNING_FLAGS} -ftrapv) + endif () + endif () + +endif () + +add_compile_definitions($<$:DEBUG>) + +# message(STATUS "GDAL_C_WARNING_FLAGS: ${GDAL_C_WARNING_FLAGS}") message(STATUS "GDAL_CXX_WARNING_FLAGS: ${GDAL_CXX_WARNING_FLAGS}") + +if (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + check_cxx_compiler_flag(-fno-finite-math-only HAVE_FLAG_NO_FINITE_MATH_ONLY) + if (HAVE_FLAG_NO_FINITE_MATH_ONLY) + # Intel CXX compiler based on clang defaults to -ffinite-math-only, which breaks std::isinf(), std::isnan(), etc. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-finite-math-only") + endif () + + set(TEST_LINK_STDCPP_SOURCE_CODE + "#include + int main(){ + std::string s; + s += \"x\"; + return 0; + }") + check_cxx_source_compiles("${TEST_LINK_STDCPP_SOURCE_CODE}" _TEST_LINK_STDCPP) + if( NOT _TEST_LINK_STDCPP ) + message(WARNING "Cannot link code using standard C++ library. Automatically adding -lstdc++ to CMAKE_EXE_LINKER_FLAGS, CMAKE_SHARED_LINKER_FLAGS and CMAKE_MODULE_LINKER_FLAGS") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lstdc++") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -lstdc++") + + check_cxx_source_compiles("${TEST_LINK_STDCPP_SOURCE_CODE}" _TEST_LINK_STDCPP_AGAIN) + if( NOT _TEST_LINK_STDCPP_AGAIN ) + message(FATAL_ERROR "Cannot link C++ program") + endif() + endif() + + check_c_compiler_flag(-wd188 HAVE_WD188) # enumerated type mixed with another type + if( HAVE_WD188 ) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -wd188) + endif() + check_c_compiler_flag(-wd2259 HAVE_WD2259) # non-pointer conversion from ... may lose significant bits + if( HAVE_WD2259 ) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -wd2259) + endif() + check_c_compiler_flag(-wd2312 HAVE_WD2312) # pointer cast involving 64-bit pointed-to type + if( HAVE_WD2259 ) + set(GDAL_C_WARNING_FLAGS ${GDAL_C_WARNING_FLAGS} -wd2312) + endif() +endif () + +# Default definitions during build +add_definitions(-DGDAL_COMPILATION) + +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) + add_definitions(-DNOMINMAX) +endif () + +if (MINGW) + if (TARGET_CPU MATCHES "x86_64") + add_definitions(-m64) + endif () + # Workaround for export too large error - force problematic large file to be optimized to prevent string table + # overflow error Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, + # excluding any optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed + # appropriate. Solves issue of https://github.com/OSGeo/gdal/issues/4706 with for example x86_64-w64-mingw32-gcc-posix + # (GCC) 9.3-posix 20200320 + if (CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE STREQUAL "") + add_compile_options(-Os) + endif () +endif () diff --git a/cmake/helpers/GdalDriverHelper.cmake b/cmake/helpers/GdalDriverHelper.cmake index b352ae1ca08b..ad07cb3d407c 100644 --- a/cmake/helpers/GdalDriverHelper.cmake +++ b/cmake/helpers/GdalDriverHelper.cmake @@ -155,7 +155,11 @@ function(add_gdal_driver) set(_COND ${_DRIVER_PLUGIN_CAPABLE_IF}) endif() - get_target_property(PLUGIN_OUTPUT_DIR ${GDAL_LIB_TARGET_NAME} PLUGIN_OUTPUT_DIR) + if(STANDALONE) + set(PLUGIN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + else() + get_target_property(PLUGIN_OUTPUT_DIR ${GDAL_LIB_TARGET_NAME} PLUGIN_OUTPUT_DIR) + endif() if (_DRIVER_PLUGIN_CAPABLE OR _DRIVER_PLUGIN_CAPABLE_IF) set(_INITIAL_VALUE OFF) @@ -293,7 +297,9 @@ function(add_gdal_driver) else() message(FATAL_ERROR "Driver ${_DRIVER_TARGET} should declare DRIVER_NO_SHARED_SYMBOL_WITH_CORE") endif() - _set_driver_core_sources(${_KEY} ${_DRIVER_TARGET} ${_DRIVER_CORE_SOURCES}) + if(NOT STANDALONE) + _set_driver_core_sources(${_KEY} ${_DRIVER_TARGET} ${_DRIVER_CORE_SOURCES}) + endif() endif () else () @@ -325,7 +331,9 @@ function(add_gdal_driver) target_compile_options(${_DRIVER_TARGET} PRIVATE $<$:${GDAL_CXX_WARNING_FLAGS}>) endif() target_compile_options(${_DRIVER_TARGET} PRIVATE $<$:${GDAL_C_WARNING_FLAGS}>) - add_dependencies(${_DRIVER_TARGET} generate_gdal_version_h) + if (NOT STANDALONE) + add_dependencies(${_DRIVER_TARGET} generate_gdal_version_h) + endif() endfunction() # Detect whether driver is built as PLUGIN or not. @@ -483,7 +491,7 @@ macro(gdal_dependent_format format desc depends) cmake_dependent_option(GDAL_ENABLE_DRIVER_${key} "Set ON to build ${desc} format" ${GDAL_BUILD_OPTIONAL_DRIVERS} "${depends}" OFF) add_feature_info(gdal_${key} GDAL_ENABLE_DRIVER_${key} "${desc}") - if ((GDAL_ENABLE_DRIVER_${key} AND NOT _GDF_SKIP_ADD_SUBDIRECTORY) OR GDAL_REGISTER_DRIVER_${key}_FOR_LATER_PLUGIN) + if (NOT STANDALONE AND (GDAL_ENABLE_DRIVER_${key} AND NOT _GDF_SKIP_ADD_SUBDIRECTORY) OR GDAL_REGISTER_DRIVER_${key}_FOR_LATER_PLUGIN) add_subdirectory(${format}) endif () endmacro() @@ -525,7 +533,7 @@ macro(ogr_dependent_driver name desc depend) "${depend}" OFF) endif() add_feature_info(ogr_${key} OGR_ENABLE_DRIVER_${key} "${desc}") - if (OGR_ENABLE_DRIVER_${key} OR OGR_REGISTER_DRIVER_${key}_FOR_LATER_PLUGIN) + if (NOT STANDALONE AND OGR_ENABLE_DRIVER_${key} OR OGR_REGISTER_DRIVER_${key}_FOR_LATER_PLUGIN) add_subdirectory(${name}) endif () endmacro() diff --git a/cmake/helpers/GdalStandardIncludes.cmake b/cmake/helpers/GdalStandardIncludes.cmake index e138d2175838..b4f98e6562f2 100644 --- a/cmake/helpers/GdalStandardIncludes.cmake +++ b/cmake/helpers/GdalStandardIncludes.cmake @@ -8,15 +8,19 @@ GdalStandardIncludes #]=======================================================================] function(gdal_standard_includes _TARGET) - target_include_directories(${_TARGET} PRIVATE - $ - $ - $ - $ - $ # port - $ - $ - $ # ogr/ogrsf_frmts - $ # frmts - ) + if (STANDALONE) + target_include_directories(${_TARGET} PRIVATE $) + else() + target_include_directories(${_TARGET} PRIVATE + $ + $ + $ + $ + $ # port + $ + $ + $ # ogr/ogrsf_frmts + $ # frmts + ) + endif() endfunction() diff --git a/cmake/helpers/GdalVersion.cmake b/cmake/helpers/GdalVersion.cmake index b466522da06d..7961085ba325 100644 --- a/cmake/helpers/GdalVersion.cmake +++ b/cmake/helpers/GdalVersion.cmake @@ -16,8 +16,10 @@ GdalVersion #]=======================================================================] +set(GDAL_ROOT_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") + # parse the version number from gdal_version.h and include in GDAL_MAJOR_VERSION and GDAL_MINOR_VERSION -file(READ ${PROJECT_SOURCE_DIR}/gcore/gdal_version.h.in GDAL_VERSION_H_CONTENTS) +file(READ ${GDAL_ROOT_SOURCE_DIR}/gcore/gdal_version.h.in GDAL_VERSION_H_CONTENTS) string(REGEX MATCH "GDAL_VERSION_MAJOR[ \t]+([0-9]+)" GDAL_VERSION_MAJOR ${GDAL_VERSION_H_CONTENTS}) string(REGEX MATCH "([0-9]+)" @@ -35,12 +37,16 @@ string(REGEX MATCH "GDAL_VERSION_BUILD[ \t]+([0-9]+)" string(REGEX MATCH "([0-9]+)" GDAL_VERSION_BUILD ${GDAL_VERSION_BUILD}) -if ((EXISTS "${PROJECT_SOURCE_DIR}/gcore/gdal_version.h") AND NOT ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")) +if (STANDALONE) + return() +endif() + +if ((EXISTS "${GDAL_ROOT_SOURCE_DIR}/gcore/gdal_version.h") AND NOT ("${GDAL_ROOT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")) # Try to detect issues when building with cmake out of source tree, but against a previous build done in source tree - message(FATAL_ERROR "${PROJECT_SOURCE_DIR}/gcore/gdal_version.h was found, and likely conflicts with ${PROJECT_BINARY_DIR}/gcore/gdal_version.h") + message(FATAL_ERROR "${GDAL_ROOT_SOURCE_DIR}/gcore/gdal_version.h was found, and likely conflicts with ${PROJECT_BINARY_DIR}/gcore/gdal_version.h") endif () -if (EXISTS ${PROJECT_SOURCE_DIR}/.git) +if (EXISTS ${GDAL_ROOT_SOURCE_DIR}/.git) set(GDAL_DEV_SUFFIX "dev") else() set(GDAL_DEV_SUFFIX "") @@ -52,11 +58,11 @@ set(GDAL_RELEASE_DATE "$ENV{GDAL_RELEASE_DATE}") add_custom_target(generate_gdal_version_h COMMAND ${CMAKE_COMMAND} - "-DSOURCE_DIR=${PROJECT_SOURCE_DIR}" + "-DSOURCE_DIR=${GDAL_ROOT_SOURCE_DIR}" "-DBINARY_DIR=${PROJECT_BINARY_DIR}" "-DGDAL_SHA1SUM=${GDAL_SHA1SUM}" "-DGDAL_RELEASE_DATE=${GDAL_RELEASE_DATE}" - -P "${PROJECT_SOURCE_DIR}/cmake/helpers/generate_gdal_version_h.cmake" + -P "${GDAL_ROOT_SOURCE_DIR}/cmake/helpers/generate_gdal_version_h.cmake" VERBATIM) if (WIN32 AND NOT MINGW) diff --git a/cmake/helpers/SetupStandalonePlugin.cmake b/cmake/helpers/SetupStandalonePlugin.cmake new file mode 100644 index 000000000000..53fee7fdcd72 --- /dev/null +++ b/cmake/helpers/SetupStandalonePlugin.cmake @@ -0,0 +1,57 @@ +# Distributed under the GDAL/OGR MIT License. See accompanying file LICENSE.TXT. +# This file is included by drivers that want to be built as plugin against an +# installed GDAL library (and thus not requiring to build libgdal itself) + +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/modules/init.cmake") + +# Hint used to alter the behavior of a number of .cmake files +set(STANDALONE ON) + +# Detect installed GDAL +find_package(GDAL REQUIRED) +set(GDAL_VERSION_IMPORTED ${GDAL_VERSION}) +set(GDAL_LIB_TARGET_NAME GDAL::GDAL) + +# Check that we build the plugin against a GDAL version that matches the one +# of the sources +include(GdalVersion) +set(GDAL_VERSION_MAJOR_SOURCE ${GDAL_VERSION_MAJOR}) +set(GDAL_VERSION_MINOR_SOURCE ${GDAL_VERSION_MINOR}) +set(GDAL_VERSION_REV_SOURCE ${GDAL_VERSION_REV}) +if(NOT "${GDAL_VERSION_IMPORTED}" MATCHES "${GDAL_VERSION_MAJOR_SOURCE}.${GDAL_VERSION_MINOR_SOURCE}.${GDAL_VERSION_REV_SOURCE}") + if (NOT IGNORE_GDAL_VERSION_MISMATCH) + message(FATAL_ERROR "Building plugin against GDAL sources ${GDAL_VERSION_MAJOR_SOURCE}.${GDAL_VERSION_MINOR_SOURCE}.${GDAL_VERSION_REV_SOURCE} whereas linked GDAL library is at version ${GDAL_VERSION_IMPORTED}. This is not a nominally supported configuration. You can bypass this check by setting the IGNORE_GDAL_VERSION_MISMATCH variable.") + endif() +endif() + +include(GdalCAndCXXStandards) +include(GdalStandardIncludes) + +include(CheckDependentLibrariesCommon) + +include(GdalCompilationFlags) + +set(GDAL_ENABLE_PLUGINS ON) +set(GDAL_BUILD_OPTIONAL_DRIVERS ON) +set(OGR_ENABLE_PLUGINS ON) +set(OGR_BUILD_OPTIONAL_DRIVERS ON) +include(GdalDriverHelper) + +include(GNUInstallDirs) +# Used by GdalDriverHelper's add_gdal_driver() +set(INSTALL_PLUGIN_DIR + "${CMAKE_INSTALL_LIBDIR}/gdalplugins" + CACHE PATH "Installation sub-directory for plugins") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") + +macro(standalone_driver_finalize VAR) + include(SystemSummary) + include(driver_declaration.cmake) + if (NOT ${VAR}) + message(FATAL_ERROR "${VAR} is not set, due to missing build requirements") + endif() + system_summary(DESCRIPTION "${PROJECT_NAME} is now configured on") + feature_summary(DESCRIPTION "Enabled drivers and features and found dependency packages" WHAT ALL) +endmacro() diff --git a/cmake/modules/thirdparty/SystemSummary.cmake b/cmake/modules/thirdparty/SystemSummary.cmake index 5251c4840a26..54164304fd09 100644 --- a/cmake/modules/thirdparty/SystemSummary.cmake +++ b/cmake/modules/thirdparty/SystemSummary.cmake @@ -23,8 +23,8 @@ macro(gather_flags with_linker result) # add the main flags without a config list(APPEND ${result} CMAKE_C_FLAGS) list(APPEND ${result} CMAKE_CXX_FLAGS) - list(APPEND ${result} CMAKE_CXX11_STANDARD_COMPILE_OPTION) - list(APPEND ${result} CMAKE_CXX11_EXTENSION_COMPILE_OPTION) + list(APPEND ${result} CMAKE_CXX17_STANDARD_COMPILE_OPTION) + list(APPEND ${result} CMAKE_CXX17_EXTENSION_COMPILE_OPTION) if(${with_linker}) list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS) diff --git a/doc/Makefile b/doc/Makefile index e9f58fee678d..163fbfde3024 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -81,18 +81,18 @@ html: generated_rst_files echo "$(SPHINXOPTS) $(SPHINXINTLOPTS) $(LA)" $(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)/$(LA)" $(SPHINXOPTS) $(O) # Hack to hide the TOC - sed 's/
/