diff --git a/.flake8 b/.flake8 index 075fb37d075..0f8b1b8e2c9 100644 --- a/.flake8 +++ b/.flake8 @@ -23,14 +23,12 @@ per-file-ignores = doc/python/m.distance.py: E501 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 - gui/wxpython/nviz/*: E722 gui/wxpython/photo2image/g.gui.photo2image.py: E501 - gui/wxpython/psmap/*: E501, E722 + gui/wxpython/psmap/*: E501 gui/wxpython/vdigit/*: F841, E722, F405, F403 gui/wxpython/animation/g.gui.animation.py: E501 gui/wxpython/tplot/frame.py: F841, E722 gui/wxpython/tplot/g.gui.tplot.py: E501 - gui/wxpython/rdigit/g.gui.rdigit.py: F841 gui/wxpython/iclass/digit.py: F405, F403 gui/wxpython/iclass/frame.py: F405, F403 gui/wxpython/iclass/g.gui.iclass.py: E501 @@ -74,8 +72,6 @@ per-file-ignores = python/grass/temporal/spatial_topology_dataset_connector.py: E722 python/grass/temporal/temporal_algebra.py: E722 python/grass/temporal/temporal_granularity.py: E722 - python/grass/temporal/temporal_raster_base_algebra.py: E722 - python/grass/temporal/temporal_topology_dataset_connector.py: E722 # Current benchmarks/tests are changing sys.path before import. # Possibly, a different approach should be taken there anyway. python/grass/pygrass/tests/benchmark.py: E402, F821 @@ -89,15 +85,10 @@ per-file-ignores = python/grass/*/*/__init__.py: F403 python/grass/*/*/*/__init__.py: F403 # E402 module level import not at top of file - scripts/r.in.wms/wms_gdal_drv.py: E722 - scripts/r.in.wms/wms_drv.py: E402, E722 - scripts/r.in.wms/srs.py: E722 scripts/r.semantic.label/r.semantic.label.py: E501 - scripts/v.report/v.report.py: E721 - scripts/db.out.ogr/db.out.ogr.py: F841 - scripts/g.extension/g.extension.py: F841, E722, E501 - scripts/v.unpack/v.unpack.py: E722, E501 - scripts/v.import/v.import.py: E722, E501 + scripts/g.extension/g.extension.py: E501 + scripts/v.unpack/v.unpack.py: E501 + scripts/v.import/v.import.py: E501 scripts/db.univar/db.univar.py: E501 scripts/i.pansharpen/i.pansharpen.py: E501 scripts/v.what.strds/v.what.strds.py: E501 diff --git a/.github/workflows/build_ubuntu-22.04.sh b/.github/workflows/build_ubuntu-22.04.sh index 3beeccf9bbd..677c46d5f33 100755 --- a/.github/workflows/build_ubuntu-22.04.sh +++ b/.github/workflows/build_ubuntu-22.04.sh @@ -31,26 +31,26 @@ set -u export INSTALL_PREFIX=$1 ./configure \ - --prefix="$INSTALL_PREFIX/" \ --enable-largefile \ - --with-cxx \ - --with-zstd \ - --with-bzlib \ + --prefix="$INSTALL_PREFIX/" \ --with-blas \ + --with-bzlib \ + --with-cxx \ + --with-fftw \ + --with-freetype \ + --with-freetype-includes="/usr/include/freetype2/" \ + --with-geos \ --with-lapack \ --with-libsvm \ - --with-readline \ + --with-netcdf \ --with-openmp \ --with-pdal \ - --with-pthread \ - --with-tiff \ - --with-freetype \ - --with-freetype-includes="/usr/include/freetype2/" \ --with-proj-share=/usr/share/proj \ - --with-geos \ + --with-pthread \ + --with-readline \ --with-sqlite \ - --with-fftw \ - --with-netcdf + --with-tiff \ + --with-zstd eval $makecmd make install diff --git a/.github/workflows/build_ubuntu-22.04_without_x.sh b/.github/workflows/build_ubuntu-22.04_without_x.sh index 5df3a0b7e33..7e05457a4ee 100755 --- a/.github/workflows/build_ubuntu-22.04_without_x.sh +++ b/.github/workflows/build_ubuntu-22.04_without_x.sh @@ -30,25 +30,25 @@ set -u export INSTALL_PREFIX=$1 ./configure \ - --prefix="$INSTALL_PREFIX/" \ --enable-largefile \ - --with-cxx \ - --with-zstd \ - --with-bzlib \ + --prefix="$INSTALL_PREFIX/" \ --with-blas \ - --with-lapack \ - --with-readline \ - --without-openmp \ - --with-pdal \ - --without-pthread \ - --with-tiff \ + --with-bzlib \ + --with-cxx \ + --with-fftw \ --with-freetype \ --with-freetype-includes="/usr/include/freetype2/" \ - --with-proj-share=/usr/share/proj \ --with-geos \ + --with-lapack \ + --with-netcdf \ + --with-pdal \ + --with-proj-share=/usr/share/proj \ + --with-readline \ --with-sqlite \ - --with-fftw \ - --with-netcdf + --with-tiff \ + --with-zstd \ + --without-openmp \ + --without-pthread eval $makecmd make install diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d98950b0818..a31f5176124 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 51ab83015ca..5253a9ee7a4 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -58,25 +58,26 @@ jobs: echo "CFLAGS=${{ env.CFLAGS }}" >> $GITHUB_ENV echo "CXXFLAGS=${{ env.CXXFLAGS }}" >> $GITHUB_ENV ./configure \ - --prefix="$HOME/install/" \ --enable-largefile \ - --with-cxx \ - --with-zstd \ - --with-bzlib \ + --prefix="$HOME/install/" \ --with-blas \ - --with-lapack \ - --with-readline \ - --without-openmp \ - --with-pdal \ - --without-pthread \ - --with-tiff \ + --with-bzlib \ + --with-cxx \ + --with-fftw \ --with-freetype \ --with-freetype-includes="/usr/include/freetype2/" \ - --with-proj-share=/usr/share/proj \ --with-geos \ + --with-lapack \ + --with-netcdf \ + --with-pdal \ + --with-proj-share=/usr/share/proj \ + --with-readline \ --with-sqlite \ - --with-fftw \ - --with-netcdf + --with-tiff \ + --with-zstd \ + --without-openmp \ + --without-pthread + env: CFLAGS: -fPIC -g CXXFLAGS: -fPIC -g diff --git a/.github/workflows/create_release_draft.yml b/.github/workflows/create_release_draft.yml index efefb0fd0c7..8147136c2eb 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -63,7 +63,8 @@ jobs: run: | cd .. tar -cvf ${{ env.OUT_DIR }}/${{ env.GRASS }}.tar \ - --exclude=".gi*" --exclude=".tr*" grass + --exclude=".gi*" --exclude=".tr*" \ + --transform s/grass/${{ env.GRASS }}/ grass cd ${{ env.OUT_DIR }} gzip -9k ${{ env.GRASS }}.tar md5sum ${{ env.GRASS }}.tar.gz > ${{ env.GRASS }}.tar.gz.md5 @@ -73,7 +74,7 @@ jobs: sha256sum ${{ env.GRASS }}.tar.xz > ${{ env.GRASS }}.tar.xz.sha256 - name: Publish draft distribution to GitHub (for tags only) if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 + uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9 with: name: GRASS GIS ${{ github.ref_name }} body: | diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index cdc02ad1432..466a61967b7 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -50,7 +50,7 @@ jobs: # Year and week of year so cache key changes weekly run: echo "date=$(date +%Y-%U)" >> "${GITHUB_OUTPUT}" - name: Setup Mamba - uses: mamba-org/setup-micromamba@617811f69075e3fd3ae68ca64220ad065877f246 # v2.0.0 + uses: mamba-org/setup-micromamba@ab6bf8bf7403e8023a094abeec19d6753bdc143e # v2.0.1 with: init-shell: bash environment-file: .github/workflows/macos_dependencies.txt diff --git a/.github/workflows/macos_dependencies.txt b/.github/workflows/macos_dependencies.txt index 8ef1d3460f6..28e680d3ae5 100644 --- a/.github/workflows/macos_dependencies.txt +++ b/.github/workflows/macos_dependencies.txt @@ -2,6 +2,7 @@ cairo clangxx_osx-arm64 clang_osx-arm64 cmake +expat fftw flex freetype diff --git a/.github/workflows/macos_install.sh b/.github/workflows/macos_install.sh index 8a94bc15c6a..31d7d23ce8d 100755 --- a/.github/workflows/macos_install.sh +++ b/.github/workflows/macos_install.sh @@ -12,51 +12,51 @@ INSTALL_PREFIX=$1 CONFIGURE_FLAGS="\ --prefix=${INSTALL_PREFIX} \ - --with-opengl=aqua \ - --with-openmp \ - --without-x \ + --with-blas=openblas \ + --with-bzlib \ + --with-bzlib-includes=${CONDA_PREFIX}/include \ + --with-bzlib-libs=${CONDA_PREFIX}/lib \ + --with-cairo \ + --with-cairo-includes=${CONDA_PREFIX}/include/cairo \ + --with-cairo-ldflags="-lcairo" \ + --with-cairo-libs=${CONDA_PREFIX}/lib \ + --with-cxx \ + --with-fftw-includes=${CONDA_PREFIX}/include \ + --with-fftw-libs=${CONDA_PREFIX}/lib \ --with-freetype \ --with-freetype-includes=${CONDA_PREFIX}/include/freetype2 \ --with-freetype-libs=${CONDA_PREFIX}/lib \ --with-gdal=${CONDA_PREFIX}/bin/gdal-config \ - --with-proj-includes=${CONDA_PREFIX}/include \ - --with-proj-libs=${CONDA_PREFIX}/lib \ - --with-proj-share=${CONDA_PREFIX}/share/proj \ --with-geos=${CONDA_PREFIX}/bin/geos-config \ + --with-includes=${CONDA_PREFIX}/include \ + --with-lapack=openblas \ --with-libpng=${CONDA_PREFIX}/bin/libpng-config \ - --with-tiff-includes=${CONDA_PREFIX}/include \ - --with-tiff-libs=${CONDA_PREFIX}/lib \ - --with-postgres=yes \ - --with-postgres-includes=${CONDA_PREFIX}/include \ - --with-postgres-libs=${CONDA_PREFIX}/lib \ - --without-mysql \ - --with-sqlite \ - --with-sqlite-libs=${CONDA_PREFIX}/lib \ - --with-sqlite-includes=${CONDA_PREFIX}/include \ - --with-fftw-includes=${CONDA_PREFIX}/include \ - --with-fftw-libs=${CONDA_PREFIX}/lib \ - --with-cxx \ - --with-cairo \ - --with-cairo-includes=${CONDA_PREFIX}/include/cairo \ - --with-cairo-libs=${CONDA_PREFIX}/lib \ - --with-cairo-ldflags="-lcairo" \ - --with-zstd \ - --with-zstd-libs=${CONDA_PREFIX}/lib \ - --with-zstd-includes=${CONDA_PREFIX}/include \ - --with-bzlib \ - --with-bzlib-libs=${CONDA_PREFIX}/lib \ - --with-bzlib-includes=${CONDA_PREFIX}/include \ + --with-libs=${CONDA_PREFIX}/lib \ --with-netcdf=${CONDA_PREFIX}/bin/nc-config \ - --with-blas=openblas \ - --with-lapack=openblas \ --with-netcdf=${CONDA_PREFIX}/bin/nc-config \ --with-nls \ - --with-libs=${CONDA_PREFIX}/lib \ - --with-includes=${CONDA_PREFIX}/include \ + --with-opengl=aqua \ + --with-openmp \ --with-pdal \ + --with-postgres-includes=${CONDA_PREFIX}/include \ + --with-postgres-libs=${CONDA_PREFIX}/lib \ + --with-postgres=yes \ + --with-proj-includes=${CONDA_PREFIX}/include \ + --with-proj-libs=${CONDA_PREFIX}/lib \ + --with-proj-share=${CONDA_PREFIX}/share/proj \ --with-readline \ --with-readline-includes=${CONDA_PREFIX}/include/readline \ --with-readline-libs=${CONDA_PREFIX}/lib + --with-sqlite \ + --with-sqlite-includes=${CONDA_PREFIX}/include \ + --with-sqlite-libs=${CONDA_PREFIX}/lib \ + --with-tiff-includes=${CONDA_PREFIX}/include \ + --with-tiff-libs=${CONDA_PREFIX}/lib \ + --with-zstd \ + --with-zstd-includes=${CONDA_PREFIX}/include \ + --with-zstd-libs=${CONDA_PREFIX}/lib \ + --without-mysql \ + --without-x \ " export CFLAGS="-O2 -pipe -arch ${CONDA_ARCH} -DGL_SILENCE_DEPRECATION -Wall -Wextra -Wpedantic -Wvla" diff --git a/.github/workflows/optional_requirements.txt b/.github/workflows/optional_requirements.txt index 244a75e2933..078e9fadfb8 100644 --- a/.github/workflows/optional_requirements.txt +++ b/.github/workflows/optional_requirements.txt @@ -1,4 +1,4 @@ folium +ipyleaflet jupyter PyVirtualDisplay -ipyleaflet diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index aa6bd33724f..e1676d179fa 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -36,7 +36,7 @@ jobs: # renovate: datasource=pypi depName=bandit BANDIT_VERSION: "1.7.10" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.7.1" + RUFF_VERSION: "0.7.3" runs-on: ${{ matrix.os }} permissions: @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 with: sarif_file: bandit.sarif diff --git a/.github/workflows/test-nix.yml b/.github/workflows/test-nix.yml index 43a1b5d40ab..6ce1285de9f 100644 --- a/.github/workflows/test-nix.yml +++ b/.github/workflows/test-nix.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install nix - uses: DeterminateSystems/nix-installer-action@da36cb69b1c3247ad7a1f931ebfd954a1105ef14 # v14 + uses: DeterminateSystems/nix-installer-action@b92f66560d6f97d6576405a7bae901ab57e72b6a # v15 - name: Setup cachix uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 diff --git a/.gunittest.cfg b/.gunittest.cfg index 2117fde9d7a..45ae87c12a4 100644 --- a/.gunittest.cfg +++ b/.gunittest.cfg @@ -12,8 +12,8 @@ exclude = python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py raster/r.in.lidar/testsuite/test_base_resolution.sh - temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py temporal/t.connect/testsuite/test_distr_tgis_db_raster.py + temporal/t.connect/testsuite/test_distr_tgis_db_raster3d.py temporal/t.connect/testsuite/test_distr_tgis_db_vector.py temporal/t.info/testsuite/test.t.info.sh temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2f3216877de..712342dc83a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.7.1 + rev: v0.7.3 hooks: # Run the linter. - id: ruff diff --git a/.travis/linux.script.sh b/.travis/linux.script.sh index 4944f7e894e..f2ab000dfc3 100755 --- a/.travis/linux.script.sh +++ b/.travis/linux.script.sh @@ -11,28 +11,28 @@ echo "MAKEFLAGS is '$MAKEFLAGS'" ./configure --host=x86_64-linux-gnu \ --build=x86_64-linux-gnu \ + --enable-largefile \ + --enable-shared \ --prefix=/usr/lib \ - --sysconfdir=/etc \ --sharedstatedir=/var \ - --enable-shared \ - --with-postgres \ + --sysconfdir=/etc \ + --with-blas \ + --with-cairo \ --with-cxx \ - --with-gdal \ --with-freetype \ - --with-readline \ - --with-nls \ - --with-odbc \ + --with-freetype-includes=/usr/include/freetype2/ \ + --with-gdal \ --with-geos \ --with-lapack \ --with-netcdf \ - --with-blas \ - --with-sqlite \ - --with-zstd \ - --enable-largefile \ - --with-freetype-includes=/usr/include/freetype2/ \ + --with-nls \ + --with-odbc \ + --with-pdal \ + --with-postgres \ --with-postgres-includes=/usr/include/postgresql/ \ --with-proj-share=/usr/share/proj \ - --with-cairo \ - --with-pdal + --with-readline \ + --with-sqlite \ + --with-zstd make CFLAGS="$CFLAGS $GRASS_EXTRA_CFLAGS" CXXFLAGS="$CXXFLAGS $GRASS_EXTRA_CXXFLAGS" diff --git a/Dockerfile b/Dockerfile index a5c6ab1ee1d..66b15d5970e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.10@sha256:865e5dd094beca432e8c0a1d5e1c465db5f998dca4e439981029b3b81fb39ed5 +# syntax=docker/dockerfile:1.11@sha256:10c699f1b6c8bdc8f6b4ce8974855dd8542f1768c26eb240237b8f1c9c6c9976 # Note: This file must be kept in sync in ./Dockerfile and ./docker/ubuntu/Dockerfile. # Changes to this file must be copied over to the other file. @@ -131,9 +131,9 @@ ARG GRASS_CONFIG="\ " ARG GRASS_PYTHON_PACKAGES="\ - Pillow \ matplotlib \ numpy \ + Pillow \ pip \ ply \ psycopg2 \ diff --git a/Vagrantfile b/Vagrantfile index 035bb0c64cb..99c373e82ef 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -43,11 +43,11 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| packageList = [ "autoconf2.69", "autotools-dev", - "make", + "bison", + "flex", "g++", "gettext", - "flex", - "bison", + "libblas-dev", "libcairo2-dev", "libfftw3-dev", "libfreetype6-dev", @@ -55,27 +55,27 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| "libgeos-dev", "libglu1-mesa-dev", "libjpeg-dev", - "libpng-dev", - "libtiff-dev", + "liblapack-dev", "libmysqlclient-dev", "libncurses5-dev", + "libnetcdf-dev", + "libpng-dev", "libpq-dev", "libproj-dev", - "proj-bin", "libreadline-dev", "libsqlite3-dev", + "libtiff-dev", "libxmu-dev", + "make", + "netcdf-bin", + "proj-bin", "python3", - "python3-wxgtk4.0", "python3-dateutil", "python3-dev", "python3-numpy", - "python3-ply", "python3-pil", - "libnetcdf-dev", - "netcdf-bin", - "libblas-dev", - "liblapack-dev", + "python3-ply", + "python3-wxgtk4.0", "unixodbc-dev", "zlib1g-dev", # "libpdal-dev" diff --git a/binder/apt.txt b/binder/apt.txt index 1ee0d6836f9..7f4a3500c82 100644 --- a/binder/apt.txt +++ b/binder/apt.txt @@ -19,7 +19,6 @@ liblapack-dev libncurses5-dev libnetcdf-dev libpdal-dev -libgeos-dev libpng-dev libpq-dev libproj-dev diff --git a/binder/postBuild b/binder/postBuild index 138326daa18..fd462729ec3 100755 --- a/binder/postBuild +++ b/binder/postBuild @@ -5,15 +5,15 @@ set -e # compile ./configure \ - --with-nls \ - --with-cxx \ - --with-readline \ --with-bzlib \ - --with-proj-share=/usr/share/proj \ - --with-geos=/usr/bin/geos-config \ --with-cairo \ - --with-opengl-libs=/usr/include/GL \ + --with-cxx \ --with-freetype=yes --with-freetype-includes="/usr/include/freetype2/" \ + --with-geos=/usr/bin/geos-config \ + --with-nls \ + --with-opengl-libs=/usr/include/GL \ + --with-proj-share=/usr/share/proj \ + --with-readline \ --with-sqlite=yes \ --without-pdal make diff --git a/contributors.csv b/contributors.csv index 5f501d9f077..c9236bb1aea 100644 --- a/contributors.csv +++ b/contributors.csv @@ -1,25 +1,25 @@ cvs_id,name,email,country,osgeo_id,rfc2_agreed,orcid --,Ivan Shmakov,,Russia,1gray,yes,- --,Eric Patton,,Canada,epatton,yes,- --,Laura Toma,,USA,ltoma,yes,- --,Markus Metz,,Germany,mmetz,yes,0000-0002-4038-8754 --,Maris Nartiss,,Latvia,marisn,yes,0000-0002-3875-740X --,Marco Pasetti,,Italy,marcopx,yes,- --,Yann Chemin,,France,ychemin,yes,0000-0001-9232-5512 --,Colin Nielsen,,USA,cnielsen,yes,- +-,Anna Petrášová,,Czech Republic,annakrat,yes,0000-0002-5120-5538 -,Anne Ghisla,,Italy,aghisla,yes,- +-,Colin Nielsen,,USA,cnielsen,yes,- +-,Eric Patton,,Canada,epatton,yes,- -,Helmut Kudrnovsky,,Austria,hellik,yes,0000-0001-6622-7169 --,Anna Petrášová,,Czech Republic,annakrat,yes,0000-0002-5120-5538 +-,Ivan Shmakov,,Russia,1gray,yes,- +-,Laura Toma,,USA,ltoma,yes,- -,Luca Delucchi,,Italy,lucadelu,yes,0000-0002-0493-3516 --,Václav Petráš,,Czech Republic,wenzeslaus,yes,0000-0001-5566-9236 --,Pietro Zambelli,,Italy,zarch,yes,0000-0002-6187-3572 --,Štěpán Turek,,Czech Republic,turek,yes,- +-,Marco Pasetti,,Italy,marcopx,yes,- -,Margherita Di Leo,,Italy,madi,yes,0000-0002-0279-7557 --,Veronica Andreo,,Argentina,veroandreo,yes,0000-0002-4633-2161 --,Stefan Blumentrath,,Norway,sbl,yes,0000-0001-6675-1331 +-,Maris Nartiss,,Latvia,marisn,yes,0000-0002-3875-740X +-,Markus Metz,,Germany,mmetz,yes,0000-0002-4038-8754 +-,Nicklas Larsson,,Hungary/Sweden,nilason,yes,- -,Ondřej Pešek,,Czech Republic,pesekon2,yes,0000-0002-2363-8002 +-,Pietro Zambelli,,Italy,zarch,yes,0000-0002-6187-3572 +-,Stefan Blumentrath,,Norway,sbl,yes,0000-0001-6675-1331 +-,Štěpán Turek,,Czech Republic,turek,yes,- -,Tomáš Zigo,,Slovak Republic,tmszi,yes,- --,Nicklas Larsson,,Hungary/Sweden,nilason,yes,- +-,Václav Petráš,,Czech Republic,wenzeslaus,yes,0000-0001-5566-9236 +-,Veronica Andreo,,Argentina,veroandreo,yes,0000-0002-4633-2161 +-,Yann Chemin,,France,ychemin,yes,0000-0001-9232-5512 alex,Alex Shevlakov,,Russia,-,-,- andreas,Andreas Lange,,Germany,-,-,- benjamin,Benjamin Ducke,,Germany,benducke,yes,0000-0002-0560-4749 @@ -52,9 +52,9 @@ michel,Michel Wurtz,,France,-,-,- mike,Mike Thomas,,Australia,-,-,- moritz,Moritz Lennert,,Belgium,mlennert,yes,0000-0002-2870-4515 msieczka,Maciej Sieczka,,Poland,msieczka,yes,- +pallech,Serena Pallecchi,,Italy,-,-,- paul,Paul Kelly,,UK,pkelly,yes,- paulo,Paulo Marcondes,,Brazil,pmarcondes,-,- -pallech,Serena Pallecchi,,Italy,-,-,- radim,Radim Blazek,,Czech Republic,rblazek,-,- roberto,Roberto Micarelli,,Italy,-,-,- robertoa,Roberto Antolin,,Spain,rantolin,yes,- diff --git a/contributors_extra.csv b/contributors_extra.csv index 5bcbcaaa67d..1cfa5ac4a82 100644 --- a/contributors_extra.csv +++ b/contributors_extra.csv @@ -1,11 +1,11 @@ name,email,country,rfc2_agreed Adam Laža,,Czech Republic,yes +Aldo Clerici,,Italy,- Alfonso Vitti,,Italy,- -Anna Zanchetta,,Italy,yes Andrea Aime,,Italy,- Angus Carr,,Canada,- +Anna Zanchetta,,Italy,yes Antonio Galea,,Italy,- -Aldo Clerici,,Italy,- Ari Jolma,,Finland,- Bill Hughes,,USA,- Brook Milligan,,USA,- @@ -23,8 +23,8 @@ Eric Mitchell,,-,- Francesco Pirotti,,Italy,- Ivan Mincik,,Slovakia,- Jacques Bouchard,,France,- -Jarrett Keifer,,USA,- Jaro Hofierka,,Slovakia,- +Jarrett Keifer,,USA,- Jeshua Lacock,,USA,- Lars Ahlzen,,-,- Lorenzo Moretti,,Italy,- diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index b6dbebf6666..8163b5d9b08 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -29,11 +29,11 @@ ENV GRASS_RUN_PACKAGES="\ gdal-driver-JP2OpenJPEG \ gdal-driver-LIBKML \ gdal-driver-MSSQLSpatial \ + gdal-driver-netCDF \ gdal-driver-ODBC \ gdal-driver-PG \ gdal-driver-PNG \ gdal-driver-WMS \ - gdal-driver-netCDF \ gdal-tools \ geos \ geos-dev \ diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 8021ccf409e..6df50c8e14d 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -88,15 +88,15 @@ RUN echo en_US.UTF-8 UTF-8 >> /etc/locale.gen && locale-gen WORKDIR /src RUN mkdir vdatum && \ cd vdatum && \ - wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2012.zip && unzip -j -u usa_geoid2012.zip -d /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2009.zip && unzip -j -u usa_geoid2009.zip -d /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2003.zip && unzip -j -u usa_geoid2003.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/egm96_15/egm96_15.gtx && mv egm96_15.gtx /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/usa_geoid1999.zip && unzip -j -u usa_geoid1999.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2003.zip && unzip -j -u usa_geoid2003.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2009.zip && unzip -j -u usa_geoid2009.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2012.zip && unzip -j -u usa_geoid2012.zip -d /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertconc.gtx && mv vertconc.gtx /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertcone.gtx && mv vertcone.gtx /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertconw.gtx && mv vertconw.gtx /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/egm96_15/egm96_15.gtx && mv egm96_15.gtx /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj; \ cd .. && \ rm -rf vdatum @@ -116,16 +116,16 @@ RUN wget -q \ -DCMAKE_C_COMPILER=gcc \ -DCMAKE_CXX_COMPILER=g++ \ -DCMAKE_MAKE_PROGRAM=make \ - -DBUILD_PLUGIN_PYTHON=ON \ + -DBUILD_PGPOINTCLOUD_TESTS=OFF \ -DBUILD_PLUGIN_CPD=OFF \ -DBUILD_PLUGIN_GREYHOUND=ON \ -DBUILD_PLUGIN_HEXBIN=ON \ - -DHEXER_INCLUDE_DIR=/usr/include/ \ - -DBUILD_PLUGIN_NITF=OFF \ -DBUILD_PLUGIN_ICEBRIDGE=ON \ + -DBUILD_PLUGIN_NITF=OFF \ -DBUILD_PLUGIN_PGPOINTCLOUD=OFF \ - -DBUILD_PGPOINTCLOUD_TESTS=OFF \ + -DBUILD_PLUGIN_PYTHON=ON \ -DBUILD_PLUGIN_SQLITE=ON \ + -DHEXER_INCLUDE_DIR=/usr/include/ \ -DWITH_LASZIP=OFF \ -DWITH_LAZPERF=ON \ -DWITH_TESTS=ON && \ diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index a5c6ab1ee1d..66b15d5970e 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.10@sha256:865e5dd094beca432e8c0a1d5e1c465db5f998dca4e439981029b3b81fb39ed5 +# syntax=docker/dockerfile:1.11@sha256:10c699f1b6c8bdc8f6b4ce8974855dd8542f1768c26eb240237b8f1c9c6c9976 # Note: This file must be kept in sync in ./Dockerfile and ./docker/ubuntu/Dockerfile. # Changes to this file must be copied over to the other file. @@ -131,9 +131,9 @@ ARG GRASS_CONFIG="\ " ARG GRASS_PYTHON_PACKAGES="\ - Pillow \ matplotlib \ numpy \ + Pillow \ pip \ ply \ psycopg2 \ diff --git a/docker/ubuntu_wxgui/Dockerfile b/docker/ubuntu_wxgui/Dockerfile index 0d1ead788a3..80dbbb1d409 100644 --- a/docker/ubuntu_wxgui/Dockerfile +++ b/docker/ubuntu_wxgui/Dockerfile @@ -122,15 +122,15 @@ RUN echo en_US.UTF-8 UTF-8 >> /etc/locale.gen && locale-gen WORKDIR /src RUN mkdir vdatum && \ cd vdatum && \ - wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2012.zip && unzip -j -u usa_geoid2012.zip -d /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2009.zip && unzip -j -u usa_geoid2009.zip -d /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2003.zip && unzip -j -u usa_geoid2003.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/egm96_15/egm96_15.gtx && mv egm96_15.gtx /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/usa_geoid1999.zip && unzip -j -u usa_geoid1999.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2003.zip && unzip -j -u usa_geoid2003.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2009.zip && unzip -j -u usa_geoid2009.zip -d /usr/share/proj; \ + wget -q http://download.osgeo.org/proj/vdatum/usa_geoid2012.zip && unzip -j -u usa_geoid2012.zip -d /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertconc.gtx && mv vertconc.gtx /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertcone.gtx && mv vertcone.gtx /usr/share/proj; \ wget -q http://download.osgeo.org/proj/vdatum/vertcon/vertconw.gtx && mv vertconw.gtx /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/egm96_15/egm96_15.gtx && mv egm96_15.gtx /usr/share/proj; \ - wget -q http://download.osgeo.org/proj/vdatum/egm08_25/egm08_25.gtx && mv egm08_25.gtx /usr/share/proj; \ cd .. && \ rm -rf vdatum @@ -150,16 +150,16 @@ RUN wget -q \ -DCMAKE_C_COMPILER=gcc \ -DCMAKE_CXX_COMPILER=g++ \ -DCMAKE_MAKE_PROGRAM=make \ - -DBUILD_PLUGIN_PYTHON=ON \ + -DBUILD_PGPOINTCLOUD_TESTS=OFF \ -DBUILD_PLUGIN_CPD=OFF \ -DBUILD_PLUGIN_GREYHOUND=ON \ -DBUILD_PLUGIN_HEXBIN=ON \ - -DHEXER_INCLUDE_DIR=/usr/include/ \ - -DBUILD_PLUGIN_NITF=OFF \ -DBUILD_PLUGIN_ICEBRIDGE=ON \ + -DBUILD_PLUGIN_NITF=OFF \ -DBUILD_PLUGIN_PGPOINTCLOUD=OFF \ - -DBUILD_PGPOINTCLOUD_TESTS=OFF \ + -DBUILD_PLUGIN_PYTHON=ON \ -DBUILD_PLUGIN_SQLITE=ON \ + -DHEXER_INCLUDE_DIR=/usr/include/ \ -DWITH_LASZIP=OFF \ -DWITH_LAZPERF=ON \ -DWITH_TESTS=ON && \ @@ -186,8 +186,8 @@ ENV CXXFLAGS "$MYCXXFLAGS" # Configure compile and install GRASS GIS # wxGUI require -# --with-x # --with-nls +# --with-x ENV NUMTHREADS=4 RUN make distclean || echo "nothing to clean" RUN /src/grass_build/configure \ diff --git a/flake.lock b/flake.lock index eacc92d3c4f..f36f65a6375 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1727826117, - "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", + "lastModified": 1730504689, + "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", + "rev": "506278e768c2a08bec68eb62932193e341f55c90", "type": "github" }, "original": { @@ -19,11 +19,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728538411, - "narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=", + "lastModified": 1730272153, + "narHash": "sha256-B5WRZYsRlJgwVHIV6DvidFN7VX7Fg9uuwkRW9Ha8z+w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221", + "rev": "2d2a9ddbe3f2c00747398f3dc9b05f7f2ebb0f53", "type": "github" }, "original": { @@ -35,14 +35,14 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1727825735, - "narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=", + "lastModified": 1730504152, + "narHash": "sha256-lXvH/vOfb4aGYyvFmZK/HlsNsr/0CVWlwYvo2rxJk3s=", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz" }, "original": { "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + "url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz" } }, "root": { diff --git a/general/g.parser/standard_option.c b/general/g.parser/standard_option.c index 12c08f96f2e..14c816a0e18 100644 --- a/general/g.parser/standard_option.c +++ b/general/g.parser/standard_option.c @@ -55,6 +55,7 @@ static char *STD_OPT_STRINGS[] = {"G_OPT_UNDEFINED", "G_OPT_F_SEP", "G_OPT_C", "G_OPT_CN", + "G_OPT_C_FORMAT", "G_OPT_M_UNITS", "G_OPT_M_DATATYPE", "G_OPT_M_MAPSET", diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index 5b58c08cc55..cde41710cd9 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -120,6 +120,14 @@ def SetId(self, id): def run(self): os.environ["GRASS_MESSAGE_FORMAT"] = "gui" while True: + variables = { + "callable": None, + "onDone": None, + "onPrepare": None, + "userData": None, + "addLayer": None, + "notification": None, + } requestId, args, kwds = self.requestQ.get() for key in ( "callable", @@ -130,13 +138,11 @@ def run(self): "notification", ): if key in kwds: - vars()[key] = kwds[key] + variables[key] = kwds[key] del kwds[key] - else: - vars()[key] = None - if not vars()["callable"]: - vars()["callable"] = GrassCmd + if not variables["callable"]: + variables["callable"] = GrassCmd requestTime = time.time() @@ -146,21 +152,21 @@ def run(self): cmd=args[0], time=requestTime, pid=requestId, - onPrepare=vars()["onPrepare"], - userData=vars()["userData"], + onPrepare=variables["onPrepare"], + userData=variables["userData"], ) wx.PostEvent(self.receiver, event) # run command event = wxCmdRun( - cmd=args[0], pid=requestId, notification=vars()["notification"] + cmd=args[0], pid=requestId, notification=variables["notification"] ) wx.PostEvent(self.receiver, event) time.sleep(0.1) - self.requestCmd = vars()["callable"](*args, **kwds) + self.requestCmd = variables["callable"](*args, **kwds) if self._want_abort_all and self.requestCmd is not None: self.requestCmd.abort() if self.requestQ.empty(): @@ -211,7 +217,7 @@ def run(self): "map=%s" % mapName, "color=%s" % colorTable, ] - self.requestCmdColor = vars()["callable"](*argsColor, **kwds) + self.requestCmdColor = variables["callable"](*argsColor, **kwds) self.resultQ.put((requestId, self.requestCmdColor.run())) if self.receiver: @@ -221,10 +227,10 @@ def run(self): returncode=returncode, time=requestTime, pid=requestId, - onDone=vars()["onDone"], - userData=vars()["userData"], - addLayer=vars()["addLayer"], - notification=vars()["notification"], + onDone=variables["onDone"], + userData=variables["userData"], + addLayer=variables["addLayer"], + notification=variables["notification"], ) # send event diff --git a/gui/wxpython/core/gthread.py b/gui/wxpython/core/gthread.py index 3437d04bf56..3e1eae86623 100644 --- a/gui/wxpython/core/gthread.py +++ b/gui/wxpython/core/gthread.py @@ -86,21 +86,25 @@ def SetId(self, id): gThread.requestId = id def run(self): + variables = { + "callable": None, + "ondone": None, + "userdata": None, + "onterminate": None, + } while True: requestId, args, kwds = self.requestQ.get() for key in ("callable", "ondone", "userdata", "onterminate"): if key in kwds: - vars()[key] = kwds[key] + variables[key] = kwds[key] del kwds[key] - else: - vars()[key] = None ret = None exception = None time.sleep(0.01) self._terminate_evt = wxThdTerminate( - onterminate=vars()["onterminate"], + onterminate=variables["onterminate"], kwds=kwds, args=args, pid=requestId, @@ -109,7 +113,7 @@ def run(self): if self.terminate: return - ret = vars()["callable"](*args, **kwds) + ret = variables["callable"](*args, **kwds) if self.terminate: return @@ -119,12 +123,12 @@ def run(self): self.resultQ.put((requestId, ret)) event = wxCmdDone( - ondone=vars()["ondone"], + ondone=variables["ondone"], kwds=kwds, args=args, # TODO expand args to kwds ret=ret, exception=exception, - userdata=vars()["userdata"], + userdata=variables["userdata"], pid=requestId, ) diff --git a/gui/wxpython/dbmgr/manager.py b/gui/wxpython/dbmgr/manager.py index b1cbd93ab71..c3821abb4ef 100644 --- a/gui/wxpython/dbmgr/manager.py +++ b/gui/wxpython/dbmgr/manager.py @@ -204,6 +204,8 @@ def OnCloseWindow(self, event): if self.parent and self.parent.GetName() == "LayerManager": # deregister ATM self.parent.dialogs["atm"].remove(self) + # set map window focus + self.parent.GetMapDisplay().GetMapWindow().SetFocus() if not isinstance(event, wx.CloseEvent): self.Destroy() diff --git a/gui/wxpython/nviz/mapwindow.py b/gui/wxpython/nviz/mapwindow.py index d3f93f94938..b6609427895 100644 --- a/gui/wxpython/nviz/mapwindow.py +++ b/gui/wxpython/nviz/mapwindow.py @@ -1390,7 +1390,7 @@ def LoadDataLayers(self): GError(parent=self, message=e.value) # when nviz.tools is not yet ready # during opening 3D view 2nd time - except: + except Exception: pass stop = gs.clock() diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index dce751e6b27..77f379ef019 100644 --- a/gui/wxpython/nviz/tools.py +++ b/gui/wxpython/nviz/tools.py @@ -160,7 +160,7 @@ def SetInitialMaps(self): else: try: selection = layers[0].GetName() - except: + except (AttributeError, IndexError): continue if ltype == "raster": self.FindWindowById(self.win["surface"]["map"]).SetValue(selection) @@ -734,24 +734,11 @@ def _createDataPage(self): self.mainPanelData = SP.ScrolledPanel(parent=self) self.mainPanelData.SetupScrolling(scroll_x=False) self.mainPanelData.AlwaysShowScrollbars(hflag=False) - try: # wxpython <= 2.8.10 - self.foldpanelData = fpb.FoldPanelBar( - parent=self.mainPanelData, - id=wx.ID_ANY, - style=fpb.FPB_DEFAULT_STYLE, - extraStyle=fpb.FPB_SINGLE_FOLD, - ) - except: - try: # wxpython >= 2.8.11 - self.foldpanelData = fpb.FoldPanelBar( - parent=self.mainPanelData, - id=wx.ID_ANY, - agwStyle=fpb.FPB_SINGLE_FOLD, - ) - except: # to be sure - self.foldpanelData = fpb.FoldPanelBar( - parent=self.mainPanelData, id=wx.ID_ANY, style=fpb.FPB_SINGLE_FOLD - ) + self.foldpanelData = fpb.FoldPanelBar( + parent=self.mainPanelData, + id=wx.ID_ANY, + agwStyle=fpb.FPB_SINGLE_FOLD, + ) self.foldpanelData.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) @@ -814,24 +801,11 @@ def _createAppearancePage(self): self.mainPanelAppear = SP.ScrolledPanel(parent=self) self.mainPanelAppear.SetupScrolling(scroll_x=False) self.mainPanelAppear.AlwaysShowScrollbars(hflag=False) - try: # wxpython <= 2.8.10 - self.foldpanelAppear = fpb.FoldPanelBar( - parent=self.mainPanelAppear, - id=wx.ID_ANY, - style=fpb.FPB_DEFAULT_STYLE, - extraStyle=fpb.FPB_SINGLE_FOLD, - ) - except: - try: # wxpython >= 2.8.11 - self.foldpanelAppear = fpb.FoldPanelBar( - parent=self.mainPanelAppear, - id=wx.ID_ANY, - agwStyle=fpb.FPB_SINGLE_FOLD, - ) - except: # to be sure - self.foldpanelAppear = fpb.FoldPanelBar( - parent=self.mainPanelAppear, id=wx.ID_ANY, style=fpb.FPB_SINGLE_FOLD - ) + self.foldpanelAppear = fpb.FoldPanelBar( + parent=self.mainPanelAppear, + id=wx.ID_ANY, + agwStyle=fpb.FPB_SINGLE_FOLD, + ) self.foldpanelAppear.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) # light page @@ -3360,7 +3334,7 @@ def OnSetSurface(self, event): name = event.GetString() try: self._getLayerPropertiesByName(name, mapType="raster")["surface"] - except: + except (AttributeError, TypeError, KeyError): self.EnablePage("fringe", False) return @@ -3384,7 +3358,7 @@ def OnSetVector(self, event): name = event.GetString() try: data = self._getLayerPropertiesByName(name, mapType="vector")["vector"] - except: + except (AttributeError, TypeError, KeyError): self.EnablePage("vector", False) return layer = self._getMapLayerByName(name, mapType="vector") @@ -3396,7 +3370,7 @@ def OnSetRaster3D(self, event): name = event.GetString() try: data = self._getLayerPropertiesByName(name, mapType="raster_3d")["volume"] - except: + except (AttributeError, TypeError, KeyError): self.EnablePage("volume", False) return @@ -4925,7 +4899,7 @@ def OnCPlaneSelection(self, event): try: planeIndex = int(plane.split()[-1]) - 1 self.EnablePage("cplane", enabled=True) - except: + except (ValueError, IndexError): planeIndex = -1 self.EnablePage("cplane", enabled=False) self.mapWindow.SelectCPlane(planeIndex) @@ -4942,7 +4916,7 @@ def OnCPlaneChanging(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except: # TODO disabled page + except (ValueError, IndexError): # TODO disabled page planeIndex = -1 if event.GetId() in ( @@ -4984,7 +4958,7 @@ def OnCPlaneShading(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except: # TODO disabled page + except (ValueError, IndexError): # TODO disabled page planeIndex = -1 self.mapWindow.cplanes[planeIndex]["shading"] = shading @@ -4999,7 +4973,7 @@ def OnCPlaneReset(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except: # TODO disabled page + except (ValueError, IndexError): # TODO disabled page planeIndex = -1 self.mapWindow.cplanes[planeIndex] = copy.deepcopy( diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index 8926b8d1e75..22194ece0c0 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -1045,19 +1045,9 @@ def makePSFont(self, textDict): if "Bold" in fontstyle: weight = wx.FONTWEIGHT_BOLD - try: - fn = wx.Font( - pointSize=fontsize, family=family, style=style, weight=weight, face=face - ) - except: - fn = wx.Font( - pointSize=fontsize, - family=wx.FONTFAMILY_DEFAULT, - style=wx.FONTSTYLE_NORMAL, - weight=wx.FONTWEIGHT_NORMAL, - ) - - return fn + return wx.Font( + pointSize=fontsize, family=family, style=style, weight=weight, faceName=face + ) def getTextExtent(self, textDict): """Estimates bounding rectangle of text""" @@ -1071,7 +1061,7 @@ def getTextExtent(self, textDict): dc.SetFont(fn) w, h, lh = dc.GetFullMultiLineTextExtent(textDict["text"]) return (w, h) - except: + except (wx.PyAssertionError, ValueError, KeyError): return (0, 0) def getInitMap(self): diff --git a/gui/wxpython/rdigit/g.gui.rdigit.py b/gui/wxpython/rdigit/g.gui.rdigit.py index ae8d9ed41d8..5b38d858835 100755 --- a/gui/wxpython/rdigit/g.gui.rdigit.py +++ b/gui/wxpython/rdigit/g.gui.rdigit.py @@ -154,7 +154,7 @@ def _addLayer(self, name, ltype="raster"): :param str name: map name :param str ltype: layer type """ - mapLayer = self._mapObj.AddLayer( + self._mapObj.AddLayer( ltype=ltype, name=name, command=["d.rast", "map={}".format(name)], diff --git a/gui/wxpython/vdigit/toolbars.py b/gui/wxpython/vdigit/toolbars.py index a9cafe3dfb4..09833758882 100644 --- a/gui/wxpython/vdigit/toolbars.py +++ b/gui/wxpython/vdigit/toolbars.py @@ -1035,6 +1035,8 @@ def OnSelectMap(self, event): # select the given map layer for editing self.StartEditing(self.layers[selection]) + wx.CallLater(100, self.MapWindow.SetFocus) + event.Skip() def StartEditing(self, mapLayer): diff --git a/imagery/i.albedo/i.albedo.html b/imagery/i.albedo/i.albedo.html index bc21720d19c..76b7e04696e 100644 --- a/imagery/i.albedo/i.albedo.html +++ b/imagery/i.albedo/i.albedo.html @@ -43,7 +43,7 @@

TODO

Maybe change input requirement of MODIS to [0.0-1.0]? -

References

+

REFERENCES

For a 2 band determination of the Aster BB Albedo see the following:

diff --git a/imagery/i.vi/main.c b/imagery/i.vi/main.c index dd1ceb8d6cf..7947aee6c50 100644 --- a/imagery/i.vi/main.c +++ b/imagery/i.vi/main.c @@ -593,6 +593,16 @@ int main(int argc, char *argv[]) else G_fatal_error(_("Unknown color request '%s'"), style); } + else if (!strcasecmp(viflag, "ndwi")) { + /* apply predefined NDWI color table */ + const char *style = "ndwi"; + + if (G_find_color_rule("ndwi")) { + Rast_make_fp_colors(&colors, style, -1.0, 1.0); + } + else + G_fatal_error(_("Unknown color request '%s'"), style); + } else { /* Color from -1.0 to +1.0 in grey */ Rast_init_colors(&colors); diff --git a/include/grass/defs/raster.h b/include/grass/defs/raster.h index 7f358562c72..bbdc8bfeaa1 100644 --- a/include/grass/defs/raster.h +++ b/include/grass/defs/raster.h @@ -392,6 +392,7 @@ int Rast_option_to_interp_type(const struct Option *); /* mask_info.c */ char *Rast_mask_info(void); +char *Rast_mask_name(void); bool Rast_mask_status(char *, char *, bool *, char *, char *); int Rast__mask_info(char *, char *); bool Rast_mask_is_present(void); diff --git a/include/grass/gis.h b/include/grass/gis.h index c032b40de06..fcc53535f47 100644 --- a/include/grass/gis.h +++ b/include/grass/gis.h @@ -316,8 +316,9 @@ typedef enum { G_OPT_F_OUTPUT, /*!< new output file */ G_OPT_F_SEP, /*!< data field separator */ - G_OPT_C, /*!< color */ - G_OPT_CN, /*!< color or none */ + G_OPT_C, /*!< color */ + G_OPT_CN, /*!< color or none */ + G_OPT_C_FORMAT, /*!< set color format to rgb,hex,hsv or triplet */ G_OPT_M_UNITS, /*!< units */ G_OPT_M_DATATYPE, /*!< datatype */ diff --git a/lib/Makefile b/lib/Makefile index a313a656f36..91c38f5c73b 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -4,11 +4,11 @@ include $(MODULE_TOPDIR)/include/Make/Vars.make #order is relevant: SUBDIRS = \ + external \ datetime \ gis \ proj \ raster \ - external \ gmath \ linkm \ driver \ diff --git a/lib/gis/colors.desc b/lib/gis/colors.desc index 673c0db8f91..c501e00c93b 100644 --- a/lib/gis/colors.desc +++ b/lib/gis/colors.desc @@ -48,6 +48,7 @@ sepia: yellowish-brown through to white slope: r.slope.aspect-type slope colors for raster values 0-90 soilmoisture: soilmoisture color table (0.0-1.0) srtm: color palette for Shuttle Radar Topography Mission elevation +srtm_percent: color palette for Shuttle Radar Topography Mission using relative elevation srtm_plus: color palette for Shuttle Radar Topography Mission elevation (with seafloor colors) terrain: global elevation color table covering -11000 to +8850m viridis: perceptually uniform sequential color table viridis diff --git a/lib/gis/colors/srtm_percent b/lib/gis/colors/srtm_percent new file mode 100644 index 00000000000..a8e0d857f76 --- /dev/null +++ b/lib/gis/colors/srtm_percent @@ -0,0 +1,7 @@ +0% 57 151 105 +25% 117 194 93 +40% 230 230 128 +55% 214 187 98 +70% 185 154 100 +80% 150 120 80 +100% 220 220 220 diff --git a/lib/gis/file_name.c b/lib/gis/file_name.c index 7bf7b9d2539..a3e7bd5d786 100644 --- a/lib/gis/file_name.c +++ b/lib/gis/file_name.c @@ -161,13 +161,13 @@ char *file_name(char *path, const char *dir, const char *element, const char *name, const char *mapset, const char *base) { const char *pname = name; + char xname[GNAME_MAX] = {'\0'}; if (base && *base) { sprintf(path, "%s", base); } else { - char xname[GNAME_MAX]; - char xmapset[GMAPSET_MAX]; + char xmapset[GMAPSET_MAX] = {'\0'}; char *location = G__location_path(); /* diff --git a/lib/gis/parser_standard_options.c b/lib/gis/parser_standard_options.c index 5c3da23c7bf..2addde624bf 100644 --- a/lib/gis/parser_standard_options.c +++ b/lib/gis/parser_standard_options.c @@ -97,6 +97,7 @@ - colors - G_OPT_C - G_OPT_CN + - G_OPT_C_FORMAT - misc - G_OPT_M_DIR @@ -652,6 +653,22 @@ struct Option *G_define_standard_option(int opt) Opt->description = _("Either a standard color name, R:G:B triplet, or \"none\""); break; + case G_OPT_C_FORMAT: + Opt->key = "color_format"; + Opt->type = TYPE_STRING; + Opt->key_desc = "name"; + Opt->required = YES; + Opt->multiple = NO; + Opt->answer = "hex"; + Opt->options = "rgb,hex,hsv,triplet"; + Opt->label = _("Color format"); + Opt->description = _("Color format for output values."); + G_asprintf( + (char **)&(Opt->descriptions), "rgb;%s;hex;%s;hsv;%s;triplet;%s", + _("output color in RGB format"), _("output color in HEX format"), + _("output color in HSV format (experimental)"), + _("output color in colon-separated RGB format")); + break; /* misc */ diff --git a/lib/ogsf/gsd_img_tif.c b/lib/ogsf/gsd_img_tif.c index 47f9b4ebbc5..c2518bb8bea 100644 --- a/lib/ogsf/gsd_img_tif.c +++ b/lib/ogsf/gsd_img_tif.c @@ -116,6 +116,7 @@ int GS_write_tif(const char *name) } G_free((void *)pixbuf); + G_free(buf); (void)TIFFClose(out); return (0); diff --git a/lib/ogsf/gsd_surf.c b/lib/ogsf/gsd_surf.c index d22e17a8918..ae7c9d5dd49 100644 --- a/lib/ogsf/gsd_surf.c +++ b/lib/ogsf/gsd_surf.c @@ -228,7 +228,7 @@ int gsd_surf_map_old(geosurf *surf) */ check_transp = 0; tratt = &(surf->att[ATT_TRANSP]); - ktrans = (255 << 24); + ktrans = (255U << 24); trans_src = surf->att[ATT_TRANSP].att_src; if (CONST_ATT == trans_src && surf->att[ATT_TRANSP].constant != 0.0) { @@ -344,7 +344,7 @@ int gsd_surf_map_old(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset, ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } gsd_litvert_func(n, ktrans | curcolor, pt); @@ -369,7 +369,7 @@ int gsd_surf_map_old(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset, ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } if (check_material) { @@ -469,7 +469,7 @@ int gsd_surf_map_old(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset, ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } if (check_material) { @@ -524,7 +524,7 @@ int gsd_surf_map_old(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset, ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } if (check_material) { @@ -580,7 +580,7 @@ int gsd_surf_map_old(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset, ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } if (check_material) { @@ -649,7 +649,7 @@ int gsd_surf_map_old(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset, ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } if (check_material) { @@ -2144,7 +2144,7 @@ int gsd_surf_map(geosurf *surf) */ check_transp = 0; tratt = &(surf->att[ATT_TRANSP]); - ktrans = (255 << 24); + ktrans = (255U << 24); trans_src = surf->att[ATT_TRANSP].att_src; if (CONST_ATT == trans_src && surf->att[ATT_TRANSP].constant != 0.0) { @@ -2328,7 +2328,7 @@ int gsd_surf_map(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset2[ii], ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } if (check_material) { diff --git a/lib/ogsf/gsd_wire.c b/lib/ogsf/gsd_wire.c index 0da492b9b15..1b3b8e6c084 100644 --- a/lib/ogsf/gsd_wire.c +++ b/lib/ogsf/gsd_wire.c @@ -645,7 +645,7 @@ int gsd_coarse_surf_map(geosurf *surf) */ check_transp = 0; tratt = &(surf->att[ATT_TRANSP]); - ktrans = (255 << 24); + ktrans = (255U << 24); trans_src = surf->att[ATT_TRANSP].att_src; if (CONST_ATT == trans_src && surf->att[ATT_TRANSP].constant != 0.0) { @@ -798,7 +798,7 @@ int gsd_coarse_surf_map(geosurf *surf) if (check_transp) { GET_MAPATT(trbuff, offset2[ii], ttr); ktrans = (char)SCALE_ATT(tratt, ttr, 0, 255); - ktrans = (char)(255 - ktrans) << 24; + ktrans = (char)(255U - ktrans) << 24; } if (check_material) { diff --git a/lib/ogsf/gvl2.c b/lib/ogsf/gvl2.c index 473d3e9406e..2c861c4b5ad 100644 --- a/lib/ogsf/gvl2.c +++ b/lib/ogsf/gvl2.c @@ -316,10 +316,16 @@ void GVL_get_dims(int id, int *rows, int *cols, int *depths) *rows = gvl->rows; *cols = gvl->cols; *depths = gvl->depths; - } - G_debug(3, "GVL_get_dims() id=%d, rows=%d, cols=%d, depths=%d", - gvl->gvol_id, gvl->rows, gvl->cols, gvl->depths); + G_debug(3, "GVL_get_dims() id=%d, rows=%d, cols=%d, depths=%d", + gvl->gvol_id, gvl->rows, gvl->cols, gvl->depths); + } + else { + G_debug(2, + "GVL_get_dims(): Attempted to access a null volume structure " + "for id=%d", + id); + } return; } diff --git a/lib/ogsf/gvld.c b/lib/ogsf/gvld.c index 91734eaac49..9c0831b5bcd 100644 --- a/lib/ogsf/gvld.c +++ b/lib/ogsf/gvld.c @@ -188,7 +188,7 @@ int gvld_isosurf(geovol *gvl) /* transparency */ check_transp[i] = 0; - ktrans[i] = (255 << 24); + ktrans[i] = (255U << 24); if (CONST_ATT == isosurf->att[ATT_TRANSP].att_src && isosurf->att[ATT_TRANSP].constant != 0.0) { ktrans[i] = (255 - (int)isosurf->att[ATT_TRANSP].constant) << 24; diff --git a/lib/raster/mask_info.c b/lib/raster/mask_info.c index 317bab75b63..25d61341ebe 100644 --- a/lib/raster/mask_info.c +++ b/lib/raster/mask_info.c @@ -49,6 +49,27 @@ char *Rast_mask_info(void) return G_store(text); } +/** + * @brief Retrieves the name of the raster mask to use. + * + * The returned raster map name is fully qualified, i.e., in the form + % "name@mapset". + * + * The mask name is "MASK@", where is the current + * mapset. + * + * The memory for the returned mask name is dynamically allocated using + * G_store(). It is the caller's responsibility to free the memory with + * G_free() when it is no longer needed. + * + * @returns A dynamically allocated string containing the mask name. + */ +char *Rast_mask_name(void) +{ + // Mask name is always "MASK@". + return G_fully_qualified_name("MASK", G_mapset()); +} + /** * @brief Get raster mask status information * diff --git a/lib/vector/Vlib/break_polygons.c b/lib/vector/Vlib/break_polygons.c index 2b82d8eff62..1eb548f96c1 100644 --- a/lib/vector/Vlib/break_polygons.c +++ b/lib/vector/Vlib/break_polygons.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -131,11 +132,19 @@ void Vect_break_polygons_file(struct Map_info *Map, int type, filename = G_tempfile(); fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); RTree = RTreeCreateTree(fd, 0, 2); - remove(filename); + (void)remove(filename); + G_free(filename); filename = G_tempfile(); xpntfd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); - remove(filename); + if (xpntfd < 0) { + close(RTree->fd); + G_free(filename); + G_fatal_error(_("Failed to create xpnt temporary file: %s"), + strerror(errno)); + } + (void)remove(filename); + G_free(filename); BPoints = Vect_new_line_struct(); Points = Vect_new_line_struct(); @@ -651,6 +660,7 @@ void Vect_break_polygons_mem(struct Map_info *Map, int type, Vect_destroy_line_struct(Points); Vect_destroy_line_struct(BPoints); Vect_destroy_cats_struct(Cats); + Vect_destroy_cats_struct(ErrCats); G_verbose_message(_("Breaks: %d"), nbreaks); } diff --git a/lib/vector/Vlib/clean_nodes.c b/lib/vector/Vlib/clean_nodes.c index bff6d502129..2ba34985549 100644 --- a/lib/vector/Vlib/clean_nodes.c +++ b/lib/vector/Vlib/clean_nodes.c @@ -241,6 +241,10 @@ int Vect_clean_small_angles_at_nodes(struct Map_info *Map, int otype, } } G_verbose_message(_("Modifications: %d"), nmodif); + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(OCats); + Vect_destroy_cats_struct(LCats); + Vect_destroy_cats_struct(SCats); return (nmodif); } diff --git a/macosx/ReadMe.md b/macosx/ReadMe.md index 86fb1c0ba38..085c09c691b 100644 --- a/macosx/ReadMe.md +++ b/macosx/ReadMe.md @@ -172,6 +172,11 @@ just remove the `--prefix` and `--enable-macosx-app` flags)*: ```bash ./configure \ + --enable-macosx-app \ + --prefix=/Applications \ + --with-cxx \ + --with-fftw-includes=/Library/Frameworks/FFTW3.framework/unix/include \ + --with-fftw-libs=/Library/Frameworks/FFTW3.framework/unix/lib \ --with-freetype \ --with-freetype-includes= \ "/Library/Frameworks/FreeType.framework/unix/include/freetype2 \ @@ -179,36 +184,31 @@ just remove the `--prefix` and `--enable-macosx-app` flags)*: --with-freetype-libs=/Library/Frameworks/FreeType.framework/unix/lib \ --with-gdal=/Library/Frameworks/GDAL.framework/Programs/gdal-config \ --with-geos=/Library/Frameworks/GEOS.framework/Programs/geos-config \ - --with-proj \ - --with-proj-includes=/Library/Frameworks/PROJ.framework/unix/include \ - --with-proj-libs=/Library/Frameworks/PROJ.framework/unix/lib \ - --with-proj-share=/Library/Frameworks/PROJ.framework/Resources/proj \ --with-jpeg-includes=/Library/Frameworks/UnixImageIO.framework/unix/include \ --with-jpeg-libs=/Library/Frameworks/UnixImageIO.framework/unix/lib \ + --with-odbc \ + --with-opengl=aqua \ --with-png-includes=/Library/Frameworks/UnixImageIO.framework/unix/include \ --with-png-libs=/Library/Frameworks/UnixImageIO.framework/unix/lib \ - --with-tiff-includes=/Library/Frameworks/UnixImageIO.framework/unix/include \ - --with-tiff-libs=/Library/Frameworks/UnixImageIO.framework/unix/lib \ - --without-postgres \ - --without-mysql \ - --with-odbc \ + --with-proj \ + --with-proj-includes=/Library/Frameworks/PROJ.framework/unix/include \ + --with-proj-libs=/Library/Frameworks/PROJ.framework/unix/lib \ + --with-proj-share=/Library/Frameworks/PROJ.framework/Resources/proj \ --with-sqlite \ - --with-sqlite-libs=/Library/Frameworks/SQLite3.framework/unix/lib \ --with-sqlite-includes=/Library/Frameworks/SQLite3.framework/unix/include \ - --with-fftw-includes=/Library/Frameworks/FFTW3.framework/unix/include \ - --with-fftw-libs=/Library/Frameworks/FFTW3.framework/unix/lib \ - --with-cxx \ + --with-sqlite-libs=/Library/Frameworks/SQLite3.framework/unix/lib \ --with-tcltk-includes="/Library/Frameworks/Tcl.framework/Headers \ /Library/Frameworks/Tk.framework/Headers \ /Library/Frameworks/Tk.framework/PrivateHeaders" \ --with-tcltk-libs=/usr/local/lib \ + --with-tiff-includes=/Library/Frameworks/UnixImageIO.framework/unix/include \ + --with-tiff-libs=/Library/Frameworks/UnixImageIO.framework/unix/lib \ --with-x \ - --without-motif \ --without-glw \ - --with-opengl=aqua \ - --without-readline \ - --prefix=/Applications \ - --enable-macosx-app + --without-motif \ + --without-mysql \ + --without-postgres \ + --without-readline ``` That's a long line, but you have to be very explicit in the GRASS configure @@ -533,10 +533,21 @@ For i386: ```sh cd build-i386 -../configure --enable-shared --disable-static --disable-debug \ - --disable-ffserver --disable-network --enable-gpl --enable-pthreads \ - --enable-swscale --disable-vhook --disable-ffplay --disable-ffmpeg \ - --disable-amd3dnow --arch=i386 --extra-cflags="-arch i386" \ +../configure \ + --arch=i386 \ + --disable-amd3dnow \ + --disable-debug \ + --disable-ffmpeg \ + --disable-ffplay \ + --disable-ffserver \ + --disable-network \ + --disable-static \ + --disable-vhook \ + --enable-gpl \ + --enable-pthreads \ + --enable-shared \ + --enable-swscale \ + --extra-cflags="-arch i386" \ --extra-ldflags="-arch i386" ``` @@ -555,10 +566,21 @@ Now, the PPC build: ```sh cd ../build-ppc -../configure --enable-shared --disable-static --disable-debug \ - --disable-ffserver --disable-network --enable-gpl --enable-pthreads \ - --enable-swscale --disable-vhook --disable-ffplay --disable-ffmpeg \ - --enable-altivec --arch=ppc --extra-cflags="-arch ppc" \ +../configure \ + --arch=ppc \ + --disable-debug \ + --disable-ffmpeg \ + --disable-ffplay \ + --disable-ffserver \ + --disable-network \ + --disable-static \ + --disable-vhook \ + --enable-altivec \ + --enable-gpl \ + --enable-pthreads \ + --enable-shared \ + --enable-swscale \ + --extra-cflags="-arch ppc" \ --extra-ldflags="-arch ppc" make ``` @@ -572,10 +594,21 @@ For x86_64: ```sh cd build-x86_64 -../configure --enable-shared --disable-static --disable-debug \ - --disable-ffserver --disable-network --enable-gpl --enable-pthreads \ - --enable-swscale --disable-vhook --disable-ffplay --disable-ffmpeg \ - --disable-amd3dnow --arch=x86_64 --extra-cflags="-arch x86\_64" \ +../configure \ + --arch=x86_64 \ + --disable-amd3dnow \ + --disable-debug \ + --disable-ffmpeg \ + --disable-ffplay \ + --disable-ffserver \ + --disable-network \ + --disable-static \ + --disable-vhook \ + --enable-gpl \ + --enable-pthreads \ + --enable-shared \ + --enable-swscale \ + --extra-cflags="-arch x86\_64" \ --extra-ldflags="-arch x86_64" ``` @@ -588,10 +621,21 @@ And ppc64: ```sh cd ../build-ppc64 -../configure --enable-shared --disable-static --disable-debug \ - --disable-ffserver --disable-network --enable-gpl --enable-pthreads \ - --enable-swscale --disable-vhook --disable-ffplay --disable-ffmpeg \ - --enable-altivec --arch=ppc64 --extra-cflags="-arch ppc64" \ +../configure \ + --arch=ppc64 \ + --disable-debug \ + --disable-ffmpeg \ + --disable-ffplay \ + --disable-ffserver \ + --disable-network \ + --disable-static \ + --disable-vhook \ + --enable-altivec \ + --enable-gpl \ + --enable-pthreads \ + --enable-shared \ + --enable-swscale \ + --extra-cflags="-arch ppc64" \ --extra-ldflags="-arch ppc64" ``` diff --git a/mswindows/crosscompile.sh b/mswindows/crosscompile.sh index d1b834df008..ec43dcab689 100755 --- a/mswindows/crosscompile.sh +++ b/mswindows/crosscompile.sh @@ -129,17 +129,17 @@ CFLAGS="-g -O2 -Wall" \ CXXFLAGS="-g -O2 -Wall" \ LDFLAGS="-lcurses" \ ./configure \ ---with-nls \ ---with-readline \ ---with-freetype-includes=$freetype_include \ ---with-bzlib \ ---with-postgres \ ---with-pthread \ ---with-openmp \ --with-blas \ ---with-lapack \ +--with-bzlib \ +--with-freetype-includes=$freetype_include \ --with-geos \ +--with-lapack \ --with-netcdf \ +--with-nls \ +--with-openmp \ +--with-postgres \ +--with-pthread \ +--with-readline \ >> /dev/stdout make clean default @@ -159,10 +159,10 @@ fi build_arch=`sed -n '/^ARCH[ \t]*=/{s/^.*=[ \t]*//; p}' include/Make/Platform.make` for i in \ config.log \ - include/Make/Platform.make \ + error.log \ include/Make/Doxyfile_arch_html \ include/Make/Doxyfile_arch_latex \ - error.log \ + include/Make/Platform.make \ ; do cp -a $i $i.$build_arch done @@ -186,19 +186,19 @@ PKG_CONFIG=$mxe_bin-pkg-config \ ./configure \ --build=$build_arch \ --host=$arch \ ---with-nls \ ---with-readline \ ---with-freetype-includes=$mxe_shared/include/freetype2 \ ---with-bzlib \ ---with-postgres \ ---with-pthread \ ---with-openmp \ --with-blas \ ---with-lapack \ +--with-bzlib \ +--with-freetype-includes=$mxe_shared/include/freetype2 \ +--with-gdal=$mxe_shared/bin/gdal-config \ --with-geos=$mxe_shared/bin/geos-config \ +--with-lapack \ --with-netcdf=$mxe_shared/bin/nc-config \ ---with-gdal=$mxe_shared/bin/gdal-config \ +--with-nls \ --with-opengl=windows \ +--with-openmp \ +--with-postgres \ +--with-pthread \ +--with-readline \ >> /dev/stdout make clean default @@ -217,10 +217,10 @@ fi arch=`sed -n '/^ARCH[ \t]*=/{s/^.*=[ \t]*//; p}' include/Make/Platform.make` for i in \ config.log \ - include/Make/Platform.make \ + error.log \ include/Make/Doxyfile_arch_html \ include/Make/Doxyfile_arch_latex \ - error.log \ + include/Make/Platform.make \ ; do cp -a $i $i.$arch done @@ -307,8 +307,8 @@ for i in \ done for i in \ - proj \ gdal \ + proj \ ; do rm -rf $dist/share/$i cp -a $mxe_shared/share/$i $dist/share/$i diff --git a/mswindows/osgeo4w/build_osgeo4w.sh b/mswindows/osgeo4w/build_osgeo4w.sh index d38354d4b78..98ed16aac1e 100755 --- a/mswindows/osgeo4w/build_osgeo4w.sh +++ b/mswindows/osgeo4w/build_osgeo4w.sh @@ -22,49 +22,48 @@ export PYTHONHOME=${OSGEO4W_ROOT_MSYS}/apps/Python312 export ARCH=x86_64-w64-mingw32 ./configure \ + --bindir=${OSGEO4W_ROOT_MSYS}/bin \ + --enable-largefile \ + --enable-shared \ --host=${ARCH} \ - --with-libs="${OSGEO4W_ROOT_MSYS}/lib ${OSGEO4W_ROOT_MSYS}/bin" \ - --with-includes=${OSGEO4W_ROOT_MSYS}/include \ + --includedir=${OSGEO4W_ROOT_MSYS}/include \ --libexecdir=${OSGEO4W_ROOT_MSYS}/bin \ --prefix=${OSGEO4W_ROOT_MSYS}/apps/grass \ - --bindir=${OSGEO4W_ROOT_MSYS}/bin \ - --includedir=${OSGEO4W_ROOT_MSYS}/include \ - --without-x \ + --with-blas \ + --with-bzlib \ + --with-cairo \ + --with-cairo-includes=${OSGEO4W_ROOT_MSYS}/include \ + --with-cairo-ldflags="-L${SRC}/mswindows/osgeo4w/lib -lcairo" \ + --with-cairo-libs=$OSGEO4W_ROOT_MSYS/lib \ --with-cxx \ - --enable-shared \ - --enable-largefile \ - --with-openmp \ --with-fftw \ - --with-nls \ - --with-readline \ - --with-blas \ - --with-lapack \ --with-freetype \ --with-freetype-includes=${OSGEO4W_ROOT_MSYS}/include/freetype2 \ - --with-proj-share=${OSGEO4W_ROOT_MSYS}/share/proj \ - --with-proj-includes=${OSGEO4W_ROOT_MSYS}/include \ - --with-proj-libs=${OSGEO4W_ROOT_MSYS}/lib \ + --with-gdal=${SRC}/mswindows/osgeo4w/gdal-config \ + --with-geos=${SRC}/mswindows/osgeo4w/geos-config \ + --with-includes=${OSGEO4W_ROOT_MSYS}/include \ + --with-lapack \ + --with-liblas=${SRC}/mswindows/osgeo4w/liblas-config \ + --with-libs="${OSGEO4W_ROOT_MSYS}/lib ${OSGEO4W_ROOT_MSYS}/bin" \ + --with-netcdf=${OSGEO4W_ROOT_MSYS}/bin/nc-config \ + --with-nls \ + --with-odbc \ + --with-opengl=windows \ + --with-openmp \ --with-postgres \ --with-postgres-includes=${OSGEO4W_ROOT_MSYS}/include \ --with-postgres-libs=${OSGEO4W_ROOT_MSYS}/lib \ - --with-gdal=${SRC}/mswindows/osgeo4w/gdal-config \ - --with-geos=${SRC}/mswindows/osgeo4w/geos-config \ + --with-proj-includes=${OSGEO4W_ROOT_MSYS}/include \ + --with-proj-libs=${OSGEO4W_ROOT_MSYS}/lib \ + --with-proj-share=${OSGEO4W_ROOT_MSYS}/share/proj \ + --with-readline \ + --with-regex \ --with-sqlite \ --with-sqlite-includes=${OSGEO4W_ROOT_MSYS}/include \ --with-sqlite-libs=${OSGEO4W_ROOT_MSYS}/lib \ - --with-regex \ - --with-nls \ --with-zstd \ - --with-odbc \ - --with-cairo \ - --with-cairo-includes=${OSGEO4W_ROOT_MSYS}/include \ - --with-cairo-libs=$OSGEO4W_ROOT_MSYS/lib \ - --with-cairo-ldflags="-L${SRC}/mswindows/osgeo4w/lib -lcairo" \ - --with-opengl=windows \ - --with-bzlib \ - --with-liblas=${SRC}/mswindows/osgeo4w/liblas-config \ - --with-netcdf=${OSGEO4W_ROOT_MSYS}/bin/nc-config \ - --without-pdal + --without-pdal \ + --without-x make diff --git a/mswindows/osgeo4w/package.sh b/mswindows/osgeo4w/package.sh index b3113292c99..c189cf92c93 100755 --- a/mswindows/osgeo4w/package.sh +++ b/mswindows/osgeo4w/package.sh @@ -107,32 +107,32 @@ fi exec 3>&1 > >(tee mswindows/osgeo4w/package.log) 2>&1 DLLS=" - /mingw64/bin/zlib1.dll - /mingw64/bin/libbz2-1.dll - /mingw64/bin/libiconv-2.dll - /mingw64/bin/libfontconfig-1.dll - /mingw64/bin/libgfortran-5.dll - /mingw64/bin/libbrotlidec.dll + /mingw64/bin/libblas.dll /mingw64/bin/libbrotlicommon.dll - /mingw64/bin/libintl-8.dll - /mingw64/bin/libsystre-0.dll - /mingw64/bin/libtre-5.dll - /mingw64/bin/libwinpthread-1.dll + /mingw64/bin/libbrotlidec.dll + /mingw64/bin/libbz2-1.dll /mingw64/bin/libcairo-2.dll - /mingw64/bin/libpixman-1-0.dll - /mingw64/bin/libpng16-16.dll + /mingw64/bin/libfftw3-3.dll + /mingw64/bin/libfontconfig-1.dll /mingw64/bin/libfreetype-6.dll - /mingw64/bin/libharfbuzz-0.dll + /mingw64/bin/libgcc_s_seh-1.dll + /mingw64/bin/libgfortran-5.dll /mingw64/bin/libglib-2.0-0.dll /mingw64/bin/libgomp-1.dll /mingw64/bin/libgraphite2.dll - /mingw64/bin/libpcre-1.dll - /mingw64/bin/libstdc++-6.dll - /mingw64/bin/libgcc_s_seh-1.dll - /mingw64/bin/libfftw3-3.dll - /mingw64/bin/libblas.dll + /mingw64/bin/libharfbuzz-0.dll + /mingw64/bin/libiconv-2.dll + /mingw64/bin/libintl-8.dll /mingw64/bin/liblapack.dll + /mingw64/bin/libpcre-1.dll + /mingw64/bin/libpixman-1-0.dll + /mingw64/bin/libpng16-16.dll /mingw64/bin/libquadmath-0.dll + /mingw64/bin/libstdc++-6.dll + /mingw64/bin/libsystre-0.dll + /mingw64/bin/libtre-5.dll + /mingw64/bin/libwinpthread-1.dll + /mingw64/bin/zlib1.dll " if ! [ -f mswindows/osgeo4w/configure-stamp ]; then @@ -153,47 +153,47 @@ if ! [ -f mswindows/osgeo4w/configure-stamp ]; then log configure ./configure \ + --bindir=$OSGEO4W_ROOT_MSYS/bin \ + --enable-largefile \ + --enable-shared \ --host=x86_64-w64-mingw32 \ - --with-libs="$OSGEO4W_ROOT_MSYS/lib" \ - --with-includes=$OSGEO4W_ROOT_MSYS/include \ + --includedir=$OSGEO4W_ROOT_MSYS/include \ --libexecdir=$OSGEO4W_ROOT_MSYS/bin \ --prefix=$OSGEO4W_ROOT_MSYS/apps/grass \ - --bindir=$OSGEO4W_ROOT_MSYS/bin \ - --includedir=$OSGEO4W_ROOT_MSYS/include \ - --with-opengl=windows \ - --without-x \ + --with-blas \ + --with-bzlib \ + --with-cairo \ + --with-cairo-includes=$OSGEO4W_ROOT_MSYS/include \ + --with-cairo-ldflags="-L$PWD/mswindows/osgeo4w/lib -lcairo -lfontconfig" \ --with-cxx \ - --enable-shared \ - --enable-largefile \ --with-fftw \ --with-freetype \ --with-freetype-includes=/mingw64/include/freetype2 \ - --with-proj-share=$OSGEO4W_ROOT_MSYS/share/proj \ - --with-proj-includes=$OSGEO4W_ROOT_MSYS/include \ - --with-proj-libs=$OSGEO4W_ROOT_MSYS/lib \ + --with-gdal=$PWD/mswindows/osgeo4w/gdal-config \ + --with-geos=$PWD/mswindows/osgeo4w/geos-config \ + --with-includes=$OSGEO4W_ROOT_MSYS/include \ + --with-lapack \ + --with-lapack-includes=/mingw64/include \ + --with-liblas=$PWD/mswindows/osgeo4w/liblas-config \ + --with-libs="$OSGEO4W_ROOT_MSYS/lib" \ + --with-netcdf=${OSGEO4W_ROOT_MSYS}/bin/nc-config \ + --with-nls \ + --with-odbc \ + --with-opengl=windows \ + --with-openmp \ --with-postgres \ --with-postgres-includes=$OSGEO4W_ROOT_MSYS/include \ --with-postgres-libs=$PWD/mswindows/osgeo4w/lib \ - --with-gdal=$PWD/mswindows/osgeo4w/gdal-config \ - --with-geos=$PWD/mswindows/osgeo4w/geos-config \ + --with-proj-includes=$OSGEO4W_ROOT_MSYS/include \ + --with-proj-libs=$OSGEO4W_ROOT_MSYS/lib \ + --with-proj-share=$OSGEO4W_ROOT_MSYS/share/proj \ + --with-regex \ --with-sqlite \ --with-sqlite-includes=$OSGEO4W_ROOT_MSYS/include \ --with-sqlite-libs=$PWD/mswindows/osgeo4w/lib \ - --with-regex \ - --with-nls \ --with-zstd \ - --with-odbc \ - --with-netcdf=${OSGEO4W_ROOT_MSYS}/bin/nc-config \ - --with-blas \ - --with-lapack \ - --with-lapack-includes=/mingw64/include \ - --with-openmp \ - --with-cairo \ - --with-cairo-includes=$OSGEO4W_ROOT_MSYS/include \ - --with-cairo-ldflags="-L$PWD/mswindows/osgeo4w/lib -lcairo -lfontconfig" \ - --with-bzlib \ - --with-liblas=$PWD/mswindows/osgeo4w/liblas-config \ - --without-pdal + --without-pdal \ + --without-x touch mswindows/osgeo4w/configure-stamp fi diff --git a/package.nix b/package.nix index 3f1d03697c7..edf1e3e18a4 100644 --- a/package.nix +++ b/package.nix @@ -100,8 +100,8 @@ stdenv.mkDerivation (finalAttrs: { "--with-cxx" "--with-fftw" "--with-freetype" - "--with-geos" "--with-gdal" + "--with-geos" "--with-lapack" "--with-libsvm" "--with-nls" diff --git a/pyproject.toml b/pyproject.toml index d739653809e..c9f621a679f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -261,6 +261,7 @@ ignore = [ # "A005", # builtin-module-shadowing # "PLW0108", # unnecessary-lambda # Ignore `E402` (import violations) in all `__init__.py` files +"**.py" = ["PYI066"] "*/testsuite/**.py" = ["PT009", "PT027"] "__init__.py" = ["E402"] "display/d.mon/render_cmd.py" = ["SIM115"] @@ -317,6 +318,7 @@ ignore = [ "python/grass/pygrass/modules/grid/testsuite/test_*_modules_grid_doctests.py" = ["F401"] "python/grass/pygrass/modules/interface/env.py" = ["SIM115"] "python/grass/pygrass/modules/testsuite/test_pygrass_modules_doctests.py" = ["F401"] +"python/grass/pygrass/raster/category.py" = ["FURB189"] "python/grass/pygrass/raster/segment.py" = ["SIM115"] "python/grass/pygrass/tests/*.py" = ["SIM115"] "python/grass/pygrass/vector/geometry.py" = ["PYI024"] @@ -326,7 +328,7 @@ ignore = [ "python/grass/script/core.py" = ["SIM115"] "python/grass/script/db.py" = ["SIM115"] "python/grass/script/raster.py" = ["SIM115"] -"python/grass/script/utils.py" = ["SIM115"] +"python/grass/script/utils.py" = ["FURB189", "SIM115"] "python/grass/temporal/aggregation.py" = ["SIM115"] "python/grass/temporal/register.py" = ["SIM115"] "python/grass/temporal/stds_export.py" = ["SIM115"] diff --git a/python/grass/pygrass/messages/__init__.py b/python/grass/pygrass/messages/__init__.py index 54d9af1b1c5..b5fe052883c 100644 --- a/python/grass/pygrass/messages/__init__.py +++ b/python/grass/pygrass/messages/__init__.py @@ -6,34 +6,45 @@ Fast and exit-safe interface to GRASS C-library message functions -(C) 2013 by the GRASS Development Team +(C) 2013-2024 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. -@author Soeren Gebbert +@author Soeren Gebbert, Edouard Choinière """ +from __future__ import annotations + import sys -from multiprocessing import Process, Lock, Pipe +from multiprocessing import Lock, Pipe, Process +from typing import TYPE_CHECKING, Literal, NoReturn import grass.lib.gis as libgis - from grass.exceptions import FatalError +if TYPE_CHECKING: + from multiprocessing.connection import Connection + from multiprocessing.context import _LockLike + + _MessagesLiteral = Literal[ + "INFO", "IMPORTANT", "VERBOSE", "WARNING", "ERROR", "FATAL" + ] + -def message_server(lock, conn): +def message_server(lock: _LockLike, conn: Connection) -> NoReturn: """The GRASS message server function designed to be a target for multiprocessing.Process :param lock: A multiprocessing.Lock - :param conn: A multiprocessing.Pipe + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe This function will use the G_* message C-functions from grass.lib.gis to provide an interface to the GRASS C-library messaging system. - The data that is send through the pipe must provide an + The data that is sent through the pipe must provide an identifier string to specify which C-function should be called. The following identifiers are supported: @@ -52,9 +63,9 @@ def message_server(lock, conn): - "FATAL" Calls G_fatal_error(), this functions is only for testing purpose - The that is end through the pipe must be a list of values: + The data that is sent through the pipe must be a list of values: - - Messages: ["INFO|VERBOSE|WARNING|ERROR|FATAL", "MESSAGE"] + - Messages: ["INFO|IMPORTANT|VERBOSE|WARNING|ERROR|FATAL", "MESSAGE"] - Debug: ["DEBUG", level, "MESSAGE"] - Percent: ["PERCENT", n, d, s] @@ -65,44 +76,42 @@ def message_server(lock, conn): # Avoid busy waiting conn.poll(None) data = conn.recv() - message_type = data[0] + message_type: Literal[_MessagesLiteral, "DEBUG", "PERCENT", "STOP"] = data[0] # Only one process is allowed to write to stderr - lock.acquire() - - # Stop the pipe and the infinite loop - if message_type == "STOP": - conn.close() - lock.release() - libgis.G_debug(1, "Stop messenger server") - sys.exit() - - message = data[1] - - if message_type == "PERCENT": - n = int(data[1]) - d = int(data[2]) - s = int(data[3]) - libgis.G_percent(n, d, s) - elif message_type == "DEBUG": - level = data[1] - message = data[2] - libgis.G_debug(level, message) - elif message_type == "VERBOSE": - libgis.G_verbose_message(message) - elif message_type == "INFO": - libgis.G_message(message) - elif message_type == "IMPORTANT": - libgis.G_important_message(message) - elif message_type == "WARNING": - libgis.G_warning(message) - elif message_type == "ERROR": - libgis.G_important_message("ERROR: %s" % message) - # This is for testing only - elif message_type == "FATAL": - libgis.G_fatal_error(message) - - lock.release() + with lock: + # Stop the pipe and the infinite loop + if message_type == "STOP": + conn.close() + libgis.G_debug(1, "Stop messenger server") + sys.exit() + + if message_type == "PERCENT": + n = int(data[1]) + d = int(data[2]) + s = int(data[3]) + libgis.G_percent(n, d, s) + continue + if message_type == "DEBUG": + level = int(data[1]) + message_debug = data[2] + libgis.G_debug(level, message_debug) + continue + + message: str = data[1] + if message_type == "VERBOSE": + libgis.G_verbose_message(message) + elif message_type == "INFO": + libgis.G_message(message) + elif message_type == "IMPORTANT": + libgis.G_important_message(message) + elif message_type == "WARNING": + libgis.G_warning(message) + elif message_type == "ERROR": + libgis.G_important_message("ERROR: %s" % message) + # This is for testing only + elif message_type == "FATAL": + libgis.G_fatal_error(message) class Messenger: @@ -165,14 +174,19 @@ class Messenger: """ - def __init__(self, raise_on_error=False): - self.client_conn = None - self.server_conn = None - self.server = None + client_conn: Connection + server_conn: Connection + server: Process + + def __init__(self, raise_on_error: bool = False) -> None: self.raise_on_error = raise_on_error - self.start_server() + self.client_conn, self.server_conn = Pipe() + self.lock = Lock() + self.server = Process(target=message_server, args=(self.lock, self.server_conn)) + self.server.daemon = True + self.server.start() - def start_server(self): + def start_server(self) -> None: """Start the messenger server and open the pipe""" self.client_conn, self.server_conn = Pipe() self.lock = Lock() @@ -180,7 +194,7 @@ def start_server(self): self.server.daemon = True self.server.start() - def _check_restart_server(self): + def _check_restart_server(self) -> None: """Restart the server if it was terminated""" if self.server.is_alive() is True: return @@ -189,55 +203,50 @@ def _check_restart_server(self): self.start_server() self.warning("Needed to restart the messenger server") - def message(self, message): + def message(self, message: str) -> None: """Send a message to stderr :param message: the text of message - :type message: str G_message() will be called in the messenger server process """ self._check_restart_server() self.client_conn.send(["INFO", message]) - def verbose(self, message): + def verbose(self, message: str) -> None: """Send a verbose message to stderr :param message: the text of message - :type message: str G_verbose_message() will be called in the messenger server process """ self._check_restart_server() self.client_conn.send(["VERBOSE", message]) - def important(self, message): + def important(self, message: str) -> None: """Send an important message to stderr :param message: the text of message - :type message: str G_important_message() will be called in the messenger server process """ self._check_restart_server() self.client_conn.send(["IMPORTANT", message]) - def warning(self, message): + def warning(self, message: str) -> None: """Send a warning message to stderr :param message: the text of message - :type message: str G_warning() will be called in the messenger server process """ self._check_restart_server() self.client_conn.send(["WARNING", message]) - def error(self, message): + def error(self, message: str) -> None: """Send an error message to stderr :param message: the text of message - :type message: str G_important_message() with an additional "ERROR:" string at the start will be called in the messenger server process @@ -245,11 +254,10 @@ def error(self, message): self._check_restart_server() self.client_conn.send(["ERROR", message]) - def fatal(self, message): + def fatal(self, message: str) -> NoReturn: """Send an error message to stderr, call sys.exit(1) or raise FatalError :param message: the text of message - :type message: str This function emulates the behavior of G_fatal_error(). It prints an error message to stderr and calls sys.exit(1). If raise_on_error @@ -264,30 +272,29 @@ def fatal(self, message): raise FatalError(message) sys.exit(1) - def debug(self, level, message): + def debug(self, level: int, message: str) -> None: """Send a debug message to stderr :param message: the text of message - :type message: str G_debug() will be called in the messenger server process """ self._check_restart_server() self.client_conn.send(["DEBUG", level, message]) - def percent(self, n, d, s): + def percent(self, n: int, d: int, s: int) -> None: """Send a percentage to stderr - :param message: the text of message - :type message: str - + :param n: The current element + :param d: Total number of elements + :param s: Increment size G_percent() will be called in the messenger server process """ self._check_restart_server() self.client_conn.send(["PERCENT", n, d, s]) - def stop(self): + def stop(self) -> None: """Stop the messenger server and close the pipe""" if self.server is not None and self.server.is_alive(): self.client_conn.send( @@ -300,12 +307,11 @@ def stop(self): if self.client_conn is not None: self.client_conn.close() - def set_raise_on_error(self, raise_on_error=True): + def set_raise_on_error(self, raise_on_error: bool = True) -> None: """Set the fatal error behavior :param raise_on_error: if True a FatalError exception will be raised instead of calling sys.exit(1) - :type raise_on_error: bool - If raise_on_error == True, a FatalError exception will be raised if fatal() is called @@ -315,7 +321,7 @@ def set_raise_on_error(self, raise_on_error=True): """ self.raise_on_error = raise_on_error - def get_raise_on_error(self): + def get_raise_on_error(self) -> bool: """Get the fatal error behavior :returns: True if a FatalError exception will be raised or False if @@ -323,7 +329,7 @@ def get_raise_on_error(self): """ return self.raise_on_error - def test_fatal_error(self, message): + def test_fatal_error(self, message: str) -> None: """Force the messenger server to call G_fatal_error()""" import time @@ -338,7 +344,7 @@ def get_msgr( ], *args, **kwargs, -): +) -> Messenger: """Return a Messenger instance. :returns: the Messenger instance. diff --git a/python/grass/pygrass/messages/testsuite/test_pygrass_messages_doctests.py b/python/grass/pygrass/messages/testsuite/test_pygrass_messages_doctests.py index 72c20873cd6..67cd9cb3aed 100644 --- a/python/grass/pygrass/messages/testsuite/test_pygrass_messages_doctests.py +++ b/python/grass/pygrass/messages/testsuite/test_pygrass_messages_doctests.py @@ -28,7 +28,7 @@ def load_tests(loader, tests, ignore): # TODO: this must be somewhere when doctest is called, not here - # TODO: ultimate solution is not to use _ as a buildin in lib/python + # TODO: ultimate solution is not to use _ as a builtin in lib/python # for now it is the only place where it works grass.gunittest.utils.do_doctest_gettext_workaround() # this should be called at some top level diff --git a/python/grass/pygrass/rpc/__init__.py b/python/grass/pygrass/rpc/__init__.py index a6ab19b9369..e95c3453250 100644 --- a/python/grass/pygrass/rpc/__init__.py +++ b/python/grass/pygrass/rpc/__init__.py @@ -11,17 +11,18 @@ """ import sys -from multiprocessing import Process, Lock, Pipe from ctypes import CFUNCTYPE, c_void_p +from multiprocessing import Lock, Pipe, Process +import grass.lib.gis as libgis from grass.exceptions import FatalError +from grass.pygrass import utils +from grass.pygrass.gis.region import Region +from grass.pygrass.raster import RasterRow, raster2numpy_img from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.basic import Bbox -from grass.pygrass.raster import RasterRow, raster2numpy_img -import grass.lib.gis as libgis + from .base import RPCServerBase -from grass.pygrass.gis.region import Region -from grass.pygrass import utils ############################################################################### ############################################################################### @@ -41,7 +42,8 @@ def _get_raster_image_as_np(lock, conn, data): a numpy array with RGB or Gray values. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, raster_name, extent, color] """ array = None @@ -87,7 +89,8 @@ def _get_vector_table_as_dict(lock, conn, data): """Get the table of a vector map layer as dictionary :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, name, mapset, where] """ @@ -128,7 +131,8 @@ def _get_vector_features_as_wkb_list(lock, conn, data): point, centroid, line, boundary, area :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id,name,mapset,extent, feature_type, field] @@ -196,7 +200,8 @@ def data_provider_server(lock, conn): multiprocessing.Process :param lock: A multiprocessing.Lock - :param conn: A multiprocessing.Pipe + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe """ def error_handler(data): @@ -229,9 +234,8 @@ def error_handler(data): # Avoid busy waiting conn.poll(None) data = conn.recv() - lock.acquire() - functions[data[0]](lock, conn, data) - lock.release() + with lock: + functions[data[0]](lock, conn, data) test_vector_name = "data_provider_vector_map" @@ -461,6 +465,7 @@ def get_vector_features_as_wkb_list( if __name__ == "__main__": import doctest + from grass.pygrass.modules import Module Module("g.region", n=40, s=0, e=40, w=0, res=10) diff --git a/python/grass/pygrass/rpc/base.py b/python/grass/pygrass/rpc/base.py index 38cf48c1581..c436300c170 100644 --- a/python/grass/pygrass/rpc/base.py +++ b/python/grass/pygrass/rpc/base.py @@ -2,7 +2,7 @@ Fast and exit-safe interface to PyGRASS Raster and Vector layer using multiprocessing -(C) 2015 by the GRASS Development Team +(C) 2015-2024 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @@ -10,35 +10,42 @@ :authors: Soeren Gebbert """ -from grass.exceptions import FatalError -import time -import threading -import sys -from multiprocessing import Process, Lock, Pipe +from __future__ import annotations + import logging +import sys +import threading +import time +from multiprocessing import Lock, Pipe, Process +from typing import TYPE_CHECKING, NoReturn + +from grass.exceptions import FatalError + +if TYPE_CHECKING: + from multiprocessing.connection import Connection + from multiprocessing.synchronize import _LockLike ############################################################################### -def dummy_server(lock, conn): +def dummy_server(lock: _LockLike, conn: Connection) -> NoReturn: """Dummy server process :param lock: A multiprocessing.Lock - :param conn: A multiprocessing.Pipe + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe """ while True: # Avoid busy waiting conn.poll(None) data = conn.recv() - lock.acquire() - if data[0] == 0: - conn.close() - lock.release() - sys.exit() - if data[0] == 1: - raise Exception("Server process intentionally killed by exception") - lock.release() + with lock: + if data[0] == 0: + conn.close() + sys.exit() + if data[0] == 1: + raise Exception("Server process intentionally killed by exception") class RPCServerBase: @@ -82,12 +89,12 @@ class RPCServerBase: """ - def __init__(self): - self.client_conn = None - self.server_conn = None + def __init__(self) -> None: + self.client_conn: Connection | None = None + self.server_conn: Connection | None = None self.queue = None self.server = None - self.checkThread = None + self.checkThread: threading.Thread | None = None self.threadLock = threading.Lock() self.start_server() self.start_checker_thread() @@ -96,10 +103,10 @@ def __init__(self): # logging.basicConfig(level=logging.DEBUG) def is_server_alive(self): - return self.server.is_alive() + return self.server.is_alive() if self.server is not None else False def is_check_thread_alive(self): - return self.checkThread.is_alive() + return self.checkThread.is_alive() if self.checkThread is not None else False def start_checker_thread(self): if self.checkThread is not None and self.checkThread.is_alive(): @@ -111,21 +118,19 @@ def start_checker_thread(self): self.checkThread.start() def stop_checker_thread(self): - self.threadLock.acquire() - self.stopThread = True - self.threadLock.release() - self.checkThread.join(None) + with self.threadLock: + self.stopThread = True + if self.checkThread is not None: + self.checkThread.join(None) def thread_checker(self): """Check every 200 micro seconds if the server process is alive""" while True: time.sleep(0.2) self._check_restart_server(caller="Server check thread") - self.threadLock.acquire() - if self.stopThread is True: - self.threadLock.release() - return - self.threadLock.release() + with self.threadLock: + if self.stopThread is True: + return def start_server(self): """This function must be re-implemented in the subclasses""" @@ -140,24 +145,25 @@ def start_server(self): def check_server(self): self._check_restart_server() - def _check_restart_server(self, caller="main thread"): + def _check_restart_server(self, caller="main thread") -> None: """Restart the server if it was terminated""" logging.debug("Check libgis server restart") - self.threadLock.acquire() - if self.server.is_alive() is True: - self.threadLock.release() - return - self.client_conn.close() - self.server_conn.close() - self.start_server() - - if self.stopped is not True: - logging.warning( - "Needed to restart the libgis server, caller: {caller}", caller=caller - ) + with self.threadLock: + if self.server is not None and self.server.is_alive() is True: + return + if self.client_conn is not None: + self.client_conn.close() + if self.server_conn is not None: + self.server_conn.close() + self.start_server() + + if self.stopped is not True: + logging.warning( + "Needed to restart the libgis server, caller: {caller}", + caller=caller, + ) - self.threadLock.release() self.stopped = False def safe_receive(self, message): @@ -184,11 +190,12 @@ def stop(self): self.stop_checker_thread() if self.server is not None and self.server.is_alive(): - self.client_conn.send( - [ - 0, - ] - ) + if self.client_conn is not None: + self.client_conn.send( + [ + 0, + ] + ) self.server.terminate() if self.client_conn is not None: self.client_conn.close() diff --git a/python/grass/script/core.py b/python/grass/script/core.py index f51814a5900..e6de4331b43 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -1447,7 +1447,7 @@ def list_strings(type, pattern=None, mapset=None, exclude=None, flag="", env=Non :return: list of elements """ if type == "cell": - verbose(_('Element type should be "raster" and not "%s"') % type) + verbose(_('Element type should be "raster" and not "%s"') % type, env=env) result = [] for line in read_command( @@ -1520,7 +1520,9 @@ def list_grouped( flag += "t" for i in range(len(types)): if types[i] == "cell": - verbose(_('Element type should be "raster" and not "%s"') % types[i]) + verbose( + _('Element type should be "raster" and not "%s"') % types[i], env=env + ) types[i] = "raster" result = {} if check_search_path: @@ -1543,7 +1545,7 @@ def list_grouped( try: name, mapset = line.split("@") except ValueError: - warning(_("Invalid element '%s'") % line) + warning(_("Invalid element '%s'") % line, env=env) continue if store_types: @@ -1701,7 +1703,7 @@ def mapsets(search_path=False, env=None): flags = "p" if search_path else "l" mapsets = read_command("g.mapsets", flags=flags, sep="newline", quiet=True, env=env) if not mapsets: - fatal(_("Unable to list mapsets")) + fatal(_("Unable to list mapsets"), env=env) return mapsets.splitlines() diff --git a/python/grass/script/db.py b/python/grass/script/db.py index 60813379501..5591b92d4ca 100644 --- a/python/grass/script/db.py +++ b/python/grass/script/db.py @@ -55,7 +55,7 @@ def db_describe(table, env=None, **args): args.pop("driver") s = read_command("db.describe", flags="c", table=table, env=env, **args) if not s: - fatal(_("Unable to describe table <%s>") % table) + fatal(_("Unable to describe table <%s>") % table, env=env) cols = [] result = {} @@ -179,7 +179,8 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): "Programmer error: '%(sql)s', '%(filename)s', or '%(table)s' must be \ provided" ) - % {"sql": "sql", "filename": "filename", "table": "table"} + % {"sql": "sql", "filename": "filename", "table": "table"}, + env=env, ) if "sep" not in args: @@ -188,7 +189,7 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): try: run_command("db.select", quiet=True, flags="c", output=fname, env=env, **args) except CalledModuleError: - fatal(_("Fetching data failed")) + fatal(_("Fetching data failed"), env=env) ofile = open(fname) result = [tuple(x.rstrip(os.linesep).split(args["sep"])) for x in ofile] diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index d82780d7c5c..aaf9e0179b0 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -66,7 +66,8 @@ def raster_history(map, overwrite=False, env=None): "Unable to write history for <%(map)s>. " "Raster map <%(map)s> not found in current mapset." ) - % {"map": map} + % {"map": map}, + env=env, ) return False @@ -143,7 +144,10 @@ def mapcalc( overwrite=overwrite, ) except CalledModuleError: - fatal(_("An error occurred while running r.mapcalc with expression: %s") % e) + fatal( + _("An error occurred while running r.mapcalc with expression: %s") % e, + env=env, + ) def mapcalc_start( diff --git a/python/grass/script/raster3d.py b/python/grass/script/raster3d.py index e3db5398158..1a4a2782984 100644 --- a/python/grass/script/raster3d.py +++ b/python/grass/script/raster3d.py @@ -108,4 +108,7 @@ def mapcalc3d( overwrite=overwrite, ) except CalledModuleError: - fatal(_("An error occurred while running r3.mapcalc with expression: %s") % e) + fatal( + _("An error occurred while running r3.mapcalc with expression: %s") % e, + env=env, + ) diff --git a/python/grass/script/vector.py b/python/grass/script/vector.py index 2d484f7d590..4adf3e38da1 100644 --- a/python/grass/script/vector.py +++ b/python/grass/script/vector.py @@ -87,7 +87,7 @@ def vector_layer_db(map, layer, env=None): try: f = vector_db(map, env=env)[int(layer)] except KeyError: - fatal(_("Database connection not defined for layer %s") % layer) + fatal(_("Database connection not defined for layer %s") % layer, env=env) return f @@ -250,7 +250,8 @@ def vector_db_select(map, layer=1, env=None, **kwargs): except KeyError: error( _("Missing layer %(layer)d in vector map <%(map)s>") - % {"layer": layer, "map": map} + % {"layer": layer, "map": map}, + env=env, ) return {"columns": [], "values": {}} @@ -259,13 +260,13 @@ def vector_db_select(map, layer=1, env=None, **kwargs): if key not in kwargs["columns"].split(","): # add key column if missing include_key = False - debug("Adding key column to the output") + debug("Adding key column to the output", env=env) kwargs["columns"] += "," + key ret = read_command("v.db.select", map=map, layer=layer, env=env, **kwargs) if not ret: - error(_("vector_db_select() failed")) + error(_("vector_db_select() failed"), env=env) return {"columns": [], "values": {}} columns = [] diff --git a/python/grass/temporal/c_libraries_interface.py b/python/grass/temporal/c_libraries_interface.py index 0d24fc0f732..2b7f9f033f3 100644 --- a/python/grass/temporal/c_libraries_interface.py +++ b/python/grass/temporal/c_libraries_interface.py @@ -2,7 +2,7 @@ Fast and exit-safe interface to GRASS C-library functions using ctypes and multiprocessing -(C) 2013 by the GRASS Development Team +(C) 2013-2024 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @@ -10,11 +10,14 @@ :authors: Soeren Gebbert """ +from __future__ import annotations + import logging import sys from ctypes import CFUNCTYPE, POINTER, byref, c_int, c_void_p, cast from datetime import datetime from multiprocessing import Lock, Pipe, Process +from typing import TYPE_CHECKING import grass.lib.date as libdate import grass.lib.gis as libgis @@ -29,6 +32,10 @@ from grass.pygrass.vector import VectorTopo from grass.script.utils import encode +if TYPE_CHECKING: + from multiprocessing.connection import Connection + from multiprocessing.synchronize import _LockLike + ############################################################################### @@ -63,12 +70,13 @@ class RPCDefs: ############################################################################### -def _read_map_full_info(lock, conn, data): +def _read_map_full_info(lock: _LockLike, conn: Connection, data): """Read full map specific metadata from the spatial database using PyGRASS functions. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset] """ info = None @@ -190,7 +198,7 @@ def _read_vector_full_info(name, mapset, layer=None): return info -def _fatal_error(lock, conn, data): +def _fatal_error(lock: _LockLike, conn: Connection, data): """Calls G_fatal_error()""" libgis.G_fatal_error("Fatal Error in C library server") @@ -198,11 +206,12 @@ def _fatal_error(lock, conn, data): ############################################################################### -def _get_mapset(lock, conn, data): +def _get_mapset(lock: _LockLike, conn: Connection, data): """Return the current mapset :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The mapset as list entry 1 [function_id] :returns: Name of the current mapset @@ -214,11 +223,12 @@ def _get_mapset(lock, conn, data): ############################################################################### -def _get_location(lock, conn, data): +def _get_location(lock: _LockLike, conn: Connection, data): """Return the current location :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The mapset as list entry 1 [function_id] :returns: Name of the location @@ -230,11 +240,12 @@ def _get_location(lock, conn, data): ############################################################################### -def _get_gisdbase(lock, conn, data): +def _get_gisdbase(lock: _LockLike, conn: Connection, data): """Return the current gisdatabase :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The mapset as list entry 1 [function_id] :returns: Name of the gisdatabase @@ -246,11 +257,12 @@ def _get_gisdbase(lock, conn, data): ############################################################################### -def _get_driver_name(lock, conn, data): +def _get_driver_name(lock: _LockLike, conn: Connection, data): """Return the temporal database driver of a specific mapset :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The mapset as list entry 1 [function_id, mapset] :returns: Name of the driver or None if no temporal database present @@ -264,11 +276,12 @@ def _get_driver_name(lock, conn, data): ############################################################################### -def _get_database_name(lock, conn, data): +def _get_database_name(lock: _LockLike, conn: Connection, data): """Return the temporal database name of a specific mapset :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The mapset as list entry 1 [function_id, mapset] :returns: Name of the database or None if no temporal database present @@ -293,11 +306,12 @@ def _get_database_name(lock, conn, data): ############################################################################### -def _available_mapsets(lock, conn, data): +def _available_mapsets(lock: _LockLike, conn: Connection, data): """Return all available mapsets the user can access as a list of strings :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id] :returns: Names of available mapsets as list of strings @@ -349,12 +363,13 @@ def _available_mapsets(lock, conn, data): ############################################################################### -def _has_timestamp(lock, conn, data): +def _has_timestamp(lock: _LockLike, conn: Connection, data): """Check if the file based GRASS timestamp is present and send True or False using the provided pipe. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset, layer] @@ -381,7 +396,7 @@ def _has_timestamp(lock, conn, data): ############################################################################### -def _read_timestamp(lock, conn, data): +def _read_timestamp(lock: _LockLike, conn: Connection, data): """Read the file based GRASS timestamp and send the result using the provided pipe. @@ -401,7 +416,8 @@ def _read_timestamp(lock, conn, data): The end time may be None in case of a time instance. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send the result + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send the result :param data: The list of data entries [function_id, maptype, name, mapset, layer] @@ -429,7 +445,7 @@ def _read_timestamp(lock, conn, data): ############################################################################### -def _write_timestamp(lock, conn, data): +def _write_timestamp(lock: _LockLike, conn: Connection, data): """Write the file based GRASS timestamp the return values of the called C-functions using the provided pipe. @@ -440,7 +456,8 @@ def _write_timestamp(lock, conn, data): values description. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset, layer, timestring] """ @@ -473,7 +490,7 @@ def _write_timestamp(lock, conn, data): ############################################################################### -def _remove_timestamp(lock, conn, data): +def _remove_timestamp(lock: _LockLike, conn: Connection, data): """Remove the file based GRASS timestamp the return values of the called C-functions using the provided pipe. @@ -484,7 +501,8 @@ def _remove_timestamp(lock, conn, data): values description. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset, layer] @@ -508,7 +526,7 @@ def _remove_timestamp(lock, conn, data): ############################################################################### -def _read_semantic_label(lock, conn, data): +def _read_semantic_label(lock: _LockLike, conn: Connection, data): """Read the file based GRASS band identifier the result using the provided pipe. @@ -516,7 +534,8 @@ def _read_semantic_label(lock, conn, data): Rast_read_semantic_label: either a semantic label string or None. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset, layer, timestring] @@ -547,14 +566,15 @@ def _read_semantic_label(lock, conn, data): ############################################################################### -def _write_semantic_label(lock, conn, data): +def _write_semantic_label(lock: _LockLike, conn: Connection, data): """Write the file based GRASS band identifier. Rises ValueError on invalid semantic label. Always sends back True. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset, layer, timestring] @@ -583,13 +603,14 @@ def _write_semantic_label(lock, conn, data): ############################################################################### -def _remove_semantic_label(lock, conn, data): +def _remove_semantic_label(lock: _LockLike, conn: Connection, data): """Remove the file based GRASS band identifier. The value to be send via pipe is the return value of G_remove_misc. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset, layer, timestring] @@ -616,14 +637,15 @@ def _remove_semantic_label(lock, conn, data): ############################################################################### -def _map_exists(lock, conn, data): +def _map_exists(lock: _LockLike, conn: Connection, data): """Check if a map exists in the spatial database The value to be send via pipe is True in case the map exists and False if not. :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset] """ @@ -648,12 +670,13 @@ def _map_exists(lock, conn, data): ############################################################################### -def _read_map_info(lock, conn, data): +def _read_map_info(lock: _LockLike, conn: Connection, data): """Read map specific metadata from the spatial database using C-library functions :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset] """ kvp = None @@ -955,11 +978,12 @@ def _read_vector_info(name, mapset): ############################################################################### -def _read_map_history(lock, conn, data): +def _read_map_history(lock: _LockLike, conn: Connection, data): """Read map history from the spatial database using C-library functions :param lock: A multiprocessing.Lock instance - :param conn: A multiprocessing.Pipe instance used to send True or False + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe used to send True or False :param data: The list of data entries [function_id, maptype, name, mapset] """ kvp = None @@ -1174,7 +1198,7 @@ def _convert_timestamp_from_grass(ts): ############################################################################### -def _stop(lock, conn, data): +def _stop(lock: _LockLike, conn: Connection, data): libgis.G_debug(1, "Stop C-interface server") conn.close() lock.release() @@ -1184,12 +1208,13 @@ def _stop(lock, conn, data): ############################################################################### -def c_library_server(lock, conn): +def c_library_server(lock: _LockLike, conn: Connection): """The GRASS C-libraries server function designed to be a target for multiprocessing.Process :param lock: A multiprocessing.Lock - :param conn: A multiprocessing.Pipe + :param conn: A multiprocessing.connection.Connection object obtained from + multiprocessing.Pipe """ def error_handler(data): @@ -1239,9 +1264,8 @@ def error_handler(data): # Avoid busy waiting conn.poll(None) data = conn.recv() - lock.acquire() - functions[data[0]](lock, conn, data) - lock.release() + with lock: + functions[data[0]](lock, conn, data) class CLibrariesInterface(RPCServerBase): diff --git a/python/grass/temporal/temporal_raster_base_algebra.py b/python/grass/temporal/temporal_raster_base_algebra.py index bb58c8405f7..9340db5593d 100644 --- a/python/grass/temporal/temporal_raster_base_algebra.py +++ b/python/grass/temporal/temporal_raster_base_algebra.py @@ -387,7 +387,7 @@ def sub_cmdstring(map_i): else: try: map_sub = map_i.get_id() - except: + except AttributeError: map_sub = map_i return map_sub diff --git a/python/grass/temporal/temporal_topology_dataset_connector.py b/python/grass/temporal/temporal_topology_dataset_connector.py index fddf478ad71..a296d9d4d78 100644 --- a/python/grass/temporal/temporal_topology_dataset_connector.py +++ b/python/grass/temporal/temporal_topology_dataset_connector.py @@ -160,47 +160,47 @@ def get_number_of_temporal_relations(self): relations = {} try: relations["equal"] = len(self._temporal_topology["EQUAL"]) - except: + except KeyError: relations["equal"] = 0 try: relations["follows"] = len(self._temporal_topology["FOLLOWS"]) - except: + except KeyError: relations["follows"] = 0 try: relations["precedes"] = len(self._temporal_topology["PRECEDES"]) - except: + except KeyError: relations["precedes"] = 0 try: relations["overlaps"] = len(self._temporal_topology["OVERLAPS"]) - except: + except KeyError: relations["overlaps"] = 0 try: relations["overlapped"] = len(self._temporal_topology["OVERLAPPED"]) - except: + except KeyError: relations["overlapped"] = 0 try: relations["during"] = len(self._temporal_topology["DURING"]) - except: + except KeyError: relations["during"] = 0 try: relations["contains"] = len(self._temporal_topology["CONTAINS"]) - except: + except KeyError: relations["contains"] = 0 try: relations["starts"] = len(self._temporal_topology["STARTS"]) - except: + except KeyError: relations["starts"] = 0 try: relations["started"] = len(self._temporal_topology["STARTED"]) - except: + except KeyError: relations["started"] = 0 try: relations["finishes"] = len(self._temporal_topology["FINISHES"]) - except: + except KeyError: relations["finishes"] = 0 try: relations["finished"] = len(self._temporal_topology["FINISHED"]) - except: + except KeyError: relations["finished"] = 0 return relations diff --git a/python/grass/temporal/univar_statistics.py b/python/grass/temporal/univar_statistics.py index b6a9c1ac508..77ebaca30b1 100755 --- a/python/grass/temporal/univar_statistics.py +++ b/python/grass/temporal/univar_statistics.py @@ -13,7 +13,7 @@ .. -(C) 2012-2013 by the GRASS Development Team +(C) 2012-2024 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @@ -57,7 +57,7 @@ def compute_univar_stats(registered_map_info, stats_module, fs, rast_region=Fals ) stats_module.inputs.map = id - if rast_region: + if rast_region and (stats_module.inputs.zones or stats_module.name == "r3.univar"): stats_module.env = gs.region_env(raster=id) stats_module.run() @@ -139,7 +139,6 @@ def print_gridded_dataset_univar_statistics( :param nprocs: Number of cores to use for processing :param rast_region: If set True ignore the current region settings and use the raster map regions for univar statistical calculation. - Only available for strds. :param region_relation: Process only maps with the given spatial relation to the computational region. A string with one of the following values: "overlaps": maps that spatially overlap ("intersect") @@ -154,9 +153,6 @@ def print_gridded_dataset_univar_statistics( sp = open_old_stds(input, type, dbif) - if output is not None: - out_file = open(output, "w") - spatial_extent = None if region_relation: spatial_extent = gs.parse_command("g.region", flags="3gu") @@ -187,10 +183,11 @@ def print_gridded_dataset_univar_statistics( ).format(type=sp.get_new_map_instance(None).get_type(), id=sp.get_id()) ) - if output is not None: - out_file.close() return + if output is not None: + out_file = open(output, "w") + if no_header is False: cols = ( ["id", "semantic_label", "start", "end"] @@ -235,7 +232,7 @@ def print_gridded_dataset_univar_statistics( flag = "g" if extended is True: flag += "e" - if type == "strds" and rast_region is True: + if type == "strds" and rast_region is True and not zones: flag += "r" # Setup pygrass module to use for computation diff --git a/python/grass/utils/download.py b/python/grass/utils/download.py index f6b734b7291..ade1ac9411c 100644 --- a/python/grass/utils/download.py +++ b/python/grass/utils/download.py @@ -13,6 +13,7 @@ """Download and extract various archives""" import os +import re import shutil import tarfile import tempfile @@ -23,6 +24,10 @@ from urllib.request import urlretrieve +reponse_content_type_header_pattern = re.compile(r"application/(zip|octet-stream)") +reponse_content_disposition_header_pattern = re.compile(r"attachment; filename=.*.zip$") + + def debug(*args, **kwargs): """Print a debug message (to be used in this module only) @@ -170,7 +175,13 @@ def download_and_extract(source, reporthook=None): ) except URLError: raise DownloadError(url_error_message.format(url=source)) - if headers.get("content-type", "") != "application/zip": + + if not re.search( + reponse_content_type_header_pattern, headers.get("content-type", "") + ) and not re.search( + reponse_content_disposition_header_pattern, + headers.get("content-disposition", ""), + ): raise DownloadError( _( "Download of <{url}> failed or file <{name}> is not a ZIP file" diff --git a/raster/r.buffer/testsuite/test_buffer.py b/raster/r.buffer/testsuite/test_buffer.py new file mode 100644 index 00000000000..97fea861104 --- /dev/null +++ b/raster/r.buffer/testsuite/test_buffer.py @@ -0,0 +1,99 @@ +from grass.gunittest.case import TestCase +from grass.gunittest.main import test +from grass.gunittest.gmodules import SimpleModule +import grass.script as gs + + +class TestRBuffer(TestCase): + + @classmethod + def setUpClass(cls): + """Set up a temporary region for testing.""" + cls.output = "test_buffer" + cls.use_temp_region() + cls.runModule("g.region", n=223000, s=220000, w=640000, e=643000, nsres=100) + + @classmethod + def tearDownClass(cls): + """Clean up after tests.""" + cls.del_temp_region() + + def tearDown(self): + """Remove temporary maps created during tests""" + gs.run_command( + "g.remove", + type="raster", + name="test_buffer,zero_map,null_map", + flags="f", + ) + + def test_buffer_creation(self): + """Test creating a buffer around roadsmajor with multiple distances.""" + distances = [100, 200, 300, 400, 500] + + module = SimpleModule( + "r.buffer", + input="roadsmajor", + output=self.output, + distances=distances, + overwrite=True, + ) + self.assertModule(module) + + self.assertRasterExists(self.output) + + expected_categories = [i + 1 for i in range(len(distances) + 1)] + + self.assertRasterMinMax( + map=self.output, + refmin=min(expected_categories), + refmax=max(expected_categories), + msg=f"Buffer zones should have category values from 1 to {max(expected_categories)}", + ) + + def test_no_non_null_values(self): + """Test r.buffer with null input raster resulting in an empty output.""" + null_map = "null_map" + self.runModule("r.mapcalc", expression=f"{null_map} = null()") + + distances = [100, 200, 300] + + module = SimpleModule( + "r.buffer", + input=null_map, + output=self.output, + distances=distances, + overwrite=True, + ) + self.assertModule(module) + + self.assertRasterExists(self.output) + + expected_stats = {"n": 0} + self.assertRasterFitsUnivar(self.output, reference=expected_stats) + + def test_ignore_zero_values(self): + """Test r.buffer with input raster of only zero values using -z flag.""" + zero_map = "zero_map" + self.runModule("r.mapcalc", expression=f"{zero_map} = 0") + + distances = [100] + + module = SimpleModule( + "r.buffer", + input=zero_map, + output=self.output, + distances=distances, + flags="z", + overwrite=True, + ) + self.assertModule(module) + + self.assertRasterExists(self.output) + + expected_stats = {"n": 0} + self.assertRasterFitsUnivar(self.output, reference=expected_stats) + + +if __name__ == "__main__": + test() diff --git a/raster/r.buildvrt/r.buildvrt.html b/raster/r.buildvrt/r.buildvrt.html index 67368179efb..d5118ba5150 100644 --- a/raster/r.buildvrt/r.buildvrt.html +++ b/raster/r.buildvrt/r.buildvrt.html @@ -12,6 +12,8 @@

NOTES

the original raster maps which is only valid if the original raster maps remain in the originally indicated mapset. A VRT can also be built from raster maps registered with r.external. +However, GRASS VRTs built from external registered data (see below) +are known to have performance issues.

Reading the whole VRT is slower than reading the equivalent single @@ -48,12 +50,23 @@

VRT from a DEM in the North Carolina sample dataset

r.buildvrt file=tilelist.csv output=elev_state_50m_vrt +

KNOWN ISSUES

+ +Users may experience significant performance degradation with virtual rasters built +with r.buildvrt over GDAL-linked (r.external) raster maps, +especially on slower file systems with latency like NFS. Performance degradation +may also occur on local file systems, but is usually less severe. For such use cases +consider using the GRASS GIS addon +r.buildvrt.gdal +or building GDAL VRTs, e.g. with gdalbuildvrt. +

SEE ALSO

r.tile, r.patch, r.external +r.buildvrt.gdal

diff --git a/raster/r.circle/testsuite/test_circle.py b/raster/r.circle/testsuite/test_circle.py new file mode 100644 index 00000000000..1c0a4b62f54 --- /dev/null +++ b/raster/r.circle/testsuite/test_circle.py @@ -0,0 +1,85 @@ +from grass.gunittest.case import TestCase +from grass.gunittest.main import test +import grass.script as gs +from grass.gunittest.gmodules import SimpleModule + + +class TestRCircle(TestCase): + + @classmethod + def setUpClass(cls): + """Set up a temporary region for testing.""" + cls.output = "test_circle" + cls.use_temp_region() + cls.runModule("g.region", n=30, s=0, e=30, w=0, res=10) + + @classmethod + def tearDownClass(cls): + """Clean up after tests.""" + cls.del_temp_region() + + def tearDown(self): + gs.run_command( + "g.remove", + type="raster", + name=self.output, + flags="f", + ) + + def test_create_circle_with_b_flag(self): + """Test creating a binary circle with r.circle using -b flag.""" + + module = SimpleModule( + "r.circle", output=self.output, coordinates=(15, 15), max=10, flags="b" + ) + + self.assertModule(module) + + self.assertRasterExists(self.output) + + self.assertRasterMinMax( + map=self.output, + refmin=1, + refmax=1, + msg="Binary circle should have category value of 1", + ) + + def test_create_circle_without_b_flag(self): + """Test creating a circle with r.circle without -b flag.""" + + module = SimpleModule( + "r.circle", output=self.output, coordinates=(15, 15), max=10 + ) + + self.assertModule(module) + + self.assertRasterExists(self.output) + + self.assertRasterMinMax( + map=self.output, + refmin=0, + refmax=10, + msg="Circle should have distance values from 0 to 10", + ) + + def test_create_circle_with_multiplier(self): + """Test creating a circle with r.circle with a multiplier.""" + + module = SimpleModule( + "r.circle", output=self.output, coordinates=(15, 15), max=10, multiplier=2 + ) + + self.assertModule(module) + + self.assertRasterExists(self.output) + + self.assertRasterMinMax( + map=self.output, + refmin=0, + refmax=20, + msg="Circle should have distance values from 0 to 20", + ) + + +if __name__ == "__main__": + test() diff --git a/raster/r.colors.out/Makefile b/raster/r.colors.out/Makefile index b6717d12937..e2acf03ca41 100644 --- a/raster/r.colors.out/Makefile +++ b/raster/r.colors.out/Makefile @@ -1,13 +1,13 @@ MODULE_TOPDIR = ../.. -LIBES2 = $(RASTERLIB) $(GISLIB) -LIBES3 = $(RASTER3DLIB) $(RASTERLIB) $(GISLIB) +LIBES2 = $(RASTERLIB) $(GISLIB) $(PARSONLIB) +LIBES3 = $(RASTER3DLIB) $(RASTERLIB) $(GISLIB) $(PARSONLIB) DEPENDENCIES = $(RASTER3DDEP) $(GISDEP) $(RASTERDEP) PROGRAMS = r.colors.out r3.colors.out -r_colors_out_OBJS = raster_main.o -r3_colors_out_OBJS = raster3d_main.o +r_colors_out_OBJS = raster_main.o prt_json.o +r3_colors_out_OBJS = raster3d_main.o prt_json.o include $(MODULE_TOPDIR)/include/Make/Multi.make diff --git a/raster/r.colors.out/local_proto.h b/raster/r.colors.out/local_proto.h new file mode 100644 index 00000000000..5ed09a06e69 --- /dev/null +++ b/raster/r.colors.out/local_proto.h @@ -0,0 +1,7 @@ +#include +#include + +enum ColorFormat { RGB, HEX, HSV, TRIPLET }; + +void print_json_colors(struct Colors *colors, DCELL min, DCELL max, FILE *fp, + int perc, enum ColorFormat clr_frmt); diff --git a/raster/r.colors.out/prt_json.c b/raster/r.colors.out/prt_json.c new file mode 100644 index 00000000000..816a63e1b0e --- /dev/null +++ b/raster/r.colors.out/prt_json.c @@ -0,0 +1,265 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "local_proto.h" + +#define COLOR_STRING_LENGTH 30 + +/*! + \brief Closes the file if it is not stdout. + + \param fp file where to print color table rules + */ +static void close_file(FILE *fp) +{ + if (fp != stdout) + fclose(fp); +} + +/*! + \brief Converts RGB color values to HSV format. + + \note This implementation is experimental and may be subject to change. + + \param r red component of the RGB color + \param g green component of the RGB color + \param b blue component of the RGB color + \param[out] h pointer to store the calculated hue + \param[out] s pointer to store the calculated saturation + \param[out] v pointer to store the calculated value + */ +static void rgb_to_hsv(int r, int g, int b, float *h, float *s, float *v) +{ + float r_norm = (float)r / 255.0f; + float g_norm = (float)g / 255.0f; + float b_norm = (float)b / 255.0f; + + float cmax = MAX(r_norm, MAX(g_norm, b_norm)); + float cmin = MIN(r_norm, MIN(g_norm, b_norm)); + float diff = cmax - cmin; + + if (cmax == cmin) { + *h = 0; + } + else if (cmax == r_norm) { + *h = fmodf((60.0f * ((g_norm - b_norm) / diff) + 360.0f), 360.0f); + } + else if (cmax == g_norm) { + *h = fmodf((60.0f * ((b_norm - r_norm) / diff) + 120.0f), 360.0f); + } + else { + *h = fmodf((60.0f * ((r_norm - g_norm) / diff) + 240.0f), 360.0f); + } + + if (cmax == 0) { + *s = 0; + } + else { + *s = (diff / cmax) * 100.0f; + } + + *v = cmax * 100.0f; +} + +/*! + \brief Writes color entry in JSON in specified clr_frmt. + + \param r red component of RGB color + \param g green component of RGB color + \param b blue component of RGB color + \param clr_frmt color format to be used (RGB, HEX, HSV, TRIPLET). + \param color_object pointer to the JSON object + */ +static void set_color(int r, int g, int b, enum ColorFormat clr_frmt, + JSON_Object *color_object) +{ + char color_string[COLOR_STRING_LENGTH]; + float h, s, v; + + switch (clr_frmt) { + case RGB: + snprintf(color_string, sizeof(color_string), "rgb(%d, %d, %d)", r, g, + b); + json_object_set_string(color_object, "rgb", color_string); + break; + + case HEX: + snprintf(color_string, sizeof(color_string), "#%02X%02X%02X", r, g, b); + json_object_set_string(color_object, "hex", color_string); + break; + + case HSV: + rgb_to_hsv(r, g, b, &h, &s, &v); + snprintf(color_string, sizeof(color_string), "hsv(%d, %d, %d)", (int)h, + (int)s, (int)v); + json_object_set_string(color_object, "hsv", color_string); + break; + + case TRIPLET: + snprintf(color_string, sizeof(color_string), "%d:%d:%d", r, g, b); + json_object_set_string(color_object, "triplet", color_string); + break; + } +} + +/*! + \brief Writes a JSON rule for a specific color entry. + + \param val pointer to the DCELL value + \param min,max minimum and maximum value for percentage output (used only + when \p perc is non-zero) + \param r red component of RGB color + \param g green component of RGB color + \param b blue component of RGB color + \param root_array pointer to the JSON array + \param perc TRUE for percentage output + \param clr_frmt color format to be used (RBG, HEX, HSV, TRIPLET). + \param fp file where to print color table rules + \param root_value pointer to json value + */ +static void write_json_rule(DCELL *val, DCELL *min, DCELL *max, int r, int g, + int b, JSON_Array *root_array, int perc, + enum ColorFormat clr_frmt, FILE *fp, + JSON_Value *root_value) +{ + static DCELL v0; + static int r0 = -1, g0 = -1, b0 = -1; + + // Skip writing if the current color is the same as the last one + if (v0 == *val && r0 == r && g0 == g && b0 == b) + return; + // Update last processed values + v0 = *val, r0 = r, g0 = g, b0 = b; + + JSON_Value *color_value = json_value_init_object(); + if (color_value == NULL) { + json_value_free(root_value); + close_file(fp); + G_fatal_error(_("Failed to initialize JSON object. Out of memory?")); + } + JSON_Object *color_object = json_object(color_value); + + // Set the value as a percentage if requested, otherwise set it as-is + if (perc) + json_object_set_number(color_object, "value", + 100 * (*val - *min) / (*max - *min)); + else + json_object_set_number(color_object, "value", *val); + + set_color(r, g, b, clr_frmt, color_object); + + json_array_append_value(root_array, color_value); +} + +/*! + \brief Print color table in JSON format + + \param colors pointer to Colors structure + \param min,max minimum and maximum value for percentage output (used only + when \p perc is non-zero) + \param fp file where to print color table rules + \param perc TRUE for percentage output + \param clr_frmt color format to be used (RBG, HEX, HSV, TRIPLET). + */ +void print_json_colors(struct Colors *colors, DCELL min, DCELL max, FILE *fp, + int perc, enum ColorFormat clr_frmt) +{ + JSON_Value *root_value = json_value_init_array(); + if (root_value == NULL) { + close_file(fp); + G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); + } + JSON_Array *root_array = json_array(root_value); + + if (colors->version < 0) { + /* 3.0 format */ + CELL lo, hi; + + // Retrieve the integer color range + Rast_get_c_color_range(&lo, &hi, colors); + + for (int i = lo; i <= hi; i++) { + unsigned char r, g, b, set; + DCELL val = (DCELL)i; + + // Look up the color for the current value and write JSON rule + Rast_lookup_c_colors(&i, &r, &g, &b, &set, 1, colors); + write_json_rule(&val, &min, &max, r, g, b, root_array, perc, + clr_frmt, fp, root_value); + } + } + else { + // Get the count of floating-point color rules + int count = Rast_colors_count(colors); + + for (int i = 0; i < count; i++) { + DCELL val1, val2; + unsigned char r1, g1, b1, r2, g2, b2; + + // Retrieve the color rule values and their respective RGB colors + Rast_get_fp_color_rule(&val1, &r1, &g1, &b1, &val2, &r2, &g2, &b2, + colors, count - 1 - i); + + // write JSON rule + write_json_rule(&val1, &min, &max, r1, g1, b1, root_array, perc, + clr_frmt, fp, root_value); + write_json_rule(&val2, &min, &max, r2, g2, b2, root_array, perc, + clr_frmt, fp, root_value); + } + } + + // Add special color entries for "null" and "default" values + { + int r, g, b; + + // Get RGB color for null values and create JSON entry + Rast_get_null_value_color(&r, &g, &b, colors); + JSON_Value *nv_value = json_value_init_object(); + if (nv_value == NULL) { + json_value_free(root_value); + close_file(fp); + G_fatal_error( + _("Failed to initialize JSON object. Out of memory?")); + } + JSON_Object *nv_object = json_object(nv_value); + json_object_set_string(nv_object, "value", "nv"); + set_color(r, g, b, clr_frmt, nv_object); + json_array_append_value(root_array, nv_value); + + // Get RGB color for default values and create JSON entry + Rast_get_default_color(&r, &g, &b, colors); + JSON_Value *default_value = json_value_init_object(); + if (default_value == NULL) { + json_value_free(root_value); + close_file(fp); + G_fatal_error( + _("Failed to initialize JSON object. Out of memory?")); + } + JSON_Object *default_object = json_object(default_value); + json_object_set_string(default_object, "value", "default"); + set_color(r, g, b, clr_frmt, default_object); + json_array_append_value(root_array, default_value); + } + + // Serialize JSON array to a string and print to the file + char *json_string = json_serialize_to_string_pretty(root_value); + if (!json_string) { + json_value_free(root_value); + close_file(fp); + G_fatal_error(_("Failed to serialize JSON to pretty format.")); + } + + fputs(json_string, fp); + + json_free_serialized_string(json_string); + json_value_free(root_value); + + close_file(fp); +} diff --git a/raster/r.colors.out/r.colors.out.html b/raster/r.colors.out/r.colors.out.html index 29423001db6..357bd1ebf6c 100644 --- a/raster/r.colors.out/r.colors.out.html +++ b/raster/r.colors.out/r.colors.out.html @@ -9,6 +9,7 @@

EXAMPLES

 r.colors.out map=el_D782_6m rules=rules.txt
 r.colors map=el_D783_6m rules=rules.txt
+r.colors.out map=el_D782_6m rules=rules.json format=json
 

SEE ALSO

diff --git a/raster/r.colors.out/r3.colors.out.html b/raster/r.colors.out/r3.colors.out.html index f86bf57b89c..04472d4de8c 100644 --- a/raster/r.colors.out/r3.colors.out.html +++ b/raster/r.colors.out/r3.colors.out.html @@ -9,6 +9,7 @@

EXAMPLES

 r3.colors.out map=volume_1 rules=rules.txt
 r3.colors map=volume_2 rules=rules.txt
+r3.colors.out map=volume_1 rules=rules.json format=json
 

SEE ALSO

diff --git a/raster/r.colors.out/raster3d_main.c b/raster/r.colors.out/raster3d_main.c index 95c05e545f1..904db24a91f 100644 --- a/raster/r.colors.out/raster3d_main.c +++ b/raster/r.colors.out/raster3d_main.c @@ -21,13 +21,16 @@ #include #include #include +#include + +#include "local_proto.h" /* Run in raster3d mode */ int main(int argc, char **argv) { struct GModule *module; struct { - struct Option *map, *file; + struct Option *map, *file, *format, *color_format; } opt; struct { struct Flag *p; @@ -38,6 +41,8 @@ int main(int argc, char **argv) struct Colors colors; struct FPRange range; + enum ColorFormat clr_frmt; + G_gisinit(argv[0]); module = G_define_module(); @@ -55,6 +60,12 @@ int main(int argc, char **argv) opt.file->description = _("If not given write to standard output"); opt.file->required = NO; + opt.format = G_define_standard_option(G_OPT_F_FORMAT); + opt.format->guisection = _("Print"); + + opt.color_format = G_define_standard_option(G_OPT_C_FORMAT); + opt.color_format->guisection = _("Color"); + flag.p = G_define_flag(); flag.p->key = 'p'; flag.p->description = _("Output values as percentages"); @@ -78,8 +89,26 @@ int main(int argc, char **argv) G_fatal_error(_("Unable to open output file <%s>"), file); } - Rast_print_colors(&colors, range.min, range.max, fp, - flag.p->answer ? 1 : 0); + if (strcmp(opt.format->answer, "json") == 0) { + if (strcmp(opt.color_format->answer, "rgb") == 0) { + clr_frmt = RGB; + } + else if (strcmp(opt.color_format->answer, "triplet") == 0) { + clr_frmt = TRIPLET; + } + else if (strcmp(opt.color_format->answer, "hsv") == 0) { + clr_frmt = HSV; + } + else { + clr_frmt = HEX; + } + print_json_colors(&colors, range.min, range.max, fp, + flag.p->answer ? 1 : 0, clr_frmt); + } + else { + Rast_print_colors(&colors, range.min, range.max, fp, + flag.p->answer ? 1 : 0); + } exit(EXIT_SUCCESS); } diff --git a/raster/r.colors.out/raster_main.c b/raster/r.colors.out/raster_main.c index b2a0a139157..6b4a8ed36ee 100644 --- a/raster/r.colors.out/raster_main.c +++ b/raster/r.colors.out/raster_main.c @@ -20,13 +20,16 @@ #include #include #include +#include + +#include "local_proto.h" /* Run in raster mode */ int main(int argc, char **argv) { struct GModule *module; struct { - struct Option *map, *file; + struct Option *map, *file, *format, *color_format; } opt; struct { struct Flag *p; @@ -37,6 +40,8 @@ int main(int argc, char **argv) struct Colors colors; struct FPRange range; + enum ColorFormat clr_frmt; + G_gisinit(argv[0]); module = G_define_module(); @@ -54,6 +59,12 @@ int main(int argc, char **argv) opt.file->description = _("If not given write to standard output"); opt.file->required = NO; + opt.format = G_define_standard_option(G_OPT_F_FORMAT); + opt.format->guisection = _("Print"); + + opt.color_format = G_define_standard_option(G_OPT_C_FORMAT); + opt.color_format->guisection = _("Color"); + flag.p = G_define_flag(); flag.p->key = 'p'; flag.p->description = _("Output values as percentages"); @@ -77,8 +88,26 @@ int main(int argc, char **argv) G_fatal_error(_("Unable to open output file <%s>"), file); } - Rast_print_colors(&colors, range.min, range.max, fp, - flag.p->answer ? 1 : 0); + if (strcmp(opt.format->answer, "json") == 0) { + if (strcmp(opt.color_format->answer, "rgb") == 0) { + clr_frmt = RGB; + } + else if (strcmp(opt.color_format->answer, "triplet") == 0) { + clr_frmt = TRIPLET; + } + else if (strcmp(opt.color_format->answer, "hsv") == 0) { + clr_frmt = HSV; + } + else { + clr_frmt = HEX; + } + print_json_colors(&colors, range.min, range.max, fp, + flag.p->answer ? 1 : 0, clr_frmt); + } + else { + Rast_print_colors(&colors, range.min, range.max, fp, + flag.p->answer ? 1 : 0); + } exit(EXIT_SUCCESS); } diff --git a/raster/r.colors.out/tests/conftest.py b/raster/r.colors.out/tests/conftest.py new file mode 100644 index 00000000000..c0c6790a75c --- /dev/null +++ b/raster/r.colors.out/tests/conftest.py @@ -0,0 +1,52 @@ +"""Fixture for r.colors.out and r3.colors.out test""" + +import os +import pytest +import grass.script as gs + + +@pytest.fixture +def raster_color_dataset(tmp_path): + """Set up a GRASS session and create test rasters with color rules.""" + project = tmp_path / "raster_color_project" + gs.create_project(project) + with gs.setup.init(project, env=os.environ.copy()) as session: + gs.run_command( + "g.region", + s=0, + n=90, + w=0, + e=100, + b=0, + t=1, + rows=3, + cols=3, + res=10, + env=session.env, + ) + gs.mapcalc("a = int(row())", env=session.env) + gs.run_command("r.colors", map="a", color="elevation", env=session.env) + yield session + + +@pytest.fixture +def raster3_color_dataset(tmp_path): + """Set up a GRASS session and create test raster3 with color rules.""" + project = tmp_path / "raster3_color_project" + gs.create_project(project) + with gs.setup.init(project, env=os.environ.copy()) as session: + gs.run_command( + "g.region", + s=0, + n=100, + w=0, + e=100, + b=5, + t=50, + tbres=10, + res3=20, + env=session.env, + ) + gs.mapcalc3d("b = double(row())", env=session.env) + gs.run_command("r3.colors", map="b", color="elevation", env=session.env) + yield session diff --git a/raster/r.colors.out/tests/r3_colors_out_test.py b/raster/r.colors.out/tests/r3_colors_out_test.py new file mode 100644 index 00000000000..670c1ef13a6 --- /dev/null +++ b/raster/r.colors.out/tests/r3_colors_out_test.py @@ -0,0 +1,175 @@ +"""Tests of r3.colors.out""" + +import grass.script as gs + + +def validate_plain_text_output(data): + """Validate the structure and content of the plain text output.""" + assert data + assert len(data) == 8, "The output does not match the expected number of items (8)." + expected = { + "1 0:191:191", + "1.8 0:255:0", + "2.6 255:255:0", + "3.4 255:127:0", + "4.2 191:127:63", + "5 200:200:200", + "nv 255:255:255", + "default 255:255:255", + } + assert ( + expected == data.keys() + ), f"test failed: expected {expected} but got {data.keys()}" + + +def test_r3_colors_out_plain_output(raster3_color_dataset): + """Test r3.colors.out command for plain output format.""" + session = raster3_color_dataset + data = gs.parse_command("r3.colors.out", map="b", format="plain", env=session.env) + validate_plain_text_output(data) + + +def test_r3_colors_out_without_format_option(raster3_color_dataset): + """Test r3.colors.out command without any format option.""" + session = raster3_color_dataset + data = gs.parse_command("r3.colors.out", map="b", env=session.env) + validate_plain_text_output(data) + + +def test_r3_colors_out_with_p_flag(raster3_color_dataset): + """Test r3.colors.out command with percentage values.""" + session = raster3_color_dataset + data = gs.parse_command("r3.colors.out", map="b", flags="p", env=session.env) + assert data + assert len(data) == 8, "The output does not match the expected number of items (8)." + expected = { + "0% 0:191:191", + "20% 0:255:0", + "40% 255:255:0", + "60% 255:127:0", + "80% 191:127:63", + "100% 200:200:200", + "nv 255:255:255", + "default 255:255:255", + } + assert ( + expected == data.keys() + ), f"test failed: expected {expected} but got {data.keys()}" + + +def validate_common_json_structure(data): + """Validate the common structure and content of the JSON output.""" + assert isinstance(data, list), "Output data should be a list of entries." + assert ( + len(data) == 8 + ), "The length of the output JSON does not match the expected value of 8." + + +def test_r3_colors_out_json_with_default_option(raster3_color_dataset): + """Test r3.colors.out command for JSON output format for default color option.""" + session = raster3_color_dataset + data = gs.parse_command("r3.colors.out", map="b", format="json", env=session.env) + validate_common_json_structure(data) + expected = [ + {"value": 1, "hex": "#00BFBF"}, + {"value": 1.8, "hex": "#00FF00"}, + {"value": 2.6, "hex": "#FFFF00"}, + {"value": 3.4, "hex": "#FF7F00"}, + {"value": 4.2, "hex": "#BF7F3F"}, + {"value": 5, "hex": "#C8C8C8"}, + {"value": "nv", "hex": "#FFFFFF"}, + {"value": "default", "hex": "#FFFFFF"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r3_colors_out_json_with_triplet_option(raster3_color_dataset): + """Test r3.colors.out command for JSON output format for triplet color option.""" + session = raster3_color_dataset + data = gs.parse_command( + "r3.colors.out", map="b", format="json", color_format="triplet", env=session.env + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "triplet": "0:191:191"}, + {"value": 1.8, "triplet": "0:255:0"}, + {"value": 2.6, "triplet": "255:255:0"}, + {"value": 3.4, "triplet": "255:127:0"}, + {"value": 4.2, "triplet": "191:127:63"}, + {"value": 5, "triplet": "200:200:200"}, + {"value": "nv", "triplet": "255:255:255"}, + {"value": "default", "triplet": "255:255:255"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r3_colors_out_json_with_rgb_option(raster3_color_dataset): + """Test r3.colors.out command for JSON output format for rgb color option.""" + session = raster3_color_dataset + data = gs.parse_command( + "r3.colors.out", + map="b", + format="json", + color_format="rgb", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "rgb": "rgb(0, 191, 191)"}, + {"value": 1.8, "rgb": "rgb(0, 255, 0)"}, + {"value": 2.6, "rgb": "rgb(255, 255, 0)"}, + {"value": 3.4, "rgb": "rgb(255, 127, 0)"}, + {"value": 4.2, "rgb": "rgb(191, 127, 63)"}, + {"value": 5, "rgb": "rgb(200, 200, 200)"}, + {"value": "nv", "rgb": "rgb(255, 255, 255)"}, + {"value": "default", "rgb": "rgb(255, 255, 255)"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r3_colors_out_json_with_hex_option(raster3_color_dataset): + """Test r3.colors.out command for JSON output format for hex color option.""" + session = raster3_color_dataset + data = gs.parse_command( + "r3.colors.out", + map="b", + format="json", + color_format="hex", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "hex": "#00BFBF"}, + {"value": 1.8, "hex": "#00FF00"}, + {"value": 2.6, "hex": "#FFFF00"}, + {"value": 3.4, "hex": "#FF7F00"}, + {"value": 4.2, "hex": "#BF7F3F"}, + {"value": 5, "hex": "#C8C8C8"}, + {"value": "nv", "hex": "#FFFFFF"}, + {"value": "default", "hex": "#FFFFFF"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r3_colors_out_json_with_hsv_option(raster3_color_dataset): + """Test r3.colors.out command for JSON output format for hsv color option.""" + session = raster3_color_dataset + data = gs.parse_command( + "r3.colors.out", + map="b", + format="json", + color_format="hsv", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "hsv": "hsv(180, 100, 74)"}, + {"value": 1.8, "hsv": "hsv(120, 100, 100)"}, + {"value": 2.6, "hsv": "hsv(60, 100, 100)"}, + {"value": 3.4, "hsv": "hsv(29, 100, 100)"}, + {"value": 4.2, "hsv": "hsv(30, 67, 74)"}, + {"value": 5, "hsv": "hsv(0, 0, 78)"}, + {"value": "nv", "hsv": "hsv(0, 0, 100)"}, + {"value": "default", "hsv": "hsv(0, 0, 100)"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" diff --git a/raster/r.colors.out/tests/r_colors_out_test.py b/raster/r.colors.out/tests/r_colors_out_test.py new file mode 100644 index 00000000000..d1abec82592 --- /dev/null +++ b/raster/r.colors.out/tests/r_colors_out_test.py @@ -0,0 +1,175 @@ +"""Tests of r.colors.out""" + +import grass.script as gs + + +def validate_plain_text_output(data): + """Validate the structure and content of the plain text output.""" + assert data + assert len(data) == 8, "The output does not match the expected number of items (8)." + expected = { + "1 0:191:191", + "1.4 0:255:0", + "1.8 255:255:0", + "2.2 255:127:0", + "2.6 191:127:63", + "3 200:200:200", + "nv 255:255:255", + "default 255:255:255", + } + assert ( + expected == data.keys() + ), f"test failed: expected {expected} but got {data.keys()}" + + +def test_r_colors_out_plain_output(raster_color_dataset): + """Test r.colors.out command for plain output format.""" + session = raster_color_dataset + data = gs.parse_command("r.colors.out", map="a", format="plain", env=session.env) + validate_plain_text_output(data) + + +def test_r_colors_out_without_format_option(raster_color_dataset): + """Test r.colors.out command without any format option.""" + session = raster_color_dataset + data = gs.parse_command("r.colors.out", map="a", env=session.env) + validate_plain_text_output(data) + + +def test_r_colors_out_with_p_flag(raster_color_dataset): + """Test r.colors.out command with percentage values.""" + session = raster_color_dataset + data = gs.parse_command("r.colors.out", map="a", flags="p", env=session.env) + assert data + assert len(data) == 8, "The output does not match the expected number of items (8)." + expected = { + "0% 0:191:191", + "20% 0:255:0", + "40% 255:255:0", + "60% 255:127:0", + "80% 191:127:63", + "100% 200:200:200", + "nv 255:255:255", + "default 255:255:255", + } + assert ( + expected == data.keys() + ), f"test failed: expected {expected} but got {data.keys()}" + + +def validate_common_json_structure(data): + """Validate the common structure and content of the JSON output.""" + assert isinstance(data, list), "Output data should be a list of entries." + assert ( + len(data) == 8 + ), "The length of the output JSON does not match the expected value of 8." + + +def test_r_colors_out_json_with_default_option(raster_color_dataset): + """Test r.colors.out command for JSON output format for default color option.""" + session = raster_color_dataset + data = gs.parse_command("r.colors.out", map="a", format="json", env=session.env) + validate_common_json_structure(data) + expected = [ + {"value": 1, "hex": "#00BFBF"}, + {"value": 1.4, "hex": "#00FF00"}, + {"value": 1.8, "hex": "#FFFF00"}, + {"value": 2.2, "hex": "#FF7F00"}, + {"value": 2.6, "hex": "#BF7F3F"}, + {"value": 3, "hex": "#C8C8C8"}, + {"value": "nv", "hex": "#FFFFFF"}, + {"value": "default", "hex": "#FFFFFF"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r_colors_out_json_with_triplet_option(raster_color_dataset): + """Test r.colors.out command for JSON output format for triplet color option.""" + session = raster_color_dataset + data = gs.parse_command( + "r.colors.out", map="a", format="json", color_format="triplet", env=session.env + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "triplet": "0:191:191"}, + {"value": 1.4, "triplet": "0:255:0"}, + {"value": 1.8, "triplet": "255:255:0"}, + {"value": 2.2, "triplet": "255:127:0"}, + {"value": 2.6, "triplet": "191:127:63"}, + {"value": 3, "triplet": "200:200:200"}, + {"value": "nv", "triplet": "255:255:255"}, + {"value": "default", "triplet": "255:255:255"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r_colors_out_json_with_rgb_option(raster_color_dataset): + """Test r.colors.out command for JSON output format for rgb color option.""" + session = raster_color_dataset + data = gs.parse_command( + "r.colors.out", + map="a", + format="json", + color_format="rgb", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "rgb": "rgb(0, 191, 191)"}, + {"value": 1.4, "rgb": "rgb(0, 255, 0)"}, + {"value": 1.8, "rgb": "rgb(255, 255, 0)"}, + {"value": 2.2, "rgb": "rgb(255, 127, 0)"}, + {"value": 2.6, "rgb": "rgb(191, 127, 63)"}, + {"value": 3, "rgb": "rgb(200, 200, 200)"}, + {"value": "nv", "rgb": "rgb(255, 255, 255)"}, + {"value": "default", "rgb": "rgb(255, 255, 255)"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r_colors_out_json_with_hex_option(raster_color_dataset): + """Test r.colors.out command for JSON output format for hex color option.""" + session = raster_color_dataset + data = gs.parse_command( + "r.colors.out", + map="a", + format="json", + color_format="hex", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "hex": "#00BFBF"}, + {"value": 1.4, "hex": "#00FF00"}, + {"value": 1.8, "hex": "#FFFF00"}, + {"value": 2.2, "hex": "#FF7F00"}, + {"value": 2.6, "hex": "#BF7F3F"}, + {"value": 3, "hex": "#C8C8C8"}, + {"value": "nv", "hex": "#FFFFFF"}, + {"value": "default", "hex": "#FFFFFF"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_r_colors_out_json_with_hsv_option(raster_color_dataset): + """Test r.colors.out command for JSON output format for hsv color option.""" + session = raster_color_dataset + data = gs.parse_command( + "r.colors.out", + map="a", + format="json", + color_format="hsv", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "hsv": "hsv(180, 100, 74)"}, + {"value": 1.4, "hsv": "hsv(120, 100, 100)"}, + {"value": 1.8, "hsv": "hsv(60, 100, 100)"}, + {"value": 2.2, "hsv": "hsv(29, 100, 100)"}, + {"value": 2.6, "hsv": "hsv(30, 67, 74)"}, + {"value": 3, "hsv": "hsv(0, 0, 78)"}, + {"value": "nv", "hsv": "hsv(0, 0, 100)"}, + {"value": "default", "hsv": "hsv(0, 0, 100)"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" diff --git a/raster/r.kappa/mask.c b/raster/r.kappa/mask.c index 729f7c5b13a..718245b6838 100644 --- a/raster/r.kappa/mask.c +++ b/raster/r.kappa/mask.c @@ -13,15 +13,17 @@ char *maskinfo(void) { struct Reclass reclass; char *results; - char text[100]; + char text[2 * GNAME_MAX + GMAPSET_MAX]; int next; int first; + char mask_name[GNAME_MAX]; + char mask_mapset[GMAPSET_MAX]; results = NULL; - if (G_find_raster("MASK", G_mapset()) == NULL) + if (!Rast_mask_status(mask_name, mask_mapset, NULL, NULL, NULL)) return "none"; - if (Rast_get_reclass("MASK", G_mapset(), &reclass) <= 0) { - sprintf(text, "MASK in %s", G_mapset()); + if (Rast_get_reclass(mask_name, mask_mapset, &reclass) <= 0) { + sprintf(text, "%s in %s", mask_name, mask_mapset); return append(results, text); } diff --git a/raster/r.li/r.li.html b/raster/r.li/r.li.html index 0ad8e5b6d77..bfe7c3498d0 100644 --- a/raster/r.li/r.li.html +++ b/raster/r.li/r.li.html @@ -1,26 +1,3 @@ - - - -r.li - GRASS GIS manual - - - - - - -
- -GRASS logo -
- -

NAME

- -r.li - Toolset for multiscale analysis of landscape structure - -

KEYWORDS

- -raster, landscape structure analysis, diversity index, patch index -

DESCRIPTION

diff --git a/raster/r.mask.status/main.c b/raster/r.mask.status/main.c index 16790adf35c..b0a7b9185c0 100644 --- a/raster/r.mask.status/main.c +++ b/raster/r.mask.status/main.c @@ -89,7 +89,7 @@ int report_status(struct Parameters *params) } // Mask raster - char *full_mask = G_fully_qualified_name(name, mapset); + char *full_mask = Rast_mask_name(); // Underlying raster if applicable char *full_underlying = NULL; if (is_mask_reclass) @@ -99,10 +99,7 @@ int report_status(struct Parameters *params) JSON_Value *root_value = json_value_init_object(); JSON_Object *root_object = json_object(root_value); json_object_set_boolean(root_object, "present", present); - if (present) - json_object_set_string(root_object, "full_name", full_mask); - else - json_object_set_null(root_object, "full_name"); + json_object_set_string(root_object, "name", full_mask); if (is_mask_reclass) json_object_set_string(root_object, "is_reclass_of", full_underlying); @@ -121,9 +118,7 @@ int report_status(struct Parameters *params) printf("1"); else printf("0"); - printf("\nfull_name="); - if (present) - printf("%s", full_mask); + printf("\nname=%s", full_mask); printf("\nis_reclass_of="); if (is_mask_reclass) printf("%s", full_underlying); @@ -135,19 +130,16 @@ int report_status(struct Parameters *params) printf("true"); else printf("false"); - printf("\nfull_name: "); - if (present) - printf("|-\n %s", full_mask); - else - printf("null"); - // Null values in YAML can be an empty (no) value (rather than null), - // so we could use that, but using the explicit null as a reasonable - // starting point. + printf("\nname: "); + printf("|-\n %s", full_mask); printf("\nis_reclass_of: "); // Using block scalar with |- to avoid need for escaping. // Alternatively, we could check mapset naming limits against YAML // escaping needs for different types of strings and do the necessary // escaping here. + // Null values in YAML can be an empty (no) value (rather than null), + // so we could use that, but using the explicit null as a reasonable + // starting point. if (is_mask_reclass) printf("|-\n %s", full_underlying); else @@ -155,14 +147,14 @@ int report_status(struct Parameters *params) printf("\n"); } else { - if (present) - printf(_("Mask is active")); - else - printf(_("Mask is not present")); if (present) { - printf("\n"); + printf(_("Mask is active")); printf(_("Mask name: %s"), full_mask); } + else { + printf(_("Mask is not present")); + printf(_("If activated, mask name will be: %s"), full_mask); + } if (is_mask_reclass) { printf("\n"); printf(_("Mask is a raster reclassified from: %s"), diff --git a/raster/r.mask.status/r.mask.status.html b/raster/r.mask.status/r.mask.status.html index 248ee3ea317..cb3897820f5 100644 --- a/raster/r.mask.status/r.mask.status.html +++ b/raster/r.mask.status/r.mask.status.html @@ -1,11 +1,21 @@

DESCRIPTION

The r.mask.status reports information about the 2D raster mask and its -status. If the mask is present, the tool reports a full name of the raster (name -including the mapset) which represents the mask. It can also report full name of -the underlying raster if the mask is reclassified from another raster. - -

+status. The tool reports whether the mask is present or not. For both active +and inactive mask, the tool reports a full name of the raster (name including +the mapset) which represents or would represent the mask. +It can also report full name of the underlying raster if the mask is +reclassified from another raster. + +The tool can be used to check if the mask is currently set +(present boolean in JSON), what is raster name used to represent +the mask (name string in JSON), and whether the raster is +reclassifed from another (is_reclass_of string or null in JSON). +YAML and shell script style outputs are following the JSON output if possible. +The plain text format outputs multi-line human-readable information in natural +language. + +

With the -t flag, no output is printed, instead a return code is used to indicate presence or absence. The convention is the same same the POSIX test utility, so r.mask.status returns 0 when the mask is diff --git a/raster/r.mask.status/tests/r_mask_status_test.py b/raster/r.mask.status/tests/r_mask_status_test.py index deafdfb145b..a5d406ad581 100644 --- a/raster/r.mask.status/tests/r_mask_status_test.py +++ b/raster/r.mask.status/tests/r_mask_status_test.py @@ -15,10 +15,11 @@ def test_json_no_mask(session_no_data): session = session_no_data data = gs.parse_command("r.mask.status", format="json", env=session.env) assert "present" in data - assert "full_name" in data + assert "name" in data + assert data["name"], "Mask name needs to be always set" + assert data["name"] == "MASK@PERMANENT", "Default mask name and current mapset" assert "is_reclass_of" in data assert data["present"] is False - assert not data["full_name"] assert not data["is_reclass_of"] @@ -28,13 +29,13 @@ def test_json_with_r_mask(session_with_data): gs.run_command("r.mask", raster="a", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is True - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert data["is_reclass_of"] == "a@PERMANENT" # Now remove the mask. gs.run_command("r.mask", flags="r", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is False - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -44,13 +45,13 @@ def test_json_with_g_copy(session_with_data): gs.run_command("g.copy", raster="a,MASK", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is True - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] # Now remove the mask. gs.run_command("g.remove", type="raster", name="MASK", flags="f", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is False - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -60,13 +61,13 @@ def test_shell(session_with_data): gs.run_command("r.mask", raster="a", env=session.env) data = gs.parse_command("r.mask.status", format="shell", env=session.env) assert int(data["present"]) - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert data["is_reclass_of"] == "a@PERMANENT" # Now remove the mask. gs.run_command("r.mask", flags="r", env=session.env) data = gs.parse_command("r.mask.status", format="shell", env=session.env) assert not int(data["present"]) - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -78,14 +79,14 @@ def test_yaml(session_with_data): text = gs.read_command("r.mask.status", format="yaml", env=session.env) data = yaml.safe_load(text) assert data["present"] is True - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert data["is_reclass_of"] == "a@PERMANENT" # Now remove the mask. gs.run_command("r.mask", flags="r", env=session.env) text = gs.read_command("r.mask.status", format="yaml", env=session.env) data = yaml.safe_load(text) assert data["present"] is False - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -101,6 +102,8 @@ def test_plain(session_with_data): gs.run_command("r.mask", flags="r", env=session.env) text = gs.read_command("r.mask.status", format="plain", env=session.env) assert text + assert "MASK@PERMANENT" in text + assert "a@PERMANENT" not in text def test_without_parameters(session_no_data): diff --git a/raster/r.random.cells/init.c b/raster/r.random.cells/init.c index 1f6ec1c7737..4cb49ce9a99 100644 --- a/raster/r.random.cells/init.c +++ b/raster/r.random.cells/init.c @@ -42,8 +42,10 @@ void Init(void) Cells = FlagCreate(Rs, Cs); CellCount = 0; - if (G_find_raster2("MASK", G_mapset())) { - FD = Rast_open_old("MASK", G_mapset()); + char mask_name[GNAME_MAX]; + char mask_mapset[GMAPSET_MAX]; + if (Rast_mask_status(mask_name, mask_mapset, NULL, NULL, NULL)) { + FD = Rast_open_old(mask_name, mask_mapset); { for (row = 0; row < Rs; row++) { Rast_get_c_row_nomask(FD, CellBuffer, row); diff --git a/raster/r.random.surface/init.c b/raster/r.random.surface/init.c index a2b4af5dc8b..44d79fd2bf8 100644 --- a/raster/r.random.surface/init.c +++ b/raster/r.random.surface/init.c @@ -35,12 +35,10 @@ void Init(void) else MinRes = NS; - if (NULL == G_find_file("cell", "MASK", G_mapset())) { - MapCount = Rs * Cs; - FDM = -1; - } - else { - FDM = Rast_open_old("MASK", G_mapset()); + char mask_name[GNAME_MAX]; + char mask_mapset[GMAPSET_MAX]; + if (Rast_mask_status(mask_name, mask_mapset, NULL, NULL, NULL)) { + FDM = Rast_open_old(mask_name, mask_mapset); { MapCount = 0; CellBuffer = Rast_allocate_c_buf(); @@ -53,6 +51,10 @@ void Init(void) } } } + else { + MapCount = Rs * Cs; + FDM = -1; + } if (Uniform->answer) sprintf(Buf, "Uni. R. S."); diff --git a/raster/r.report/maskinfo.c b/raster/r.report/maskinfo.c index cfe2a382029..70f9043d0f8 100644 --- a/raster/r.report/maskinfo.c +++ b/raster/r.report/maskinfo.c @@ -13,15 +13,17 @@ char *maskinfo(void) { struct Reclass reclass; char *results; - char text[100]; + char text[2 * GNAME_MAX + GMAPSET_MAX]; int next; int first; + char mask_name[GNAME_MAX]; + char mask_mapset[GMAPSET_MAX]; results = NULL; - if (G_find_raster("MASK", G_mapset()) == NULL) + if (!Rast_mask_status(mask_name, mask_mapset, NULL, NULL, NULL)) return "none"; - if (Rast_get_reclass("MASK", G_mapset(), &reclass) <= 0) { - sprintf(text, "MASK in %s", G_mapset()); + if (Rast_get_reclass(mask_name, mask_mapset, &reclass) <= 0) { + sprintf(text, "%s in %s", mask_name, mask_mapset); return append(results, text); } diff --git a/raster/r.surf.contour/main.c b/raster/r.surf.contour/main.c index 4c28d848822..202cc99e758 100644 --- a/raster/r.surf.contour/main.c +++ b/raster/r.surf.contour/main.c @@ -80,8 +80,10 @@ int main(int argc, char *argv[]) alt_row = (DCELL *)G_malloc(ncols * sizeof(DCELL)); seen = flag_create(nrows, ncols); mask = flag_create(nrows, ncols); - if (NULL != G_find_file("cell", "MASK", G_mapset())) { - file_fd = Rast_open_old("MASK", G_mapset()); + char mask_name[GNAME_MAX]; + char mask_mapset[GMAPSET_MAX]; + if (Rast_mask_status(mask_name, mask_mapset, NULL, NULL, NULL)) { + file_fd = Rast_open_old(mask_name, mask_mapset); for (r = 0; r < nrows; r++) { Rast_get_d_row_nomask(file_fd, alt_row, r); for (c = 0; c < ncols; c++) diff --git a/raster/r.to.vect/areas_io.c b/raster/r.to.vect/areas_io.c index 86760038d61..6d9cfd10e84 100644 --- a/raster/r.to.vect/areas_io.c +++ b/raster/r.to.vect/areas_io.c @@ -371,6 +371,7 @@ int write_area( if (equivs) G_free(equivs); + Vect_destroy_line_struct(points); return 0; } diff --git a/raster/r.viewshed/grass.cpp b/raster/r.viewshed/grass.cpp index 89d2879db0d..6ab70e4d9e2 100644 --- a/raster/r.viewshed/grass.cpp +++ b/raster/r.viewshed/grass.cpp @@ -450,6 +450,7 @@ AMI_STREAM *init_event_list(char *rastName, Viewpoint *vp, Rast_set_null_value(inrast[2], ncols, data_type); /*scan through the raster data */ + // int isnull = 0; dimensionType i, j; double ax, ay; AEvent e; @@ -483,7 +484,7 @@ AMI_STREAM *init_event_list(char *rastName, Viewpoint *vp, e.col = j; /*read the elevation value into the event */ - Rast_is_null_value(&(inrast[1][j]), data_type); + // isnull = Rast_is_null_value(&(inrast[1][j]), data_type); e.elev[1] = inrast[1][j]; /* adjust for curvature */ @@ -971,18 +972,19 @@ void save_io_vis_and_elev_to_GRASS(IOVisibilityGrid *visgrid, char *elevfname, for (j = 0; j < Rast_window_cols(); j++) { /* read the current elevation value */ + // int isNull = 0; switch (elev_data_type) { case CELL_TYPE: - Rast_is_c_null_value(&((CELL *)elevrast)[j]); + // isNull = Rast_is_c_null_value(&((CELL *)elevrast)[j]); elev = (double)(((CELL *)elevrast)[j]); break; case FCELL_TYPE: - Rast_is_f_null_value(&((FCELL *)elevrast)[j]); + // isNull = Rast_is_f_null_value(&((FCELL *)elevrast)[j]); elev = (double)(((FCELL *)elevrast)[j]); break; case DCELL_TYPE: - Rast_is_d_null_value(&((DCELL *)elevrast)[j]); + // isNull = Rast_is_d_null_value(&((DCELL *)elevrast)[j]); elev = (double)(((DCELL *)elevrast)[j]); break; } diff --git a/raster/r.volume/main.c b/raster/r.volume/main.c index 236cc3f6255..4fd71b56071 100644 --- a/raster/r.volume/main.c +++ b/raster/r.volume/main.c @@ -12,10 +12,10 @@ * * PURPOSE: r.volume is a program to compute the total, and average of * cell values within regions of a map defined by clumps or - * patches on a second map (or MASK). It also computes the - * "volume" by multiplying the total within a clump by the area - * of each cell. It also outputs the "centroid" location of each - * clump. Output is to standard out. + * patches on a second map (or by raster mask). It also computes + * the "volume" by multiplying the total within a clump by the + * area of each cell. It also outputs the "centroid" location of + * each clump. Output is to standard out. * * COPYRIGHT: (C) 1999-2006, 2013 by the GRASS Development Team * @@ -43,7 +43,8 @@ int main(int argc, char *argv[]) CELL i, max; int row, col, rows, cols; - int out_mode, use_MASK; + int out_mode; + bool use_mask; unsigned long *n, *e; long int *count; int fd_data, fd_clump; @@ -92,7 +93,8 @@ int main(int argc, char *argv[]) opt.clump->required = NO; opt.clump->label = _("Name of input clump raster map"); opt.clump->description = _("Preferably the output of r.clump. " - "If no clump map is given than MASK is used."); + "If no clump map is given, " + "raster mask is used instead."); opt.centroids = G_define_standard_option(G_OPT_V_OUTPUT); opt.centroids->key = "centroids"; @@ -134,24 +136,28 @@ int main(int argc, char *argv[]) out_mode = (!flag.report->answer); /* - * see if MASK or a separate "clumpmap" raster map is to be used + * see if raster mask or a separate "clumpmap" raster map is to be used * -- it must(!) be one of those two choices. */ - use_MASK = 0; + use_mask = false; + char mask_name[GNAME_MAX]; + char mask_mapset[GMAPSET_MAX]; if (!clumpmap) { - clumpmap = "MASK"; - use_MASK = 1; - if (!G_find_raster2(clumpmap, G_mapset())) - G_fatal_error(_("No MASK found. If no clump map is given than the " - "MASK is required. " - "You need to define a clump raster map or create a " - "MASK by r.mask command.")); - G_important_message(_("No clump map given, using MASK")); + bool present = + Rast_mask_status(mask_name, mask_mapset, NULL, NULL, NULL); + if (!present) + G_fatal_error(_("No clump map <%s> given and no raster mask found. " + "You need to define a clump raster map or create " + "a raster mask using r.mask."), + opt.clump->key); + clumpmap = mask_name; + use_mask = true; + G_important_message(_("No clump map given, using raster mask")); } /* open input and clump raster maps */ fd_data = Rast_open_old(datamap, ""); - fd_clump = Rast_open_old(clumpmap, use_MASK ? G_mapset() : ""); + fd_clump = Rast_open_old(clumpmap, use_mask ? mask_mapset : ""); /* initialize vector map (for centroids) if needed */ if (centroidsmap) { @@ -175,7 +181,7 @@ int main(int argc, char *argv[]) } /* initialize data accumulation arrays */ - max = Rast_get_max_c_cat(clumpmap, use_MASK ? G_mapset() : ""); + max = Rast_get_max_c_cat(clumpmap, use_mask ? mask_mapset : ""); sum = (double *)G_malloc((max + 1) * sizeof(double)); count = (long int *)G_malloc((max + 1) * sizeof(long int)); diff --git a/raster/r.volume/r.volume.html b/raster/r.volume/r.volume.html index 6f79e6ee76f..f9c20e324c1 100644 --- a/raster/r.volume/r.volume.html +++ b/raster/r.volume/r.volume.html @@ -8,7 +8,7 @@

DESCRIPTION

from a input raster map sorted by category on a clump raster map, and optionally generates a vector points map of the centroids for each clump. If a clump map is not specified, the -current MASK is used. The MASK can be defined +current raster mask is used. The raster mask can be defined by r.mask. The sum is multiplied by the area of a cell to give the volume occupied by that cell. See below for an example of the output table. @@ -24,12 +24,12 @@

DESCRIPTION

NOTES

-If a clump map is not given and a MASK not set, the program exits with -an error message. +If a clump map is not given and a raster mask is not set, the program exits +with an error message.

r.volume works in the current region and respects the current -MASK. +raster mask.

CENTROIDS

diff --git a/raster3d/r3.in.v5d/binio.c b/raster3d/r3.in.v5d/binio.c index b47723a2929..98cf70a9fdd 100644 --- a/raster3d/r3.in.v5d/binio.c +++ b/raster3d/r3.in.v5d/binio.c @@ -32,26 +32,11 @@ * If an ANSI compiler is used prototypes and ANSI function declarations * are used. Otherwise use K&R conventions. * - * If we're running on a CRAY (8-byte ints and floats), conversions will - * be done as needed. - */ - -/* - * Updates: - * - * April 13, 1995, brianp - * added cray_to_ieee and iee_to_cray array conversion functions. - * fixed potential cray bug in write_float4_array function. - * */ #include #include #include -#ifdef _CRAY -#include -#include -#endif #include "binio.h" /**********************************************************************/ @@ -94,132 +79,6 @@ void flip2(const unsigned short *src, unsigned short *dest, int n) } } -#ifdef _CRAY - -/***************************************************************************** - * - * The following source code is in the public domain. - * Specifically, we give to the public domain all rights for future licensing - * of the source code, all resale rights, and all publishing rights. - * - * We ask, but do not require, that the following message be included in all - * derived works: - * - * Portions developed at the National Center for Supercomputing Applications at - * the University of Illinois at Urbana-Champaign. - * - * THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE - * SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION, - * WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE - * - ****************************************************************************/ - -/** THESE ROUTINES MUST BE COMPILED ON THE CRAY ONLY SINCE THEY **/ - -/** REQUIRE 8-BYTES PER C-TYPE LONG **/ - -/* Cray to IEEE single precision */ -static void c_to_if(long *t, const long *f) -{ - if (*f != 0) { - *t = (((*f & 0x8000000000000000) | /* sign bit */ - ((((*f & 0x7fff000000000000) >> 48) - 16258) << 55)) + /* exp */ - (((*f & 0x00007fffff000000) + ((*f & 0x0000000000800000) << 1)) - << 8)); /* mantissa */ - } - else - *t = *f; -} - -#define C_TO_IF(T, F) \ - if (F != 0) { \ - T = (((F & 0x8000000000000000) | \ - ((((F & 0x7fff000000000000) >> 48) - 16258) << 55)) + \ - (((F & 0x00007fffff000000) + ((F & 0x0000000000800000) << 1)) \ - << 8)); \ - } \ - else { \ - T = F; \ - } - -/* IEEE single precision to Cray */ -static void if_to_c(long *t, const long *f) -{ - if (*f != 0) { - *t = (((*f & 0x8000000000000000) | - ((*f & 0x7f80000000000000) >> 7) + (16258L << 48)) | - (((*f & 0x007fffff00000000) >> 8) | (0x0000800000000000))); - if ((*f << 1) == 0) - *t = 0; - } - else - *t = *f; -} - -/* T and F must be longs! */ -#define IF_TO_C(T, F) \ - if (F != 0) { \ - T = (((F & 0x8000000000000000) | \ - ((F & 0x7f80000000000000) >> 7) + (16258L << 48)) | \ - (((F & 0x007fffff00000000) >> 8) | (0x0000800000000000))); \ - if ((F << 1) == 0) \ - T = 0; \ - } \ - else { \ - T = F; \ - } - -/* - * Convert an array of Cray 8-byte floats to an array of IEEE 4-byte floats. - */ -void cray_to_ieee_array(long *dest, const float *source, int n) -{ - long *dst; - const long *src; - long tmp1, tmp2; - int i; - - dst = dest; - src = (const long *)source; - - for (i = 0; i < n; i += 2) { /* add 1 in case n is odd */ - c_to_if(&tmp1, &src[i]); - c_to_if(&tmp2, &src[i + 1]); - *dst = (tmp1 & 0xffffffff00000000) | (tmp2 >> 32); - dst++; - } -} - -/* - * Convert an array of IEEE 4-byte floats to an array of 8-byte Cray floats. - */ -void ieee_to_cray_array(float *dest, const long *source, int n) -{ - long *dst; - const long *src; - int i; - long ieee; - - src = source; - dst = (long *)dest; - - for (i = 0; i < n; i++) { - /* most significant 4-bytes of ieee contain bit pattern to convert */ - if ((i & 1) == 0) { - /* get upper half */ - ieee = src[i / 2] & 0xffffffff00000000; - } - else { - /* get lower half */ - ieee = src[i / 2] << 32; - } - if_to_c(dst, &ieee); - dst++; - } -} - -#endif /*_CRAY*/ - /**********************************************************************/ /***** Read Functions *****/ @@ -247,25 +106,6 @@ int read_bytes(int f, void *b, int n) */ int read_int2_array(int f, short *iarray, int n) { -#ifdef _CRAY - int i; - signed char *buffer; - int nread; - - buffer = (signed char *)G_malloc(n * 2); - if (!buffer) - return 0; - nread = read(f, buffer, n * 2); - if (nread <= 0) - return 0; - nread /= 2; - for (i = 0; i < nread; i++) { - /* don't forget about sign extension! */ - iarray[i] = (buffer[i * 2] * 256) | buffer[i * 2 + 1]; - } - G_free(buffer); - return nread; -#else int nread = read(f, iarray, n * 2); if (nread <= 0) @@ -274,7 +114,6 @@ int read_int2_array(int f, short *iarray, int n) flip2((const unsigned short *)iarray, (unsigned short *)iarray, nread / 2); #endif return nread / 2; -#endif } /* @@ -286,24 +125,6 @@ int read_int2_array(int f, short *iarray, int n) */ int read_uint2_array(int f, unsigned short *iarray, int n) { -#ifdef _CRAY - int i; - unsigned char *buffer; - int nread; - - buffer = (unsigned char *)G_malloc(n * 2); - if (!buffer) - return 0; - nread = read(f, buffer, n * 2); - if (nread <= 0) - return 0; - nread /= 2; - for (i = 0; i < nread; i++) { - iarray[i] = (buffer[i * 2] << 8) | buffer[i * 2 + 1]; - } - G_free(buffer); - return nread; -#else int nread = read(f, iarray, n * 2); if (nread <= 0) @@ -312,7 +133,6 @@ int read_uint2_array(int f, unsigned short *iarray, int n) flip2(iarray, iarray, nread / 2); #endif return nread / 2; -#endif } /* @@ -336,9 +156,6 @@ int read_int4(int f, int *i) } #else if (read(f, i, 4) == 4) { -#ifdef _CRAY - *i = *i >> 32; -#endif return 1; } else { @@ -356,30 +173,6 @@ int read_int4(int f, int *i) */ int read_int4_array(int f, int *iarray, int n) { -#ifdef _CRAY - int j, nread; - int *buffer; - - buffer = (int *)G_malloc((n + 1) * 4); - if (!buffer) - return 0; - nread = read(f, buffer, 4 * n); - if (nread <= 0) { - return 0; - } - nread /= 4; - - for (j = 0; j < nread; j++) { - if ((j & 1) == 0) { - iarray[j] = buffer[j / 2] >> 32; - } - else { - iarray[j] = buffer[j / 2] & 0xffffffff; - } - } - G_free(buffer); - return nread; -#else int nread = read(f, iarray, 4 * n); if (nread <= 0) @@ -388,7 +181,6 @@ int read_int4_array(int f, int *iarray, int n) flip4((const unsigned int *)iarray, (unsigned int *)iarray, nread / 4); #endif return nread / 4; -#endif } /* @@ -399,16 +191,6 @@ int read_int4_array(int f, int *iarray, int n) */ int read_float4(int f, float *x) { -#ifdef _CRAY - long buffer = 0; - - if (read(f, &buffer, 4) == 4) { - /* convert IEEE float (buffer) to Cray float (x) */ - if_to_c((long *)x, &buffer); - return 1; - } - return 0; -#else #ifdef LITTLE unsigned int n, *iptr; @@ -428,7 +210,6 @@ int read_float4(int f, float *x) return 0; } #endif -#endif } /* @@ -440,22 +221,6 @@ int read_float4(int f, float *x) */ int read_float4_array(int f, float *x, int n) { -#ifdef _CRAY - /* read IEEE floats into buffer, then convert to Cray format */ - long *buffer; - int i, nread; - - buffer = (long *)G_malloc((n + 1) * 4); - if (!buffer) - return 0; - nread = read(f, buffer, n * 4); - if (nread <= 0) - return 0; - nread /= 4; - ieee_to_cray_array(x, buffer, nread); - G_free(buffer); - return nread; -#else int nread = read(f, x, 4 * n); if (nread <= 0) @@ -464,7 +229,6 @@ int read_float4_array(int f, float *x, int n) flip4((const unsigned int *)x, (unsigned int *)x, nread / 4); #endif return nread / 4; -#endif } /* @@ -541,10 +305,6 @@ int write_bytes(int f, const void *b, int n) */ int write_int2_array(int f, const short *iarray, int n) { -#ifdef _CRAY - printf("write_int2_array not implemented!\n"); - exit(1); -#else int nwritten; #ifdef LITTLE @@ -557,7 +317,6 @@ int write_int2_array(int f, const short *iarray, int n) if (nwritten <= 0) return 0; return nwritten / 2; -#endif } /* @@ -569,24 +328,6 @@ int write_int2_array(int f, const short *iarray, int n) */ int write_uint2_array(int f, const unsigned short *iarray, int n) { -#ifdef _CRAY - int i, nwritten; - unsigned char *buffer; - - buffer = (unsigned char *)G_malloc(2 * n); - if (!buffer) - return 0; - for (i = 0; i < n; i++) { - buffer[i * 2] = (iarray[i] >> 8) & 0xff; - buffer[i * 2 + 1] = iarray[i] & 0xff; - } - nwritten = write(f, buffer, 2 * n); - G_free(buffer); - if (nwritten <= 0) - return 0; - else - return nwritten / 2; -#else int nwritten; #ifdef LITTLE @@ -600,7 +341,6 @@ int write_uint2_array(int f, const unsigned short *iarray, int n) return 0; else return nwritten / 2; -#endif } /* @@ -611,15 +351,10 @@ int write_uint2_array(int f, const unsigned short *iarray, int n) */ int write_int4(int f, int i) { -#ifdef _CRAY - i = i << 32; - return write(f, &i, 4) > 0; -#else #ifdef LITTLE i = FLIP4(i); #endif return write(f, &i, 4) > 0; -#endif } /* @@ -631,28 +366,6 @@ int write_int4(int f, int i) */ int write_int4_array(int f, const int *i, int n) { -#ifdef _CRAY - int j, nwritten; - char *buf, *b, *ptr; - - b = buf = (char *)G_malloc(n * 4 + 8); - if (!b) - return 0; - ptr = (char *)i; - for (j = 0; j < n; j++) { - ptr += 4; /* skip upper 4 bytes */ - *b++ = *ptr++; - *b++ = *ptr++; - *b++ = *ptr++; - *b++ = *ptr++; - } - nwritten = write(f, buf, 4 * n); - G_free(buf); - if (nwritten <= 0) - return 0; - else - return nwritten / 4; -#else #ifdef LITTLE int nwritten; @@ -666,7 +379,6 @@ int write_int4_array(int f, const int *i, int n) #else return write(f, i, 4 * n) / 4; #endif -#endif } /* @@ -677,12 +389,6 @@ int write_int4_array(int f, const int *i, int n) */ int write_float4(int f, float x) { -#ifdef _CRAY - char buffer[8]; - - c_to_if((long *)buffer, (const long *)&x); - return write(f, buffer, 4) > 0; -#else #ifdef LITTLE float y; unsigned int *iptr = (unsigned int *)&y, temp; @@ -696,7 +402,6 @@ int write_float4(int f, float x) y = (float)x; return write(f, &y, 4) > 0; #endif -#endif } /* @@ -708,22 +413,6 @@ int write_float4(int f, float x) */ int write_float4_array(int f, const float *x, int n) { -#ifdef _CRAY - /* convert cray floats to IEEE and put into buffer */ - int nwritten; - long *buffer; - - buffer = (long *)G_malloc(n * 4 + 8); - if (!buffer) - return 0; - cray_to_ieee_array(buffer, x, n); - nwritten = write(f, buffer, 4 * n); - G_free(buffer); - if (nwritten <= 0) - return 0; - else - return nwritten / 4; -#else #ifdef LITTLE int nwritten; @@ -737,7 +426,6 @@ int write_float4_array(int f, const float *x, int n) #else return write(f, x, 4 * n) / 4; #endif -#endif } /* diff --git a/raster3d/r3.in.v5d/binio.h b/raster3d/r3.in.v5d/binio.h index f987e3cf64b..e6a80d8a9db 100644 --- a/raster3d/r3.in.v5d/binio.h +++ b/raster3d/r3.in.v5d/binio.h @@ -37,11 +37,6 @@ extern void flip4(const unsigned int *src, unsigned int *dest, int n); extern void flip2(const unsigned short *src, unsigned short *dest, int n); -#ifdef _CRAY -extern void cray_to_ieee_array(long *dest, const float *source, int n); -extern void ieee_to_cray_array(float *dest, const long *source, int n); -#endif - /**********************************************************************/ /***** Read Functions *****/ diff --git a/raster3d/r3.in.v5d/v5d.c b/raster3d/r3.in.v5d/v5d.c index 54f75f2361a..ef9f7487ae3 100644 --- a/raster3d/r3.in.v5d/v5d.c +++ b/raster3d/r3.in.v5d/v5d.c @@ -49,13 +49,6 @@ * values are in IEEE format. */ -/* - * Updates: - * - * April 13, 1995, brianp - * finished Cray support for 2-byte and 4-byte compress modes - */ - #include #include #include @@ -721,21 +714,6 @@ void v5dCompressGrid(int nr, int nc, int nl, int compressmode, else { one_over_a = 1.0 / ga[lev]; } -#ifdef _CRAY - /* this is tricky because sizeof(V5Dushort)==8, not 2 */ - for (i = 0; i < nrnc; i++, p++) { - V5Dushort compvalue; - - if (IS_MISSING(data[p])) { - compvalue = 65535; - } - else { - compvalue = (V5Dushort)(int)((data[p] - b) * one_over_a); - } - compdata1[p * 2 + 0] = compvalue >> 8; /* upper byte */ - compdata1[p * 2 + 1] = compvalue & 0xffu; /* lower byte */ - } -#else for (i = 0; i < nrnc; i++, p++) { if (IS_MISSING(data[p])) { compdata2[p] = 65535; @@ -745,20 +723,14 @@ void v5dCompressGrid(int nr, int nc, int nl, int compressmode, } } /* TODO: byte-swapping on little endian??? */ -#endif } } else { /* compressmode==4 */ -#ifdef _CRAY - cray_to_ieee_array(compdata, data, nrncnl); -#else - /* other machines: just copy 4-byte IEEE floats */ assert(sizeof(float) == 4); memcpy(compdata, data, nrncnl * 4); /* TODO: byte-swapping on little endian??? */ -#endif } } @@ -834,20 +806,6 @@ void v5dDecompressGrid(int nr, int nc, int nl, int compressmode, void *compdata, float a = ga[lev]; float b = gb[lev]; -#ifdef _CRAY - /* this is tricky because sizeof(V5Dushort)==8, not 2 */ - for (i = 0; i < nrnc; i++, p++) { - int compvalue; - - compvalue = (compdata1[p * 2] << 8) | compdata1[p * 2 + 1]; - if (compvalue == 65535) { - data[p] = MISSING; - } - else { - data[p] = (float)compvalue * a + b; - } - } -#else /* sizeof(V5Dushort)==2! */ for (i = 0; i < nrnc; i++, p++) { if (compdata2[p] == 65535) { @@ -857,19 +815,13 @@ void v5dDecompressGrid(int nr, int nc, int nl, int compressmode, void *compdata, data[p] = (float)(int)compdata2[p] * a + b; } } -#endif } } else { /* compressmode==4 */ -#ifdef _CRAY - ieee_to_cray_array(data, compdata, nrncnl); -#else - /* other machines: just copy 4-byte IEEE floats */ assert(sizeof(float) == 4); memcpy(data, compdata, nrncnl * 4); -#endif } } @@ -2720,11 +2672,7 @@ int v5dClose(void) #ifdef UNDERSCORE int v5dcreate_ #else -#ifdef _CRAY -int V5DCREATE -#else int v5dcreate -#endif #endif (const char *name, const int *numtimes, const int *numvars, const int *nr, @@ -2883,11 +2831,7 @@ int v5dcreate #ifdef UNDERSCORE int v5dcreatesimple_ #else -#ifdef _CRAY -int V5DCREATESIMPLE -#else int v5dcreatesimple -#endif #endif (const char *name, const int *numtimes, const int *numvars, const int *nr, @@ -2920,12 +2864,7 @@ int v5dcreatesimple #ifdef UNDERSCORE return v5dcreate_ #else -#ifdef _CRAY - return V5DCREATE -#else - return v5dcreate -#endif #endif (name, numtimes, numvars, nr, nc, varnl, varname, timestamp, datestamp, &compressmode, &projection, projarg, &vertical, vertarg); @@ -2939,11 +2878,7 @@ int v5dcreatesimple #ifdef UNDERSCORE int v5dsetlowlev_ #else -#ifdef _CRAY -int V5DSETLOWLEV -#else int v5dsetlowlev -#endif #endif (int *lowlev) { @@ -2959,11 +2894,7 @@ int v5dsetlowlev #ifdef UNDERSCORE int v5dsetunits_ #else -#ifdef _CRAY -int V5DSETUNITS -#else int v5dsetunits -#endif #endif (int *var, char *name) { @@ -2980,11 +2911,7 @@ int v5dsetunits #ifdef UNDERSCORE int v5dwrite_ #else -#ifdef _CRAY -int V5DWRITE -#else int v5dwrite -#endif #endif (const int *time, const int *var, const float *data) { @@ -3001,11 +2928,7 @@ int v5dwrite #ifdef UNDERSCORE int v5dmcfile_ #else -#ifdef _CRAY -int V5DMCFILE -#else int v5dmcfile -#endif #endif (const int *time, const int *var, const int *mcfile, const int *mcgrid) { @@ -3029,12 +2952,8 @@ int v5dmcfile #ifdef UNDERSCORE int v5dclose_(void) #else -#ifdef _CRAY -int V5DCLOSE(void) -#else int v5dclose(void) #endif -#endif { return v5dClose(); } diff --git a/raster3d/r3.in.v5d/v5d.h b/raster3d/r3.in.v5d/v5d.h index 49a604416fa..b2c985dca12 100644 --- a/raster3d/r3.in.v5d/v5d.h +++ b/raster3d/r3.in.v5d/v5d.h @@ -43,8 +43,8 @@ * Define our own 1 and 2-byte data types. We use these names to avoid * collisions with types defined by the OS include files. */ -typedef unsigned char V5Dubyte; /* Must be 1 byte, except for cray */ -typedef unsigned short V5Dushort; /* Must be 2 byte, except for cray */ +typedef unsigned char V5Dubyte; /* Must be 1 byte */ +typedef unsigned short V5Dushort; /* Must be 2 byte */ #define MISSING 1.0e35 #define IS_MISSING(X) ((X) >= 1.0e30) diff --git a/raster3d/r3.out.v5d/binio.c b/raster3d/r3.out.v5d/binio.c index f8582e97313..98cf70a9fdd 100644 --- a/raster3d/r3.out.v5d/binio.c +++ b/raster3d/r3.out.v5d/binio.c @@ -32,26 +32,11 @@ * If an ANSI compiler is used prototypes and ANSI function declarations * are used. Otherwise use K&R conventions. * - * If we're running on a CRAY (8-byte ints and floats), conversions will - * be done as needed. - */ - -/* - * Updates: - * - * April 13, 1995, brianp - * added cray_to_ieee and iee_to_cray array conversion functions. - * fixed potential cray bug in write_float4_array function. - * */ #include #include #include -#ifdef _CRAY -#include -#include -#endif #include "binio.h" /**********************************************************************/ @@ -94,132 +79,6 @@ void flip2(const unsigned short *src, unsigned short *dest, int n) } } -#ifdef _CRAY - -/***************************************************************************** - * - * The following source code is in the public domain. - * Specifically, we give to the public domain all rights for future licensing - * of the source code, all resale rights, and all publishing rights. - * - * We ask, but do not require, that the following message be included in all - * derived works: - * - * Portions developed at the National Center for Supercomputing Applications at - * the University of Illinois at Urbana-Champaign. - * - * THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE - * SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION, - * WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE - * - ****************************************************************************/ - -/** THESE ROUTINES MUST BE COMPILED ON THE CRAY ONLY SINCE THEY **/ - -/** REQUIRE 8-BYTES PER C-TYPE LONG **/ - -/* Cray to IEEE single precision */ -static void c_to_if(long *t, const long *f) -{ - if (*f != 0) { - *t = (((*f & 0x8000000000000000) | /* sign bit */ - ((((*f & 0x7fff000000000000) >> 48) - 16258) << 55)) + /* exp */ - (((*f & 0x00007fffff000000) + ((*f & 0x0000000000800000) << 1)) - << 8)); /* mantissa */ - } - else - *t = *f; -} - -#define C_TO_IF(T, F) \ - if (F != 0) { \ - T = (((F & 0x8000000000000000) | \ - ((((F & 0x7fff000000000000) >> 48) - 16258) << 55)) + \ - (((F & 0x00007fffff000000) + ((F & 0x0000000000800000) << 1)) \ - << 8)); \ - } \ - else { \ - T = F; \ - } - -/* IEEE single precision to Cray */ -static void if_to_c(long *t, const long *f) -{ - if (*f != 0) { - *t = (((*f & 0x8000000000000000) | - ((*f & 0x7f80000000000000) >> 7) + (16258 << 48)) | - (((*f & 0x007fffff00000000) >> 8) | (0x0000800000000000))); - if ((*f << 1) == 0) - *t = 0; - } - else - *t = *f; -} - -/* T and F must be longs! */ -#define IF_TO_C(T, F) \ - if (F != 0) { \ - T = (((F & 0x8000000000000000) | \ - ((F & 0x7f80000000000000) >> 7) + (16258 << 48)) | \ - (((F & 0x007fffff00000000) >> 8) | (0x0000800000000000))); \ - if ((F << 1) == 0) \ - T = 0; \ - } \ - else { \ - T = F; \ - } - -/* - * Convert an array of Cray 8-byte floats to an array of IEEE 4-byte floats. - */ -void cray_to_ieee_array(long *dest, const float *source, int n) -{ - long *dst; - const long *src; - long tmp1, tmp2; - int i; - - dst = dest; - src = (const long *)source; - - for (i = 0; i < n; i += 2) { /* add 1 in case n is odd */ - c_to_if(&tmp1, &src[i]); - c_to_if(&tmp2, &src[i + 1]); - *dst = (tmp1 & 0xffffffff00000000) | (tmp2 >> 32); - dst++; - } -} - -/* - * Convert an array of IEEE 4-byte floats to an array of 8-byte Cray floats. - */ -void ieee_to_cray_array(float *dest, const long *source, int n) -{ - long *dst; - const long *src; - int i; - long ieee; - - src = source; - dst = (long *)dest; - - for (i = 0; i < n; i++) { - /* most significant 4-bytes of ieee contain bit pattern to convert */ - if ((i & 1) == 0) { - /* get upper half */ - ieee = src[i / 2] & 0xffffffff00000000; - } - else { - /* get lower half */ - ieee = src[i / 2] << 32; - } - if_to_c(dst, &ieee); - dst++; - } -} - -#endif /*_CRAY*/ - /**********************************************************************/ /***** Read Functions *****/ @@ -247,25 +106,6 @@ int read_bytes(int f, void *b, int n) */ int read_int2_array(int f, short *iarray, int n) { -#ifdef _CRAY - int i; - signed char *buffer; - int nread; - - buffer = (signed char *)G_malloc(n * 2); - if (!buffer) - return 0; - nread = read(f, buffer, n * 2); - if (nread <= 0) - return 0; - nread /= 2; - for (i = 0; i < nread; i++) { - /* don't forget about sign extension! */ - iarray[i] = (buffer[i * 2] * 256) | buffer[i * 2 + 1]; - } - G_free(buffer); - return nread; -#else int nread = read(f, iarray, n * 2); if (nread <= 0) @@ -274,7 +114,6 @@ int read_int2_array(int f, short *iarray, int n) flip2((const unsigned short *)iarray, (unsigned short *)iarray, nread / 2); #endif return nread / 2; -#endif } /* @@ -286,24 +125,6 @@ int read_int2_array(int f, short *iarray, int n) */ int read_uint2_array(int f, unsigned short *iarray, int n) { -#ifdef _CRAY - int i; - unsigned char *buffer; - int nread; - - buffer = (unsigned char *)G_malloc(n * 2); - if (!buffer) - return 0; - nread = read(f, buffer, n * 2); - if (nread <= 0) - return 0; - nread /= 2; - for (i = 0; i < nread; i++) { - iarray[i] = (buffer[i * 2] << 8) | buffer[i * 2 + 1]; - } - G_free(buffer); - return nread; -#else int nread = read(f, iarray, n * 2); if (nread <= 0) @@ -312,7 +133,6 @@ int read_uint2_array(int f, unsigned short *iarray, int n) flip2(iarray, iarray, nread / 2); #endif return nread / 2; -#endif } /* @@ -336,9 +156,6 @@ int read_int4(int f, int *i) } #else if (read(f, i, 4) == 4) { -#ifdef _CRAY - *i = *i >> 32; -#endif return 1; } else { @@ -356,30 +173,6 @@ int read_int4(int f, int *i) */ int read_int4_array(int f, int *iarray, int n) { -#ifdef _CRAY - int j, nread; - int *buffer; - - buffer = (int *)G_malloc((n + 1) * 4); - if (!buffer) - return 0; - nread = read(f, buffer, 4 * n); - if (nread <= 0) { - return 0; - } - nread /= 4; - - for (j = 0; j < nread; j++) { - if ((j & 1) == 0) { - iarray[j] = buffer[j / 2] >> 32; - } - else { - iarray[j] = buffer[j / 2] & 0xffffffff; - } - } - G_free(buffer); - return nread; -#else int nread = read(f, iarray, 4 * n); if (nread <= 0) @@ -388,7 +181,6 @@ int read_int4_array(int f, int *iarray, int n) flip4((const unsigned int *)iarray, (unsigned int *)iarray, nread / 4); #endif return nread / 4; -#endif } /* @@ -399,16 +191,6 @@ int read_int4_array(int f, int *iarray, int n) */ int read_float4(int f, float *x) { -#ifdef _CRAY - long buffer = 0; - - if (read(f, &buffer, 4) == 4) { - /* convert IEEE float (buffer) to Cray float (x) */ - if_to_c((long *)x, &buffer); - return 1; - } - return 0; -#else #ifdef LITTLE unsigned int n, *iptr; @@ -428,7 +210,6 @@ int read_float4(int f, float *x) return 0; } #endif -#endif } /* @@ -440,22 +221,6 @@ int read_float4(int f, float *x) */ int read_float4_array(int f, float *x, int n) { -#ifdef _CRAY - /* read IEEE floats into buffer, then convert to Cray format */ - long *buffer; - int i, nread; - - buffer = (long *)G_malloc((n + 1) * 4); - if (!buffer) - return 0; - nread = read(f, buffer, n * 4); - if (nread <= 0) - return 0; - nread /= 4; - ieee_to_cray_array(x, buffer, nread); - G_free(buffer); - return nread; -#else int nread = read(f, x, 4 * n); if (nread <= 0) @@ -464,7 +229,6 @@ int read_float4_array(int f, float *x, int n) flip4((const unsigned int *)x, (unsigned int *)x, nread / 4); #endif return nread / 4; -#endif } /* @@ -541,10 +305,6 @@ int write_bytes(int f, const void *b, int n) */ int write_int2_array(int f, const short *iarray, int n) { -#ifdef _CRAY - printf("write_int2_array not implemented!\n"); - exit(1); -#else int nwritten; #ifdef LITTLE @@ -557,7 +317,6 @@ int write_int2_array(int f, const short *iarray, int n) if (nwritten <= 0) return 0; return nwritten / 2; -#endif } /* @@ -569,24 +328,6 @@ int write_int2_array(int f, const short *iarray, int n) */ int write_uint2_array(int f, const unsigned short *iarray, int n) { -#ifdef _CRAY - int i, nwritten; - unsigned char *buffer; - - buffer = (unsigned char *)G_malloc(2 * n); - if (!buffer) - return 0; - for (i = 0; i < n; i++) { - buffer[i * 2] = (iarray[i] >> 8) & 0xff; - buffer[i * 2 + 1] = iarray[i] & 0xff; - } - nwritten = write(f, buffer, 2 * n); - G_free(buffer); - if (nwritten <= 0) - return 0; - else - return nwritten / 2; -#else int nwritten; #ifdef LITTLE @@ -600,7 +341,6 @@ int write_uint2_array(int f, const unsigned short *iarray, int n) return 0; else return nwritten / 2; -#endif } /* @@ -611,15 +351,10 @@ int write_uint2_array(int f, const unsigned short *iarray, int n) */ int write_int4(int f, int i) { -#ifdef _CRAY - i = i << 32; - return write(f, &i, 4) > 0; -#else #ifdef LITTLE i = FLIP4(i); #endif return write(f, &i, 4) > 0; -#endif } /* @@ -631,28 +366,6 @@ int write_int4(int f, int i) */ int write_int4_array(int f, const int *i, int n) { -#ifdef _CRAY - int j, nwritten; - char *buf, *b, *ptr; - - b = buf = (char *)G_malloc(n * 4 + 8); - if (!b) - return 0; - ptr = (char *)i; - for (j = 0; j < n; j++) { - ptr += 4; /* skip upper 4 bytes */ - *b++ = *ptr++; - *b++ = *ptr++; - *b++ = *ptr++; - *b++ = *ptr++; - } - nwritten = write(f, buf, 4 * n); - G_free(buf); - if (nwritten <= 0) - return 0; - else - return nwritten / 4; -#else #ifdef LITTLE int nwritten; @@ -666,7 +379,6 @@ int write_int4_array(int f, const int *i, int n) #else return write(f, i, 4 * n) / 4; #endif -#endif } /* @@ -677,12 +389,6 @@ int write_int4_array(int f, const int *i, int n) */ int write_float4(int f, float x) { -#ifdef _CRAY - char buffer[8]; - - c_to_if((long *)buffer, (const long *)&x); - return write(f, buffer, 4) > 0; -#else #ifdef LITTLE float y; unsigned int *iptr = (unsigned int *)&y, temp; @@ -696,7 +402,6 @@ int write_float4(int f, float x) y = (float)x; return write(f, &y, 4) > 0; #endif -#endif } /* @@ -708,22 +413,6 @@ int write_float4(int f, float x) */ int write_float4_array(int f, const float *x, int n) { -#ifdef _CRAY - /* convert cray floats to IEEE and put into buffer */ - int nwritten; - long *buffer; - - buffer = (long *)G_malloc(n * 4 + 8); - if (!buffer) - return 0; - cray_to_ieee_array(buffer, x, n); - nwritten = write(f, buffer, 4 * n); - G_free(buffer); - if (nwritten <= 0) - return 0; - else - return nwritten / 4; -#else #ifdef LITTLE int nwritten; @@ -737,7 +426,6 @@ int write_float4_array(int f, const float *x, int n) #else return write(f, x, 4 * n) / 4; #endif -#endif } /* diff --git a/raster3d/r3.out.v5d/binio.h b/raster3d/r3.out.v5d/binio.h index f987e3cf64b..e6a80d8a9db 100644 --- a/raster3d/r3.out.v5d/binio.h +++ b/raster3d/r3.out.v5d/binio.h @@ -37,11 +37,6 @@ extern void flip4(const unsigned int *src, unsigned int *dest, int n); extern void flip2(const unsigned short *src, unsigned short *dest, int n); -#ifdef _CRAY -extern void cray_to_ieee_array(long *dest, const float *source, int n); -extern void ieee_to_cray_array(float *dest, const long *source, int n); -#endif - /**********************************************************************/ /***** Read Functions *****/ diff --git a/raster3d/r3.out.v5d/v5d.c b/raster3d/r3.out.v5d/v5d.c index a68fe75928e..f44bbc1a86a 100644 --- a/raster3d/r3.out.v5d/v5d.c +++ b/raster3d/r3.out.v5d/v5d.c @@ -49,13 +49,6 @@ * values are in IEEE format. */ -/* - * Updates: - * - * April 13, 1995, brianp - * finished Cray support for 2-byte and 4-byte compress modes - */ - #include #include #include @@ -719,21 +712,6 @@ void v5dCompressGrid(int nr, int nc, int nl, int compressmode, else { one_over_a = 1.0 / ga[lev]; } -#ifdef _CRAY - /* this is tricky because sizeof(V5Dushort)==8, not 2 */ - for (i = 0; i < nrnc; i++, p++) { - V5Dushort compvalue; - - if (IS_MISSING(data[p])) { - compvalue = 65535; - } - else { - compvalue = (V5Dushort)(int)((data[p] - b) * one_over_a); - } - compdata1[p * 2 + 0] = compvalue >> 8; /* upper byte */ - compdata1[p * 2 + 1] = compvalue & 0xffu; /* lower byte */ - } -#else for (i = 0; i < nrnc; i++, p++) { if (IS_MISSING(data[p])) { compdata2[p] = 65535; @@ -743,20 +721,14 @@ void v5dCompressGrid(int nr, int nc, int nl, int compressmode, } } /* TODO: byte-swapping on little endian??? */ -#endif } } else { /* compressmode==4 */ -#ifdef _CRAY - cray_to_ieee_array(compdata, data, nrncnl); -#else - /* other machines: just copy 4-byte IEEE floats */ assert(sizeof(float) == 4); memcpy(compdata, data, nrncnl * 4); /* TODO: byte-swapping on little endian??? */ -#endif } } @@ -832,20 +804,6 @@ void v5dDecompressGrid(int nr, int nc, int nl, int compressmode, void *compdata, float a = ga[lev]; float b = gb[lev]; -#ifdef _CRAY - /* this is tricky because sizeof(V5Dushort)==8, not 2 */ - for (i = 0; i < nrnc; i++, p++) { - int compvalue; - - compvalue = (compdata1[p * 2] << 8) | compdata1[p * 2 + 1]; - if (compvalue == 65535) { - data[p] = MISSING; - } - else { - data[p] = (float)compvalue * a + b; - } - } -#else /* sizeof(V5Dushort)==2! */ for (i = 0; i < nrnc; i++, p++) { if (compdata2[p] == 65535) { @@ -855,19 +813,13 @@ void v5dDecompressGrid(int nr, int nc, int nl, int compressmode, void *compdata, data[p] = (float)(int)compdata2[p] * a + b; } } -#endif } } else { /* compressmode==4 */ -#ifdef _CRAY - ieee_to_cray_array(data, compdata, nrncnl); -#else - /* other machines: just copy 4-byte IEEE floats */ assert(sizeof(float) == 4); memcpy(data, compdata, nrncnl * 4); -#endif } } @@ -2687,11 +2639,7 @@ int v5dClose(void) #ifdef UNDERSCORE int v5dcreate_ #else -#ifdef _CRAY -int V5DCREATE -#else int v5dcreate -#endif #endif (const char *name, const int *numtimes, const int *numvars, const int *nr, @@ -2850,11 +2798,7 @@ int v5dcreate #ifdef UNDERSCORE int v5dcreatesimple_ #else -#ifdef _CRAY -int V5DCREATESIMPLE -#else int v5dcreatesimple -#endif #endif (const char *name, const int *numtimes, const int *numvars, const int *nr, @@ -2887,12 +2831,7 @@ int v5dcreatesimple #ifdef UNDERSCORE return v5dcreate_ #else -#ifdef _CRAY - return V5DCREATE -#else - return v5dcreate -#endif #endif (name, numtimes, numvars, nr, nc, varnl, varname, timestamp, datestamp, &compressmode, &projection, projarg, &vertical, vertarg); @@ -2906,11 +2845,7 @@ int v5dcreatesimple #ifdef UNDERSCORE int v5dsetlowlev_ #else -#ifdef _CRAY -int V5DSETLOWLEV -#else int v5dsetlowlev -#endif #endif (int *lowlev) { @@ -2926,11 +2861,7 @@ int v5dsetlowlev #ifdef UNDERSCORE int v5dsetunits_ #else -#ifdef _CRAY -int V5DSETUNITS -#else int v5dsetunits -#endif #endif (int *var, char *name) { @@ -2947,11 +2878,7 @@ int v5dsetunits #ifdef UNDERSCORE int v5dwrite_ #else -#ifdef _CRAY -int V5DWRITE -#else int v5dwrite -#endif #endif (const int *time, const int *var, const float *data) { @@ -2968,11 +2895,7 @@ int v5dwrite #ifdef UNDERSCORE int v5dmcfile_ #else -#ifdef _CRAY -int V5DMCFILE -#else int v5dmcfile -#endif #endif (const int *time, const int *var, const int *mcfile, const int *mcgrid) { @@ -2996,12 +2919,8 @@ int v5dmcfile #ifdef UNDERSCORE int v5dclose_(void) #else -#ifdef _CRAY -int V5DCLOSE(void) -#else int v5dclose(void) #endif -#endif { return v5dClose(); } diff --git a/raster3d/r3.out.v5d/v5d.h b/raster3d/r3.out.v5d/v5d.h index b7675d8b501..d027d85011d 100644 --- a/raster3d/r3.out.v5d/v5d.h +++ b/raster3d/r3.out.v5d/v5d.h @@ -43,8 +43,8 @@ * Define our own 1 and 2-byte data types. We use these names to avoid * collisions with types defined by the OS include files. */ -typedef unsigned char V5Dubyte; /* Must be 1 byte, except for cray */ -typedef unsigned short V5Dushort; /* Must be 2 byte, except for cray */ +typedef unsigned char V5Dubyte; /* Must be 1 byte */ +typedef unsigned short V5Dushort; /* Must be 2 byte */ #define MISSING 1.0e35 #define IS_MISSING(X) ((X) >= 1.0e30) diff --git a/rpm/grass.spec b/rpm/grass.spec index 90c79bc939f..3e4675db621 100644 --- a/rpm/grass.spec +++ b/rpm/grass.spec @@ -1,8 +1,8 @@ -%global shortver 83 +%global shortver 84 %global macrosdir %(d=%{_rpmconfigdir}/macros.d; [ -d $d ] || d=%{_sysconfdir}/rpm; echo $d) Name: grass -Version: 8.3.0 +Version: 8.4.0 Release: 3%{?dist} Summary: GRASS GIS - Geographic Resources Analysis Support System @@ -37,64 +37,66 @@ BuildRequires: flexiblas-devel %else BuildRequires: blas-devel, lapack-devel %endif +BuildRequires: bzip2-devel BuildRequires: cairo-devel -BuildRequires: gcc-c++ BuildRequires: desktop-file-utils BuildRequires: fftw-devel BuildRequires: flex BuildRequires: freetype-devel +BuildRequires: gcc-c++ BuildRequires: gdal-devel BuildRequires: geos-devel BuildRequires: gettext BuildRequires: laszip-devel BuildRequires: libappstream-glib BuildRequires: libpng-devel +%if 0%{?rhel} && 0%{?rhel} == 7 +BuildRequires: postgresql-devel +%else +BuildRequires: libpq-devel +%endif BuildRequires: libtiff-devel BuildRequires: libXmu-devel -BuildRequires: mesa-libGL-devel -BuildRequires: mesa-libGLU-devel +BuildRequires: libzstd-devel +BuildRequires: make %if (0%{?rhel} > 7 || 0%{?fedora}) BuildRequires: mariadb-connector-c-devel openssl-devel %else BuildRequires: mysql-devel %endif +BuildRequires: mesa-libGL-devel +BuildRequires: mesa-libGLU-devel BuildRequires: netcdf-devel +BuildRequires: PDAL +BuildRequires: PDAL-devel +BuildRequires: PDAL-libs +BuildRequires: proj-devel BuildRequires: python3 %if 0%{?rhel} == 7 # EPEL7 -BuildRequires: python%{python3_version_nodots}-numpy -%else -BuildRequires: python3-numpy -%endif -%if 0%{?rhel} && 0%{?rhel} == 7 -BuildRequires: postgresql-devel +BuildRequires: python%{python3_version_nodots}-dateutil %else -BuildRequires: libpq-devel +BuildRequires: python3-dateutil %endif -BuildRequires: proj-devel +BuildRequires: python3-devel %if 0%{?rhel} == 7 # EPEL7 -BuildRequires: python%{python3_version_nodots}-dateutil +BuildRequires: python%{python3_version_nodots}-numpy %else -BuildRequires: python3-dateutil +BuildRequires: python3-numpy %endif -BuildRequires: python3-devel BuildRequires: python3-pillow -BuildRequires: PDAL -BuildRequires: PDAL-libs -BuildRequires: PDAL-devel BuildRequires: readline-devel BuildRequires: sqlite-devel BuildRequires: subversion BuildRequires: unixODBC-devel BuildRequires: zlib-devel -BuildRequires: bzip2-devel -BuildRequires: libzstd-devel -BuildRequires: make Requires: bzip2-libs -Requires: libzstd Requires: geos +Requires: libzstd +Requires: PDAL +Requires: PDAL-libs # fedora >= 34: Nothing %if (0%{?rhel} > 7 || 0%{?fedora} < 34) Requires: proj-datumgrid @@ -103,26 +105,23 @@ Requires: proj-datumgrid-world Requires: python3 %if 0%{?rhel} == 7 # EPEL7 -Requires: python%{python3_version_nodots}-numpy +Requires: python%{python3_version_nodots}-dateutil %else -Requires: python3-numpy +Requires: python3-dateutil %endif %if 0%{?rhel} == 7 # EPEL7 -Requires: python%{python3_version_nodots}-dateutil +Requires: python%{python3_version_nodots}-numpy %else -Requires: python3-dateutil +Requires: python3-numpy %endif Requires: python3-wxpython4 -Requires: PDAL -Requires: PDAL-libs %if "%{_lib}" == "lib" %global cpuarch 32 %else %global cpuarch 64 %endif - Requires: %{name}-libs%{?_isa} = %{version}-%{release} %description @@ -170,47 +169,50 @@ find -name \*.pl | xargs sed -i -e 's,#!/usr/bin/env perl,#!%{__perl},' %build %configure \ --prefix=%{_libdir} \ - --with-cxx \ - --with-tiff \ - --with-png \ - --with-postgres \ -%if 0%{?rhel} > 7 - --with-mysql=no \ -%else - --with-mysql \ -%endif - --with-opengl \ - --with-odbc \ - --with-fftw \ --with-blas \ - --with-lapack \ %if %{with flexiblas} --with-blas-includes=%{_includedir}/flexiblas \ - --with-lapack-includes=%{_includedir}/flexiblas \ %endif + --with-bzlib \ --with-cairo \ + --with-cairo-ldflags=-lfontconfig \ + --with-cxx \ + --with-fftw \ --with-freetype \ - --with-nls \ - --with-pdal \ - --with-readline \ - --with-regex \ - --with-openmp \ + --with-freetype-includes=%{_includedir}/freetype2 \ --with-gdal=%{_bindir}/gdal-config \ - --with-wxwidgets=%{_bindir}/wx-config \ --with-geos=%{_bindir}/geos-config \ - --with-netcdf=%{_bindir}/nc-config \ + --with-lapack \ +%if %{with flexiblas} + --with-lapack-includes=%{_includedir}/flexiblas \ +%endif +%if 0%{?rhel} > 7 + --with-mysql=no \ +%else + --with-mysql \ +%endif --with-mysql-includes=%{_includedir}/mysql \ %if (0%{?fedora} >= 27) --with-mysql-libs=%{_libdir} \ %else --with-mysql-libs=%{_libdir}/mysql \ %endif + --with-netcdf=%{_bindir}/nc-config \ + --with-nls \ + --with-odbc \ + --with-opengl \ + --with-openmp \ + --with-pdal \ + --with-png \ + --with-postgres \ --with-postgres-includes=%{_includedir}/pgsql \ - --with-cairo-ldflags=-lfontconfig \ - --with-freetype-includes=%{_includedir}/freetype2 \ - --with-bzlib \ - --with-zstd \ - --with-proj-share=%{_datadir}/proj + --with-proj-share=%{_datadir}/proj \ + --with-readline \ + --with-regex \ + --with-tiff \ + --with-wxwidgets=%{_bindir}/wx-config \ + --with-zstd + # .package_note hack for RHBZ #2084342 and RHBZ #2102895 sed -i "s+ -Wl,-dT,${RPM_BUILD_DIR}/grass-%{version}/.package_note-grass-%{version}-%{release}.%{_arch}.ld++g" include/Make/Platform.make @@ -338,6 +340,48 @@ fi %{_libdir}/%{name}%{shortver}/include %changelog +* Sat Oct 26 2024 Markus Neteler - 8.4.0-3 +- Sort requirements and flags (https://github.com/OSGeo/grass/pull/4563/ by Edouard Choinière) + +* Fri Sep 06 2024 Sandro Mani - 8.4.0-2 +- Rebuild (PDAL) + +* Sun Jul 28 2024 Markus Neteler - 8.4.0-1 +- Update to 8.4.0 + +* Thu Jul 18 2024 Fedora Release Engineering - 8.3.2-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Tue May 14 2024 Sandro Mani - 8.3.2-3 +- Rebuild (gdal) + +* Tue Mar 19 2024 Sandro Mani - 8.3.2-2 +- Rebuild (PDAL) + +* Thu Mar 07 2024 Markus Neteler - 8.3.2-1 +- Update to 8.3.2 (#2268514) + +* Wed Jan 24 2024 Fedora Release Engineering - 8.3.1-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sat Jan 20 2024 Fedora Release Engineering - 8.3.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Wed Jan 3 2024 Florian Weimer - 8.3.1-4 +- Fix C compatibility issue in MySQL port handling + +* Wed Nov 15 2023 Sandro Mani - 8.3.1-3 +- Rebuild (gdal) + +* Sat Oct 28 2023 Markus Neteler 8.3.1-2 +- fix obsolete configure parameters + +* Thu Oct 26 2023 Fedora Release Monitoring - 8.3.1-1 +- Update to GRASS GIS 8.3.1 (#2246359) + +* Sat Oct 14 2023 Sandro Mani - 8.3.0-4 +- Rebuild (PDAL) + * Sun Aug 06 2023 Alexandre Detiste - 8.3.0-3 - Remove support for RHEL6: Grass is now Python3 only diff --git a/scripts/d.correlate/d.correlate.py b/scripts/d.correlate/d.correlate.py index 1068733a11b..af0f1840356 100755 --- a/scripts/d.correlate/d.correlate.py +++ b/scripts/d.correlate/d.correlate.py @@ -54,7 +54,7 @@ def main(): os.environ["GRASS_RENDER_FILE_READ"] = "TRUE" - colors = "red black blue green gray violet".split() + colors = ["red", "black", "blue", "green", "gray", "violet"] line = 2 iloop = 0 jloop = 0 diff --git a/scripts/db.dropcolumn/db.dropcolumn.py b/scripts/db.dropcolumn/db.dropcolumn.py index 24681b18b23..e038deda38a 100755 --- a/scripts/db.dropcolumn/db.dropcolumn.py +++ b/scripts/db.dropcolumn/db.dropcolumn.py @@ -102,7 +102,8 @@ def main(): driver=driver, ).split(".")[0:2] - if [int(i) for i in sqlite3_version] >= [int(i) for i in "3.35".split(".")]: + # sqlite version 3.35 compared here + if [int(i) for i in sqlite3_version] >= [int(i) for i in ["3", "35"]]: sql = "ALTER TABLE %s DROP COLUMN %s" % (table, column) if column == "cat": sql = "DROP INDEX %s_%s; %s" % (table, column, sql) diff --git a/scripts/db.out.ogr/db.out.ogr.py b/scripts/db.out.ogr/db.out.ogr.py index 4fdfed23648..4fe5b4f9854 100755 --- a/scripts/db.out.ogr/db.out.ogr.py +++ b/scripts/db.out.ogr/db.out.ogr.py @@ -67,7 +67,6 @@ def main(): layer = options["layer"] format = options["format"] output = options["output"] - table = options["table"] if format.lower() == "dbf": format = "ESRI_Shapefile" diff --git a/scripts/r.in.wms/srs.py b/scripts/r.in.wms/srs.py index 8d996fcde94..752f71d8151 100644 --- a/scripts/r.in.wms/srs.py +++ b/scripts/r.in.wms/srs.py @@ -79,7 +79,7 @@ def __init__(self, srs): # code is always the last value try: self.code = int(values[-1]) - except: + except (IndexError, ValueError): self.code = values[-1] elif len(values) == 2: # it's an authority:code code diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index e825aabe438..f5e8cbeb914 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -18,13 +18,13 @@ """ import socket -import grass.script as gs - from time import sleep +import grass.script as gs + try: from osgeo import gdal -except: +except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package 'python-gdal' " @@ -32,21 +32,16 @@ ) ) -import numpy as np - -np.arrayrange = np.arange - -from math import pi, floor - -from urllib.error import HTTPError from http.client import HTTPException - +from math import floor, pi +from urllib.error import HTTPError from xml.etree.ElementTree import ParseError -from wms_base import GetEpsg, GetSRSParamVal, WMSBase +import numpy as np -from wms_cap_parsers import WMTSCapabilitiesTree, OnEarthCapabilitiesTree from srs import Srs +from wms_base import GetEpsg, GetSRSParamVal, WMSBase +from wms_cap_parsers import OnEarthCapabilitiesTree, WMTSCapabilitiesTree class WMSDrv(WMSBase): @@ -291,9 +286,9 @@ def _pct2rgb(self, src_filename, dst_filename): # Build color table lookup = [ - np.arrayrange(256), - np.arrayrange(256), - np.arrayrange(256), + np.arange(256), + np.arange(256), + np.arange(256), np.ones(256) * 255, ] diff --git a/scripts/r.in.wms/wms_gdal_drv.py b/scripts/r.in.wms/wms_gdal_drv.py index 830be2b593e..869f71195a2 100644 --- a/scripts/r.in.wms/wms_gdal_drv.py +++ b/scripts/r.in.wms/wms_gdal_drv.py @@ -17,7 +17,7 @@ try: from osgeo import gdal -except: +except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package 'python-gdal' being " diff --git a/scripts/v.import/v.import.py b/scripts/v.import/v.import.py index 4f579c4bf45..1e467cd190b 100755 --- a/scripts/v.import/v.import.py +++ b/scripts/v.import/v.import.py @@ -263,7 +263,7 @@ def main(): if OGRdatasource.lower().endswith("gml"): try: from osgeo import gdal - except: + except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package " @@ -338,7 +338,7 @@ def main(): if OGRdatasource.lower().endswith("gml"): try: from osgeo import gdal - except: + except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package " diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index 29d9d3c914e..80e9e8a1189 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -224,7 +224,7 @@ def main(): # calculate percentages records4 = [float(r[-1]) * 100 / total for r in records3] - if type(records1[0]) == int: + if isinstance(records1[0], int): records3 = [[r1] + [r4] for r1, r4 in zip(records1, records4)] else: records3 = [r1 + [r4] for r1, r4 in zip(records1, records4)] diff --git a/scripts/v.unpack/v.unpack.py b/scripts/v.unpack/v.unpack.py index c3a7a55deb7..7baa1042ccd 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -77,7 +77,7 @@ def main(): tar = tarfile.TarFile.open(name=input_base, mode="r") try: data_name = tar.getnames()[0] - except: + except IndexError: grass.fatal(_("Pack file unreadable")) if flags["p"]: diff --git a/singularity/debian/singularityfile_debian b/singularity/debian/singularityfile_debian index 267d7a74ad5..5858bec6911 100644 --- a/singularity/debian/singularityfile_debian +++ b/singularity/debian/singularityfile_debian @@ -17,8 +17,8 @@ Singularity container for GRASS GIS to be run into GRASS main directory # Install useful libraries apt-get -y update apt-get -y install \ - build-essential \ bison \ + build-essential \ bzip2 \ cmake \ curl \ @@ -40,10 +40,10 @@ Singularity container for GRASS GIS to be run into GRASS main directory libgsl-dev \ libjpeg-dev \ libjsoncpp-dev \ + libncurses5-dev \ + libnetcdf-dev \ libopenblas-base \ libopenblas-dev \ - libnetcdf-dev \ - libncurses5-dev \ libopenjp2-7 \ libopenjp2-7-dev \ libpdal-dev \ @@ -94,29 +94,29 @@ Singularity container for GRASS GIS to be run into GRASS main directory GRASS_PYTHON=/usr/bin/python3 ./configure \ --enable-largefile \ - --with-cxx \ - --with-nls \ - --with-readline \ - --with-sqlite \ --with-bzlib \ - --with-zstd \ --with-cairo \ --with-cairo-ldflags=-lfontconfig \ + --with-cxx \ + --with-fftw \ --with-freetype \ --with-freetype-includes="/usr/include/freetype2/" \ - --with-fftw \ + --with-geos=/usr/bin/geos-config \ --with-netcdf \ + --with-nls \ --with-pdal \ - --with-proj \ - --with-proj-share=/usr/share/proj \ - --with-geos=/usr/bin/geos-config \ --with-postgres \ --with-postgres-includes="/usr/include/postgresql" \ + --with-proj \ + --with-proj-share=/usr/share/proj \ + --with-readline \ + --with-sqlite \ + --with-zstd \ + --without-ffmpeg \ --without-mysql \ --without-odbc \ - --without-openmp \ - --without-ffmpeg \ - --without-opengl + --without-opengl \ + --without-openmp make -j 2 && make install && ldconfig # Create generic GRASS GIS binary name regardless of version number ln -sf `find /usr/local/bin -name "grass??" | sort | tail -n 1` /usr/local/bin/grass diff --git a/temporal/t.rast.univar/t.rast.univar.py b/temporal/t.rast.univar/t.rast.univar.py index bd199f9e801..dbc2a31ab4d 100755 --- a/temporal/t.rast.univar/t.rast.univar.py +++ b/temporal/t.rast.univar/t.rast.univar.py @@ -91,7 +91,6 @@ # %rules # % requires: percentile,-e -# % exclusive: zones,-r # %end import grass.script as gs @@ -130,9 +129,7 @@ def main(): # Make sure the temporal database exists tgis.init() - if not output: - output = None - if output == "-": + if not output or output == "-": output = None # Check if zones map exists and is of type CELL diff --git a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py index 83e5c2d6229..7bdfe9f7f6a 100644 --- a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py +++ b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py @@ -348,6 +348,45 @@ def test_with_zones(self): a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|1|400|400|400|400|0|0|0|240000|0|600|600 a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|2|400|400|400|400|0|0|0|672000|0|1680|1680 a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|3|400|400|400|400|0|0|0|2928000|0|7320|7320 +""" + + for ref, res in zip( + univar_text.split("\n"), t_rast_univar.outputs.stdout.split("\n") + ): + if ref and res: + ref_line = ref.split("|", 1)[1] + res_line = res.split("|", 1)[1] + self.assertLooksLike(ref_line, res_line) + + @xfail_windows + def test_with_zones_and_r(self): + """Test use of zones and r-flag""" + + t_rast_univar = SimpleModule( + "t.rast.univar", + flags="r", + input="A", + where="start_time >= '2001-01-01'", + zones="zones", + overwrite=True, + verbose=True, + ) + self.runModule("g.region", **self.default_region, res=1) + self.assertModule(t_rast_univar) + + univar_text = """id|semantic_label|start|end|zone|mean|min|max|mean_of_abs|stddev|variance|coeff_var|sum|null_cells|cells|non_null_cells +a_1@PERMANENT||2001-01-01 00:00:00|2001-04-01 00:00:00|1|100|100|100|100|0|0|0|60000|0|600|600 +a_1@PERMANENT||2001-01-01 00:00:00|2001-04-01 00:00:00|2|100|100|100|100|0|0|0|168000|0|1680|1680 +a_1@PERMANENT||2001-01-01 00:00:00|2001-04-01 00:00:00|3|100|100|100|100|0|0|0|732000|0|7320|7320 +a_2@PERMANENT||2001-04-01 00:00:00|2001-07-01 00:00:00|1|200|200|200|200|0|0|0|120000|0|600|600 +a_2@PERMANENT||2001-04-01 00:00:00|2001-07-01 00:00:00|2|200|200|200|200|0|0|0|336000|0|1680|1680 +a_2@PERMANENT||2001-04-01 00:00:00|2001-07-01 00:00:00|3|200|200|200|200|0|0|0|1464000|0|7320|7320 +a_3@PERMANENT||2001-07-01 00:00:00|2001-10-01 00:00:00|1|300|300|300|300|0|0|0|180000|0|600|600 +a_3@PERMANENT||2001-07-01 00:00:00|2001-10-01 00:00:00|2|300|300|300|300|0|0|0|504000|0|1680|1680 +a_3@PERMANENT||2001-07-01 00:00:00|2001-10-01 00:00:00|3|300|300|300|300|0|0|0|2196000|0|7320|7320 +a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|1|400|400|400|400|0|0|0|240000|0|600|600 +a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|2|400|400|400|400|0|0|0|672000|0|1680|1680 +a_4@PERMANENT||2001-10-01 00:00:00|2002-01-01 00:00:00|3|400|400|400|400|0|0|0|2928000|0|7320|7320 """ for ref, res in zip( diff --git a/utils/svn_name_git_author.csv b/utils/svn_name_git_author.csv index 4811a539a82..ba1ac70d21d 100644 --- a/utils/svn_name_git_author.csv +++ b/utils/svn_name_git_author.csv @@ -130,7 +130,6 @@ paul,Paul Kelly pcav,Paolo Cavallini pesekon2,Ondřej Pešek pierreroudier,Pierre Roudier -rodrigopitanga,Rodrigo Rodrigues Da Silva pkelly,Paul Kelly pmarcondes,Paulo Marcondes @@ -146,6 +145,7 @@ robertomarzocchi,Roberto Marzocchi roberto,Roberto Flor roberto,Roberto Micarelli Robifag,Roberta Fagandini +rodrigopitanga,Rodrigo Rodrigues Da Silva roger,Roger S. Miller rorschach,Ben Hur sbl,Stefan Blumentrath diff --git a/utils/svn_name_github_name.csv b/utils/svn_name_github_name.csv index 55504c24d67..97f0f859267 100644 --- a/utils/svn_name_github_name.csv +++ b/utils/svn_name_github_name.csv @@ -1,56 +1,56 @@ svn_name,github_name 1gray,1gray aghisla,aghisla -benjamin,benducke +annakrat,petrasovaa +barton,cmbarton benducke,benducke +benjamin,benducke bernhard,bernhardreiter -cnielsen,cdwren -pvanbosgeo,ecodiv -radim,blazek -barton,cmbarton -cmbarton,cmbarton -michael,cmbarton -mic,zwischenloesung -maciej,czka -msieczka,czka +cepicky,jachym +chemin,YannChemin +cho,HuidaeCho clements,glynnc +cmbarton,cmbarton +cnielsen,cdwren +frankw,warmerdam glynn,glynnc hamish,HamishB -hellik,hellik +hcho,HuidaeCho helena,hmitaso -soeren,huhabla +hellik,hellik huhabla,huhabla -cho,HuidaeCho -hcho,HuidaeCho +isaacullah,isaacullah jachym,jachym -cepicky,jachym -william,kyngchaos kyngchaos,kyngchaos landa,landam -martinl,landam ltoma,lauratoma lucadelu,lucadelu +maciej,czka madi,madi -mmetz,metzm +markus,neteler +martinl,landam +michael,cmbarton +mic,zwischenloesung mlennert,mlennert +mmetz,metzm moritz,mlennert -markus,neteler +msieczka,czka neteler,neteler nikosa,NikosAlexandris -sbl,ninsbl -turek,ostepok paulo,paulomarcondes -annakrat,petrasovaa +pvanbosgeo,ecodiv +radim,blazek rantolin,rantolin robertoa,rantolin +sbl,ninsbl sholl,sholl +soeren,huhabla stephan,sholl +turek,ostepok +ullah,isaacullah veroandreo,veroandreo -frankw,warmerdam warmerdam,warmerdam wenzeslaus,wenzeslaus -chemin,YannChemin +william,kyngchaos ychemin,YannChemin zarch,zarch -ullah,isaacullah -isaacullah,isaacullah diff --git a/utils/vagrant/compile.sh b/utils/vagrant/compile.sh index 058eb70b1f9..5e1abc01735 100755 --- a/utils/vagrant/compile.sh +++ b/utils/vagrant/compile.sh @@ -19,31 +19,31 @@ cd /vagrant if [ ! -f "include/Make/Platform.make" ] ; then ./configure \ --bindir=/usr/bin \ - --srcdir=/vagrant \ - --prefix=/usr/lib \ + --enable-largefile \ --enable-shared \ - --with-postgres \ - --with-mysql \ + --prefix=/usr/lib \ + --srcdir=/vagrant \ + --with-blas \ + --with-bzlib \ + --with-cairo \ --with-cxx \ - --with-x \ + --with-freetype \ + --with-freetype-includes=/usr/include/freetype2 \ --with-gdal \ --with-geos \ - --with-freetype \ - --with-readline \ + --with-lapack \ + --with-mysql \ + --with-mysql-includes=`mysql_config --include | sed -e 's/-I//'` \ + --with-netcdf \ --with-nls \ --with-odbc \ - --with-netcdf \ - --with-blas \ - --with-lapack \ - --with-sqlite \ - --enable-largefile \ - --with-freetype-includes=/usr/include/freetype2 \ + --with-postgres \ --with-postgres-includes=`pg_config --includedir` \ - --with-mysql-includes=`mysql_config --include | sed -e 's/-I//'` \ --with-proj-share=/usr/share/proj \ - --with-cairo \ --with-pthread \ - --with-bzlib \ + --with-readline \ + --with-sqlite \ + --with-x \ --without-pdal fi diff --git a/vector/v.delaunay/in_out.c b/vector/v.delaunay/in_out.c index 8cc62cd8a0e..51938859847 100644 --- a/vector/v.delaunay/in_out.c +++ b/vector/v.delaunay/in_out.c @@ -178,6 +178,8 @@ void output_triangles(unsigned int n, int mode3d UNUSED, int type, e = NEXT(e, u); } while (!SAME_EDGE(e, e_start)); } + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(Cats); } void remove_duplicates(unsigned int *size) diff --git a/vector/v.info/local_proto.h b/vector/v.info/local_proto.h index 1ed32468562..b1a7d5795cb 100644 --- a/vector/v.info/local_proto.h +++ b/vector/v.info/local_proto.h @@ -19,7 +19,8 @@ void parse_args(int, char **, char **, char **, int *, int *, int *, void format_double(double, char *); void print_region(struct Map_info *, enum OutputFormat, JSON_Object *); void print_topo(struct Map_info *, enum OutputFormat, JSON_Object *); -void print_columns(struct Map_info *, const char *, const char *); +void print_columns(struct Map_info *, const char *, const char *, + enum OutputFormat); void print_info(struct Map_info *); void print_shell(struct Map_info *, const char *, enum OutputFormat, JSON_Object *); diff --git a/vector/v.info/main.c b/vector/v.info/main.c index 6f4aa9a8fcf..ef1f5c44d06 100644 --- a/vector/v.info/main.c +++ b/vector/v.info/main.c @@ -54,11 +54,6 @@ int main(int argc, char *argv[]) parse_args(argc, argv, &input_opt, &field_opt, &hist_flag, &col_flag, &shell_flag, &format); - if (format == JSON) { - root_value = json_value_init_object(); - root_object = json_value_get_object(root_value); - } - /* try to open head-only on level 2 */ if (Vect_open_old_head2(&Map, input_opt, "", field_opt) < 2) { /* force level 1, open fully @@ -85,13 +80,18 @@ int main(int argc, char *argv[]) } } else if (col_flag) { - print_columns(&Map, input_opt, field_opt); + print_columns(&Map, input_opt, field_opt, format); } Vect_close(&Map); return (EXIT_SUCCESS); } + if (format == JSON) { + root_value = json_value_init_object(); + root_object = json_value_get_object(root_value); + } + if ((shell_flag & SHELL_BASIC) || format == JSON) { print_shell(&Map, field_opt, format, root_object); } diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 6c36d6391f6..ae913bf2e3d 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -176,7 +176,7 @@ void print_topo(struct Map_info *Map, enum OutputFormat format, } void print_columns(struct Map_info *Map, const char *input_opt, - const char *field_opt) + const char *field_opt, enum OutputFormat format) { int num_dblinks, col, ncols; @@ -189,6 +189,7 @@ void print_columns(struct Map_info *Map, const char *input_opt, num_dblinks = Vect_get_num_dblinks(Map); if (num_dblinks <= 0) { + Vect_close(Map); G_fatal_error( _("Database connection for map <%s> is not defined in DB file"), input_opt); @@ -198,32 +199,97 @@ void print_columns(struct Map_info *Map, const char *input_opt, "layer <%s>:"), field_opt); - if ((fi = Vect_get_field2(Map, field_opt)) == NULL) + if ((fi = Vect_get_field2(Map, field_opt)) == NULL) { + Vect_close(Map); G_fatal_error( _("Database connection not defined for layer <%s> of <%s>"), field_opt, input_opt); + } driver = db_start_driver(fi->driver); - if (driver == NULL) + if (driver == NULL) { + Vect_close(Map); G_fatal_error(_("Unable to open driver <%s>"), fi->driver); + } db_init_handle(&handle); db_set_handle(&handle, fi->database, NULL); - if (db_open_database(driver, &handle) != DB_OK) + if (db_open_database(driver, &handle) != DB_OK) { + db_shutdown_driver(driver); + Vect_close(Map); G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); + } db_init_string(&table_name); db_set_string(&table_name, fi->table); - if (db_describe_table(driver, &table_name, &table) != DB_OK) + if (db_describe_table(driver, &table_name, &table) != DB_OK) { + db_close_database_shutdown_driver(driver); + Vect_close(Map); G_fatal_error(_("Unable to describe table <%s>"), fi->table); + } + + JSON_Value *root_value = NULL, *columns_value = NULL, *column_value = NULL; + JSON_Object *root_object = NULL, *column_object = NULL; + JSON_Array *columns_array = NULL; + + if (format == JSON) { + root_value = json_value_init_object(); + root_object = json_object(root_value); + columns_value = json_value_init_array(); + columns_array = json_array(columns_value); + json_object_set_value(root_object, "columns", columns_value); + } ncols = db_get_table_number_of_columns(table); - for (col = 0; col < ncols; col++) - fprintf(stdout, "%s|%s\n", - db_sqltype_name( - db_get_column_sqltype(db_get_table_column(table, col))), + for (col = 0; col < ncols; col++) { + switch (format) { + case SHELL: + break; + + case JSON: + column_value = json_value_init_object(); + column_object = json_object(column_value); + + json_object_set_string( + column_object, "name", db_get_column_name(db_get_table_column(table, col))); - db_close_database(driver); - db_shutdown_driver(driver); + int sql_type = + db_get_column_sqltype(db_get_table_column(table, col)); + json_object_set_string(column_object, "sql_type", + db_sqltype_name(sql_type)); + + int c_type = db_sqltype_to_Ctype(sql_type); + json_object_set_boolean( + column_object, "is_number", + (c_type == DB_C_TYPE_INT || c_type == DB_C_TYPE_DOUBLE)); + + json_array_append_value(columns_array, column_value); + break; + + case PLAIN: + fprintf(stdout, "%s|%s\n", + db_sqltype_name( + db_get_column_sqltype(db_get_table_column(table, col))), + db_get_column_name(db_get_table_column(table, col))); + break; + } + } + + if (format == JSON) { + char *serialized_string = NULL; + serialized_string = json_serialize_to_string_pretty(root_value); + if (serialized_string == NULL) { + json_value_free(root_value); + db_close_database_shutdown_driver(driver); + Vect_close(Map); + G_fatal_error(_("Failed to initialize pretty JSON string.")); + } + puts(serialized_string); + json_free_serialized_string(serialized_string); + json_value_free(root_value); + } + + Vect_destroy_field_info(fi); + db_close_database_shutdown_driver(driver); } void print_shell(struct Map_info *Map, const char *field_opt, diff --git a/vector/v.info/testsuite/test_vinfo.py b/vector/v.info/testsuite/test_vinfo.py index c8183f76412..366859aebae 100644 --- a/vector/v.info/testsuite/test_vinfo.py +++ b/vector/v.info/testsuite/test_vinfo.py @@ -250,6 +250,27 @@ def test_json(self): result.pop(field) self.assertDictEqual(expected, result) + def test_json_column(self): + module = SimpleModule( + "v.info", map=self.test_vinfo_with_db_3d, format="json", flags="c" + ) + self.runModule(module) + + expected_json = { + "columns": [ + {"is_number": True, "name": "cat", "sql_type": "INTEGER"}, + { + "is_number": True, + "name": "elevation", + "sql_type": "DOUBLE PRECISION", + }, + ] + } + + result = json.loads(module.outputs.stdout) + + self.assertDictEqual(expected_json, result) + def test_database_table(self): """Test the database table column and type of the two vector maps with attribute data""" self.assertModuleKeyValue( diff --git a/vector/v.rectify/v.rectify.html b/vector/v.rectify/v.rectify.html index 6bfb8e628bf..a90eefef229 100644 --- a/vector/v.rectify/v.rectify.html +++ b/vector/v.rectify/v.rectify.html @@ -46,11 +46,12 @@

Coordinate transformation and RMSE

The desired order of transformation (1, 2, or 3) is selected with the order option. -v.rectify will calculate the RMSE if the -r flag is -given and print out statistcs in tabular format. The last row gives a -summary with the first column holding the number of active points, -followed by average deviations for each dimension and both forward and -backward transformation and finally forward and backward overall RMSE. +If the -r flag is given, v.rectify will calculate the +Root Mean Square Error (RMSE) and print out statistics in tabular format. +The last row gives a summary with the first column holding the number of +active points, followed by average deviations for each dimension and both +forward and backward transformation and finally forward and backward +overall RMSE.

2D linear affine transformation (1st order transformation)