diff --git a/.cppcheck-suppressions b/.cppcheck-suppressions new file mode 100644 index 00000000000..a02a60aa5aa --- /dev/null +++ b/.cppcheck-suppressions @@ -0,0 +1,173 @@ +# True positives +# imagery +invalidFunctionArg:imagery/i.gensigset/subcluster.c:369 +invalidFunctionArg:imagery/i.smap/model.c:158 + +# lib +memleakOnRealloc:lib/external/shapelib/dbfopen.c:448 +va_end_missing:lib/gis/debug.c:82 +nullPointer:lib/vector/Vlib/cats.c:513 +nullPointer:lib/vector/Vlib/cats.c:517 + +# False positives +# binder +syntaxError:binder/postBuild:7 + +# config.guess, config.log, config.status, config.sub, configure, configure.ac +syntaxError:config* + +# db +syntaxError:db/databaseintro.html + +# demolocation +syntaxError:demolocation/Makefile +syntaxError:demolocation/grassrc.tmpl + +# display +syntaxError:display/displaydrivers.html + +# dist.x86_64-pc-linux-gnu +syntaxError:dist.x86_64-pc-linux-gnu/* + +# doc +syntaxError:doc/* + +# docker +syntaxError:docker/README.md + +# general/g.version +internalAstError:general/g.version/main.c:49 +syntaxError:general/g.version/Makefile:8 +syntaxError:general/g.version/g.version.html:72 + +# imagery/ +syntaxError:imagery/imageryintro.html +## We are erroring out early if index is negative, so we won't be hitting this case! +negativeIndex:imagery/i.atcorr/computations.cpp:459 +negativeIndex:imagery/i.atcorr/computations.cpp:1025 + + +# include/ +syntaxError:include/Makefile +syntaxError:include/VERSION:1 + +# text files +syntaxError:INSTALL.md +syntaxError:install-sh +syntaxError:GPL.TXT +syntaxError:aclocal.m4 +syntaxError:AUTHORS +syntaxError:CITATION.cff +syntaxError:CITING +syntaxError:codecov.yaml +syntaxError:CODE_OF_CONDUCT.md +syntaxError:config.log +syntaxError:configure.ac +syntaxError:CONTRIBUTING.md +syntaxError:contributors.csv +syntaxError:contributors_extra.csv +syntaxError:COPYING +syntaxError:Dockerfile +syntaxError:error.log +syntaxError:flake.lock +syntaxError:flake.nix +syntaxError:grasslib.dox +syntaxError:grass.pc* +syntaxError:Makefile +syntaxError:package.nix +syntaxError:pyproject.toml +syntaxError:README.md +syntaxError:renovate.json5 +syntaxError:REQUIREMENTS.md +syntaxError:SECURITY.md +syntaxError:test_keyvalue_result.txt +syntaxError:TODO +syntaxError:translators.csv +syntaxError:Vagrantfile +syntaxError:binaryInstall.src +syntaxError:codecov.yml:19 + +# lib/ +syntaxError:lib/README:3 +# Internally generated file while compiling +nullPointer:lib/db/sqlp/sqlp.yy.c +nullPointer: +syntaxError:lib/db/sqlp/README +syntaxError:lib/db/sqlp/sql* +## va_copy() was used and it doesn't require va_start. +va_list_usedBeforeStarted:lib/gis/aprintf.c:293 +va_list_usedBeforeStarted:lib/gis/aprintf.c:301 +va_list_usedBeforeStarted:lib/gis/aprintf.c:348 +## Though it's not explicity initialized, the loop next will initialize it. So, it's alright to ignore this. +uninitvar:lib/vector/dglib/tavl.c:380 +missingReturn:lib/vector/dglib/nodemgmt-template.c:437 +## Though it's not explicity initialized, the loop next will initialize it. So, it's alright to ignore this. +uninitvar:lib/vector/dglib/avl.c:291 +unknownMacro:lib/bitmap/Makefile:13 +## I feel we can just avoid syntaxError issues, as code can't be compiled unless it's syntax is correct! +## And these usually have a tendency to pop up in the non-C or non-C++ programs!! +syntaxError:lib/* +unknownMacro:lib/gmath/Makefile +unknownMacro:lib/lidar/Makefile + + +# locale +syntaxError:locale/README.md +syntaxError:locale/Makefile +syntaxError:locale/grass_po_stats.py +unknownMacro:locale/* + +# macosx +syntaxError:macosx/* + +# man +syntaxError:man/* + +# mswindows +syntaxError:mswindows/* + +# raster +## FP error, as while loop before ensures that log argument is never equal to 1. +invalidFunctionArg:raster/r.sim/simlib/random.c:36 +invalidFunctionArg:raster/r.sim/simlib/random.c:57 + +## Different rules under different ifdef. +ctuOneDefinitionRuleViolation:raster/r.in.pdal/grassrasterwriter.h:39 +syntaxError:raster/rasterintro.html +syntaxError:raster/Makefile:155 + +# raster3d + +## 'missingReturn` error is mostly from blocks for local computations +missingReturn:raster3d/r3.showdspf/draw_cap_ogl.c:68 +missingReturn:raster3d/r3.showdspf/make_header.c:32 + +syntaxError:raster3d/raster3dintro.html:194 + +# rpm +syntaxError:rpm/grass.spec:244 +syntaxError:rpm/grass-pkgconfig.patch:9 + +# scripts +syntaxError:scripts/windows_sh_launch.bat:11 +syntaxError:scripts/windows_launch.bat:1 + +# temporal +syntaxError:temporal/benchmark.sh:19 +syntaxError:temporal/run_all_tests.sh +syntaxError:temporal/temporalintro.html + +# testsuite +syntaxError:testsuite/raster_md5test.sh:11 +syntaxError:testsuite/README.md:38 + +# utils +syntaxError:utils/* +unknownMacro:utils/coverage_mapper.py:13 +unknownMacro:utils/Makefile:8 + +# vector + +## We are expected to use the memory allocated some other place, so it's FP. +memleak:vector/v.lidar.growing/ConvexHull.c:246 +syntaxError:vector/vectorintro.html:11 diff --git a/.dockerignore b/.dockerignore index 3571e8f05f7..d09a4d1166a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -16,3 +16,4 @@ dist.* !.git/refs/heads !.git/objects .git/objects/* +!.git/objects/pack diff --git a/.flake8 b/.flake8 index c0c4c6230a3..18f3bb7536d 100644 --- a/.flake8 +++ b/.flake8 @@ -14,43 +14,30 @@ per-file-ignores = # E402 module level import not at top of file # E501 line too long # W605 invalid escape sequence - # F401 imported but unused # F821 undefined name 'unicode' # F841 local variable assigned to but never used # E741 ambiguous variable name 'l' - __init__.py: F401, F403 man/build_html.py: E501 + man/build_md.py: E501 doc/python/m.distance.py: E501 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 - gui/wxpython/modules/*: F841 - gui/wxpython/nviz/*: F841, E266, F403, F405 - gui/wxpython/photo2image/*: F841, E265 - gui/wxpython/photo2image/g.gui.photo2image.py: E501, F841 - gui/wxpython/psmap/*: F841, E266, F405, F403 - gui/wxpython/vdigit/*: F841, F405, F403 - gui/wxpython/vnet/*: F841 - gui/wxpython/wxgui.py: F841 + gui/wxpython/photo2image/g.gui.photo2image.py: E501 + 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 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 gui/wxpython/iclass/statistics.py: F841, F405, F403 - gui/wxpython/wxplot/profile.py: F841 - gui/wxpython/wxplot/base.py: F841 - gui/wxpython/location_wizard/dialogs.py: F841 + gui/wxpython/location_wizard/wizard.py: E722 + gui/wxpython/mapdisp/main.py: E722 gui/wxpython/mapdisp/test_mapdisp.py: E501 - gui/wxpython/mapdisp/statusbar.py: F841 gui/wxpython/mapswipe/g.gui.mapswipe.py: E501 - gui/wxpython/startup/locdownload.py: E402 + gui/wxpython/mapwin/base.py: E722 + gui/wxpython/mapwin/buffered.py: E722 + gui/wxpython/mapwin/graphics.py: E722 gui/wxpython/timeline/g.gui.timeline.py: E501 - gui/wxpython/web_services/cap_interface.py: E501 - gui/wxpython/web_services/widgets.py: F841, E402 - gui/wxpython/rlisetup/sampling_frame.py: F841 - gui/wxpython/rlisetup/wizard.py: E741 # Generated file gui/wxpython/menustrings.py: E501 # F821 undefined name 'cmp' @@ -59,37 +46,26 @@ per-file-ignores = # C wrappers call libgis.G_gisinit before importing other modules. # TODO: Is this really needed? python/grass/pygrass/vector/__init__.py: E402 - python/grass/pygrass/raster/__init__.py: E402 - python/grass/gunittest/invoker.py: E721 python/grass/pygrass/vector/__init__.py: E402 - python/grass/pygrass/modules/interface/*.py: F401 - python/grass/pygrass/modules/grid/*.py: F401 - python/grass/pygrass/raster/category.py: E721 - python/grass/pygrass/rpc/__init__.py: F401, F403 - python/grass/pygrass/utils.py: E402 - python/grass/temporal/univar_statistics.py: E231 + python/grass/temporal/abstract_space_time_dataset.py: E722 + python/grass/temporal/c_libraries_interface.py: E722 + python/grass/temporal/core.py: E722 + python/grass/temporal/datetime_math.py: E722 + python/grass/temporal/spatial_topology_dataset_connector.py: E722 + python/grass/temporal/temporal_algebra.py: E722 + python/grass/temporal/temporal_granularity.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, F401, F821 + python/grass/pygrass/tests/benchmark.py: F821 # Configuration file for Sphinx: # Ignoring import/code mix and line length. - python/grass/docs/conf.py: E402 # Files not managed by Black - python/grass/imaging/images2gif.py: E226 # Unused imports in init files - # F401 imported but unused # F403 star import used; unable to detect undefined names - python/grass/*/__init__.py: F401, F403 - python/grass/*/*/__init__.py: F401, F403 - python/grass/*/*/*/__init__.py: F401, F403 + python/grass/temporal/__init__.py: F401, F403 # E402 module level import not at top of file - scripts/d.polar/d.polar.py: F841 - scripts/r.in.wms/wms_cap_parsers.py: F841, E741 - scripts/r.in.wms/wms_drv.py: E402 - scripts/r.semantic.label/r.semantic.label.py: F841, E501 - scripts/v.report/v.report.py: F841, E721 - scripts/db.out.ogr/db.out.ogr.py: F841 - scripts/g.extension/g.extension.py: F841, E501 + scripts/r.semantic.label/r.semantic.label.py: 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 @@ -99,8 +75,7 @@ per-file-ignores = scripts/*/*.py: E501 temporal/t.rast.to.vect/t.rast.to.vect.py: E501 temporal/t.vect.algebra/t.vect.algebra.py: E501 - # ## used (##% key: r etc) - temporal/t.rast.what/t.rast.what.py: E265, E266, E501 + temporal/t.rast.what/t.rast.what.py: E501 # Line too long (esp. module interface definitions) temporal/*/*.py: E501 diff --git a/.github/actions/create-upload-suggestions/action.yml b/.github/actions/create-upload-suggestions/action.yml index b80c08c1b46..791df86541b 100644 --- a/.github/actions/create-upload-suggestions/action.yml +++ b/.github/actions/create-upload-suggestions/action.yml @@ -225,7 +225,7 @@ runs: env: FORMATTED_URL: >- [`formatted-${{ steps.tool-name-safe.outputs.tool-name }}`](${{ - steps.upload-changes.outputs.artifact-url }}) + steps.upload-changes.outputs.artifact-url }}) - name: Fail action if some files were changed if: >- ${{ (steps.files_changed.outputs.files_changed == 'true') && diff --git a/.github/workflows/additional_checks.yml b/.github/workflows/additional_checks.yml index a91d221f1e4..76554f24db3 100644 --- a/.github/workflows/additional_checks.yml +++ b/.github/workflows/additional_checks.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository contents - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 31 @@ -43,7 +43,7 @@ jobs: exclude: mswindows .*\.bat .*/testsuite/data/.* - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: '3.10' 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/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 13ba5bb3cd9..489d8197c09 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -16,7 +16,7 @@ jobs: name: Formatting Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6672287794c..ce80ab353d2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -40,9 +40,9 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: '3.x' - name: Install non-Python dependencies @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/init@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 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@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/analyze@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 22a6b7a42a8..5253a9ee7a4 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 if: github.repository == 'OSGeo/grass' steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get dependencies run: | @@ -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 3112fb8b33f..37585bb7ebb 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -30,12 +30,12 @@ jobs: contents: write steps: - name: Checks-out repository - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.ref }} fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: '3.11' - name: Create output directory @@ -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@7b4da11513bf3f43f9999e90eabced41ab8bb048 # v2.2.0 with: name: GRASS GIS ${{ github.ref_name }} body: | diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4de674ee9a2..577a9702011 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,12 +49,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Docker meta id: meta - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 + uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1 with: images: osgeo/grass-gis tags: | @@ -76,7 +76,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 with: push: true pull: true diff --git a/.github/workflows/gcc.yml b/.github/workflows/gcc.yml index 651cb272fba..6b6286ef3f0 100644 --- a/.github/workflows/gcc.yml +++ b/.github/workflows/gcc.yml @@ -26,7 +26,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get dependencies run: | sudo apt-get update -y diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 41ac51df8ff..ff40402fda4 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -44,13 +44,13 @@ jobs: -mindepth 1 -maxdepth 1 -type f -print -delete # Rehash to forget about the deleted files hash -r - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get current date cache key segment id: date # 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@068f1ab4b37ed9b3d9f73da7db90a0cda0a48d29 # v2.0.3 with: init-shell: bash environment-file: .github/workflows/macos_dependencies.txt @@ -104,7 +104,7 @@ jobs: --min-success 100 --config .github/workflows/macos_gunittest.cfg env: SampleData: "https://grass.osgeo.org/sampledata/north_carolina/\ - nc_spm_full_v2alpha2.tar.gz" + nc_spm_full_v2alpha2.tar.gz" - name: Make HTML test report available if: ${{ !cancelled() }} uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 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/osgeo4w.yml b/.github/workflows/osgeo4w.yml index a7694fa9b30..b58b168cb3d 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -31,22 +31,43 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - - uses: msys2/setup-msys2@ddf331adaebd714795f1042345e6ca57bd66cea8 # v2.24.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: msys2/setup-msys2@d44ca8e88d8b43d56cf5670f91747359d5537f97 # v2.26.0 with: path-type: inherit location: D:\ update: true msystem: MINGW64 - install: tar libintl make bison flex diffutils git dos2unix zip mingw-w64-x86_64-toolchain - mingw-w64-x86_64-fftw mingw-w64-x86_64-openblas mingw-w64-x86_64-pkgconf - mingw-w64-x86_64-gcc mingw-w64-x86_64-ccache mingw-w64-x86_64-zlib mingw-w64-x86_64-libiconv - mingw-w64-x86_64-bzip2 mingw-w64-x86_64-gettext mingw-w64-x86_64-libsystre - mingw-w64-x86_64-libtre-git mingw-w64-x86_64-libwinpthread-git mingw-w64-x86_64-libpng - mingw-w64-x86_64-pcre + install: >- + bison + diffutils + dos2unix + flex + git + libintl + make + tar + zip + pacboy: >- + bzip2 + ccache + fftw + gcc + gettext + libiconv + libpng + libsystre + libtre-git + libwinpthread-git + openblas + pcre + pkgconf + toolchain + zlib - name: Setup OSGeo4W environment - uses: echoix/setup-OSGeo4W@17deecd39e077a80bf1081443998ea8edd6f15bf # v0.1.0 + uses: echoix/setup-OSGeo4W@f4311523e39f2c8b10e34ebbc3f2ff437ecfb9ed # v0.2.0 + id: osgeo4w with: package-dir: "D:/OSGeo4W_pkg" packages: | @@ -96,7 +117,9 @@ jobs: run: .github/workflows/print_versions.sh - name: Test executing of the grass command - run: .github/workflows/test_simple.bat 'C:\OSGeo4W\opt\grass\grass85.bat' + run: .github/workflows/test_simple.bat '${{env.O4WROOT}}\opt\grass\grass85.bat' + env: + O4WROOT: ${{ steps.osgeo4w.outputs.root }} - name: Test executing of the grass command in bash shell: msys2 {0} @@ -116,7 +139,9 @@ jobs: shell: cmd /D /E:ON /V:OFF /S /C "CALL C:/OSGeo4W/OSGeo4W.bat "{0}"" - name: Run tests - run: .github/workflows/test_thorough.bat 'C:\OSGeo4W\opt\grass\grass85.bat' 'C:\OSGeo4W\bin\python3' + run: .github/workflows/test_thorough.bat '${{env.O4WROOT}}\opt\grass\grass85.bat' '${{env.O4WROOT}}\bin\python3' + env: + O4WROOT: ${{ steps.osgeo4w.outputs.root }} - name: Make HTML test report available if: ${{ always() }} diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index 17855d6149e..d27b8664c55 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -21,7 +21,7 @@ jobs: - name: Create URL to the run output id: vars run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: "Check that autoconf scripts are up-to-date:" run: | rm -f config.guess config.sub diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index e1b3b84b54e..5ccf299f3ef 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -32,10 +32,10 @@ jobs: PYTHONWARNINGS: always steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{ matrix.python-version }} cache: pip @@ -115,7 +115,7 @@ jobs: coverage html - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 + uses: codecov/codecov-action@7f8b4b4bde536c465e797be725718b88c5d95e0e # v5.1.1 with: verbose: true flags: pytest-python-${{ matrix.python-version }} diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 886cbe56b47..442a9bb11a8 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -34,9 +34,9 @@ jobs: # renovate: datasource=pypi depName=pylint PYLINT_VERSION: "2.12.2" # renovate: datasource=pypi depName=bandit - BANDIT_VERSION: "1.7.10" + BANDIT_VERSION: "1.8.0" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.6.9" + RUFF_VERSION: "0.8.2" runs-on: ${{ matrix.os }} permissions: @@ -54,10 +54,10 @@ jobs: echo Bandit: ${{ env.BANDIT_VERSION }} echo Ruff: ${{ env.RUFF_VERSION }} - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{ env.PYTHON_VERSION }} cache: pip @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: sarif_file: bandit.sarif diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 62328723f77..b8fe555a343 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -25,13 +25,13 @@ jobs: statuses: write steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # super-linter needs the full git history to get the # list of files that changed across commits fetch-depth: 0 - name: Lint code base - uses: super-linter/super-linter/slim@b92721f792f381cedc002ecdbb9847a15ece5bb8 # v7.1.0 + uses: super-linter/super-linter/slim@e1cb86b6e8d119f789513668b4b30bf17fe1efe4 # v7.2.0 env: DEFAULT_BRANCH: main # To report GitHub Actions status checks diff --git a/.github/workflows/test-nix.yml b/.github/workflows/test-nix.yml index ba14e0747ab..e6a4ebf14c6 100644 --- a/.github/workflows/test-nix.yml +++ b/.github/workflows/test-nix.yml @@ -28,10 +28,10 @@ jobs: contents: read steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install nix - uses: DeterminateSystems/nix-installer-action@da36cb69b1c3247ad7a1f931ebfd954a1105ef14 # v14 + uses: DeterminateSystems/nix-installer-action@e50d5f73bfe71c2dd0aa4218de8f4afa59f8f81d # v16 - name: Setup cachix uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 diff --git a/.github/workflows/titles.yml b/.github/workflows/titles.yml index f202fdafe02..9821a209a87 100644 --- a/.github/workflows/titles.yml +++ b/.github/workflows/titles.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout base repository (doesn't include the PR changes) - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Call PR title validation function run: python utils/generate_release_notes.py check "${PR_TITLE}" "" "" env: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 966dbfe21ab..9023df7d1b3 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -59,7 +59,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Invert inclusion list to an exclusion list id: get-exclude 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 2c136da40ff..c094d2bbd05 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,13 +37,13 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.9 + rev: v0.8.2 hooks: # Run the linter. - id: ruff args: [--fix, --preview] - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.42.0 + rev: v0.43.0 hooks: - id: markdownlint-fix # Using this mirror lets us use mypyc-compiled black, which is about 2x faster diff --git a/.travis.yml b/.travis.yml index 50dff8d2fa7..435d0013de8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,11 @@ env: - GRASS_EXTRA_CXXFLAGS="-Werror -fPIC -Wfatal-errors" before_install: + # Show available versions if ever pyenv global fails + - pyenv versions + - pyenv global 3.10 + # Show that the selected version is correctly set + - pyenv versions - ./.travis/$TRAVIS_OS_NAME.before_install.sh install: 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/AUTHORS b/AUTHORS index a81f5a75e39..952b369702f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -206,7 +206,7 @@ MS-Windows/Cygwin: Huidae Cho Source code Quality assessment system - SOCCER Labs at Ecole Polytechnique de Montreal, Canada http://web.soccerlab.polymtl.ca/grass-evolution/grass-browsers/grass-index-en.html - http://lists.osgeo.org/mailman/listinfo/grass-qa + https://lists.osgeo.org/mailman/listinfo/grass-qa GRASS 5.7/6.0: Primary authors of new source code diff --git a/Dockerfile b/Dockerfile index 41fb3264c07..6b18a841ad4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ -# syntax=docker/dockerfile:1.10@sha256:865e5dd094beca432e8c0a1d5e1c465db5f998dca4e439981029b3b81fb39ed5 +# syntax=docker/dockerfile:1.12@sha256:db1ff77fb637a5955317c7a3a62540196396d565f3dd5742e76dddbb6d75c4c5 # 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. ARG GUI=without -FROM ubuntu:22.04@sha256:58b87898e82351c6cf9cf5b9f3c20257bb9e2dcf33af051e12ce532d7f94e3fe as common_start +FROM ubuntu:22.04@sha256:0e5e4a57c2499249aafc3b40fcd541e9a456aab7296681a3994d631587203f97 as common_start LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann,Stefan Blumentrath" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" @@ -131,9 +131,9 @@ ARG GRASS_CONFIG="\ " ARG GRASS_PYTHON_PACKAGES="\ - Pillow \ matplotlib \ numpy \ + Pillow \ pip \ ply \ psycopg2 \ diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index 7b2757d38f5..ff13e49331e 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -35,6 +35,8 @@ for other platforms you may have to install some of them. GDAL: [https://gdal.org](https://gdal.org) - **Python >= 3.8** (for temporal framework, scripts, wxGUI, and ctypes interface) [https://www.python.org](https://www.python.org) +- **MkDocs** with "Material" theme Python packages for the manual pages: + See `man/mkdocs/requirements.txt`. ## Optional packages @@ -49,7 +51,7 @@ Note: also the respective development packages (commonly named `xxx-dev` or [https://facebook.github.io/zstd](https://facebook.github.io/zstd) - **FFTW 2.x or 3.x** (library for computing the Discrete Fourier Transform), required for `i.fft` and `i.ifft` and other modules - [http://www.fftw.org](http://www.fftw.org) + [https://fftw.org](https://fftw.org) - **GEOS** (Geometry Engine library), needed for `v.buffer` and adds extended options to the `v.select` module [https://libgeos.org/](https://libgeos.org/) @@ -81,7 +83,7 @@ Note: also the respective development packages (commonly named `xxx-dev` or - **SQLite libraries** (for the SQLite database interface) [https://www.sqlite.org](https://www.sqlite.org) - **unixODBC** (for the ODBC database interface) - [http://www.unixodbc.org](http://www.unixodbc.org) + [https://www.unixodbc.org](https://www.unixodbc.org) - **R Statistics** (for the R statistical language interface) [https://cran.r-project.org](https://cran.r-project.org) - **FreeType2** (for TrueType font support and `d.text.freetype`) diff --git a/TODO b/TODO index 510d38dfa6b..5750175258e 100644 --- a/TODO +++ b/TODO @@ -39,6 +39,6 @@ Imagery ----------------- See also -http://trac.osgeo.org/grass/wiki/Grass7Planning +https://trac.osgeo.org/grass/wiki/Grass7Planning -http://trac.osgeo.org/grass/wiki/Grass8Planning +https://trac.osgeo.org/grass/wiki/Grass8Planning 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/binaryInstall.src b/binaryInstall.src index 5ab008dd796..2bcb3165327 100755 --- a/binaryInstall.src +++ b/binaryInstall.src @@ -109,7 +109,7 @@ if [ $? -eq 0 ] ; then IFS="$IFSSAVE" if [ ! "$GUNZIP" ] ; then echo "No gunzip installed. Please get from:" - echo " http://www.gnu.org/software/gzip/gzip.html" + echo " https://www.gnu.org/software/gzip/gzip.html" exit fi else 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/configure b/configure index 56b203e0c13..335f79ecf08 100755 --- a/configure +++ b/configure @@ -10411,38 +10411,6 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ printf "%s\n" "#define HAVE_PDAL 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use PDAL NoFilenameWriter" >&5 -printf %s "checking whether to use PDAL NoFilenameWriter... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - class St:public pdal::NoFilenameWriter {}; -int -main (void) -{ - - class NFWTest : public pdal::NoFilenameWriter {}; - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO" -then : - - -printf "%s\n" "#define HAVE_PDAL_NOFILENAMEWRITER 1" >>confdefs.h - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=${ac_save_libs} CFLAGS=${ac_save_cflags} fi diff --git a/configure.ac b/configure.ac index 52a985960c3..0aeef9efc05 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ # Public License (>=v2). Read the file COPYING that # comes with GRASS for details. # -# MANUAL: http://www.gnu.org/software/autoconf/manual/autoconf.html +# MANUAL: https://www.gnu.org/software/autoconf/manual/autoconf.html # http://savannah.gnu.org/projects/autoconf/ # Website for config.guess, config.sub: # wget http://git.savannah.gnu.org/cgit/config.git/plain/config.guess @@ -1092,16 +1092,6 @@ else AC_DEFINE(HAVE_PDAL, 1, [Define to 1 if PDAL exists.]) - AC_MSG_CHECKING(whether to use PDAL NoFilenameWriter) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include - class St:public pdal::NoFilenameWriter {};]], [[ - class NFWTest : public pdal::NoFilenameWriter {}; - ]])], - [ - AC_DEFINE(HAVE_PDAL_NOFILENAMEWRITER, 1, [Define to 1 if PDAL NoFilenameWriter is present.]) - AC_MSG_RESULT(yes) - ],[AC_MSG_RESULT(no)]) - LIBS=${ac_save_libs} CFLAGS=${ac_save_cflags} fi 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/db/databaseintro.html b/db/databaseintro.html index ef7d34791b5..c400ab6e0ed 100644 --- a/db/databaseintro.html +++ b/db/databaseintro.html @@ -36,7 +36,7 @@

Attribute data import and export

Further conversion tools: @@ -101,4 +101,5 @@

See also

  • Introduction into image processing
  • Introduction into temporal data processing
  • Projections and spatial transformations
  • +
  • Graphical User Interface
  • diff --git a/db/db.connect/db.connect.html b/db/db.connect/db.connect.html index 48d6dbee02f..434124b4e65 100644 --- a/db/db.connect/db.connect.html +++ b/db/db.connect/db.connect.html @@ -36,7 +36,7 @@

    SQLite (default backend)

    PostgreSQL (local connection)

    Local storage, database tables stored in database "mydb" -(may require the use of db.login): +(may require the use of db.login):
     db.connect driver=pg database=mydb
    @@ -49,7 +49,7 @@ 

    PostgreSQL (local connection)

    PostgreSQL (network connection)

    Network storage, database tables stored in database "mydb" -(may require the use of db.login): +(may require the use of db.login):
     db.connect driver=pg database=mydb
    @@ -62,7 +62,7 @@ 

    PostgreSQL (network connection)

    MySQL (local connection)

    Local storage, database tables stored in database "mydb" (may require -the use of db.login): +the use of db.login):
     db.connect driver=mysql database=mydb
    @@ -75,7 +75,7 @@ 

    MySQL (local connection)

    MySQL (network connection)

    Network storage, database tables stored in database "mydb" -(may require the use of db.login): +(may require the use of db.login):
     db.connect driver=mysql database=mydb
    @@ -88,7 +88,7 @@ 

    MySQL (network connection)

    ODBC

    Network storage, database tables stored in database "mydb" -(may require the use of db.login): +(may require the use of db.login):
     db.connect driver=odbc database=mydb
    diff --git a/db/db.execute/db.execute.html b/db/db.execute/db.execute.html
    index 8700258b404..b8fcce41d7b 100644
    --- a/db/db.execute/db.execute.html
    +++ b/db/db.execute/db.execute.html
    @@ -104,7 +104,7 @@ 

    SEE ALSO

    GRASS SQL interface - +

    AUTHOR

    diff --git a/db/db.login/main.c b/db/db.login/main.c index 9147c0e7f1f..f073b654665 100644 --- a/db/db.login/main.c +++ b/db/db.login/main.c @@ -98,9 +98,9 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); } - if (db_set_login2(driver->answer, database->answer, user->answer, - password->answer, host->answer, port->answer, - G_get_overwrite()) == DB_FAILED) { + if (db_set_login(driver->answer, database->answer, user->answer, + password->answer, host->answer, port->answer, + G_get_overwrite()) == DB_FAILED) { G_fatal_error(_("Unable to set user/password")); } diff --git a/db/db.select/db.select.html b/db/db.select/db.select.html index 175151cbe55..58ceba5443d 100644 --- a/db/db.select/db.select.html +++ b/db/db.select/db.select.html @@ -62,7 +62,7 @@

    Execute multiple SQL statements

     cat file.sql
     SELECT * FROM busstopsall WHERE cat = 1
    -SELECT cat FROM busstopsall WHERE cat > 4 AND cat < 8
    +SELECT cat FROM busstopsall WHERE cat > 4 AND cat < 8
     
     db.select input=file.sql
     
    diff --git a/db/drivers/README b/db/drivers/README deleted file mode 100644 index e2a2d435f2e..00000000000 --- a/db/drivers/README +++ /dev/null @@ -1,28 +0,0 @@ -This directory contains drivers for the DBMI library. -The driver functions are for internal usage. - -The DBMI API to be used for module programming is available in: -lib/db/ - - -NOTE: -db__driver_* functions are implemented in a driver. If some of them -are not used or defined, the driver will use stub functions in -lib/db/stubs/ - -For some platforms like Cygwin, multiply defined symbols are not -resolved in a way that UNIX does. Even worse is that it is impossible -to build shared libraries with undefined symbols. For example, -libgrass_dbmidriver.so cannot be built without any implementations -of db__driver_* functions which should be specific to a db driver. - -To work around this problem, function pointers are defined to use -driver's implementations instead of those of the db stubs library. -To do this automatically, run '../mk_dbdriver_h.sh' in driver's -directory, #include "dbdriver.h" from main.c, and execute init_dbdriver(). - -Function pointers are defined in grass6/lib/db/dbmi_driver/dbstubs.h -This header file can be generated with -lib/db/dbmi_driver/mk_dbstubs_h.sh - -Please read lib/db/README diff --git a/db/drivers/README.md b/db/drivers/README.md new file mode 100644 index 00000000000..e98c617267c --- /dev/null +++ b/db/drivers/README.md @@ -0,0 +1,30 @@ +This directory contains drivers for the DBMI library. +The driver functions are for internal usage. + +The DBMI API to be used for module programming is available in: +`lib/db/` + +NOTE: +`db__driver_*` functions are implemented in a driver. If some of them +are not used or defined, the driver will use stub functions in +`lib/db/stubs/`. + +For some platforms like Cygwin, multiply defined symbols are not +resolved in a way that UNIX does. Even worse is that it is impossible +to build shared libraries with undefined symbols. For example, +`libgrass*dbmidriver.so` cannot be built without any implementations +of `db__driver*\*` functions which should be specific to a db driver. + +To work around this problem, function pointers are defined to use +driver's implementations instead of those of the db stubs library. +To do this automatically, run `../mk_dbdriver_h.sh` (GRASS GIS 6) +in driver's directory, `#include "dbdriver.h"` from `main.c`, and +execute `init_dbdriver()`. + +Function pointers are defined in `lib/db/dbmi_driver/dbstubs.h` +This header file can be generated with +`lib/db/dbmi_driver/mk_dbstubs_h.sh` (GRASS GIS 6). + +Please read lib/db/README.md and + + diff --git a/db/drivers/mysql/db.c b/db/drivers/mysql/db.c index 5c98c652e95..b83d3d7064d 100644 --- a/db/drivers/mysql/db.c +++ b/db/drivers/mysql/db.c @@ -51,7 +51,7 @@ int db__driver_open_database(dbHandle *handle) connpar.host, connpar.port, connpar.dbname, connpar.user, connpar.password); - db_get_login2("mysql", name, &user, &password, &host, &port); + db_get_login("mysql", name, &user, &password, &host, &port); connection = mysql_init(NULL); res = diff --git a/db/drivers/mysql/grass-mesql.html b/db/drivers/mysql/grass-mesql.html index 8e2aca2155c..3e2299b0d88 100644 --- a/db/drivers/mysql/grass-mesql.html +++ b/db/drivers/mysql/grass-mesql.html @@ -1,28 +1,7 @@ - - - -GRASS-MySQL embedded driver - GRASS GIS manual - - - - - - - -GRASS logo
    - -

    MySQL embedded driver in GRASS

    - -

    KEYWORDS

    - -database, attribute table, driver - -

    DESCRIPTION

    -MySQL database driver in GRASS enables GRASS to store vector -attributes in MySQL embedded database without necessity -to run MySQL server. +MySQL database driver enables GRASS to store vector attributes +in MySQL embedded database without necessity to run MySQL server.

    Driver and database name

    @@ -35,9 +14,9 @@

    Driver and database name

    before use of the driver. In the name of database it is possible to use 3 variables:
      -
    • $GISDBASE - path to current GISBASE -
    • $LOCATION_NAME - name of current location -
    • $MAPSET - name of current mapset +
    • $GISDBASE - path to current GISBASE
    • +
    • $LOCATION_NAME - name of current location
    • +
    • $MAPSET - name of current mapset

    @@ -68,14 +47,7 @@

    Troubleshooting: SQL syntax error

    Attempting to use a reserved SQL word as column or table name will result in a "SQL syntax" error. The list of reserved words for MySQL can be -found in the MySQL manual. - -

    SEE ALSO

    - - -db.connect, -SQL support in GRASS GIS - +found in the MySQL manual.

    AUTHOR

    @@ -83,12 +55,12 @@

    AUTHOR

    Credits: Development of the driver was sponsored by -Faunalia (Italy) -as part of a project for ATAC. +Faunalia (Italy) +as part of a project for ATAC. +

    SEE ALSO

    -
    -

    Main index - Database index - Topics index - Keywords Index - Full index

    -

    © 2003-2022 GRASS Development Team, GRASS GIS 8 Reference Manual

    - - + +db.connect, +SQL support in GRASS GIS + diff --git a/db/drivers/mysql/grass-mysql.html b/db/drivers/mysql/grass-mysql.html index 60c7fbe4f78..f86dab367d3 100644 --- a/db/drivers/mysql/grass-mysql.html +++ b/db/drivers/mysql/grass-mysql.html @@ -1,7 +1,7 @@ -MySQL database driver enables GRASS to store vector attributes in -MySQL server. +MySQL database driver enables GRASS to store vector attributes +in MySQL server.

    Because vector attribute tables @@ -14,7 +14,7 @@

    Creating a MySQL database

    A new database is created within MySQL:
    -mysql> CREATE DATABASE mydb;
    +mysql> CREATE DATABASE mydb;
     
    See the MySQL manual for details. @@ -27,39 +27,41 @@

    Driver and database name

    The parameter 'database' can be given in two formats:
      -
    • Database name - in case of connection from localhost -
    • String of comma separated list of kye=value options. +
    • Database name - in case of connection from localhost
    • +
    • String of comma separated list of key=value options. Supported options are: -
        -
      • dbname - database name -
      • host - host name or IP address -
      • port - server port number -
      +
        +
      • dbname - database name
      • +
      • host - host name or IP address
      • +
      • port - server port number
      • +
      +
    +

    Examples of connection parameters: -

    -  db.connect driver=mysql database=mytest
    -  db.connect driver=mysql database='dbname=mytest,host=test.grass.org'
    -
    +
    +db.connect driver=mysql database=mytest
    +db.connect driver=mysql database='dbname=mytest,host=test.grass.org'
    +

    Data types

    GRASS supports almost all MySQL data types with following limitations:
      -
    • Binary columns (BINARY, VARBINARY, TINYBLOB, MEDIUMBLOB, - BLOB, LONGBLOB) are not not supported. - If a table with binary column(s) is used in GRASS - a warning is printed and only the supported columns are - returned in query results. +
    • Binary columns (BINARY, VARBINARY, TINYBLOB, MEDIUMBLOB, +BLOB, LONGBLOB) are not not supported. +If a table with binary column(s) is used in GRASS +a warning is printed and only the supported columns are +returned in query results.
    • -
    • Columns of type SET and ENUM are represented as string (VARCHAR). +
    • Columns of type SET and ENUM are represented as string (VARCHAR).
    • -
    • Very large integers in columns of type BIGINT can be lost - or corrupted because GRASS does not support 64 bin integeres - on most platforms. +
    • Very large integers in columns of type BIGINT can be lost +or corrupted because GRASS does not support 64 bin integeres +on most platforms.
    • -
    • GRASS does not currently distinguish types TIMESTAMP and - DATETIME. Both types are in GRASS interpreted as TIMESTAMP. +
    • GRASS does not currently distinguish types TIMESTAMP and +DATETIME. Both types are in GRASS interpreted as TIMESTAMP.

    Indexes

    @@ -80,11 +82,12 @@

    Privileges

    to other users you have to ask your MySQL server administrator to grant select privilege to them on the MySQL database used for that mapset. For example, to allow everybody to read data -in from your database 'mydb':
    -
    +in from your database 'mydb':
    +
    +
     shell> mysql --user=root mysql
     mysql> GRANT SELECT ON mydb.* TO ''@'%';
    -
    +

    Schemas

    @@ -104,7 +107,16 @@

    Troubleshooting: SQL syntax error

    Attempting to use a reserved SQL word as column or table name will result in a "SQL syntax" error. The list of reserved words for MySQL can be -found in the MySQL manual. +found in the MySQL manual. + +

    AUTHOR

    + +Radim Blazek + +

    +Credits: Development of the driver was sponsored by +Faunalia (Italy) +as part of a project for ATAC.

    SEE ALSO

    @@ -112,13 +124,3 @@

    SEE ALSO

    db.connect, SQL support in GRASS GIS
    - -

    Credits

    - -Development of the driver was sponsored by -Faunalia (Italy) -as part of a project for ATAC. - -

    AUTHOR

    - -Radim Blazek diff --git a/db/drivers/odbc/INSTALL b/db/drivers/odbc/INSTALL index 74928ff55a6..3f485ee3f20 100644 --- a/db/drivers/odbc/INSTALL +++ b/db/drivers/odbc/INSTALL @@ -1,4 +1,4 @@ -1. Download, compile, install and configure ODBC (http://www.unixodbc.org/) +1. Download, compile, install and configure ODBC (https://www.unixodbc.org/) 2. Copy ODBC include files to /usr/include/odbc 3. Compile src/libes/dbmi/drivers/odbc 4. Add row for ODBC driver to dbmscap file diff --git a/db/drivers/odbc/grass-odbc.html b/db/drivers/odbc/grass-odbc.html index 7692893ca92..75a5ca578d7 100644 --- a/db/drivers/odbc/grass-odbc.html +++ b/db/drivers/odbc/grass-odbc.html @@ -95,10 +95,10 @@

    Linux

     ConnSettings            =
    Configuration of an DSN without GUI is described on -http://www.unixodbc.org/odbcinst.html, +https://www.unixodbc.org/odbcinst.html, but odbc.ini and .odbc.ini may be created by the 'ODBCConfig' tool. You can easily view your DSN structure by 'DataManager'. Configuration with -GUI is described on http://www.unixodbc.org/doc/UserManual/ +GUI is described on https://www.unixodbc.org/doc/UserManual/

    To find out about your PostgreSQL protocol, run:

    @@ -159,6 +159,6 @@ 

    SEE ALSO

    db.connect, v.db.connect, -unixODBC web site, +unixODBC web site, SQL support in GRASS GIS diff --git a/db/drivers/ogr/grass-ogr.html b/db/drivers/ogr/grass-ogr.html index dbeca085ecf..c573f882288 100644 --- a/db/drivers/ogr/grass-ogr.html +++ b/db/drivers/ogr/grass-ogr.html @@ -7,7 +7,7 @@

    SEE ALSO

    SQL support in GRASS GIS - +

    diff --git a/db/drivers/postgres/README b/db/drivers/postgres/README index 254a0fd28c9..a2959739f6e 100644 --- a/db/drivers/postgres/README +++ b/db/drivers/postgres/README @@ -19,7 +19,7 @@ Check also for PostgreSQL data types for defining them in GRASS: Supported types in ./globals.h: -(See http://www.postgresql.org/docs/9.4/interactive/datatype.html) +(See https://www.postgresql.org/docs/9.4/interactive/datatype.html) DB_C_TYPE_INT: bit, int2, smallint, int4, int, integer, int8, bigint, serial, oid diff --git a/db/drivers/postgres/db.c b/db/drivers/postgres/db.c index 5343acf03d8..aa27d370419 100644 --- a/db/drivers/postgres/db.c +++ b/db/drivers/postgres/db.c @@ -54,7 +54,7 @@ int db__driver_open_database(dbHandle *handle) return DB_FAILED; } - db_get_login2("pg", name, &user, &password, &host, &port); + db_get_login("pg", name, &user, &password, &host, &port); pg_conn = PQsetdbLogin(host, port, pgconn.options, pgconn.tty, pgconn.dbname, user, password); @@ -241,7 +241,7 @@ int create_delete_db(dbHandle *handle, int create) pgconn.host, pgconn.port, pgconn.options, pgconn.tty, pgconn.dbname, pgconn.user, pgconn.password, pgconn.host, pgconn.port, pgconn.schema); - db_get_login2("pg", template_db, &user, &password, &host, &port); + db_get_login("pg", template_db, &user, &password, &host, &port); pg_conn = PQsetdbLogin(host, port, pgconn.options, pgconn.tty, pgconn.dbname, user, password); diff --git a/db/drivers/postgres/execute.c b/db/drivers/postgres/execute.c index fa6dd556101..99a6c79df11 100644 --- a/db/drivers/postgres/execute.c +++ b/db/drivers/postgres/execute.c @@ -1,7 +1,7 @@ /*! \file db/driver/postgres/execute.c - \brief DBMI - Low Level PostgreSQL database driver - execute statemets + \brief DBMI - Low Level PostgreSQL database driver - execute statements This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. diff --git a/db/drivers/postgres/grass-pg.html b/db/drivers/postgres/grass-pg.html index 72c292aade4..3950c0dd315 100644 --- a/db/drivers/postgres/grass-pg.html +++ b/db/drivers/postgres/grass-pg.html @@ -6,7 +6,7 @@

    Creating a PostgreSQL database

    A new database is created with createdb, see -the PostgreSQL +the PostgreSQL manual for details.

    Connecting GRASS to PostgreSQL

    @@ -115,12 +115,12 @@

    Example: Import from PostGIS

    Geometry Converters

    • PostGIS with shp2pgsql:
      - shp2pgsql -D lakespy2 lakespy2 test > lakespy2.sql + shp2pgsql -D lakespy2 lakespy2 test > lakespy2.sql
    • e00pg: E00 to PostGIS filter, see also v.in.e00.
    • -
    • GDAL/OGR ogrinfo and ogr2ogr: +
    • GDAL/OGR ogrinfo and ogr2ogr: GIS vector format converter and library, e.g. ArcInfo or SHAPE to PostGIS.
      ogr2ogr -f "PostgreSQL" shapefile ??
    • @@ -141,8 +141,8 @@

      SEE ALSO

      REFERENCES

      diff --git a/db/drivers/postgres/listdb.c b/db/drivers/postgres/listdb.c index 0efa0328c0f..974141f1e36 100644 --- a/db/drivers/postgres/listdb.c +++ b/db/drivers/postgres/listdb.c @@ -48,7 +48,7 @@ int db__driver_list_databases(dbString *dbpath, int npaths, dbHandle **dblist, pgconn.dbname, pgconn.user, pgconn.password, pgconn.host, pgconn.port, pgconn.options, pgconn.tty); - db_get_login2("pg", NULL, &user, &passwd, &host, &port); + db_get_login("pg", NULL, &user, &passwd, &host, &port); G_debug(1, "user = %s, passwd = %s", user, passwd ? "xxx" : ""); if (user || passwd) { diff --git a/db/drivers/sqlite/README b/db/drivers/sqlite/README index b0c59be7d64..955cbede58a 100644 --- a/db/drivers/sqlite/README +++ b/db/drivers/sqlite/README @@ -14,7 +14,7 @@ db.connect driver=sqlite \ The database is created automatically when used first time. That is SQLite feature followed also in the driver. -SQLite uses "type affinity", (http://www.sqlite.org/datatype3.html) +SQLite uses "type affinity", (https://www.sqlite.org/datatype3.html) that means column types are recommended, but not required. If the driver in GRASS has to determine column type, it first reads diff --git a/db/drivers/sqlite/fetch.c b/db/drivers/sqlite/fetch.c index 8e020753293..44a62b4bb4d 100644 --- a/db/drivers/sqlite/fetch.c +++ b/db/drivers/sqlite/fetch.c @@ -130,7 +130,7 @@ int db__driver_fetch(dbCursor *cn, int position, int *more) G_debug(3, "col %d, litetype %d, sqltype %d: val = '%s'", col, litetype, sqltype, text); - /* http://www.sqlite.org/capi3ref.html#sqlite3_column_type + /* https://www.sqlite.org/capi3ref.html#sqlite3_column_type SQLITE_INTEGER 1 SQLITE_FLOAT 2 SQLITE_TEXT 3 diff --git a/db/drivers/sqlite/grass-sqlite.html b/db/drivers/sqlite/grass-sqlite.html index e746f5820c0..ea2f9526506 100644 --- a/db/drivers/sqlite/grass-sqlite.html +++ b/db/drivers/sqlite/grass-sqlite.html @@ -25,8 +25,8 @@

      Supported SQL commands

      All SQL commands supported by SQLite (for limitations, see SQLite help page: -SQL As Understood By SQLite and -Unsupported SQL). +SQL As Understood By SQLite and +Unsupported SQL).

      Operators available in conditions

      @@ -46,7 +46,7 @@

      Browsing table data in DB

    + + +

    Introduction to the GRASS GIS Graphical User Interface

    + +

    Overview

    + +The wxGUI (wxPython-based Graphical User Interface) is the primary user +interface for GRASS GIS. Designed for efficiency and ease of use, the +wxGUI provides an intuitive way to interact with spatial data and the +powerful tools available in GRASS GIS. + +The GUI supports the visualisation of spatial data, the execution of +geoprocessing tasks or the management of complex workflows and offers a +comprehensive set of tools. + +

    Features

    + +The wxGUI is designed to cater to both novice and advanced users with +the following features: + +
      +
    • A clean and customizable layout for efficient workspace management.
    • +
    • Integrated support for both raster and vector data operations.
    • +
    • Drag-and-drop capabilities for quick layer addition and arrangement.
    • +
    • Support for live previews of data and processing results.
    • +
    • Direct access to GRASS GIS modules, complete with user-friendly + dialog windows.
    • +
    • Advanced debugging and scripting capabilities for developers and + power users.
    • +
    + +

    Getting Started

    + +To launch the wxGUI, simply start GRASS GIS. Upon startup, the wxGUI will +load, providing access to its various components. + +The wxGUI usage is explained in greater detail here. + +New GRASS GIS users can explore the integrated help system or visit the +GRASS GIS documentation +for tutorials and guides. + +

    Key Components

    + +The wxGUI is composed of several modules and features: + +
      +
    • Map Display: Visualize raster, vector, and 3D data + layers in an interactive map viewer.
    • +
    • Layer Manager: Organize and control the visibility, + styling, and properties of your data layers.
    • +
    • Data Catalog: Explore and manage GRASS GIS mapsets + and spatial data with ease.
    • +
    • Geoprocessing Tools: Access a wide range of geospatial + analysis and modeling tools through an easy-to-use interface.
    • +
    • Command Console: Run GRASS GIS commands directly, + with syntax highlighting and autocompletion support.
    • +
    • 3D View: Analyze and visualize 3D landscapes + using NVIZ.
    • +
    + +The wxGUI components are explained in greater detail +here. + +

    See also

    + + diff --git a/gui/wxpython/animation/dialogs.py b/gui/wxpython/animation/dialogs.py index bc7e7fe2482..5a634b3bb16 100644 --- a/gui/wxpython/animation/dialogs.py +++ b/gui/wxpython/animation/dialogs.py @@ -1619,10 +1619,7 @@ def SetStdsProperties(self, layer): dlg.CenterOnParent() if dlg.ShowModal() == wx.ID_OK: layer = dlg.GetLayer() - if hidden: - signal = self.layerAdded - else: - signal = self.cmdChanged + signal = self.layerAdded if hidden else self.cmdChanged signal.emit(index=self._layerList.GetLayerIndex(layer), layer=layer) elif hidden: self._layerList.RemoveLayer(layer) @@ -2023,7 +2020,7 @@ def _createTemporalPage(self, notebook): panel, id=wx.ID_ANY, label=_("Learn more about formatting options"), - url="http://docs.python.org/2/library/datetime.html#" + url="https://docs.python.org/2/library/datetime.html#" "strftime-and-strptime-behavior", ) link.SetNormalColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) diff --git a/gui/wxpython/animation/frame.py b/gui/wxpython/animation/frame.py index 6496920a5cd..42953803778 100644 --- a/gui/wxpython/animation/frame.py +++ b/gui/wxpython/animation/frame.py @@ -274,17 +274,11 @@ def OnStop(self, event): self.controller.EndAnimation() def OnOneDirectionReplay(self, event): - if event.IsChecked(): - mode = ReplayMode.REPEAT - else: - mode = ReplayMode.ONESHOT + mode = ReplayMode.REPEAT if event.IsChecked() else ReplayMode.ONESHOT self.controller.SetReplayMode(mode) def OnBothDirectionReplay(self, event): - if event.IsChecked(): - mode = ReplayMode.REVERSE - else: - mode = ReplayMode.ONESHOT + mode = ReplayMode.REVERSE if event.IsChecked() else ReplayMode.ONESHOT self.controller.SetReplayMode(mode) def OnAdjustSpeed(self, event): @@ -642,11 +636,8 @@ def _updateFrameIndex(self, index): } else: label = _("to %(to)s") % {"to": self.timeLabels[index][1]} - else: # noqa: PLR5501 - if self.temporalType == TemporalType.ABSOLUTE: - label = start - else: - label = "" + else: + label = start if self.temporalType == TemporalType.ABSOLUTE else "" self.label2.SetLabel(label) if self.temporalType == TemporalType.RELATIVE: self.indexField.SetValue(start) diff --git a/gui/wxpython/animation/g.gui.animation.html b/gui/wxpython/animation/g.gui.animation.html index effb852357c..cf22e6b3cd1 100644 --- a/gui/wxpython/animation/g.gui.animation.html +++ b/gui/wxpython/animation/g.gui.animation.html @@ -81,7 +81,7 @@

    EXAMPLES

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    @@ -98,4 +98,4 @@

    SEE ALSO

    AUTHOR

    Anna Kratochvilova, -Czech Technical University in Prague, Czech Republic +Czech Technical University in Prague, Czech Republic diff --git a/gui/wxpython/animation/provider.py b/gui/wxpython/animation/provider.py index 43929a1873d..1b07f63841f 100644 --- a/gui/wxpython/animation/provider.py +++ b/gui/wxpython/animation/provider.py @@ -657,7 +657,7 @@ def CompositeProcess( :param tempDir: directory for rendering :param cmdList: list of d.rast/d.vect commands :param region: region as a dict or None - :param opacites: list of opacities + :param opacities: list of opacities :param bgcolor: background color as a tuple of 3 values 0 to 255 :param fileQueue: the inter process communication queue storing the file name of the image @@ -896,7 +896,7 @@ def test(): if os.path.exists(tempDir): shutil.rmtree(tempDir) os.mkdir(tempDir) - # comment this line to keep the directory after prgm ends + # comment this line to keep the directory after program ends # cleanUp = CleanUp(tempDir) # import atexit # atexit.register(cleanUp) diff --git a/gui/wxpython/animation/temporal_manager.py b/gui/wxpython/animation/temporal_manager.py index ef782543089..0f00cc6e329 100644 --- a/gui/wxpython/animation/temporal_manager.py +++ b/gui/wxpython/animation/temporal_manager.py @@ -259,10 +259,8 @@ def _getLabelsAndMaps(self, timeseries): elif self.temporalType == TemporalType.RELATIVE: unit = self.timeseriesInfo[timeseries]["unit"] - if self.granularityMode == GranularityMode.ONE_UNIT: - gran = 1 - else: - gran = granNum + gran = 1 if self.granularityMode == GranularityMode.ONE_UNIT else granNum + # start sampling - now it can be used for both interval and point data # after instance, there can be a gap or an interval # if it is a gap we remove it and put there the previous instance instead @@ -299,10 +297,9 @@ def _getLabelsAndMaps(self, timeseries): # skip this one, already there followsPoint = False continue - else: - # append the last one (of point time) - listOfMaps.append(lastTimeseries) - end = None + # append the last one (of point time) + listOfMaps.append(lastTimeseries) + end = None else: # append series which is None listOfMaps.append(series) diff --git a/gui/wxpython/animation/utils.py b/gui/wxpython/animation/utils.py index 5f69bc40d35..72e817ae962 100644 --- a/gui/wxpython/animation/utils.py +++ b/gui/wxpython/animation/utils.py @@ -15,7 +15,7 @@ This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. -@author Anna Perasova +@author Anna Petrasova """ import os diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py index a173e28c7f8..0c64f0d0973 100644 --- a/gui/wxpython/core/gcmd.py +++ b/gui/wxpython/core/gcmd.py @@ -311,9 +311,8 @@ def recv_some(p, t=0.1, e=1, tr=5, stderr=0): if r is None: if e: raise Exception(message) - else: - break - elif r: + break + if r: y.append(decode(r)) else: time.sleep(max((x - time.time()) / tr, 0)) @@ -415,7 +414,7 @@ def __init__( _("Error: ") + self.__GetError(), ) ) - elif rerr == sys.stderr: # redirect message to sys + if rerr == sys.stderr: # redirect message to sys stderr.write("Execution failed: '%s'" % (" ".join(self.cmd))) stderr.write( "%sDetails:%s%s" @@ -498,7 +497,7 @@ def __ProcessStdErr(self): def __GetError(self): """Get error message or ''""" if not self.cmdThread.module: - return _("Unable to exectute command: '%s'") % " ".join(self.cmd) + return _("Unable to execute command: '%s'") % " ".join(self.cmd) for type, msg in self.__ProcessStdErr(): if type == "ERROR": @@ -644,7 +643,7 @@ def _formatMsg(text): for line in text.splitlines(): if len(line) == 0: continue - elif ( + if ( "GRASS_INFO_MESSAGE" in line or "GRASS_INFO_WARNING" in line or "GRASS_INFO_ERROR" in line @@ -709,10 +708,7 @@ def RunCommand( kwargs["stdin"] = subprocess.PIPE # Do not change the environment, only a local copy. - if env: - env = env.copy() - else: - env = os.environ.copy() + env = env.copy() if env else os.environ.copy() if parent: env["GRASS_MESSAGE_FORMAT"] = "standard" diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index acf8f67310a..a33535ca942 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -121,6 +121,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", @@ -131,13 +139,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() @@ -147,21 +153,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(): @@ -212,7 +218,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: @@ -222,10 +228,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 @@ -311,10 +317,7 @@ def write(self, s): if "GRASS_INFO_PERCENT" in line: value = int(line.rsplit(":", 1)[1].strip()) - if value >= 0 and value < 100: - progressValue = value - else: - progressValue = 0 + progressValue = value if value >= 0 and value < 100 else 0 elif "GRASS_INFO_MESSAGE" in line: self.type = "message" self.message += line.split(":", 1)[1].strip() + "\n" @@ -633,10 +636,7 @@ def load_source(modname, filename): return - if env: - env = env.copy() - else: - env = os.environ.copy() + env = env.copy() if env else os.environ.copy() # activate computational region (set with g.region) # for all non-display commands. if compReg and "GRASS_REGION" in env: diff --git a/gui/wxpython/core/giface.py b/gui/wxpython/core/giface.py index 3a1d8c61612..1b17a3e5932 100644 --- a/gui/wxpython/core/giface.py +++ b/gui/wxpython/core/giface.py @@ -91,7 +91,7 @@ def GetLayersByName(self, name): .. todo:: if common usage is just to check the presence of layer, - intoroduce a new method ContainsLayerByName(name) + introduce a new method ContainsLayerByName(name) """ raise NotImplementedError diff --git a/gui/wxpython/core/globalvar.py b/gui/wxpython/core/globalvar.py index 7624183796c..e0397a2b121 100644 --- a/gui/wxpython/core/globalvar.py +++ b/gui/wxpython/core/globalvar.py @@ -233,7 +233,7 @@ def UpdateGRASSAddOnCommands(eList=None): Debug.msg(1, "Number of GRASS AddOn commands: %d", nCmd) -"""@brief Collected GRASS-relared binaries/scripts""" +"""@brief Collected GRASS-related binaries/scripts""" grassCmd, grassScripts = get_commands() Debug.msg(1, "Number of core GRASS commands: %d", len(grassCmd)) UpdateGRASSAddOnCommands() 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/core/menutree.py b/gui/wxpython/core/menutree.py index fba33daf705..ef3ebd7b414 100644 --- a/gui/wxpython/core/menutree.py +++ b/gui/wxpython/core/menutree.py @@ -108,30 +108,14 @@ def _createItem(self, item, node): shortcut = item.find("shortcut") # optional wxId = item.find("id") # optional icon = item.find("icon") # optional - if gcmd is not None: - gcmd = gcmd.text - else: - gcmd = "" - if desc.text: - desc = _(desc.text) - else: - desc = "" - if keywords is None or keywords.text is None: - keywords = "" - else: - keywords = keywords.text - if shortcut is not None: - shortcut = shortcut.text - else: - shortcut = "" - if wxId is not None: - wxId = eval("wx." + wxId.text) - else: - wxId = wx.ID_ANY - if icon is not None: - icon = icon.text - else: - icon = "" + gcmd = gcmd.text if gcmd is not None else "" + desc = _(desc.text) if desc.text else "" + keywords = ( + "" if keywords is None or keywords.text is None else keywords.text + ) + shortcut = shortcut.text if shortcut is not None else "" + wxId = eval("wx." + wxId.text) if wxId is not None else wx.ID_ANY + icon = icon.text if icon is not None else "" label = origLabel if gcmd: if self.menustyle == 1: @@ -152,7 +136,7 @@ def _createItem(self, item, node): elif item.tag == "menu": self._createMenu(item, node) else: - raise ValueError(_("Unknow tag %s") % item.tag) + raise ValueError(_("Unknown tag %s") % item.tag) def GetModel(self, separators=False): """Returns copy of model with or without separators diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index 7da922be1b8..2ea7a1d0ab0 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -100,10 +100,7 @@ def __init__( if mapfile: self.mapfile = mapfile else: - if ltype == "overlay": - tempfile_sfx = ".png" - else: - tempfile_sfx = ".ppm" + tempfile_sfx = ".png" if ltype == "overlay" else ".ppm" self.mapfile = get_tempfile_name(suffix=tempfile_sfx) @@ -661,7 +658,7 @@ def Render(self, force=False, windres=False): def OnRenderDone(self, env): """Rendering process done - Make image composiotion, emits updateMap event. + Make image composition, emits updateMap event. """ maps = [] masks = [] @@ -790,10 +787,7 @@ def ReportProgress(self, env, layer=None): stText += "..." if self.progressInfo["range"] != len(self.progressInfo["rendered"]): - if stText: - stText = _("Rendering & ") + stText - else: - stText = _("Rendering...") + stText = _("Rendering & ") + stText if stText else _("Rendering...") self.updateProgress.emit( range=self.progressInfo["range"], @@ -1190,32 +1184,32 @@ def SetRegion(self, windres=False, windres3=False): if key == "north": grass_region += "north: %s; " % (region["n"]) continue - elif key == "south": + if key == "south": grass_region += "south: %s; " % (region["s"]) continue - elif key == "east": + if key == "east": grass_region += "east: %s; " % (region["e"]) continue - elif key == "west": + if key == "west": grass_region += "west: %s; " % (region["w"]) continue - elif key == "e-w resol": + if key == "e-w resol": grass_region += "e-w resol: %.10f; " % (region["ewres"]) continue - elif key == "n-s resol": + if key == "n-s resol": grass_region += "n-s resol: %.10f; " % (region["nsres"]) continue - elif key == "cols": + if key == "cols": if windres: continue grass_region += "cols: %d; " % region["cols"] continue - elif key == "rows": + if key == "rows": if windres: continue grass_region += "rows: %d; " % region["rows"] continue - elif key == "n-s resol3" and windres3: + if key == "n-s resol3" and windres3: grass_region += "n-s resol3: %f; " % (region["nsres3"]) elif key == "e-w resol3" and windres3: grass_region += "e-w resol3: %f; " % (region["ewres3"]) @@ -1260,16 +1254,8 @@ def GetListOfLayers( :return: list of selected layers """ selected = [] - - if isinstance(ltype, str): - one_type = True - else: - one_type = False - - if one_type and ltype == "overlay": - llist = self.overlays - else: - llist = self.layers + one_type = bool(isinstance(ltype, str)) + llist = self.overlays if one_type and ltype == "overlay" else self.layers # ["raster", "vector", "wms", ... ] for layer in llist: @@ -1332,10 +1318,7 @@ def Render(self, force=False, windres=False): self.renderMgr.Render(force, windres) def _addLayer(self, layer, pos=-1): - if layer.type == "overlay": - llist = self.overlays - else: - llist = self.layers + llist = self.overlays if layer.type == "overlay" else self.layers # add maplayer to the list of layers if pos > -1: @@ -1410,7 +1393,7 @@ def AddLayer( def DeleteAllLayers(self, overlay=False): """Delete all layers - :param overlay: True to delete also overlayes + :param overlay: True to also delete overlays """ self.layers = [] if overlay: @@ -1426,12 +1409,9 @@ def DeleteLayer(self, layer, overlay=False): """ Debug.msg(3, "Map.DeleteLayer(): name=%s" % layer.name) - if overlay: - list = self.overlays - else: - list = self.layers + list_ = self.overlays if overlay else self.layers - if layer in list: + if layer in list_: if layer.mapfile: base, mapfile = os.path.split(layer.mapfile) tempbase = mapfile.split(".")[0] @@ -1448,7 +1428,7 @@ def DeleteLayer(self, layer, overlay=False): if os.path.isfile(layer._legrow): os.remove(layer._legrow) - list.remove(layer) + list_.remove(layer) self.layerRemoved.emit(layer=layer) return layer @@ -1583,13 +1563,10 @@ def GetLayerIndex(self, layer, overlay=False): :return: layer index :return: -1 if layer not found """ - if overlay: - list = self.overlays - else: - list = self.layers + list_ = self.overlays if overlay else self.layers - if layer in list: - return list.index(layer) + if layer in list_: + return list_.index(layer) return -1 diff --git a/gui/wxpython/core/settings.py b/gui/wxpython/core/settings.py index 7fa627dce9e..7d21d04b260 100644 --- a/gui/wxpython/core/settings.py +++ b/gui/wxpython/core/settings.py @@ -772,7 +772,7 @@ def _defaultSettings(self): }, } - # quick fix, http://trac.osgeo.org/grass/ticket/1233 + # quick fix, https://trac.osgeo.org/grass/ticket/1233 # TODO if sys.platform == "darwin": self.defaultSettings["general"]["defWindowPos"]["enabled"] = False @@ -966,10 +966,7 @@ def _readLegacyFile(self, settings=None): del kv[0] idx = 0 while idx < len(kv): - if subkeyMaster: - subkey = [subkeyMaster, kv[idx]] - else: - subkey = kv[idx] + subkey = [subkeyMaster, kv[idx]] if subkeyMaster else kv[idx] value = kv[idx + 1] value = self._parseValue(value, read=True) self.Append(settings, group, key, subkey, value) diff --git a/gui/wxpython/core/toolboxes.py b/gui/wxpython/core/toolboxes.py index 46b886e4996..d3b50cb1ea5 100644 --- a/gui/wxpython/core/toolboxes.py +++ b/gui/wxpython/core/toolboxes.py @@ -308,7 +308,7 @@ def toolboxes2menudata(mainMenu, toolboxes, userToolboxes, wxguiItems, moduleIte userHasToolboxes = False - # in case user has empty toolboxes file (to avoid genereation) + # in case user has empty toolboxes file (to avoid generation) if userToolboxes and userToolboxes.findall(".//toolbox"): _expandUserToolboxesItem(root, userToolboxes) _expandToolboxes(root, userToolboxes) @@ -746,7 +746,7 @@ def _convertTree(root): def _getXMLString(root): """Converts XML tree to string - Since it is usually requier, this function adds a comment (about + Since it is usually required, this function adds a comment (about autogenerated file) to XML file. :return: XML as string diff --git a/gui/wxpython/core/treemodel.py b/gui/wxpython/core/treemodel.py index fb18384ba36..0ce69133e1b 100644 --- a/gui/wxpython/core/treemodel.py +++ b/gui/wxpython/core/treemodel.py @@ -294,15 +294,12 @@ def __init__(self, label=None, data=None): def label(self): return self._label - def match(self, key, value, case_sensitive=False): + def match(self, key, value, case_sensitive=False) -> bool: """Method used for searching according to command, keywords or description.""" if not self.data: return False - if isinstance(key, str): - keys = [key] - else: - keys = key + keys = [key] if isinstance(key, str) else key for key in keys: if key not in {"command", "keywords", "description"}: diff --git a/gui/wxpython/core/units.py b/gui/wxpython/core/units.py index 46b8f91266b..51a3d81174f 100644 --- a/gui/wxpython/core/units.py +++ b/gui/wxpython/core/units.py @@ -195,7 +195,7 @@ def formatDist(distance, mapunits): outdistance = round(distance / divisor, 1) elif (distance / divisor) > 0.0: outdistance = round( - distance / divisor, int(math.ceil(3 - math.log10(distance / divisor))) + distance / divisor, math.ceil(3 - math.log10(distance / divisor)) ) else: outdistance = float(distance / divisor) diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index 4dec112bfbf..f1981bca58c 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -20,6 +20,7 @@ import re import inspect import operator +from string import digits from grass.script import core as grass from grass.script import task as gtask @@ -437,7 +438,7 @@ def __ll_parts(value, reverse=False, precision=3): if value == 0.0: return "%s%.*f" % ("00:00:0", precision, 0.0) - d = int(int(value)) + d = int(value) m = int((value - d) * 60) s = ((value - d) * 60 - m) * 60 if m < 0: @@ -864,10 +865,7 @@ def StoreEnvVariable(key, value=None, envFile=None): ) ) return - if windows: - expCmd = "set" - else: - expCmd = "export" + expCmd = "set" if windows else "export" for key, value in environ.items(): fd.write("%s %s=%s\n" % (expCmd, key, value)) @@ -937,7 +935,7 @@ def SetAddOnPath(addonPath=None, key="PATH"): def color_resolve(color): - if len(color) > 0 and color[0] in "0123456789": + if len(color) > 0 and color[0] in digits: rgb = tuple(map(int, color.split(":"))) label = color else: diff --git a/gui/wxpython/core/workspace.py b/gui/wxpython/core/workspace.py index 65364a3f2f3..a0c5df320af 100644 --- a/gui/wxpython/core/workspace.py +++ b/gui/wxpython/core/workspace.py @@ -169,11 +169,8 @@ def __processFile(self): size = None extentAttr = display.get("extent", "") - if extentAttr: - # w, s, e, n - extent = map(float, extentAttr.split(",")) - else: - extent = None + # w, s, e, n + extent = map(float, extentAttr.split(",")) if extentAttr else None # projection node_projection = display.find("projection") @@ -312,10 +309,7 @@ def __processLayer(self, layer): ) ) - if layer.find("selected") is not None: - selected = True - else: - selected = False + selected = layer.find("selected") is not None # # Vector digitizer settings @@ -330,10 +324,7 @@ def __processLayer(self, layer): # Nviz (3D settings) # node_nviz = layer.find("nviz") - if node_nviz is not None: - nviz = self.__processLayerNviz(node_nviz) - else: - nviz = None + nviz = self.__processLayerNviz(node_nviz) if node_nviz is not None else None return (cmd, selected, vdigit, nviz) @@ -729,10 +720,7 @@ def __processLayerNvizNode(self, node, tag, cast, dc=None): try: value = cast(node_tag.text) except ValueError: - if cast == str: - value = "" - else: - value = None + value = "" if cast == str else None if dc: dc[tag] = {} dc[tag]["value"] = value diff --git a/gui/wxpython/datacatalog/g.gui.datacatalog.html b/gui/wxpython/datacatalog/g.gui.datacatalog.html index 9a918dd3039..8fe684349ba 100644 --- a/gui/wxpython/datacatalog/g.gui.datacatalog.html +++ b/gui/wxpython/datacatalog/g.gui.datacatalog.html @@ -33,12 +33,12 @@

    NOTES

    WARNING

    When renaming, copying or deleting maps outside of Data Catalog, you need to reload -the current mapset or entire database, because it is currently not synchronised. +the current mapset or entire database, because it is currently not synchronized.

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 176f5231712..bf06fd11ab8 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -2016,10 +2016,7 @@ def _getNewMapName(self, message, title, value, element, mapset, env): mapset=mapset, ) dlg.SetValue(value) - if dlg.ShowModal() == wx.ID_OK: - name = dlg.GetValue() - else: - name = None + name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None dlg.Destroy() return name diff --git a/gui/wxpython/dbmgr/base.py b/gui/wxpython/dbmgr/base.py index b6ec1fa105b..3905acb1d73 100644 --- a/gui/wxpython/dbmgr/base.py +++ b/gui/wxpython/dbmgr/base.py @@ -747,7 +747,7 @@ def __init__( :param item: item from Layer Tree :param log: log window :param statusbar: widget with statusbar - :param kwagrs: other wx.Frame's arguments + :param kwargs: other wx.Frame's arguments """ # stores all data, which are shared by pages @@ -918,7 +918,7 @@ def __init__(self, parent, parentDbMgrBase): self.listOfCommands = [] self.listOfSQLStatements = [] - # initializet pages + # initialize pages self.pages = self.parentDbMgrBase.pages # shared data among pages @@ -1138,7 +1138,7 @@ def __init__(self, parent, parentDbMgrBase, onlyLayer=-1): def AddLayer(self, layer, pos=-1): """Adds tab which represents table and enables browse it - :param layer: vector map layer conntected to table + :param layer: vector map layer connected to table :param pos: position of tab, if -1 it is added to end :return: True if layer was added @@ -1542,10 +1542,7 @@ def OnDataItemEdit(self, event): column = tlist.columns[columnName[i]] if len(values[i]) > 0: try: - if missingKey is True: - idx = i - 1 - else: - idx = i + idx = i - 1 if missingKey else i if column["ctype"] != str: tlist.itemDataMap[item][idx] = column["ctype"]( @@ -1662,8 +1659,8 @@ def OnDataItemAdd(self, event): raise ValueError( _("Category number (column %s) is missing.") % keyColumn ) - else: - continue + + continue try: if tlist.columns[columnName[i]]["ctype"] == int: @@ -1707,10 +1704,7 @@ def OnDataItemAdd(self, event): del values[0] # add new item to the tlist - if len(tlist.itemIndexMap) > 0: - index = max(tlist.itemIndexMap) + 1 - else: - index = 0 + index = max(tlist.itemIndexMap) + 1 if len(tlist.itemIndexMap) > 0 else 0 tlist.itemIndexMap.append(index) tlist.itemDataMap[index] = values @@ -1828,11 +1822,7 @@ def _drawSelected(self, zoom, selectedOnly=True): return tlist = self.FindWindowById(self.layerPage[self.selLayer]["data"]) - if selectedOnly: - fn = tlist.GetSelectedItems - else: - fn = tlist.GetItems - + fn = tlist.GetSelectedItems if selectedOnly else tlist.GetItems cats = list(map(int, fn())) digitToolbar = None @@ -1929,11 +1919,7 @@ def AddQueryMapLayer(self, selectedOnly=True): :return: True if map has been redrawn, False if no map is given """ tlist = self.FindWindowById(self.layerPage[self.selLayer]["data"]) - if selectedOnly: - fn = tlist.GetSelectedItems - else: - fn = tlist.GetItems - + fn = tlist.GetSelectedItems if selectedOnly else tlist.GetItems cats = {self.selLayer: fn()} if self.mapdisplay.Map.GetLayerIndex(self.qlayer) < 0: @@ -2237,10 +2223,7 @@ def ValidateSelectStatement(self, statement): break cols += c index += 1 - if cols == "*": - cols = None - else: - cols = cols.split(",") + cols = None if cols == "*" else cols.split(",") tablelen = len(self.dbMgrData["mapDBInfo"].layers[self.selLayer]["table"]) @@ -2251,10 +2234,7 @@ def ValidateSelectStatement(self, statement): if len(statement[index + 7 + tablelen :]) > 0: index = statement.lower().find("where ") - if index > -1: - where = statement[index + 6 :] - else: - where = None + where = statement[index + 6 :] if index > -1 else None else: where = None @@ -3325,10 +3305,7 @@ def _createAddPage(self): row = 0 for key in ("layer", "driver", "database", "table", "key", "addCat"): label, value = self.addLayerWidgets[key] - if not value: - span = (1, 2) - else: - span = (1, 1) + span = (1, 2) if not value else (1, 1) dataSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0), span=span) if not value: @@ -4054,7 +4031,7 @@ def Update(self, driver, database, table, column): database=database, ) if not dataStr: - GError(parent=self.parent, message=_("Unable to calculte statistics.")) + GError(parent=self.parent, message=_("Unable to calculate statistics.")) self.Close() return @@ -4063,7 +4040,7 @@ def Update(self, driver, database, table, column): GError( parent=self.parent, message=_( - "Unable to calculte statistics. " + "Unable to calculate statistics. " "Invalid number of lines %d (should be %d)." ) % (len(dataLines), len(stats)), @@ -4090,7 +4067,7 @@ def Update(self, driver, database, table, column): ) if not dataVar: GWarning( - parent=self.parent, message=_("Unable to calculte standard deviation.") + parent=self.parent, message=_("Unable to calculate standard deviation.") ) varSum = 0 for var in decode(dataVar).splitlines(): diff --git a/gui/wxpython/dbmgr/dialogs.py b/gui/wxpython/dbmgr/dialogs.py index 0d7c6e9e523..c94e2a71e40 100644 --- a/gui/wxpython/dbmgr/dialogs.py +++ b/gui/wxpython/dbmgr/dialogs.py @@ -393,10 +393,7 @@ def UpdateDialog(self, map=None, query=None, cats=None, fid=-1, action=None): """ if action: self.action = action - if action == "display": - enabled = False - else: - enabled = True + enabled = action != "display" self.closeDialog.Enable(enabled) self.FindWindowById(wx.ID_OK).Enable(enabled) @@ -420,10 +417,7 @@ def UpdateDialog(self, map=None, query=None, cats=None, fid=-1, action=None): idx = 0 for layer in data["Layer"]: layer = int(layer) - if data["Id"][idx] is not None: - tfid = int(data["Id"][idx]) - else: - tfid = 0 # Area / Volume + tfid = int(data["Id"][idx]) if data["Id"][idx] is not None else 0 if tfid not in self.cats: self.cats[tfid] = {} if layer not in self.cats[tfid]: @@ -654,15 +648,14 @@ def __init__( self.boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL) cId += 1 continue - else: - valueWin = SpinCtrl( - parent=self.dataPanel, - id=wx.ID_ANY, - value=value, - min=-1e9, - max=1e9, - size=(250, -1), - ) + valueWin = SpinCtrl( + parent=self.dataPanel, + id=wx.ID_ANY, + value=value, + min=-1e9, + max=1e9, + size=(250, -1), + ) else: valueWin = TextCtrl( parent=self.dataPanel, id=wx.ID_ANY, value=value, size=(250, -1) diff --git a/gui/wxpython/dbmgr/g.gui.dbmgr.html b/gui/wxpython/dbmgr/g.gui.dbmgr.html index 9ea595a754e..0416843d43b 100644 --- a/gui/wxpython/dbmgr/g.gui.dbmgr.html +++ b/gui/wxpython/dbmgr/g.gui.dbmgr.html @@ -41,7 +41,7 @@

    SQL Builder

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/dbmgr/manager.py b/gui/wxpython/dbmgr/manager.py index b1cbd93ab71..86c522282fd 100644 --- a/gui/wxpython/dbmgr/manager.py +++ b/gui/wxpython/dbmgr/manager.py @@ -65,7 +65,7 @@ def __init__( :param item: item from Layer Tree :param log: log window :param selection: name of page to be selected - :param kwagrs: other wx.Frame's arguments + :param kwargs: other wx.Frame's arguments """ self.parent = parent try: @@ -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/dbmgr/sqlbuilder.py b/gui/wxpython/dbmgr/sqlbuilder.py index 5e6fe0e7706..fd9378846d7 100644 --- a/gui/wxpython/dbmgr/sqlbuilder.py +++ b/gui/wxpython/dbmgr/sqlbuilder.py @@ -49,7 +49,7 @@ class SQLBuilder(wx.Frame): - """SQLBuider class + """SQLBuilder class Base class for classes, which builds SQL statements. """ @@ -314,8 +314,8 @@ def _doLayout(self, modeChoices, showDbInfo=False): flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5, ) - # self.pagesizer.Add(self.btn_uniqe,0,wx.ALIGN_LEFT|wx.TOP,border=5) - # self.pagesizer.Add(self.btn_uniqesample,0,wx.ALIGN_LEFT|wx.TOP,border=5) + # self.pagesizer.Add(self.btn_unique,0,wx.ALIGN_LEFT|wx.TOP,border=5) + # self.pagesizer.Add(self.btn_uniquesample,0,wx.ALIGN_LEFT|wx.TOP,border=5) self.pagesizer.Add( self.btn_logicpanel, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL ) @@ -574,10 +574,7 @@ def _add(self, element, value): idx1 = len("select") idx2 = sqlstr.lower().find("from") colstr = sqlstr[idx1:idx2].strip() - if colstr == "*": - cols = [] - else: - cols = colstr.split(",") + cols = [] if colstr == "*" else colstr.split(",") if value in cols: cols.remove(value) else: @@ -922,10 +919,7 @@ def _add(self, element, value): print(__doc__, file=sys.stderr) sys.exit() - if len(sys.argv) == 3: - layer = 1 - else: - layer = int(sys.argv[3]) + layer = 1 if len(sys.argv) == 3 else int(sys.argv[3]) if sys.argv[1] == "select": sqlBuilder = SQLBuilderSelect diff --git a/gui/wxpython/docs/wxGUI.html b/gui/wxpython/docs/wxGUI.html index eca0dc5d3ed..fec5ced8c22 100644 --- a/gui/wxpython/docs/wxGUI.html +++ b/gui/wxpython/docs/wxGUI.html @@ -110,38 +110,38 @@

    Layer Manager Toolbar

    icon  - Add 3D raster map layer
    + Add 3D raster map layer
    Adds 3D raster map to layer tree.
    icon  - Add RGB raster layer
    + Add RGB raster layer
    Combines and displays three raster maps defined as red, green, - and blue channels to create an RGB color map, - see d.rgb.
    + and blue channels to create an RGB color map, + see d.rgb.
    icon  - Add HIS raster layer
    + Add HIS raster layer
    Combines and displays two or three raster maps defined as hue, - intensity, and (optionally) saturation channels to create a color map, - see d.his.
    + intensity, and (optionally) saturation channels to create a color map, + see d.his.
    icon  - Add shaded relief raster map layer
    + Add shaded relief raster map layer
    Adds shaded relief raster map layer, see r.relief and d.shade.
    icon  - Add raster arrows layer
    + Add raster arrows layer
    Adds map of raster cells with directional arrows drawn. Arrow - direction and length are determined by separate aspect/directional map - and (optional) slope/intensity map, - see d.rast.arrow.
    + direction and length are determined by separate aspect/directional map + and (optional) slope/intensity map, + see d.rast.arrow.
    icon  - Add raster numbers layer
    + Add raster numbers layer
    Adds map of raster cells with numbers representing the cell values, - see d.rast.num.
    + see d.rast.num.
    icon  @@ -155,26 +155,26 @@

    Layer Manager Toolbar

    icon  - Add thematic area (choropleth) map layer - (for all vector types)
    + Add thematic area (choropleth) map layer + (for all vector types)
    Adds layer for thematic display values from a numeric attribute - column associated with a vector map. Options include: thematic display - type (graduated colors or point sizes), methods for creating display - intervals, SQL query of attribute column to limit vector objects to - display, control of point icon types and sizes, control of thematic - color schemes, creation of legend for thematic map, and saving the - results of thematic mapping to a ps.map instructions file for later - printing, - see d.vect.thematic.
    + column associated with a vector map. Options include: thematic display + type (graduated colors or point sizes), methods for creating display + intervals, SQL query of attribute column to limit vector objects to + display, control of point icon types and sizes, control of thematic + color schemes, creation of legend for thematic map, and saving the + results of thematic mapping to a ps.map instructions file for later + printing, + see d.vect.thematic.
    icon  - Add thematic chart layer (for vector points)
    + Add thematic chart layer (for vector points)
    Adds layer in which pie or bar charts can be automatically created - at vector point locations. Charts display values from selected columns - in the associated attribute table. Options include: chart type, layer - and attributes to chart, chart colors, and chart size (fixed or based - on attribute column), - see d.vect.chart.
    + at vector point locations. Charts display values from selected columns + in the associated attribute table. Options include: chart type, layer + and attributes to chart, chart colors, and chart size (fixed or based + on attribute column), + see d.vect.chart.
    icon  @@ -186,32 +186,32 @@

    Layer Manager Toolbar

    Opens a dropdown menu that allows user to select to:
    icon  - Add overlay grids and lines
    + Add overlay grids and lines
    Adds layer to display regular grid - see d.grid
    + see d.grid
    icon  - Add labels layer for vector objects (from existing labels file)
    + Add labels layer for vector objects (from existing labels file)
    Add a layer of text from a labels file for vector objects - created with the v.label module. - A labels file can also be created with a text editor, - see d.labels.
    + created with the v.label module. + A labels file can also be created with a text editor, + see d.labels.
    icon  - Add geodesic line layer
    + Add geodesic line layer
    Add layer to display geodesic line for latitude/longitude projects only, - see d.geodesic
    + see d.geodesic
    icon  - Add rhumbline layer -
    Add layer to display rhumblines (for latitude/longitude projects only), + Add rhumbline layer +
    Add layer to display rhumblines (for latitude/longitude projects only), see d.rhumbline.
    icon  - Add command layer
    + Add command layer
    Adds a layer in which a GRASS GIS command or command list can be entered. - For a command list use the semi-colon (";") symbol as a separator. - For example: + For a command list use the semi-colon (";") symbol as a separator. + For example:
     d.rast soils;d.rast -o roads;d.vect streams col=blue
    @@ -241,37 +241,37 @@ 

    Layer Manager Toolbar

    icon  - Import raster data
    + Import raster data
    Import selected raster data into GRASS using r.in.gdal and load them into current layer tree.
    icon  - Link external raster data
    + Link external raster data
    Link selected external raster data as GRASS raster maps (using r.external) and load them into current layer tree.
    icon  - Set raster output format
    + Set raster output format
    Define external format for newly created raster maps (see r.external.out for details)
    icon  - Import vector data
    + Import vector data
    Import selected vector data into GRASS using v.in.ogr and load them into current layer tree.
    icon  - Link external vector data
    + Link external vector data
    Link selected external vector data as GRASS vector maps (using v.external) and load them into current layer tree.
    icon  - Set vector output format
    + Set vector output format
    Define external format for newly created vector maps (see v.external.out for details)
    @@ -375,10 +375,10 @@

    Map Display Toolbar

    icon  Query raster/vector maps
    Query selected raster, RGB raster (all three map channels will be - queried), or vector map(s) using the mouse. Map(s) must be selected - before query. Vector charts and thematic vector maps cannot be - queried. The results of the query will be displayed in a dialog. - See r.what, v.what. + queried), or vector map(s) using the mouse. Map(s) must be selected + before query. Vector charts and thematic vector maps cannot be + queried. The results of the query will be displayed in a dialog. + See r.what, v.what.
    icon  @@ -473,9 +473,9 @@

    Map Display Toolbar

    icon  Profile surface map
    Interactively create profile of a raster map. Profile transect is - drawn with the mouse in map display. The profile may be of the - displayed map or a different map. Up to three maps can be profiled - simultaneously.
    + drawn with the mouse in map display. The profile may be of the + displayed map or a different map. Up to three maps can be profiled + simultaneously.
    icon  Create bivariate scatterplot of raster maps
    @@ -546,25 +546,25 @@

    Map Display Toolbar

    2D view
    Normal GIS display. All active layers are composited and displayed - in 2D mode.
    + in 2D mode.
    3D view
    Experimental replacement for NVIZ. Displays all active layers in - 3D perspective using OpenGL. A new control panel opens to manage the - 3D view. 3D view can be zoomed, panned, rotated, and tilted. The - vertical exaggeration of rasters and 3D vectors can be set. Various - color and lighten settings are possible. Not yet functional for - Windows platforms
    + 3D perspective using OpenGL. A new control panel opens to manage the + 3D view. 3D view can be zoomed, panned, rotated, and tilted. The + vertical exaggeration of rasters and 3D vectors can be set. Various + color and lighten settings are possible. Not yet functional for + Windows platforms
    Vector digitizer
    Puts display into vector digitizing mode and opens a new digitizing - toolbar. The user can digitize a new vector map or edit an existing - map.
    + toolbar. The user can digitize a new vector map or edit an existing + map.
    Raster digitizer
    Puts display into raster digitizing mode and opens a new digitizing - toolbar. The user can digitize a new raster map or edit an existing - map.
    + toolbar. The user can digitize a new raster map or edit an existing + map. @@ -686,14 +686,14 @@

    Starting the GUI from command line

    Background information

    wxGUI is a native Graphical User Interface (GUI) for -GRASS GIS written in Python +GRASS GIS written in Python using wxPython library.

    SEE ALSO

    - wxGUI components
    - wxGUI module dialogs + wxGUI components, + wxGUI module dialogs, wxGUI toolboxes (menu customization)
    diff --git a/gui/wxpython/docs/wxGUI.iscatt.html b/gui/wxpython/docs/wxGUI.iscatt.html index 85ef25d164d..d1601eb1c0d 100644 --- a/gui/wxpython/docs/wxGUI.iscatt.html +++ b/gui/wxpython/docs/wxGUI.iscatt.html @@ -69,7 +69,7 @@

    KNOWN ISSUES

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components, r.rescale
    diff --git a/gui/wxpython/docs/wxGUI.modules.html b/gui/wxpython/docs/wxGUI.modules.html index dd9d3e2b34f..44aeedace61 100644 --- a/gui/wxpython/docs/wxGUI.modules.html +++ b/gui/wxpython/docs/wxGUI.modules.html @@ -174,7 +174,7 @@

    NOTES

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/docs/wxGUI.nviz.html b/gui/wxpython/docs/wxGUI.nviz.html index aed1c0b0a8e..3c0767f9598 100644 --- a/gui/wxpython/docs/wxGUI.nviz.html +++ b/gui/wxpython/docs/wxGUI.nviz.html @@ -319,7 +319,7 @@

    Appearance

    • Lighting for adjusting light source
    • -
    • Fringe for drawing fringes +
    • Fringe for drawing fringes
    • Decorations to display north arrow and scale bar

    @@ -386,7 +386,7 @@

    NOTE

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/docs/wxGUI.toolboxes.html b/gui/wxpython/docs/wxGUI.toolboxes.html index 4920fe07c3f..ccbf4f6415c 100644 --- a/gui/wxpython/docs/wxGUI.toolboxes.html +++ b/gui/wxpython/docs/wxGUI.toolboxes.html @@ -7,11 +7,11 @@

    DESCRIPTION

      -
    • hide unused menu items in menu (e.g. Imagery, Database) or submenu (e.g. Wildfire modeling) -
    • change order of menu items and subitems -
    • add new menu items (e.g. Temporal) -
    • add addons modules -
    • add your own modules +
    • hide unused menu items in menu (e.g. Imagery, Database) or submenu (e.g. Wildfire modeling)
    • +
    • change order of menu items and subitems
    • +
    • add new menu items (e.g. Temporal)
    • +
    • add addons modules
    • +
    • add your own modules

    @@ -194,7 +194,7 @@

    NOTES

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/docs/wxGUI.vnet.html b/gui/wxpython/docs/wxGUI.vnet.html index cad3fe0b9cc..c1b8a51831b 100644 --- a/gui/wxpython/docs/wxGUI.vnet.html +++ b/gui/wxpython/docs/wxGUI.vnet.html @@ -89,7 +89,7 @@

    KNOWN ISSUES

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/docs/wxgui_sphinx/src/index.rst b/gui/wxpython/docs/wxgui_sphinx/src/index.rst index 3db1c955bba..f2959542a77 100644 --- a/gui/wxpython/docs/wxgui_sphinx/src/index.rst +++ b/gui/wxpython/docs/wxgui_sphinx/src/index.rst @@ -7,7 +7,7 @@ The documentation is intended to be used by GRASS GIS developers only because the documented API is not guaranteed to be stable. If you are thinking about doing some development using this API, please contact other developers at -`grass-dev `_ mailing list. +`grass-dev `_ mailing list. .. toctree:: diff --git a/gui/wxpython/gcp/g.gui.gcp.html b/gui/wxpython/gcp/g.gui.gcp.html index 4585de25674..97713d9a763 100644 --- a/gui/wxpython/gcp/g.gui.gcp.html +++ b/gui/wxpython/gcp/g.gui.gcp.html @@ -26,11 +26,11 @@

    DESCRIPTION

    manipulate and analyze GCPs are provided in the toolbar. This panel can be moved out of the GCP manager window by either dragging with the caption or by clicking on the pin button on the right in the caption. - This panel can also be placed below the map displays by dragging. + This panel can also be placed below the map displays by dragging.
  • The two panels in the lower part are used for map and GCP display, the left pane showing a map from the source project and the right pane showing a reference map from the target project. Numbered Ground - Control Points are shown on both map displays. + Control Points are shown on both map displays.
  • @@ -50,7 +50,7 @@

    Components of the GCP Manager

    List of ground control points

    The list of Ground Control Points can be sorted by clicking on a column -header. Clicking on a cloumn header will sort the GCPs ascending, a +header. Clicking on a column header will sort the GCPs ascending, a second click on the same column will sort the GCPs descending. Overall RMS error and individual RMS errors of all points are often improved if the GCP with the highest RMS error is adjusted. Individual coordinates @@ -292,7 +292,7 @@

    GCP Map Display Statusbar

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/gcp/g.gui.gcp.py b/gui/wxpython/gcp/g.gui.gcp.py index 12f0a152090..2201b7c2280 100755 --- a/gui/wxpython/gcp/g.gui.gcp.py +++ b/gui/wxpython/gcp/g.gui.gcp.py @@ -29,7 +29,7 @@ # %end """ -Module to run GCP management tool as stadalone application. +Module to run GCP management tool as standalone application. @author Vaclav Petras (standalone module) """ diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 3b6dd398b51..fc8fa869781 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -23,7 +23,7 @@ @author Original author Michael Barton @author Original version improved by Martin Landa -@author Rewritten by Markus Metz redesign georectfier -> GCP Manage +@author Rewritten by Markus Metz redesign georectifier -> GCP Manage @author Support for GraphicsSet added by Stepan Turek (2012) """ @@ -469,11 +469,7 @@ def __init__(self, wizard, parent): def OnMaptype(self, event): """Change map type""" global maptype - - if event.GetInt() == 0: - maptype = "raster" - else: - maptype = "vector" + maptype = "raster" if event.GetInt() == 0 else "vector" def OnLocation(self, event): """Sets source location for map(s) to georectify""" @@ -1057,10 +1053,10 @@ def __init__( # register data structures for drawing GCP's # self.pointsToDrawTgt = self.TgtMapWindow.RegisterGraphicsToDraw( - graphicsType="point", setStatusFunc=self.SetGCPSatus + graphicsType="point", setStatusFunc=self.SetGCPStatus ) self.pointsToDrawSrc = self.SrcMapWindow.RegisterGraphicsToDraw( - graphicsType="point", setStatusFunc=self.SetGCPSatus + graphicsType="point", setStatusFunc=self.SetGCPStatus ) # connect to the map windows signals @@ -1414,7 +1410,7 @@ def SetSettings(self): # overwrite result map self.overwrite = UserSettings.Get(group="gcpman", key="map", subkey="overwrite") - def SetGCPSatus(self, item, itemIndex): + def SetGCPStatus(self, item, itemIndex): """Before GCP is drawn, decides it's colour and whether it will be drawn. """ @@ -1433,10 +1429,7 @@ def SetGCPSatus(self, item, itemIndex): else: item.SetPropertyVal("hide", False) if self.highest_only: - if itemIndex == self.highest_key: - wxPen = "highest" - else: - wxPen = "default" + wxPen = "highest" if itemIndex == self.highest_key else "default" elif self.mapcoordlist[key][5] > self.rmsthresh: wxPen = "highest" else: @@ -1670,16 +1663,13 @@ def ReloadGCPs(self, event): targetMapWin.UpdateMap(render=False, renderVector=False) def OnFocus(self, event): - # TODO: it is here just to remove old or obsolete beavior of base class + # TODO: it is here just to remove old or obsolete behavior of base class # gcp/MapPanel? # self.grwiz.SwitchEnv('source') pass def _onMouseLeftUpPointer(self, mapWindow, x, y): - if mapWindow == self.SrcMapWindow: - coordtype = "source" - else: - coordtype = "target" + coordtype = "source" if mapWindow == self.SrcMapWindow else "target" coord = (x, y) self.SetGCPData(coordtype, coord, self, confirm=True) @@ -1806,10 +1796,7 @@ def OnGeorect(self, event): self.grwiz.SwitchEnv("source") - if self.clip_to_region: - flags = "ac" - else: - flags = "a" + flags = "ac" if self.clip_to_region else "a" with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): wx.GetApp().Yield() diff --git a/gui/wxpython/gmodeler/canvas.py b/gui/wxpython/gmodeler/canvas.py index bfe5f7a90af..642f007e273 100644 --- a/gui/wxpython/gmodeler/canvas.py +++ b/gui/wxpython/gmodeler/canvas.py @@ -329,10 +329,10 @@ def OnRightClick(self, x, y, keys=0, attachment=0): self.frame.Bind(wx.EVT_MENU, self.OnEnable, id=self.popupID["enable"]) if isinstance(shape, (ModelAction, ModelComment)): popupMenu.AppendSeparator() - if isinstance(shape, ModelAction): - popupMenu.Append(self.popupID["label"], _("Set label")) - self.frame.Bind(wx.EVT_MENU, self.OnSetLabel, id=self.popupID["label"]) - if isinstance(shape, (ModelAction, ModelComment)): + if isinstance(shape, ModelAction): + popupMenu.Append(self.popupID["label"], _("Set label")) + self.frame.Bind(wx.EVT_MENU, self.OnSetLabel, id=self.popupID["label"]) + popupMenu.Append(self.popupID["comment"], _("Set comment")) self.frame.Bind(wx.EVT_MENU, self.OnSetComment, id=self.popupID["comment"]) @@ -440,12 +440,8 @@ def _onSelectShape(self, shape, append=False): shape.Select(False, dc) else: shapeList = canvas.GetDiagram().GetShapeList() - toUnselect = [] - if not append: - for s in shapeList: - if s.Selected(): - toUnselect.append(s) + toUnselect = [s for s in shapeList if s.Selected()] if not append else [] shape.Select(True, dc) diff --git a/gui/wxpython/gmodeler/dialogs.py b/gui/wxpython/gmodeler/dialogs.py index 7cd7cbd1147..ba966ea6a53 100644 --- a/gui/wxpython/gmodeler/dialogs.py +++ b/gui/wxpython/gmodeler/dialogs.py @@ -11,7 +11,7 @@ - dialogs::ModelLoopDialog - dialogs::ModelConditionDialog - dialogs::ModelListCtrl - - dialogs::ValiableListCtrl + - dialogs::VariableListCtrl - dialogs::ItemListCtrl - dialogs::ItemCheckListCtrl @@ -291,11 +291,7 @@ def GetPanel(self): def _getCmd(self): line = self.cmd_prompt.GetCurLine()[0].strip() - if len(line) == 0: - cmd = [] - else: - cmd = utils.split(str(line)) - return cmd + return [] if len(line) == 0 else utils.split(str(line)) def GetCmd(self): """Get command""" @@ -980,10 +976,7 @@ def Populate(self, data): checked.append(None) else: bId = action.GetBlockId() - if not bId: - bId = _("No") - else: - bId = _("Yes") + bId = _("No") if not bId else _("Yes") options = action.GetParameterizedParams() params = [] for f in options["flags"]: @@ -1110,10 +1103,7 @@ def MoveItems(self, items, up): idxList = {} itemsToSelect = [] for i in items: - if up: - idx = i - 1 - else: - idx = i + 1 + idx = i - 1 if up else i + 1 itemsToSelect.append(idx) idxList[model.GetItemIndex(modelActions[i])] = model.GetItemIndex( modelActions[idx] diff --git a/gui/wxpython/gmodeler/g.gui.gmodeler.html b/gui/wxpython/gmodeler/g.gui.gmodeler.html index 631c06de9d8..dae5aefea52 100644 --- a/gui/wxpython/gmodeler/g.gui.gmodeler.html +++ b/gui/wxpython/gmodeler/g.gui.gmodeler.html @@ -107,15 +107,15 @@

    Components of models

    Different model elements are shown in the figures below.
      -
    • (A) raster data: raster -
    • (B) relation: relation -
    • (C) GRASS module: module -
    • (D) loop: loop -
    • (E) database table: db -
    • (F) 3D raster data: raster3D -
    • (G) vector data: vector -
    • (H) disabled GRASS module: module -
    • (I) comment: comment +
    • (A) raster data: raster
    • +
    • (B) relation: relation
    • +
    • (C) GRASS module: module
    • +
    • (D) loop: loop
    • +
    • (E) database table: db
    • +
    • (F) 3D raster data: raster3D
    • +
    • (G) vector data: vector
    • +
    • (H) disabled GRASS module: module
    • +
    • (I) comment: comment
    @@ -460,13 +460,13 @@

    Defining loops

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components

    See also selected user models available from -GRASS Addons repository. +GRASS Addons repository.

    See also diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 23e308037ff..2a4673f511a 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -161,7 +161,7 @@ def ReorderItems(self, idxList): self.canvas.parent.DefineCondition(mo) def Normalize(self): - # check for inconsistecies + # check for inconsistencies for idx in range(1, len(self.items)): if not self.items[idx].GetBlock() and isinstance( self.items[idx - 1], ModelLoop @@ -525,7 +525,7 @@ def Validate(self): def _substituteFile(self, item, params=None, checkOnly=False): """Substitute variables in command file inputs - :param bool checkOnly: tuble - True to check variable, don't touch files + :param bool checkOnly: True to check variable, don't touch files :return: list of undefined variables """ @@ -770,7 +770,7 @@ def Run(self, log, onDone, parent=None): p["value"] = "" def DeleteIntermediateData(self, log): - """Detele intermediate data""" + """Delete intermediate data""" rast, vect, rast3d, msg = self.GetIntermediateData() if rast: @@ -833,10 +833,7 @@ def Parameterize(self): if gtype in {"raster", "vector", "mapset", "file", "region", "dir"}: gisprompt = True prompt = gtype - if gtype == "raster": - element = "cell" - else: - element = gtype + element = "cell" if gtype == "raster" else gtype ptype = "string" else: gisprompt = False @@ -1102,10 +1099,7 @@ def _setPen(self): group="modeler", key="action", subkey=("width", "default") ) ) - if self.isEnabled: - style = wx.SOLID - else: - style = wx.DOT + style = wx.SOLID if self.isEnabled else wx.DOT pen = wx.Pen(wx.BLACK, width, style) self.SetPen(pen) @@ -1453,10 +1447,7 @@ def SetValue(self, value): self.SetLabel() for direction in ("from", "to"): for rel in self.GetRelations(direction): - if direction == "from": - action = rel.GetTo() - else: - action = rel.GetFrom() + action = rel.GetTo() if direction == "from" else rel.GetFrom() task = GUI(show=None).ParseCommand(cmd=action.GetLog(string=False)) task.set_param(rel.GetLabel(), self.value) @@ -1525,10 +1516,7 @@ def _getPen(self): group="modeler", key="action", subkey=("width", "default") ) ) - if self.intermediate: - style = wx.DOT - else: - style = wx.SOLID + style = wx.DOT if self.intermediate else wx.SOLID return wx.Pen(wx.BLACK, width, style) @@ -1718,10 +1706,7 @@ def __init__( def _setPen(self): """Set pen""" - if self.isEnabled: - style = wx.SOLID - else: - style = wx.DOT + style = wx.SOLID if self.isEnabled else wx.DOT pen = wx.Pen(wx.BLACK, 1, style) self.SetPen(pen) @@ -1986,10 +1971,7 @@ def __init__(self, tree): self.root = self.tree.getroot() # check if input is a valid GXM file if self.root is None or self.root.tag != "gxm": - if self.root is not None: - tagName = self.root.tag - else: - tagName = _("empty") + tagName = self.root.tag if self.root is not None else _("empty") raise GException(_("Details: unsupported tag name '{0}'.").format(tagName)) # list of actions, data @@ -2099,10 +2081,7 @@ def _processActions(self): aId = int(action.get("id", -1)) label = action.get("name") comment = action.find("comment") - if comment is not None: - commentString = comment.text - else: - commentString = "" + commentString = comment.text if comment is not None else "" self.actions.append( { @@ -2285,7 +2264,6 @@ def _processComments(self): "size": size, "text": text, "id": int(node.get("id", -1)), - "text": text, } ) @@ -2516,10 +2494,7 @@ def _data(self, dataList): # relations for ft in ("from", "to"): for rel in data.GetRelations(ft): - if ft == "from": - aid = rel.GetTo().GetId() - else: - aid = rel.GetFrom().GetId() + aid = rel.GetTo().GetId() if ft == "from" else rel.GetFrom().GetId() self.fd.write( '%s\n' % (" " * self.indent, ft, aid, rel.GetLabel()) @@ -2697,7 +2672,7 @@ def _getParamName(self, parameter_name, item): @staticmethod def _getModuleNickname(item): return "{module_name}{module_id}".format( - module_name=re.sub("[^a-zA-Z]+", "", item.GetLabel()), + module_name=re.sub(r"[^a-zA-Z]+", "", item.GetLabel()), module_id=item.GetId(), ) @@ -2988,10 +2963,7 @@ def _write_input_outputs(self, item, intermediates): parameterized_params = item.GetParameterizedParams() for flag in parameterized_params["flags"]: - if flag["label"]: - desc = flag["label"] - else: - desc = flag["description"] + desc = flag["label"] or flag["description"] if flag["value"]: value = '\n{}default="{}"'.format( @@ -3257,12 +3229,7 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): return ret def _getParamDesc(self, param): - if param["label"]: - desc = param["label"] - else: - desc = param["description"] - - return desc + return param["label"] or param["description"] def _getParamValue(self, param): if param["value"] and "output" not in param["name"]: @@ -3375,10 +3342,7 @@ def _writePython(self): for item in modelItems: parametrizedParams = item.GetParameterizedParams() for flag in parametrizedParams["flags"]: - if flag["label"]: - desc = flag["label"] - else: - desc = flag["description"] + desc = flag["label"] or flag["description"] self.fd.write( r"""# %option # % key: {flag_name} @@ -3399,10 +3363,7 @@ def _writePython(self): self.fd.write("# %end\n") for param in parametrizedParams["params"]: - if param["label"]: - desc = param["label"] - else: - desc = param["description"] + desc = param["label"] or param["description"] self.fd.write( r"""# %option # % key: {param_name} @@ -3775,5 +3736,5 @@ def GetErrors(self): return errList def DeleteIntermediateData(self) -> bool: - """Check if to detele intermediate data""" + """Check if to delete intermediate data""" return bool(self.interData.IsShown() and self.interData.IsChecked()) diff --git a/gui/wxpython/gmodeler/panels.py b/gui/wxpython/gmodeler/panels.py index 416a9b85592..fbdc2048620 100644 --- a/gui/wxpython/gmodeler/panels.py +++ b/gui/wxpython/gmodeler/panels.py @@ -622,10 +622,7 @@ def LoadModelFile(self, filename): item.Show(True) # relations/data for rel in item.GetRelations(): - if rel.GetFrom() == item: - dataItem = rel.GetTo() - else: - dataItem = rel.GetFrom() + dataItem = rel.GetTo() if rel.GetFrom() == item else rel.GetFrom() self._addEvent(dataItem) self.canvas.diagram.AddShape(dataItem) self.AddLine(rel) @@ -1663,13 +1660,8 @@ def GetScriptExt(self): """Get extension for script exporting. :return: script extension """ - if self.write_object == WriteActiniaFile: - ext = "json" - else: - # Python, PyWPS - ext = "py" - - return ext + # return "py" for Python, PyWPS + return "json" if self.write_object == WriteActiniaFile else "py" def SetWriteObject(self, script_type): """Set correct self.write_object depending on the script type. diff --git a/gui/wxpython/gmodeler/toolbars.py b/gui/wxpython/gmodeler/toolbars.py index ca6a75b4804..4e7acf500b0 100644 --- a/gui/wxpython/gmodeler/toolbars.py +++ b/gui/wxpython/gmodeler/toolbars.py @@ -24,7 +24,7 @@ class ModelerToolbar(BaseToolbar): - """Graphical modeler toolbaro (see gmodeler.py)""" + """Graphical modeler toolbar (see gmodeler.py)""" def __init__(self, parent): BaseToolbar.__init__(self, parent) diff --git a/gui/wxpython/gui_core/dialogs.py b/gui/wxpython/gui_core/dialogs.py index 793f9cb39b9..60581564f04 100644 --- a/gui/wxpython/gui_core/dialogs.py +++ b/gui/wxpython/gui_core/dialogs.py @@ -466,10 +466,7 @@ def CreateNewVector( """ vExternalOut = grass.parse_command("v.external.out", flags="g") isNative = vExternalOut["format"] == "native" - if cmd[0] == "v.edit" and not isNative: - showType = True - else: - showType = False + showType = bool(cmd[0] == "v.edit" and not isNative) dlg = NewVectorDialog( parent, title=title, @@ -1340,10 +1337,7 @@ def ShowResult(self, group, returnCode, create): def GetSelectedGroup(self): """Return currently selected group (without mapset)""" g = self.groupSelect.GetValue().split("@")[0] - if self.edit_subg: - s = self.subGroupSelect.GetValue() - else: - s = None + s = self.subGroupSelect.GetValue() if self.edit_subg else None return g, s def GetGroupLayers(self, group, subgroup=None): @@ -1374,10 +1368,7 @@ def ApplyChanges(self): GMessage(parent=self, message=_("No subgroup selected.")) return 0 - if self.edit_subg: - subgroup = self.currentSubgroup - else: - subgroup = None + subgroup = self.currentSubgroup if self.edit_subg else None groups = self.GetExistGroups() if group in groups: @@ -1476,7 +1467,7 @@ def _addApplyButton(self): """ def _fullyQualifiedNames(self): - """Adds CheckBox which determines is fully qualified names are retuned.""" + """Adds CheckBox which determines if fully qualified names are returned.""" self.fullyQualified = wx.CheckBox( parent=self, id=wx.ID_ANY, label=_("Use fully-qualified map names") ) diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index e90801a6e95..0526015d045 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -193,10 +193,7 @@ def run(self): if not pMap: pMap = self.task.get_param("input", raiseError=False) - if pMap: - map = pMap.get("value", "") - else: - map = None + map = pMap.get("value", "") if pMap else None # avoid running db.describe several times cparams = {} @@ -278,10 +275,7 @@ def run(self): elif p.get("element", "") in {"layer", "layer_all"}: # -> layer # get layer layer = p.get("value", "") - if layer != "": - layer = p.get("value", "") - else: - layer = p.get("default", "") + layer = p.get("value", "") if layer != "" else p.get("default", "") # get map name pMapL = self.task.get_param( @@ -722,10 +716,7 @@ def __init__( sizeFrame = self.GetBestSize() self.SetMinSize(sizeFrame) - if hasattr(self, "closebox"): - scale = 0.33 - else: - scale = 0.50 + scale = 0.33 if hasattr(self, "closebox") else 0.5 self.SetSize( wx.Size( round(sizeFrame[0]), @@ -813,10 +804,7 @@ def OnMapCreated(self, name, ltype, add: bool | None = None): :param ltype: layer type (prompt value) :param add: whether to display layer or not """ - if hasattr(self, "addbox") and self.addbox.IsChecked(): - add = True - else: - add = False + add = bool(hasattr(self, "addbox") and self.addbox.IsChecked()) if self._giface: self._giface.mapCreated.emit(name=name, ltype=ltype, add=add) @@ -1156,10 +1144,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar else: title_sizer = wx.BoxSizer(wx.HORIZONTAL) title_txt = StaticText(parent=which_panel) - if p["key_desc"]: - ltype = ",".join(p["key_desc"]) - else: - ltype = p["type"] + ltype = ",".join(p["key_desc"]) if p["key_desc"] else p["type"] # red star for required options if p.get("required", False): required_txt = StaticText(parent=which_panel, label="*") @@ -1900,10 +1885,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar win.Bind(wx.EVT_COMBOBOX, self.OnSetValue) elif prompt == "mapset": - if p.get("age", "old") == "old": - new = False - else: - new = True + new = p.get("age", "old") != "old" win = gselect.MapsetSelect( parent=which_panel, @@ -2008,10 +1990,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar # file selector elif p.get("prompt", "") != "color" and p.get("prompt", "") == "file": - if p.get("age", "new") == "new": - fmode = wx.FD_SAVE - else: - fmode = wx.FD_OPEN + fmode = wx.FD_SAVE if p.get("age", "new") == "new" else wx.FD_OPEN # check wildcard try: fExt = os.path.splitext(p.get("key_desc", ["*.*"])[0])[1] @@ -2770,11 +2749,7 @@ def OnVerbosity(self, event): event.Skip() def OnPageChange(self, event): - if not event: - sel = self.notebook.GetSelection() - else: - sel = event.GetSelection() - + sel = self.notebook.GetSelection() if not event else event.GetSelection() idx = self.notebook.GetPageIndexByName("manual") if idx > -1 and sel == idx: # calling LoadPage() is strangely time-consuming (only first call) diff --git a/gui/wxpython/gui_core/goutput.py b/gui/wxpython/gui_core/goutput.py index 3c8927f2233..6676eb69935 100644 --- a/gui/wxpython/gui_core/goutput.py +++ b/gui/wxpython/gui_core/goutput.py @@ -20,6 +20,7 @@ """ import textwrap +from string import digits import wx from wx import stc @@ -624,7 +625,7 @@ def AddStyledMessage(self, message, style=None): self.linePos = self.GetCurrentPos() if c != " ": last_c = c - if last_c not in ("0123456789"): + if last_c not in (digits): self.AddTextWrapped("\n", wrap=None) self.linePos = -1 else: diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index ff256803a97..67b8a1280e2 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -1394,10 +1394,7 @@ def __init__( super().__init__(parent, id=wx.ID_ANY, size=size, **kwargs) self.SetName("FormatSelect") - if ogr: - ftype = "ogr" - else: - ftype = "gdal" + ftype = "ogr" if ogr else "gdal" formats = [] for f in GetFormats()[ftype][srcType].items(): @@ -1504,10 +1501,7 @@ def __init__( self.protocolWidgets = {} self.pgWidgets = {} - if ogr: - fType = "ogr" - else: - fType = "gdal" + fType = "ogr" if ogr else "gdal" # file fileMask = "%(all)s (*)|*|" % {"all": _("All files")} @@ -2290,12 +2284,7 @@ def hasRastSameProjAsLocation(dsn, table=None): return projectionMatch def getProjMatchCaption(projectionMatch): - if projectionMatch == "0": - projectionMatchCaption = _("No") - else: - projectionMatchCaption = _("Yes") - - return projectionMatchCaption + return _("No") if projectionMatch == "0" else _("Yes") dsn = self.GetDsn() if not dsn: @@ -2440,15 +2429,9 @@ def OnHelp(self, event): """Show related manual page""" cmd = "" if self.dest: - if self.ogr: - cmd = "v.external.out" - else: - cmd = "r.external.out" + cmd = "v.external.out" if self.ogr else "r.external.out" elif self.link: - if self.ogr: - cmd = "v.external" - else: - cmd = "r.external" + cmd = "v.external" if self.ogr else "r.external" elif self.ogr: cmd = "v.in.ogr" else: diff --git a/gui/wxpython/gui_core/mapdisp.py b/gui/wxpython/gui_core/mapdisp.py index a2810c9892b..d72fabe4438 100644 --- a/gui/wxpython/gui_core/mapdisp.py +++ b/gui/wxpython/gui_core/mapdisp.py @@ -380,10 +380,7 @@ def StatusbarEnableLongHelp(self, enable=True): toolbar.EnableLongHelp(enable) def ShowAllToolbars(self, show=True): - if not show: # hide - action = self.RemoveToolbar - else: - action = self.AddToolbar + action = self.RemoveToolbar if not show else self.AddToolbar for toolbar in self.GetToolbarNames(): action(toolbar) @@ -583,7 +580,7 @@ class DoubleMapPanel(MapPanelBase): It is expected that derived class will call _bindWindowsActivation() when both map windows will be initialized. - Drived class should have method GetMapToolbar() returns toolbar + Derived classes should have method GetMapToolbar() returns toolbar which has methods SetActiveMap() and Enable(). @note To access maps use getters only @@ -608,7 +605,7 @@ def __init__( r""" \a firstMap is set as active (by assign it to \c self.Map). - Derived class should assging to \c self.MapWindow to make one + Derived class should assigning to \c self.MapWindow to make one map window current by default. :param parent: gui parent diff --git a/gui/wxpython/gui_core/menu.py b/gui/wxpython/gui_core/menu.py index b284461af0a..34d6eeffd31 100644 --- a/gui/wxpython/gui_core/menu.py +++ b/gui/wxpython/gui_core/menu.py @@ -91,10 +91,7 @@ def _createMenuItem( menu.AppendSeparator() return - if command: - helpString = command + " -- " + description - else: - helpString = description + helpString = command + " -- " + description if command else description if shortcut: label += "\t" + shortcut diff --git a/gui/wxpython/gui_core/preferences.py b/gui/wxpython/gui_core/preferences.py index 724e4a5aec0..85e5313da0e 100644 --- a/gui/wxpython/gui_core/preferences.py +++ b/gui/wxpython/gui_core/preferences.py @@ -2268,10 +2268,7 @@ def OnEnableWheelZoom(self, event): """Enable/disable wheel zoom mode control""" choiceId = self.winId["display:mouseWheelZoom:selection"] choice = self.FindWindowById(choiceId) - if choice.GetSelection() == 2: - enable = False - else: - enable = True + enable = choice.GetSelection() != 2 scrollId = self.winId["display:scrollDirection:selection"] self.FindWindowById(scrollId).Enable(enable) diff --git a/gui/wxpython/gui_core/prompt.py b/gui/wxpython/gui_core/prompt.py index 6734de169a9..3857f04fb32 100644 --- a/gui/wxpython/gui_core/prompt.py +++ b/gui/wxpython/gui_core/prompt.py @@ -428,10 +428,7 @@ def GetWordLeft(self, withDelimiter=False, ignoredDelimiter=None): ignoredDelimiter = "" for char in set(" .,-=") - set(ignoredDelimiter): - if not withDelimiter: - delimiter = "" - else: - delimiter = char + delimiter = "" if not withDelimiter else char parts.append(delimiter + textLeft.rpartition(char)[2]) return min(parts, key=lambda x: len(x)) diff --git a/gui/wxpython/gui_core/treeview.py b/gui/wxpython/gui_core/treeview.py index a7660308843..2fde45feec8 100644 --- a/gui/wxpython/gui_core/treeview.py +++ b/gui/wxpython/gui_core/treeview.py @@ -209,10 +209,7 @@ class CTreeView(AbstractTreeViewMixin, CustomTreeCtrl): """Tree view class inheriting from wx.TreeCtrl""" def __init__(self, model, parent, **kw): - if hasAgw: - style = "agwStyle" - else: - style = "style" + style = "agwStyle" if hasAgw else "style" if style not in kw: kw[style] = ( diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index 48d7f1da561..6ade30d1278 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -1052,7 +1052,7 @@ def __init__(self, num_of_params): super().__init__() def _enableDisableBtn(self, enable): - """Enable/Disable buttomn + """Enable/Disable button :param bool enable: Enable/Disable btn """ @@ -1603,7 +1603,7 @@ def _loadSettings_v2(self, fd_lines): idx = line.find(";", i_last) if idx < 0: break - elif idx != 0: + if idx != 0: # find out whether it is separator # $$$$; - it is separator # $$$$$; - it is not separator diff --git a/gui/wxpython/iclass/dialogs.py b/gui/wxpython/iclass/dialogs.py index 322bfcf5721..c868c6e08cf 100644 --- a/gui/wxpython/iclass/dialogs.py +++ b/gui/wxpython/iclass/dialogs.py @@ -486,9 +486,8 @@ def GetSelectedIndices(self, state=wx.LIST_STATE_SELECTED): index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) if index == -1: break - else: - lastFound = index - indices.append(index) + lastFound = index + indices.append(index) return indices def OnEdit(self, event): @@ -586,13 +585,9 @@ def ContrastColor(color): could be useful by other apps, consider moving it into gui_core """ # gacek, - # http://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color + # https://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color a = 1 - (0.299 * color[0] + 0.587 * color[1] + 0.114 * color[2]) / 255 - - if a < 0.5: - d = 0 - else: - d = 255 + d = 0 if a < 0.5 else 255 # maybe return just bool if text should be dark or bright return (d, d, d) diff --git a/gui/wxpython/iclass/digit.py b/gui/wxpython/iclass/digit.py index 85334993db1..9b9356cee02 100644 --- a/gui/wxpython/iclass/digit.py +++ b/gui/wxpython/iclass/digit.py @@ -17,16 +17,29 @@ """ import wx - +from core.gcmd import GWarning from vdigit.mapwindow import VDigitWindow from vdigit.wxdigit import IVDigit -from vdigit.wxdisplay import DisplayDriver, TYPE_AREA -from core.gcmd import GWarning +from vdigit.wxdisplay import TYPE_AREA, DisplayDriver try: - from grass.lib.gis import G_verbose, G_set_verbose - from grass.lib.vector import * - from grass.lib.vedit import * + from ctypes import pointer + + from grass.lib.gis import G_set_verbose, G_verbose + from grass.lib.vector import ( + Map_info, + Vect_build, + Vect_close, + Vect_copy_map_lines, + Vect_get_area_cat, + Vect_get_num_lines, + Vect_is_3d, + Vect_open_new, + Vect_open_tmp_new, + Vect_open_tmp_update, + Vect_open_update, + ) + from grass.lib.vedit import TYPE_CENTROIDIN, Vedit_delete_areas_cat except ImportError: pass @@ -156,15 +169,9 @@ def CopyMap(self, name, tmp=False, update=False): poMapInfoNew = pointer(Map_info()) if not tmp: - if update: - open_fn = Vect_open_update - else: - open_fn = Vect_open_new - else: # noqa: PLR5501 - if update: - open_fn = Vect_open_tmp_update - else: - open_fn = Vect_open_tmp_new + open_fn = Vect_open_update if update else Vect_open_new + else: + open_fn = Vect_open_tmp_update if update else Vect_open_tmp_new if update: if open_fn(poMapInfoNew, name, "") == -1: diff --git a/gui/wxpython/iclass/frame.py b/gui/wxpython/iclass/frame.py index 606c364c76f..b19d8d7d3ac 100644 --- a/gui/wxpython/iclass/frame.py +++ b/gui/wxpython/iclass/frame.py @@ -515,7 +515,7 @@ def ActivateSecondMap(self, event=None): def GetMapToolbar(self): """Returns toolbar with zooming tools""" - return self.toolbars["iClassMap"] if "iClassMap" in self.toolbars else None + return self.toolbars.get("iClassMap", None) def GetClassColor(self, cat): """Get class color as string diff --git a/gui/wxpython/iclass/g.gui.iclass.html b/gui/wxpython/iclass/g.gui.iclass.html index dd789cd75b5..3ce1bd580e6 100644 --- a/gui/wxpython/iclass/g.gui.iclass.html +++ b/gui/wxpython/iclass/g.gui.iclass.html @@ -82,7 +82,7 @@

    DESCRIPTION

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components, Interactive Scatter Plot Tool
    @@ -90,12 +90,12 @@

    SEE ALSO

    See also user wiki page -and development page. +and development page.

    AUTHORS

    Anna Kratochvilova, - Czech Technical University in Prague, Czech Republic
    + Czech Technical University in Prague, Czech Republic
    Vaclav Petras, - Czech Technical University in Prague, Czech Republic + Czech Technical University in Prague, Czech Republic diff --git a/gui/wxpython/image2target/g.gui.image2target.html b/gui/wxpython/image2target/g.gui.image2target.html index af1aec5a55d..35b9c7023dd 100644 --- a/gui/wxpython/image2target/g.gui.image2target.html +++ b/gui/wxpython/image2target/g.gui.image2target.html @@ -26,11 +26,11 @@

    DESCRIPTION

    manipulate and analyze GCPs are provided in the toolbar. This panel can be moved out of the GCP manager window by either dragging with the caption or by clicking on the pin button on the right in the caption. - This panel can also be placed below the map displays by dragging. + This panel can also be placed below the map displays by dragging.
  • The two panels in the lower part are used for map and GCP display, the left pane showing a map from the source project and the right pane showing a reference map from the target project. Numbered Ground - Control Points are shown on both map displays. + Control Points are shown on both map displays.
  • Components of the GCP Manager

    @@ -49,7 +49,7 @@

    Components of the GCP Manager

    List of ground control points

    The list of Ground Control Points can be sorted by clicking on a column -header. Clicking on a cloumn header will sort the GCPs ascending, a +header. Clicking on a column header will sort the GCPs ascending, a second click on the same column will sort the GCPs descending. Overall RMS error and individual RMS errors of all points are often improved if the GCP with the highest RMS error is adjusted. Individual coordinates @@ -291,7 +291,7 @@

    GCP Map Display Statusbar

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/image2target/g.gui.image2target.py b/gui/wxpython/image2target/g.gui.image2target.py index e2704dc371b..f7370a71adf 100755 --- a/gui/wxpython/image2target/g.gui.image2target.py +++ b/gui/wxpython/image2target/g.gui.image2target.py @@ -32,7 +32,7 @@ """ -Module to run GCP management tool as stadalone application. +Module to run GCP management tool as standalone application. """ import os diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index 6ed97bc46c1..0329516e04a 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -1014,10 +1014,7 @@ def OnSetDatabase(self, event): def OnBrowse(self, event): """'Browse' button clicked""" - if not event: - defaultPath = os.getenv("HOME") - else: - defaultPath = "" + defaultPath = os.getenv("HOME") if not event else "" dlg = wx.DirDialog( parent=self, diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 3adcf5ef9bd..bfc5bbc3489 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -23,7 +23,7 @@ @author Original author Michael Barton @author Original version improved by Martin Landa -@author Rewritten by Markus Metz redesign georectfier -> GCP Manage +@author Rewritten by Markus Metz redesign georectifier -> GCP Manage @author Support for GraphicsSet added by Stepan Turek (2012) @author port i.image.2target (v6) to version 7 in 2017 by Yann """ @@ -488,11 +488,7 @@ def __init__(self, wizard, parent): def OnMaptype(self, event): """Change map type""" global maptype - - if event.GetInt() == 0: - maptype = "raster" - else: - maptype = "vector" + maptype = "raster" if event.GetInt() == 0 else "vector" def OnLocation(self, event): """Sets source location for map(s) to georectify""" @@ -1034,10 +1030,10 @@ def __init__( # register data structures for drawing GCP's # self.pointsToDrawTgt = self.TgtMapWindow.RegisterGraphicsToDraw( - graphicsType="point", setStatusFunc=self.SetGCPSatus + graphicsType="point", setStatusFunc=self.SetGCPStatus ) self.pointsToDrawSrc = self.SrcMapWindow.RegisterGraphicsToDraw( - graphicsType="point", setStatusFunc=self.SetGCPSatus + graphicsType="point", setStatusFunc=self.SetGCPStatus ) # connect to the map windows signals @@ -1397,7 +1393,7 @@ def SetSettings(self): self.pointsToDrawSrc.SetPropertyVal("text", textProp) self.pointsToDrawTgt.SetPropertyVal("text", copy(textProp)) - def SetGCPSatus(self, item, itemIndex): + def SetGCPStatus(self, item, itemIndex): """Before GCP is drawn, decides it's colour and whether it will be drawn. """ @@ -1416,10 +1412,7 @@ def SetGCPSatus(self, item, itemIndex): else: item.SetPropertyVal("hide", False) if self.highest_only: - if itemIndex == self.highest_key: - wxPen = "highest" - else: - wxPen = "default" + wxPen = "highest" if itemIndex == self.highest_key else "default" elif self.mapcoordlist[key][7] > self.rmsthresh: wxPen = "highest" else: @@ -1702,10 +1695,7 @@ def OnFocus(self, event): pass def _onMouseLeftUpPointer(self, mapWindow, x, y): - if mapWindow == self.SrcMapWindow: - coordtype = "source" - else: - coordtype = "target" + coordtype = "source" if mapWindow == self.SrcMapWindow else "target" coord = (x, y) self.SetGCPData(coordtype, coord, self, confirm=True) @@ -1761,11 +1751,7 @@ def OnGeorect(self, event): if maptype == "raster": self.grwiz.SwitchEnv("source") - - if self.clip_to_region: - flags = "ac" - else: - flags = "a" + flags = "ac" if self.clip_to_region else "a" with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): wx.GetApp().Yield() diff --git a/gui/wxpython/iscatt/controllers.py b/gui/wxpython/iscatt/controllers.py index e0cdc5a458a..41a32e9b4ab 100644 --- a/gui/wxpython/iscatt/controllers.py +++ b/gui/wxpython/iscatt/controllers.py @@ -149,10 +149,7 @@ def SetBands(self, bands): callable=self.core.CleanUp, ondone=lambda event: self.CleanUpDone() ) - if self.show_add_scatt_plot: - show_add = True - else: - show_add = False + show_add = bool(self.show_add_scatt_plot) self.all_bands_to_bands = dict(zip(bands, [-1] * len(bands))) self.all_bands = bands @@ -508,7 +505,7 @@ class PlotsRenderingManager: """Manages rendering of scatter plot. .. todo:: - still space for optimalization + still space for optimization """ def __init__(self, scatt_mgr, cats_mgr, core): @@ -697,10 +694,7 @@ def SetData(self): def AddCategory(self, cat_id=None, name=None, color=None, nstd=None): if cat_id is None: - if self.cats_ids: - cat_id = max(self.cats_ids) + 1 - else: - cat_id = 1 + cat_id = max(self.cats_ids) + 1 if self.cats_ids else 1 if self.scatt_mgr.data_set: self.scatt_mgr.thread.Run(callable=self.core.AddCategory, cat_id=cat_id) diff --git a/gui/wxpython/iscatt/core_c.py b/gui/wxpython/iscatt/core_c.py index 8be04964b90..93f90e6a2ee 100644 --- a/gui/wxpython/iscatt/core_c.py +++ b/gui/wxpython/iscatt/core_c.py @@ -19,7 +19,7 @@ import numpy as np try: - from grass.lib.gis import G_get_window + from grass.lib.gis import G_get_window, struct_Cell_head from grass.lib.imagery import ( SC_SCATT_CONDITIONS, SC_SCATT_DATA, @@ -35,10 +35,9 @@ I_sc_insert_scatt_data, I_scd_init_scatt_data, scdScattData, - struct_Cell_head, - struct_Range, struct_scCats, ) + from grass.lib.raster import struct_Range except ImportError as e: sys.stderr.write(_("Loading ctypes libs failed: %s") % e) @@ -214,11 +213,7 @@ def _regionToCellHead(region): } for k, v in region.items(): - if k in {"rows", "cols", "cells", "zone"}: # zone added in r65224 - v = int(v) - else: - v = float(v) - + v = int(v) if k in {"rows", "cols", "cells", "zone"} else float(v) if k in convert_dict: k = convert_dict[k] diff --git a/gui/wxpython/iscatt/frame.py b/gui/wxpython/iscatt/frame.py index f14c68d3671..1bd2900123c 100644 --- a/gui/wxpython/iscatt/frame.py +++ b/gui/wxpython/iscatt/frame.py @@ -243,8 +243,8 @@ def SetBusy(self, busy): def CursorPlotMove(self, x, y, scatt_id): try: - x = int(round(x)) - y = int(round(y)) + x = round(x) + y = round(y) coords = True except (TypeError, ValueError): coords = False @@ -501,9 +501,8 @@ def GetSelectedIndices(self, state=wx.LIST_STATE_SELECTED): index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) if index == -1: break - else: - lastFound = index - indices.append(index) + lastFound = index + indices.append(index) return indices def DeselectAll(self): @@ -568,11 +567,7 @@ def OnCategoryRightUp(self, event): item = menu.Append(wx.ID_ANY, _("Change opacity level")) self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, item) - if showed: - text = _("Hide") - else: - text = _("Show") - + text = _("Hide") if showed else _("Show") item = menu.Append(wx.ID_ANY, text) self.Bind( wx.EVT_MENU, diff --git a/gui/wxpython/iscatt/iscatt_core.py b/gui/wxpython/iscatt/iscatt_core.py index 86321ed2ff1..c23d9ff97f7 100644 --- a/gui/wxpython/iscatt/iscatt_core.py +++ b/gui/wxpython/iscatt/iscatt_core.py @@ -214,7 +214,7 @@ def SetVectMap(self, vectMap): def SyncWithMap(self): # TODO possible optimization - bbox only of vertex and its two - # neighbours + # neighbors region = self.an_data.GetRegion() @@ -237,7 +237,7 @@ def SyncWithMap(self): def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats): # TODO possible optimization - bbox only of vertex and its two - # neighbours + # neighbors bboxs = old_bboxs + new_bboxs areas_cats = old_areas_cats + new_areas_cats @@ -633,7 +633,7 @@ def GetEllipses(self, scatt_id, styles): def _getEllipse(self, cat_id, scatt_id, nstd): # Joe Kington - # http://stackoverflow.com/questions/12301071/multidimensional-confidence-intervals + # https://stackoverflow.com/questions/12301071/multidimensional-confidence-intervals data = np.copy(self.cats[cat_id][scatt_id]["np_vals"]) @@ -732,7 +732,7 @@ def GetCatsRasts(self): def RasterizePolygon(pol, height, min_h, width, min_w): # Joe Kington - # http://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask + # https://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask #poly_verts = [(1,1), (1,4), (4,4),(4,1), (1,1)] @@ -805,11 +805,7 @@ def _parseRegion(region_str): for param in region_str: k, v = param.split("=") - if k in {"rows", "cols", "cells"}: - v = int(v) - else: - v = float(v) - region[k] = v + region[k] = int(v) if k in {"rows", "cols", "cells"} else float(v) return region diff --git a/gui/wxpython/iscatt/plots.py b/gui/wxpython/iscatt/plots.py index 9c6f50b3b9f..30498c35fbe 100644 --- a/gui/wxpython/iscatt/plots.py +++ b/gui/wxpython/iscatt/plots.py @@ -235,7 +235,7 @@ def Plot(self, cats_order, scatts, ellipses, styles): img = imshow( self.axes, merged_img, - extent=[int(ceil(x)) for x in self.full_extend], + extent=[ceil(x) for x in self.full_extend], origin="lower", interpolation="nearest", aspect="equal", @@ -321,7 +321,7 @@ def ZoomWheel(self, event): if not event.inaxes: return # tcaswell - # http://stackoverflow.com/questions/11551049/matplotlib-plot-zooming-with-scroll-wheel + # https://stackoverflow.com/questions/11551049/matplotlib-plot-zooming-with-scroll-wheel cur_xlim = self.axes.get_xlim() cur_ylim = self.axes.get_ylim() diff --git a/gui/wxpython/iscatt/toolbars.py b/gui/wxpython/iscatt/toolbars.py index 7f813723282..9633c147500 100644 --- a/gui/wxpython/iscatt/toolbars.py +++ b/gui/wxpython/iscatt/toolbars.py @@ -95,19 +95,19 @@ def _toolbarData(self): ( ("pan", icons["pan"].label), icons["pan"], - lambda event: self.SetPloltsMode(event, "pan"), + lambda event: self.SetPlotsMode(event, "pan"), wx.ITEM_CHECK, ), ( ("zoom", icons["zoomIn"].label), icons["zoomIn"], - lambda event: self.SetPloltsMode(event, "zoom"), + lambda event: self.SetPlotsMode(event, "zoom"), wx.ITEM_CHECK, ), ( ("zoom_extend", icons["zoomExtent"].label), icons["zoomExtent"], - lambda event: self.SetPloltsMode(event, "zoom_extend"), + lambda event: self.SetPlotsMode(event, "zoom_extend"), wx.ITEM_CHECK, ), (None,), @@ -145,7 +145,7 @@ def _toolbarData(self): def GetToolId(self, toolName): # TODO can be useful in base return vars(self)[toolName] - def SetPloltsMode(self, event, tool_name): + def SetPlotsMode(self, event, tool_name): self.scatt_mgr.modeSet.disconnect(self.ModeSet) if event.IsChecked(): for i_tool_data in self.controller.data: diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 2413d3b7c4a..1b69a517717 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -747,10 +747,7 @@ def OnLocationWizard(self, event): self._giface.grassdbChanged.emit( grassdb=grassdb, location=location, action="new", element="location" ) - if grassdb == gisenv["GISDBASE"]: - switch_grassdb = None - else: - switch_grassdb = grassdb + switch_grassdb = grassdb if grassdb != gisenv["GISDBASE"] else None if can_switch_mapset_interactive(self, grassdb, location, mapset): switch_mapset_interactively( self, @@ -985,7 +982,7 @@ def RunDisplayCmd(self, command): """Handles display commands. :param command: command in a list - :return int: False if failed, True if succcess + :return int: False if failed, True if success """ if not self.currentPage: self.NewDisplay(show=True) @@ -1116,10 +1113,7 @@ def GetMenuCmd(self, event): :return: command as a list""" layer = None - if event: - cmd = self.menucmd[event.GetId()] - else: - cmd = "" + cmd = self.menucmd[event.GetId()] if event else "" try: cmdlist = cmd.split(" ") @@ -1135,7 +1129,7 @@ def GetMenuCmd(self, event): layer = self.GetLayerTree().layer_selected name = self.GetLayerTree().GetLayerInfo(layer, key="maplayer").name type = self.GetLayerTree().GetLayerInfo(layer, key="type") - except AttributeError: + except (AttributeError, TypeError): layer = None if layer and len(cmdlist) == 1: # only if no parameters given @@ -1183,7 +1177,7 @@ def OnVDigit(self, event): # available only for vector map layers try: mapLayer = tree.GetLayerInfo(layer, key="maplayer") - except AttributeError: + except (AttributeError, TypeError): mapLayer = None if not mapLayer or mapLayer.GetType() != "vector": @@ -1860,7 +1854,7 @@ def OnShowAttributeTable(self, event, selection=None): # available only for vector map layers try: maptype = tree.GetLayerInfo(layer, key="maplayer").type - except AttributeError: + except (AttributeError, TypeError): maptype = None if not maptype or maptype != "vector": diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index 86531bcb5ad..350320d97a7 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -688,10 +688,7 @@ def OnLayerContextMenu(self, event): ) digitToolbar = self.mapdisplay.GetToolbar("vdigit") - if digitToolbar: - vdigitLayer = digitToolbar.GetLayer() - else: - vdigitLayer = None + vdigitLayer = digitToolbar.GetLayer() if digitToolbar else None layer = self.GetLayerInfo(self.layer_selected, key="maplayer") if vdigitLayer is not layer: item = wx.MenuItem( @@ -1569,10 +1566,7 @@ def AddLayer( name = None - if ctrl: - ctrlId = ctrl.GetId() - else: - ctrlId = None + ctrlId = ctrl.GetId() if ctrl else None # add a data object to hold the layer's command (does not # apply to generic command layers) @@ -1606,11 +1600,7 @@ def AddLayer( prevMapLayer = self.GetLayerInfo(prevItem, key="maplayer") prevItem = self.GetNextItem(prevItem) - - if prevMapLayer: - pos = self.Map.GetLayerIndex(prevMapLayer) - else: - pos = -1 + pos = self.Map.GetLayerIndex(prevMapLayer) if prevMapLayer else -1 maplayer = self.Map.AddLayer( pos=pos, @@ -1758,7 +1748,7 @@ def OnDeleteLayer(self, event): try: if self.GetLayerInfo(item, key="type") != "group": self.Map.DeleteLayer(self.GetLayerInfo(item, key="maplayer")) - except AttributeError: + except (AttributeError, TypeError): pass # redraw map if auto-rendering is enabled @@ -2063,12 +2053,8 @@ def RecreateItem(self, dragItem, dropTarget, parent=None): # decide where to put recreated item if dropTarget is not None and dropTarget != self.GetRootItem(): - if parent: - # new item is a group - afteritem = parent - else: - # new item is a single layer - afteritem = dropTarget + # new item is a group (parent is truthy) or else new item is a single layer + afteritem = parent or dropTarget # dragItem dropped on group if self.GetLayerInfo(afteritem, key="type") == "group": @@ -2399,7 +2385,7 @@ def __FindSubItemByName(self, item, value): while item and item.IsOk(): try: itemLayer = self.GetLayerInfo(item, key="maplayer") - except KeyError: + except (KeyError, TypeError): return None if itemLayer and value == itemLayer.GetName(): diff --git a/gui/wxpython/lmgr/menudata.py b/gui/wxpython/lmgr/menudata.py index 59eb72ecb67..88f769af403 100644 --- a/gui/wxpython/lmgr/menudata.py +++ b/gui/wxpython/lmgr/menudata.py @@ -25,10 +25,7 @@ class LayerManagerMenuData(MenuTreeModelBuilder): def __init__(self, filename=None, message_handler=GError): - if filename: - expandAddons = False - else: - expandAddons = True + expandAddons = not filename fallback = os.path.join(WXGUIDIR, "xml", "menudata.xml") if not filename: @@ -57,10 +54,7 @@ def __init__(self, filename=None, message_handler=GError): class LayerManagerModuleTree(MenuTreeModelBuilder): def __init__(self, filename=None, message_handler=GError): - if filename: - expandAddons = False - else: - expandAddons = True + expandAddons = not filename fallback = os.path.join(WXGUIDIR, "xml", "module_tree_menudata.xml") if not filename: diff --git a/gui/wxpython/lmgr/workspace.py b/gui/wxpython/lmgr/workspace.py index 774c22bf4ed..b1e7aa400f0 100644 --- a/gui/wxpython/lmgr/workspace.py +++ b/gui/wxpython/lmgr/workspace.py @@ -519,12 +519,20 @@ def CreateRecentFilesMenu(self, menu=None): :return None """ if menu: - file_menu = menu.GetMenu( - menuIndex=menu.FindMenu(title=_("File")), - ) - workspace_item = file_menu.FindItem( - id=file_menu.FindItem(itemString=_("Workspace")), - )[0] + menu_index = menu.FindMenu(_("File")) + if menu_index == wx.NOT_FOUND: + # try untranslated version + menu_index = menu.FindMenu("File") + if menu_index == wx.NOT_FOUND: + return + file_menu = menu.GetMenu(menu_index) + workspace_index = file_menu.FindItem(_("Workspace")) + if workspace_index == wx.NOT_FOUND: + workspace_index = file_menu.FindItem("Workspace") + if workspace_index == wx.NOT_FOUND: + return + workspace_item = file_menu.FindItemById(workspace_index) + self._recent_files = RecentFilesMenu( app_name="main", parent_menu=workspace_item.GetSubMenu(), diff --git a/gui/wxpython/location_wizard/dialogs.py b/gui/wxpython/location_wizard/dialogs.py index 079fca1f6d4..74a59cca525 100644 --- a/gui/wxpython/location_wizard/dialogs.py +++ b/gui/wxpython/location_wizard/dialogs.py @@ -550,7 +550,7 @@ def OnValue(self, event): except ValueError as e: if len(event.GetString()) > 0 and event.GetString() != "-": - dlg = wx.MessageBox( + wx.MessageBox( parent=self, message=_("Invalid value: %s") % e, caption=_("Error"), diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index 3ac0d1b3693..fc6e1f48798 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -900,8 +900,7 @@ def OnPageChange(self, event=None): if param["type"] == "bool": if param["value"] is False: continue - else: - self.p4projparams += " +" + param["proj4"] + self.p4projparams += " +" + param["proj4"] elif param["value"] is None: wx.MessageBox( parent=self, @@ -1358,7 +1357,7 @@ def OnPageChanging(self, event): # FIXME: index number doesn't translate when you've given a valid name # from the other list def OnText(self, event): - """Ellipspoid code changed""" + """Ellipsoid code changed""" self.ellipse = event.GetString() nextButton = wx.FindWindowById(wx.ID_FORWARD) if len(self.ellipse) == 0 or ( @@ -1604,9 +1603,12 @@ def __init__(self, wizard, parent): self, data=None, columns=[_("Code"), _("Description"), _("Parameters")] ) - # epsg.io hyperlink + # A hyperlink to a CRS database (PROJ related) self.tlink = HyperlinkCtrl( - self, id=wx.ID_ANY, label="epsg.io", url="https://epsg.io/" + self, + id=wx.ID_ANY, + label="spatialreference.org", + url="https://spatialreference.org/", ) self.tlink.SetNormalColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) self.tlink.SetVisitedColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) @@ -1688,14 +1690,14 @@ def EnableNext(self, enable=True): def OnTextChange(self, event): value = self.searchb.GetValue() if value == "": - self.tlink.SetURL("https://epsg.io/") + self.tlink.SetURL("https://spatialreference.org/") self.epsgcode = None self.epsgdesc = self.epsgparams = "" self.searchb.ChangeValue("") self.OnBrowseCodes(None) self.EnableNext(False) else: - self.tlink.SetURL(str("https://epsg.io/?q={0}".format(value))) + self.tlink.SetURL(f"https://spatialreference.org/ref/?&search={value}") data = self.epsglist.Search(index=[0, 1, 2], pattern=value, firstOnly=False) if data: index = 0 @@ -2757,10 +2759,7 @@ def CreateProj4String(self): # set ellipsoid parameters for item in ellipseparams: - if item[:4] == "f=1/": - item = " +rf=" + item[4:] - else: - item = " +" + item + item = " +rf=" + item[4:] if item[:4] == "f=1/" else " +" + item proj4string = "%s %s" % (proj4string, item) # set datum transform parameters if relevant diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index cef4aee7121..a4a4dfea8e2 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -861,10 +861,7 @@ def OnLocationWizard(self, event): self._giface.grassdbChanged.emit( grassdb=grassdb, location=location, action="new", element="location" ) - if grassdb == gisenv["GISDBASE"]: - switch_grassdb = None - else: - switch_grassdb = grassdb + switch_grassdb = grassdb if grassdb != gisenv["GISDBASE"] else None if can_switch_mapset_interactive(self, grassdb, location, mapset): switch_mapset_interactively( self, @@ -1123,7 +1120,7 @@ def RunDisplayCmd(self, command): """Handles display commands. :param command: command in a list - :return int: False if failed, True if succcess + :return int: False if failed, True if success """ if not self.currentPage: self.NewDisplay(show=True) @@ -1268,10 +1265,7 @@ def GetMenuCmd(self, event): :return: command as a list""" layer = None - if event: - cmd = self.menucmd[event.GetId()] - else: - cmd = "" + cmd = self.menucmd[event.GetId()] if event else "" try: cmdlist = cmd.split(" ") diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index c9b5d86e4ba..a7622616b34 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -783,10 +783,7 @@ def DOutFile(self, command, callback=None): # --overwrite continue if p == "format": # must be there - if self.IsPaneShown("3d"): - extType = "ppm" - else: - extType = val + extType = "ppm" if self.IsPaneShown("3d") else val if p == "output": # must be there name = val elif p == "size": @@ -798,10 +795,8 @@ def DOutFile(self, command, callback=None): elif ext[1:] != extType: extType = ext[1:] - if self.IsPaneShown("3d"): - bitmapType = "ppm" - else: - bitmapType = wx.BITMAP_TYPE_PNG # default type + # default type is PNG + bitmapType = "ppm" if self.IsPaneShown("3d") else wx.BITMAP_TYPE_PNG for each in ltype: if each["ext"] == extType: bitmapType = each["type"] @@ -1505,7 +1500,7 @@ def OnSetWindToRegion(self, event): self.MapWindow.SetRegion(zoomOnly=False) def OnSetExtentToWind(self, event): - """Set compulational region extent interactively""" + """Set computational region extent interactively""" self.MapWindow.SetModeDrawRegion() def OnSaveDisplayRegion(self, event): @@ -1569,7 +1564,7 @@ def SetProperties( def GetMapToolbar(self): """Returns toolbar with zooming tools""" - return self.toolbars["map"] if "map" in self.toolbars else None + return self.toolbars.get("map", None) def GetDialog(self, name): """Get selected dialog if exist""" diff --git a/gui/wxpython/mapdisp/statusbar.py b/gui/wxpython/mapdisp/statusbar.py index 4fea1ffcc81..ca69416af85 100644 --- a/gui/wxpython/mapdisp/statusbar.py +++ b/gui/wxpython/mapdisp/statusbar.py @@ -542,23 +542,22 @@ def ReprojectENToMap(self, e, n, useDefinedProjection): ) if not settings: raise SbException(_("Projection not defined (check the settings)")) + # reproject values + projIn = settings + projOut = RunCommand("g.proj", flags="jf", read=True) + proj = projIn.split(" ")[0].split("=")[1] + if proj in {"ll", "latlong", "longlat"}: + e, n = utils.DMS2Deg(e, n) + proj, coord1 = utils.ReprojectCoordinates( + coord=(e, n), projIn=projIn, projOut=projOut, flags="d" + ) + e, n = coord1 else: - # reproject values - projIn = settings - projOut = RunCommand("g.proj", flags="jf", read=True) - proj = projIn.split(" ")[0].split("=")[1] - if proj in {"ll", "latlong", "longlat"}: - e, n = utils.DMS2Deg(e, n) - proj, coord1 = utils.ReprojectCoordinates( - coord=(e, n), projIn=projIn, projOut=projOut, flags="d" - ) - e, n = coord1 - else: - e, n = float(e), float(n) - proj, coord1 = utils.ReprojectCoordinates( - coord=(e, n), projIn=projIn, projOut=projOut, flags="d" - ) - e, n = coord1 + e, n = float(e), float(n) + proj, coord1 = utils.ReprojectCoordinates( + coord=(e, n), projIn=projIn, projOut=projOut, flags="d" + ) + e, n = coord1 elif self.mapFrame.GetMap().projinfo["proj"] == "ll": e, n = utils.DMS2Deg(e, n) else: @@ -620,32 +619,28 @@ def GetCenterString(self, map): if self.mapFrame.GetProperty("useDefinedProjection"): if not projection: raise SbException(_("Projection not defined (check the settings)")) - else: - proj, coord = utils.ReprojectCoordinates( - coord=(region["center_easting"], region["center_northing"]), - projOut=projection, - flags="d", - ) - if coord: - if proj in {"ll", "latlong", "longlat"} and format == "DMS": - return "%s" % utils.Deg2DMS( - coord[0], coord[1], precision=precision - ) - return "%.*f; %.*f" % (precision, coord[0], precision, coord[1]) - raise SbException(_("Error in projection (check the settings)")) - elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": + proj, coord = utils.ReprojectCoordinates( + coord=(region["center_easting"], region["center_northing"]), + projOut=projection, + flags="d", + ) + if coord: + if proj in {"ll", "latlong", "longlat"} and format == "DMS": + return "%s" % utils.Deg2DMS(coord[0], coord[1], precision=precision) + return "%.*f; %.*f" % (precision, coord[0], precision, coord[1]) + raise SbException(_("Error in projection (check the settings)")) + if self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": return "%s" % utils.Deg2DMS( region["center_easting"], region["center_northing"], precision=precision, ) - else: - return "%.*f; %.*f" % ( - precision, - region["center_easting"], - precision, - region["center_northing"], - ) + return "%.*f; %.*f" % ( + precision, + region["center_easting"], + precision, + region["center_northing"], + ) def SetCenter(self): """Set current map center as item value""" @@ -761,7 +756,7 @@ def Show(self): self.SetValue(e.message) # TODO: remove these excepts, they just hide errors, solve problems # differently - except TypeError as e: + except TypeError: self.SetValue("") except AttributeError: # during initialization MapFrame has no MapWindow @@ -795,21 +790,19 @@ def ReprojectENFromMap(self, e, n, useDefinedProjection, precision, format): ) if not settings: raise SbException(_("Projection not defined (check the settings)")) - else: - # reproject values - proj, coord = utils.ReprojectCoordinates( - coord=(e, n), projOut=settings, flags="d" - ) - if coord: - e, n = coord - if proj in {"ll", "latlong", "longlat"} and format == "DMS": - return utils.Deg2DMS(e, n, precision=precision) - return "%.*f; %.*f" % (precision, e, precision, n) - raise SbException(_("Error in projection (check the settings)")) - elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": + # reproject values + proj, coord = utils.ReprojectCoordinates( + coord=(e, n), projOut=settings, flags="d" + ) + if coord: + e, n = coord + if proj in {"ll", "latlong", "longlat"} and format == "DMS": + return utils.Deg2DMS(e, n, precision=precision) + return "%.*f; %.*f" % (precision, e, precision, n) + raise SbException(_("Error in projection (check the settings)")) + if self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": return utils.Deg2DMS(e, n, precision=precision) - else: - return "%.*f; %.*f" % (precision, e, precision, n) + return "%.*f; %.*f" % (precision, e, precision, n) class SbRegionExtent(SbTextItem): @@ -872,54 +865,53 @@ def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format if not settings: raise SbException(_("Projection not defined (check the settings)")) - else: - projOut = settings - proj, coord1 = utils.ReprojectCoordinates( - coord=(region["w"], region["s"]), projOut=projOut, flags="d" - ) - proj, coord2 = utils.ReprojectCoordinates( - coord=(region["e"], region["n"]), projOut=projOut, flags="d" - ) - # useless, used in derived class - proj, coord3 = utils.ReprojectCoordinates( - coord=(0.0, 0.0), projOut=projOut, flags="d" - ) - proj, coord4 = utils.ReprojectCoordinates( - coord=(region["ewres"], region["nsres"]), projOut=projOut, flags="d" - ) - if coord1 and coord2: - if proj in {"ll", "latlong", "longlat"} and format == "DMS": - w, s = utils.Deg2DMS( - coord1[0], coord1[1], string=False, precision=precision - ) - e, n = utils.Deg2DMS( - coord2[0], coord2[1], string=False, precision=precision - ) - ewres, nsres = utils.Deg2DMS( - abs(coord3[0]) - abs(coord4[0]), - abs(coord3[1]) - abs(coord4[1]), - string=False, - hemisphere=False, - precision=precision, - ) - return self._formatRegion( - w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres - ) - w, s = coord1 - e, n = coord2 - ewres, nsres = coord3 - return self._formatRegion( - w=w, - s=s, - e=e, - n=n, - ewres=ewres, - nsres=nsres, + projOut = settings + proj, coord1 = utils.ReprojectCoordinates( + coord=(region["w"], region["s"]), projOut=projOut, flags="d" + ) + proj, coord2 = utils.ReprojectCoordinates( + coord=(region["e"], region["n"]), projOut=projOut, flags="d" + ) + # useless, used in derived class + proj, coord3 = utils.ReprojectCoordinates( + coord=(0.0, 0.0), projOut=projOut, flags="d" + ) + proj, coord4 = utils.ReprojectCoordinates( + coord=(region["ewres"], region["nsres"]), projOut=projOut, flags="d" + ) + if coord1 and coord2: + if proj in {"ll", "latlong", "longlat"} and format == "DMS": + w, s = utils.Deg2DMS( + coord1[0], coord1[1], string=False, precision=precision + ) + e, n = utils.Deg2DMS( + coord2[0], coord2[1], string=False, precision=precision + ) + ewres, nsres = utils.Deg2DMS( + abs(coord3[0]) - abs(coord4[0]), + abs(coord3[1]) - abs(coord4[1]), + string=False, + hemisphere=False, precision=precision, ) - raise SbException(_("Error in projection (check the settings)")) + return self._formatRegion( + w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres + ) + w, s = coord1 + e, n = coord2 + ewres, nsres = coord3 + return self._formatRegion( + w=w, + s=s, + e=e, + n=n, + ewres=ewres, + nsres=nsres, + precision=precision, + ) + raise SbException(_("Error in projection (check the settings)")) - elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": + if self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": w, s = utils.Deg2DMS( region["w"], region["s"], string=False, precision=precision ) @@ -930,13 +922,12 @@ def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format region["ewres"], region["nsres"], string=False, precision=precision ) return self._formatRegion(w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres) - else: - w, s = region["w"], region["s"] - e, n = region["e"], region["n"] - ewres, nsres = region["ewres"], region["nsres"] - return self._formatRegion( - w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres, precision=precision - ) + w, s = region["w"], region["s"] + e, n = region["e"], region["n"] + ewres, nsres = region["ewres"], region["nsres"] + return self._formatRegion( + w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres, precision=precision + ) class SbCompRegionExtent(SbRegionExtent): diff --git a/gui/wxpython/mapdisp/toolbars.py b/gui/wxpython/mapdisp/toolbars.py index 4eb49846d4f..18459b26e17 100644 --- a/gui/wxpython/mapdisp/toolbars.py +++ b/gui/wxpython/mapdisp/toolbars.py @@ -285,10 +285,7 @@ def RemoveTool(self, tool): def ChangeToolsDesc(self, mode2d): """Change description of zoom tools for 2D/3D view""" - if mode2d: - icons = BaseIcons - else: - icons = NvizIcons + icons = BaseIcons if mode2d else NvizIcons for i, data in enumerate(self.controller.data): for tool in ("zoomIn", "zoomOut"): if data[0] == tool: diff --git a/gui/wxpython/mapswipe/frame.py b/gui/wxpython/mapswipe/frame.py index a7dd0df8f56..b7b81636605 100644 --- a/gui/wxpython/mapswipe/frame.py +++ b/gui/wxpython/mapswipe/frame.py @@ -545,15 +545,15 @@ class _onDone: we are pasting together 2 rendered images, so we need to know when both are finished.""" - def __init__(self2): + def __init__(self2): # noqa: N805 self2.called = 0 - def __call__(self2): + def __call__(self2): # noqa: N805 self2.called += 1 if self2.called == 2: self2.process() - def process(self2): + def process(self2): # noqa: N805 # create empty white image - needed for line im = wx.Image(width, height) im.Replace(0, 0, 0, 255, 255, 255) diff --git a/gui/wxpython/mapswipe/g.gui.mapswipe.html b/gui/wxpython/mapswipe/g.gui.mapswipe.html index 9c04c9db77f..ae4fe135a0f 100644 --- a/gui/wxpython/mapswipe/g.gui.mapswipe.html +++ b/gui/wxpython/mapswipe/g.gui.mapswipe.html @@ -39,7 +39,7 @@

    DESCRIPTION

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    @@ -49,4 +49,4 @@

    SEE ALSO

    AUTHOR

    Anna Kratochvilova, -Czech Technical University in Prague, Czech Republic +Czech Technical University in Prague, Czech Republic diff --git a/gui/wxpython/mapwin/buffered.py b/gui/wxpython/mapwin/buffered.py index 6e6276a5fdf..6692afced54 100644 --- a/gui/wxpython/mapwin/buffered.py +++ b/gui/wxpython/mapwin/buffered.py @@ -344,10 +344,7 @@ def Draw( # TODO: find better solution if not pen: - if pdctype == "polyline": - pen = self.polypen - else: - pen = self.pen + pen = self.polypen if pdctype == "polyline" else self.pen if img and pdctype == "image": # self.imagedict[img]['coords'] = coords @@ -501,10 +498,7 @@ def Draw( elif pdctype == "text": # draw text on top of map if not img["active"]: return # only draw active text - if "rotation" in img: - rotation = float(img["rotation"]) - else: - rotation = 0.0 + rotation = float(img["rotation"]) if "rotation" in img else 0.0 w, h = self.GetFullTextExtent(img["text"])[0:2] pdc.SetFont(img["font"]) pdc.SetTextForeground(img["color"]) @@ -536,10 +530,7 @@ def TextBounds(self, textinfo, relcoords=False): :return: bbox of rotated text bbox (wx.Rect) :return: relCoords are text coord inside bbox """ - if "rotation" in textinfo: - rotation = float(textinfo["rotation"]) - else: - rotation = 0.0 + rotation = float(textinfo["rotation"]) if "rotation" in textinfo else 0.0 coords = textinfo["coords"] bbox = Rect(coords[0], coords[1], 0, 0) @@ -1469,10 +1460,7 @@ def OnMouseWheel(self, event): wheel = event.GetWheelRotation() Debug.msg(5, "BufferedWindow.MouseAction(): wheel=%d" % wheel) - if wheel > 0: - zoomtype = 1 - else: - zoomtype = -1 + zoomtype = 1 if wheel > 0 else -1 if UserSettings.Get(group="display", key="scrollDirection", subkey="selection"): zoomtype *= -1 # zoom 1/2 of the screen (TODO: settings) @@ -1504,10 +1492,7 @@ def OnDragging(self, event): previous = self.mouse["begin"] move = (current[0] - previous[0], current[1] - previous[1]) - if self.digit: - digitToolbar = self.toolbar - else: - digitToolbar = None + digitToolbar = self.toolbar if self.digit else None # dragging or drawing box with left button if self.mouse["use"] == "pan" or event.MiddleIsDown(): @@ -2117,7 +2102,7 @@ def DisplayToWind(self): self.UpdateMap(render=False) def SetRegion(self, zoomOnly=True): - """Set display extents/compulational region from named region + """Set display extents/computational region from named region file. :param zoomOnly: zoom to named region only (computational region is not saved) @@ -2125,7 +2110,7 @@ def SetRegion(self, zoomOnly=True): if zoomOnly: label = _("Zoom to saved region extents") else: - label = _("Set compulational region from named region") + label = _("Set computational region from named region") dlg = SavedRegion(parent=self, title=label, loadsave="load") if dlg.ShowModal() == wx.ID_CANCEL or not dlg.GetName(): @@ -2159,7 +2144,7 @@ def SetRegion(self, zoomOnly=True): self.UpdateMap() def SaveRegion(self, display=True): - """Save display extents/compulational region to named region + """Save display extents/computational region to named region file. :param display: True for display extends otherwise computational region diff --git a/gui/wxpython/mapwin/decorations.py b/gui/wxpython/mapwin/decorations.py index 24db63d8492..9c643d17752 100644 --- a/gui/wxpython/mapwin/decorations.py +++ b/gui/wxpython/mapwin/decorations.py @@ -323,14 +323,8 @@ def ResizeLegend(self, begin, end, screenSize): """Resize legend according to given bbox coordinates.""" w = abs(begin[0] - end[0]) h = abs(begin[1] - end[1]) - if begin[0] < end[0]: - x = begin[0] - else: - x = end[0] - if begin[1] < end[1]: - y = begin[1] - else: - y = end[1] + x = min(end[0], begin[0]) + y = min(end[1], begin[1]) at = [ (screenSize[1] - (y + h)) / float(screenSize[1]) * 100, diff --git a/gui/wxpython/modules/colorrules.py b/gui/wxpython/modules/colorrules.py index a11190b1b61..dcb34619b57 100644 --- a/gui/wxpython/modules/colorrules.py +++ b/gui/wxpython/modules/colorrules.py @@ -407,7 +407,7 @@ def _initLayer(self): layer = sel else: layer = self.layerTree.FindItemByData(key="type", value=self.mapType) - except Exception: + except (AttributeError, TypeError): layer = None if layer: mapLayer = self.layerTree.GetLayerInfo(layer, key="maplayer") @@ -977,10 +977,7 @@ def OnSelectionInput(self, event): self.cr_label.SetLabel(_("Enter raster category values or percents")) return - if info["datatype"] == "CELL": - mapRange = _("range") - else: - mapRange = _("fp range") + mapRange = _("range") if info["datatype"] == "CELL" else _("fp range") self.cr_label.SetLabel( _("Enter raster category values or percents (%(range)s = %(min)d-%(max)d)") % { @@ -1409,10 +1406,7 @@ def AddTemporaryColumn(self, type): idx += 1 self.properties["tmpColumn"] = name + "_" + str(idx) - if self.version7: - modul = "v.db.addcolumn" - else: - modul = "v.db.addcol" + modul = "v.db.addcolumn" if self.version7 else "v.db.addcol" RunCommand( modul, parent=self, @@ -1427,10 +1421,7 @@ def DeleteTemporaryColumn(self): return if self.inmap: - if self.version7: - modul = "v.db.dropcolumn" - else: - modul = "v.db.dropcol" + modul = "v.db.dropcolumn" if self.version7 else "v.db.dropcol" RunCommand( modul, map=self.inmap, @@ -1452,10 +1443,7 @@ def OnLayerSelection(self, event): self.sourceColumn.SetValue("cat") self.properties["sourceColumn"] = self.sourceColumn.GetValue() - if self.attributeType == "color": - type = ["character"] - else: - type = ["integer"] + type = ["character"] if self.attributeType == "color" else ["integer"] self.fromColumn.InsertColumns( vector=self.inmap, layer=vlayer, @@ -1502,10 +1490,7 @@ def OnAddColumn(self, event): self.columnsProp[self.attributeType]["name"] not in self.fromColumn.GetColumns() ): - if self.version7: - modul = "v.db.addcolumn" - else: - modul = "v.db.addcol" + modul = "v.db.addcolumn" if self.version7 else "v.db.addcol" RunCommand( modul, map=self.inmap, diff --git a/gui/wxpython/modules/extensions.py b/gui/wxpython/modules/extensions.py index f7822e0cb0e..7837a92589d 100644 --- a/gui/wxpython/modules/extensions.py +++ b/gui/wxpython/modules/extensions.py @@ -356,11 +356,7 @@ def _expandPrefix(self, c): def Load(self, url, full=True): """Load list of extensions""" self._emptyTree() - - if full: - flags = "g" - else: - flags = "l" + flags = "g" if full else "l" retcode, ret, msg = RunCommand( "g.extension", read=True, getErrorMsg=True, url=url, flags=flags, quiet=True ) diff --git a/gui/wxpython/modules/histogram.py b/gui/wxpython/modules/histogram.py index 44f2f643c33..61d41809858 100644 --- a/gui/wxpython/modules/histogram.py +++ b/gui/wxpython/modules/histogram.py @@ -496,7 +496,6 @@ def SaveToFile(self, event): def PrintMenu(self, event): """Print options and output menu""" - point = wx.GetMousePosition() printmenu = Menu() # Add items to the menu setup = wx.MenuItem(printmenu, id=wx.ID_ANY, text=_("Page setup")) diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index 2cca4329c02..7b3d3482523 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -18,9 +18,11 @@ @author Martin Landa @author Anna Kratochvilova (GroupDialog, SymbolDialog) +@author William Welch (commands running queue) """ import os +from collections import deque from pathlib import Path @@ -60,6 +62,8 @@ def __init__( self.commandId = -1 # id of running command + self._commands_running = deque() + wx.Dialog.__init__( self, parent, id, title, style=style, name="MultiImportDialog" ) @@ -122,8 +126,9 @@ def __init__( # buttons # # cancel + self._DEFAULT_CLOSE_BTN_TEXT = _("Close dialog") self.btn_close = CloseButton(parent=self.panel) - self.btn_close.SetToolTip(_("Close dialog")) + self.btn_close.SetToolTip(_(self._DEFAULT_CLOSE_BTN_TEXT)) self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) # run self.btn_run = Button(parent=self.panel, id=wx.ID_OK, label=_("&Import")) @@ -131,7 +136,7 @@ def __init__( self.btn_run.SetDefault() self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun) - self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy()) + self.Bind(wx.EVT_CLOSE, self._handleCloseEvent) self.notebook = GNotebook(parent=self, style=globalvar.FNPageDStyle) @@ -270,6 +275,33 @@ def _validateOutputMapName(self): return False return True + def _handleCloseEvent(self, event: wx.CloseEvent): + if event.CanVeto() and len(self._commands_running) > 0: + # prevent dialog close while async commands are running + event.Veto() + return + self.Destroy() + + def _addToCommandQueue(self): + self._commands_running.append(True) + + # disable the dialog close button + self.btn_close.SetToolTip( + _("Dialog cannot be closed while command is running.") + ) + self.btn_close.Disable() + + def _removeFromCommandQueue(self): + try: + self._commands_running.pop() + except IndexError: + pass + finally: + if len(self._commands_running) == 0: + # enable the dialog close button + self.btn_close.Enable() + self.btn_close.SetToolTip(self._DEFAULT_CLOSE_BTN_TEXT) + def OnClose(self, event=None): """Close dialog""" self.Close() @@ -296,20 +328,14 @@ def AddLayers(self, returncode, cmd=None, userData=None): self.commandId += 1 layer, output = self.list.GetLayers()[self.commandId][:2] - if "@" not in output: - name = output + "@" + grass.gisenv()["MAPSET"] - else: - name = output + name = output + "@" + grass.gisenv()["MAPSET"] if "@" not in output else output # add imported layers into layer tree # an alternative would be emit signal (mapCreated) and (optionally) # connect to this signal llist = self._giface.GetLayerList() if self.importType == "gdal": - if userData: - nBands = int(userData.get("nbands", 1)) - else: - nBands = 1 + nBands = int(userData.get("nbands", 1)) if userData else 1 if UserSettings.Get(group="rasterLayer", key="opaque", subkey="enabled"): nFlag = True @@ -461,7 +487,6 @@ def OnRun(self, event): dsn = self.dsnInput.GetDsn() if not dsn: return - ext = self.dsnInput.GetFormatExt() for layer, output, listId in data: userData = {} @@ -519,6 +544,7 @@ def OnRun(self, event): ): cmd.append("--overwrite") + self._addToCommandQueue() # run in Layer Manager self._giface.RunCmd( cmd, onDone=self.OnCmdDone, userData=userData, addLayer=False @@ -527,9 +553,11 @@ def OnRun(self, event): def OnCmdDone(self, event): """Load layers and close if required""" if not hasattr(self, "AddLayers"): + self._removeFromCommandQueue() return self.AddLayers(event.returncode, event.cmd, event.userData) + self._removeFromCommandQueue() if event.returncode == 0 and self.closeOnFinish.IsChecked(): self.Close() @@ -613,7 +641,7 @@ def OnRun(self, event): return if not data: - GMessage(_("No layers selected. Operation canceled."), parent=self) + GMessage(parent=self, message=_("No layers selected. Operation canceled.")) return if not self._validateOutputMapName(): @@ -644,13 +672,7 @@ def OnRun(self, event): if ext and layer.rfind(ext) > -1: layer = layer.replace("." + ext, "") if "|" in layer: - layer, geometry = layer.split("|", 1) - else: - geometry = None - - # TODO: v.import has no geometry option - # if geometry: - # cmd.append('geometry=%s' % geometry) + layer = layer.split("|", 1)[0] cmd = self.getSettingsPageCmd() cmd.append("input=%s" % dsn) @@ -670,6 +692,7 @@ def OnRun(self, event): ): cmd.append("--overwrite") + self._addToCommandQueue() # run in Layer Manager self._giface.RunCmd( cmd, onDone=self.OnCmdDone, userData=userData, addLayer=False @@ -678,10 +701,13 @@ def OnRun(self, event): def OnCmdDone(self, event): """Load layers and close if required""" if not hasattr(self, "AddLayers"): + self._removeFromCommandQueue() return self.AddLayers(event.returncode, event.cmd, event.userData) + self._removeFromCommandQueue() + if self.popOGR: os.environ.pop("GRASS_VECTOR_OGR") @@ -880,16 +906,20 @@ def OnRun(self, event): ): cmd.append("--overwrite") + self._commands_running.append(True) # run in Layer Manager self._giface.RunCmd(cmd, onDone=self.OnCmdDone, addLayer=False) def OnCmdDone(self, event): """Load layers and close if required""" if not hasattr(self, "AddLayers"): + self._removeFromCommandQueue() return self.AddLayers(event.returncode, event.cmd) + self._removeFromCommandQueue() + if self.closeOnFinish.IsChecked(): self.Close() diff --git a/gui/wxpython/modules/mapsets_picker.py b/gui/wxpython/modules/mapsets_picker.py index e7ea7a3e40a..73df8fde3cc 100755 --- a/gui/wxpython/modules/mapsets_picker.py +++ b/gui/wxpython/modules/mapsets_picker.py @@ -12,7 +12,7 @@ def main(): - app = wx.App() + wx.App() dlg = MapsetAccess(parent=None) dlg.CenterOnScreen() diff --git a/gui/wxpython/modules/mcalc_builder.py b/gui/wxpython/modules/mcalc_builder.py index 8eabc04181d..9476e9f0acb 100644 --- a/gui/wxpython/modules/mcalc_builder.py +++ b/gui/wxpython/modules/mcalc_builder.py @@ -681,10 +681,7 @@ def OnMCalcRun(self, event): self.log.RunCmd(cmd, onDone=self.OnDone) self.parent.Raise() else: - if self.overwrite.IsChecked(): - overwrite = True - else: - overwrite = False + overwrite = bool(self.overwrite.IsChecked()) params = {"expression": "%s=%s" % (name, expr), "overwrite": overwrite} if seed_flag: params["flags"] = "s" diff --git a/gui/wxpython/nviz/mapwindow.py b/gui/wxpython/nviz/mapwindow.py index 7940124e6a6..c459e5f4f89 100644 --- a/gui/wxpython/nviz/mapwindow.py +++ b/gui/wxpython/nviz/mapwindow.py @@ -335,7 +335,7 @@ def ComputeFlyValues(self, mx, my): self.fly["value"][2] = -my * 100.0 * self.fly["interval"] / 1000.0 def ChangeFlySpeed(self, increase): - """Increase/decrease flight spped""" + """Increase/decrease flight speed""" if increase: self.fly["flySpeed"] += self.fly["flySpeedStep"] else: @@ -382,10 +382,7 @@ def OnEraseBackground(self, event): def OnSize(self, event): size = self.GetClientSize() - if CheckWxVersion(version=[2, 9]): - context = self.context - else: - context = self.GetContext() + context = self.context if CheckWxVersion(version=[2, 9]) else self.GetContext() if self.size != size and context: Debug.msg( 3, "GLCanvas.OnSize(): w = %d, h = %d" % (size.width, size.height) @@ -412,7 +409,7 @@ def OnPaint(self, event): Debug.msg(1, "GLCanvas.OnPaint()") self.render["overlays"] = True - dc = wx.PaintDC(self) + wx.PaintDC(self) self.DoPaint() def DoPaint(self): @@ -1438,7 +1435,7 @@ def UnloadDataLayers(self, force=False): GError(parent=self, message=e.value) if force and self.baseId > 0: # unload base surface when quitting - ret = self._display.UnloadSurface(self.baseId) + self._display.UnloadSurface(self.baseId) self.baseId = -1 if update: self.lmgr.nviz.UpdateSettings() @@ -2134,10 +2131,10 @@ def UpdateVolumeProperties(self, id, data, isosurfId=None): # sliceId = 0 for slice in data["slice"]: - ret = self._display.AddSlice(id, slice_id=sliceId) + self._display.AddSlice(id, slice_id=sliceId) if "update" in slice["position"]: pos = slice["position"] - ret = self._display.SetSlicePosition( + self._display.SetSlicePosition( id, sliceId, pos["x1"], diff --git a/gui/wxpython/nviz/preferences.py b/gui/wxpython/nviz/preferences.py index 9bd4614a670..ebd7e5d66b5 100644 --- a/gui/wxpython/nviz/preferences.py +++ b/gui/wxpython/nviz/preferences.py @@ -258,7 +258,7 @@ def _createFlyPage(self, notebook): notebook.AddPage(page=panel, text=" %s " % _("Fly-through")) pageSizer = wx.BoxSizer(wx.VERTICAL) - # fly throuhg mode + # fly through mode box = StaticBox( parent=panel, id=wx.ID_ANY, label=" %s " % (_("Fly-through mode")) ) diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index dfdfef66371..530ad453353 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 (IndexError, AttributeError): + except (AttributeError, IndexError): continue if ltype == "raster": self.FindWindowById(self.win["surface"]["map"]).SetValue(selection) @@ -667,7 +667,6 @@ def _createAnimationPage(self): parent=panel, id=wx.ID_ANY, label=" %s " % (_("Save image sequence")) ) boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL) - vSizer = wx.BoxSizer(wx.VERTICAL) gridSizer = wx.GridBagSizer(vgap=5, hgap=10) pwd = str(Path.cwd()) @@ -735,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 Exception: - try: # wxpython >= 2.8.11 - self.foldpanelData = fpb.FoldPanelBar( - parent=self.mainPanelData, - id=wx.ID_ANY, - agwStyle=fpb.FPB_SINGLE_FOLD, - ) - except Exception: # 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) @@ -815,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 Exception: - try: # wxpython >= 2.8.11 - self.foldpanelAppear = fpb.FoldPanelBar( - parent=self.mainPanelAppear, - id=wx.ID_ANY, - agwStyle=fpb.FPB_SINGLE_FOLD, - ) - except Exception: # 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 @@ -1197,33 +1170,6 @@ def _createSurfacePage(self, parent): flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=3, ) - # - # mask - # - # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, - # label = " %s " % (_("Mask"))) - ## boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL) - ## gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5) - ## - # gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, - # label = _("Mask zeros:")), - # pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL) - ## - # elev = wx.CheckBox(parent = panel, id = wx.ID_ANY, - # label = _("by elevation")) - # elev.Enable(False) # TODO: not implemented yet - ## gridSizer.Add(item = elev, pos = (0, 1)) - ## - # color = wx.CheckBox(parent = panel, id = wx.ID_ANY, - # label = _("by color")) - # color.Enable(False) # TODO: not implemented yet - ## gridSizer.Add(item = color, pos = (0, 2)) - ## - # boxSizer.Add(item = gridSizer, proportion = 1, - # flag = wx.ALL | wx.EXPAND, border = 3) - # pageSizer.Add(item = boxSizer, proportion = 0, - ## flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, - # border = 3) panel.SetSizer(pageSizer) @@ -1853,24 +1799,6 @@ def _createVectorPage(self, parent): icolor.Bind(csel.EVT_COLOURSELECT, self.OnVectorPoints) gridSizer.Add(icolor, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT, pos=(0, 4)) - # icon width - seems to do nothing - # gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, - # label = _("width")), - # pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL | - # wx.ALIGN_RIGHT) - ## - # iwidth = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1), - ## initial = 1, - ## min = 1, - # max = 1e6) - # iwidth.SetName('value') - # iwidth.SetValue(100) - ## self.win['vector']['points']['width'] = iwidth.GetId() - ## iwidth.Bind(wx.EVT_SPINCTRL, self.OnVectorPoints) - ## iwidth.Bind(wx.EVT_TEXT, self.OnVectorPoints) - # gridSizer.Add(item = iwidth, pos = (1, 2), - # flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT) - # icon symbol gridSizer.Add( StaticText(parent=panel, id=wx.ID_ANY, label=_("symbol:")), pos=(0, 5), @@ -2817,7 +2745,6 @@ def OnAnimationFinished(self, mode): self.UpdateFrameIndex(index=0) slider = self.FindWindowById(self.win["anim"]["frameIndex"]["slider"]) - text = self.FindWindowById(self.win["anim"]["frameIndex"]["text"]) if mode == "record": count = anim.GetFrameCount() @@ -2922,7 +2849,7 @@ def OnConstantSelection(self, event): layerIdx = self.FindWindowById(self.win["constant"]["surface"]).GetSelection() if layerIdx == wx.NOT_FOUND: return - name = _("constant#") + str(layerIdx + 1) + data = self.mapWindow.constants[layerIdx] for attr, value in data["constant"].items(): if attr == "color": @@ -3086,7 +3013,6 @@ def _createIsosurfacePanel(self, parent): ) value.Bind(wx.EVT_TEXT_ENTER, self.OnVolumeIsosurfMap) value.Bind(wx.EVT_KILL_FOCUS, self.OnVolumeIsosurfMap) - ## value.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap) else: size = (65, -1) value = SpinCtrl(parent=panel, id=wx.ID_ANY, size=size, initial=0) @@ -3123,8 +3049,6 @@ def _createIsosurfacePanel(self, parent): def _createSlicePanel(self, parent): panel = wx.Panel(parent=parent, id=wx.ID_ANY) - vSizer = wx.BoxSizer(wx.HORIZONTAL) - box = StaticBox( parent=panel, id=wx.ID_ANY, label=" %s " % (_("Slice attributes")) ) @@ -3260,10 +3184,7 @@ def _createControl( "style": style, "size": sizeW, } - if floatSlider: - slider = FloatSlider(**kwargs) - else: - slider = Slider(**kwargs) + slider = FloatSlider(**kwargs) if floatSlider else Slider(**kwargs) slider.SetName("slider") if bind[0]: @@ -3412,12 +3333,11 @@ def OnSetSurface(self, event): """Surface selected, currently used for fringes""" name = event.GetString() try: - data = self._getLayerPropertiesByName(name, mapType="raster")["surface"] - except Exception: + self._getLayerPropertiesByName(name, mapType="raster")["surface"] + except (AttributeError, TypeError, KeyError): self.EnablePage("fringe", False) return - layer = self._getMapLayerByName(name, mapType="raster") self.EnablePage("fringe", True) def OnSetRaster(self, event): @@ -3425,7 +3345,7 @@ def OnSetRaster(self, event): name = event.GetString() try: data = self._getLayerPropertiesByName(name, mapType="raster")["surface"] - except TypeError as e: + except TypeError: self.EnablePage("surface", False) return @@ -3438,7 +3358,7 @@ def OnSetVector(self, event): name = event.GetString() try: data = self._getLayerPropertiesByName(name, mapType="vector")["vector"] - except Exception: + except (AttributeError, TypeError, KeyError): self.EnablePage("vector", False) return layer = self._getMapLayerByName(name, mapType="vector") @@ -3450,7 +3370,7 @@ def OnSetRaster3D(self, event): name = event.GetString() try: data = self._getLayerPropertiesByName(name, mapType="raster_3d")["volume"] - except Exception: + except (AttributeError, TypeError, KeyError): self.EnablePage("volume", False) return @@ -3473,22 +3393,17 @@ def OnViewChange(self, event): self.AdjustSliderRange(slider=slider, value=value) - if winName == "height": - view = self.mapWindow.iview # internal - else: - view = self.mapWindow.view + # iview is internal + view = self.mapWindow.iview if winName == "height" else self.mapWindow.view if winName == "z-exag" and value >= 0: self.PostViewEvent(zExag=True) else: self.PostViewEvent(zExag=False) - if winName in {"persp", "twist"}: - convert = int - else: - convert = float - - view[winName]["value"] = convert(value) + view[winName]["value"] = ( + int(value) if winName in {"persp", "twist"} else float(value) + ) for win in self.win["view"][winName].values(): self.FindWindowById(win).SetValue(value) @@ -3701,10 +3616,8 @@ def EnablePage(self, name, enabled=True): def SetMapObjUseMap(self, nvizType, attrb, map=None): """Update dialog widgets when attribute type changed""" - if attrb in {"topo", "color", "shine"}: - incSel = -1 # decrement selection (no 'unset') - else: - incSel = 0 + # decrement selection (no 'unset') + incSel = -1 if attrb in {"topo", "color", "shine"} else 0 if nvizType == "volume" and attrb == "topo": return if map is True: # map @@ -3878,7 +3791,7 @@ def OnSurfaceModeAll(self, event): for name in self.mapWindow.GetLayerNames(type="raster"): data = self._getLayerPropertiesByName(name, mapType="raster") if not data: - continue # shouldy no happen + continue # should not happen data["surface"]["draw"]["all"] = True data["surface"]["draw"]["mode"] = { @@ -3932,11 +3845,7 @@ def _get3dRange(self, name): def _getPercent(self, value, toPercent=True): """Convert values 0 - 255 to percents and vice versa""" value = int(value) - if toPercent: - value = int(value / 255.0 * 100) - else: - value = int(value / 100.0 * 255) - return value + return int(value / 255.0 * 100) if toPercent else int(value / 100.0 * 255) def OnSurfaceWireColor(self, event): """Set wire color""" @@ -3998,8 +3907,7 @@ def OnSurfacePosition(self, event): self.win["surface"]["position"]["reset"], }: continue - else: - self.FindWindowById(win).SetValue(value) + self.FindWindowById(win).SetValue(value) data = self.GetLayerData("surface") id = data["surface"]["object"]["id"] @@ -4250,10 +4158,7 @@ def OnVectorHeightText(self, event): def OnVectorSurface(self, event): """Reference surface for vector map (lines/points)""" id = event.GetId() - if id == self.win["vector"]["lines"]["surface"]: - vtype = "lines" - else: - vtype = "points" + vtype = "lines" if id == self.win["vector"]["lines"]["surface"] else "points" checkList = self.FindWindowById(self.win["vector"][vtype]["surface"]) checked = [] surfaces = [] @@ -4329,10 +4234,7 @@ def OnCheckThematic(self, event): check = self.win["vector"][vtype]["thematic"]["check" + attrType] button = self.win["vector"][vtype]["thematic"]["button" + attrType] - if self.FindWindowById(check).GetValue(): - checked = True - else: - checked = False + checked = bool(self.FindWindowById(check).GetValue()) self.FindWindowById(button).Enable(checked) data = self.GetLayerData("vector") @@ -4590,10 +4492,6 @@ def OnVolumeSelect(self, event): if not winUp.IsEnabled(): winUp.Enable() - # update dialog - name = self.FindWindowById(self.win["volume"]["map"]).GetValue() - layer = self._getMapLayerByName(name, mapType="raster_3d") - if mode == "isosurf": data = self.GetLayerData("volume")["volume"]["isosurface"][selection] self.UpdateVolumeIsosurfPage(data) @@ -4694,8 +4592,6 @@ def OnVolumeDelete(self, event): if list.GetCount() > 0: list.SetSelection(list.GetCount() - 1) - name = self.FindWindowById(self.win["volume"]["map"]).GetValue() - layer = self._getMapLayerByName(name, mapType="raster_3d") data = self.GetLayerData("volume")["volume"] vid = data["object"]["id"] @@ -4736,8 +4632,6 @@ def OnVolumeMoveUp(self, event): if sel < 1: return # this should not happen - name = self.FindWindowById(self.win["volume"]["map"]).GetValue() - layer = self._getMapLayerByName(name, mapType="raster_3d") data = self.GetLayerData("volume")["volume"] id = data["object"]["id"] @@ -4776,8 +4670,6 @@ def OnVolumeMoveDown(self, event): if sel >= list.GetCount() - 1: return # this should not happen - name = self.FindWindowById(self.win["volume"]["map"]).GetValue() - layer = self._getMapLayerByName(name, mapType="raster_3d") data = self.GetLayerData("volume")["volume"] id = data["object"]["id"] @@ -4828,8 +4720,8 @@ def OnVolumePosition(self, event): self.win["volume"]["position"]["reset"], }: continue - else: - self.FindWindowById(win).SetValue(value) + + self.FindWindowById(win).SetValue(value) data = self.GetLayerData("volume") id = data["volume"]["object"]["id"] @@ -5007,7 +4899,7 @@ def OnCPlaneSelection(self, event): try: planeIndex = int(plane.split()[-1]) - 1 self.EnablePage("cplane", enabled=True) - except Exception: + except (ValueError, IndexError): planeIndex = -1 self.EnablePage("cplane", enabled=False) self.mapWindow.SelectCPlane(planeIndex) @@ -5024,7 +4916,7 @@ def OnCPlaneChanging(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except (IndexError, TypeError, ValueError): # TODO disabled page + except (ValueError, IndexError, TypeError): # TODO disabled page planeIndex = -1 if event.GetId() in ( @@ -5066,7 +4958,7 @@ def OnCPlaneShading(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except (IndexError, TypeError, ValueError): # TODO disabled page + except (ValueError, IndexError, TypeError): # TODO disabled page planeIndex = -1 self.mapWindow.cplanes[planeIndex]["shading"] = shading @@ -5081,7 +4973,7 @@ def OnCPlaneReset(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except (TypeError, ValueError, IndexError): # TODO disabled page + except (ValueError, IndexError, TypeError): # TODO disabled page planeIndex = -1 self.mapWindow.cplanes[planeIndex] = copy.deepcopy( diff --git a/gui/wxpython/nviz/workspace.py b/gui/wxpython/nviz/workspace.py index 1e38aee239a..ac9e0582b2d 100644 --- a/gui/wxpython/nviz/workspace.py +++ b/gui/wxpython/nviz/workspace.py @@ -136,10 +136,7 @@ def SetVolumeDefaultProp(self): sel = UserSettings.Get( group="nviz", key="volume", subkey=["draw", "mode"] ) - if sel == 0: - desc = "isosurface" - else: - desc = "slice" + desc = "isosurface" if sel == 0 else "slice" data["draw"]["mode"] = { "value": sel, "desc": desc, diff --git a/gui/wxpython/nviz/wxnviz.py b/gui/wxpython/nviz/wxnviz.py index 47cf99c079d..06812e81be6 100644 --- a/gui/wxpython/nviz/wxnviz.py +++ b/gui/wxpython/nviz/wxnviz.py @@ -22,9 +22,9 @@ @author Anna Kratochvilova (Google SoC 2011) """ -import sys import locale import struct +import sys from math import sqrt try: @@ -42,26 +42,213 @@ import wx try: - from ctypes import * + from ctypes import ( + CFUNCTYPE, + byref, + c_char_p, + c_double, + c_float, + c_int, + c_ubyte, + create_string_buffer, + pointer, + ) except KeyError as e: print("wxnviz.py: {}".format(e), file=sys.stderr) try: - from grass.lib.gis import * - from grass.lib.raster3d import * - from grass.lib.vector import * - from grass.lib.ogsf import * - from grass.lib.nviz import * - from grass.lib.raster import * + from grass.lib.ctypes_preamble import UNCHECKED, String + from grass.lib.gis import ( + Colors, + G_find_raster2, + G_find_raster3d, + G_find_vector2, + G_free, + G_fully_qualified_name, + G_gisinit, + G_set_error_routine, + G_set_percent_routine, + G_unset_error_routine, + G_unset_percent_routine, + G_unset_window, + G_warning, + ) + from grass.lib.nviz import ( + DRAW_QUICK_SURFACE, + DRAW_QUICK_VLINES, + DRAW_QUICK_VOLUME, + DRAW_QUICK_VPOINTS, + MAP_OBJ_SITE, + MAP_OBJ_SURF, + MAP_OBJ_UNDEFINED, + MAP_OBJ_VECT, + MAP_OBJ_VOL, + Nviz_change_exag, + Nviz_color_from_str, + Nviz_del_texture, + Nviz_delete_arrow, + Nviz_delete_scalebar, + Nviz_draw_all, + Nviz_draw_arrow, + Nviz_draw_cplane, + Nviz_draw_fringe, + Nviz_draw_image, + Nviz_draw_model, + Nviz_draw_quick, + Nviz_draw_scalebar, + Nviz_flythrough, + Nviz_get_bgcolor, + Nviz_get_cplane_rotation, + Nviz_get_cplane_translation, + Nviz_get_current_cplane, + Nviz_get_exag, + Nviz_get_exag_height, + Nviz_get_focus, + Nviz_get_longdim, + Nviz_get_max_texture, + Nviz_get_modelview, + Nviz_get_viewpoint_height, + Nviz_get_viewpoint_position, + Nviz_get_xyrange, + Nviz_get_zrange, + Nviz_has_focus, + Nviz_init_data, + Nviz_init_rotation, + Nviz_init_view, + Nviz_load_image, + Nviz_look_here, + Nviz_new_map_obj, + Nviz_num_cplanes, + Nviz_off_cplane, + Nviz_on_cplane, + Nviz_resize_window, + Nviz_set_2D, + Nviz_set_arrow, + Nviz_set_attr, + Nviz_set_bgcolor, + Nviz_set_cplane_here, + Nviz_set_cplane_rotation, + Nviz_set_cplane_translation, + Nviz_set_fence_color, + Nviz_set_focus, + Nviz_set_focus_map, + Nviz_set_fringe, + Nviz_set_light_ambient, + Nviz_set_light_bright, + Nviz_set_light_color, + Nviz_set_light_position, + Nviz_set_rotation, + Nviz_set_scalebar, + Nviz_set_surface_attr_default, + Nviz_set_viewpoint_height, + Nviz_set_viewpoint_persp, + Nviz_set_viewpoint_position, + Nviz_set_viewpoint_twist, + Nviz_unset_attr, + Nviz_unset_rotation, + nv_data, + ) + from grass.lib.ogsf import ( + ATT_COLOR, + ATT_EMIT, + ATT_MASK, + ATT_SHINE, + ATT_TOPO, + ATT_TRANSP, + CONST_ATT, + DM_FLAT, + DM_GOURAUD, + DM_GRID_SURF, + DM_GRID_WIRE, + DM_POLY, + DM_WIRE, + DM_WIRE_POLY, + MAP_ATT, + MAX_ISOSURFS, + GP_delete_site, + GP_get_sitename, + GP_select_surf, + GP_set_style, + GP_set_style_thematic, + GP_set_trans, + GP_set_zmode, + GP_site_exists, + GP_unselect_surf, + GP_unset_style_thematic, + GS_clear, + GS_delete_surface, + GS_get_cat_at_xy, + GS_get_distance_alongsurf, + GS_get_rotation_matrix, + GS_get_selected_point_on_surface, + GS_get_surf_list, + GS_get_trans, + GS_get_val_at_xy, + GS_get_viewdir, + GS_libinit, + GS_num_surfs, + GS_set_att_const, + GS_set_drawmode, + GS_set_drawres, + GS_set_rotation_matrix, + GS_set_trans, + GS_set_viewdir, + GS_set_wire_color, + GS_setall_drawmode, + GS_setall_drawres, + GS_surf_exists, + GS_write_ppm, + GS_write_tif, + GV_delete_vector, + GV_get_vectname, + GV_select_surf, + GV_set_style, + GV_set_style_thematic, + GV_set_trans, + GV_surf_is_selected, + GV_unselect_surf, + GV_unset_style_thematic, + GV_vect_exists, + GVL_delete_vol, + GVL_get_trans, + GVL_init_region, + GVL_isosurf_add, + GVL_isosurf_del, + GVL_isosurf_move_down, + GVL_isosurf_move_up, + GVL_isosurf_num_isosurfs, + GVL_isosurf_set_att_const, + GVL_isosurf_set_att_map, + GVL_isosurf_set_drawmode, + GVL_isosurf_set_drawres, + GVL_isosurf_set_flags, + GVL_isosurf_unset_att, + GVL_libinit, + GVL_set_draw_wire, + GVL_set_trans, + GVL_slice_add, + GVL_slice_del, + GVL_slice_move_down, + GVL_slice_move_up, + GVL_slice_num_slices, + GVL_slice_set_drawmode, + GVL_slice_set_drawres, + GVL_slice_set_pos, + GVL_slice_set_transp, + GVL_vol_exists, + ) + from grass.lib.raster import Rast__init_window, Rast_unset_window + from grass.lib.vector import Vect_read_colors except (ImportError, OSError, TypeError) as e: print("wxnviz.py: {}".format(e), file=sys.stderr) +import grass.script as gs + from core.debug import Debug -from core.utils import autoCropImageFromFile from core.gcmd import DecodeString from core.globalvar import wxPythonPhoenix +from core.utils import autoCropImageFromFile from gui_core.wrap import Rect -import grass.script as gs log = None progress = None @@ -708,11 +895,7 @@ def SetSurfaceAttr(self, id, attr, map, value): if map: ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, MAP_ATT, value, -1.0, self.data) else: - if attr == ATT_COLOR: - val = Nviz_color_from_str(value) - else: - val = float(value) - + val = Nviz_color_from_str(value) if attr == ATT_COLOR else float(value) ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, CONST_ATT, None, val, self.data) Debug.msg( @@ -1505,11 +1688,7 @@ def SetIsosurfaceAttr(self, id, isosurf_id, attr, map, value): if map: ret = GVL_isosurf_set_att_map(id, isosurf_id, attr, value) else: - if attr == ATT_COLOR: - val = Nviz_color_from_str(value) - else: - val = float(value) - + val = Nviz_color_from_str(value) if attr == ATT_COLOR else float(value) ret = GVL_isosurf_set_att_const(id, isosurf_id, attr, val) Debug.msg( @@ -2109,7 +2288,7 @@ def FlyThrough(self, flyInfo, mode, exagInfo): """Fly through the scene :param flyInfo: fly parameters - :param mode: 0 or 1 for different fly behaviour + :param mode: 0 or 1 for different fly behavior :param exagInfo: parameters changing fly speed """ fly = (c_float * 3)() @@ -2175,10 +2354,7 @@ def Resize(self): def Load(self): """Load image to texture""" - if self.image.HasAlpha(): - bytesPerPixel = 4 - else: - bytesPerPixel = 3 + bytesPerPixel = 4 if self.image.HasAlpha() else 3 bytes = bytesPerPixel * self.width * self.height rev_val = self.height - 1 im = (c_ubyte * bytes)() @@ -2266,3 +2442,21 @@ def GetCmd(self): def Corresponds(self, item): return sorted(self.GetCmd()) == sorted(item.GetCmd()) + + +__all__ = [ + "DM_FLAT", + "DM_GOURAUD", + "DM_GRID_SURF", + "DM_GRID_WIRE", + "DM_POLY", + "DM_WIRE", + "DM_WIRE_POLY", + "DRAW_QUICK_SURFACE", + "DRAW_QUICK_VLINES", + "DRAW_QUICK_VOLUME", + "DRAW_QUICK_VPOINTS", + "MAX_ISOSURFS", + "ImageTexture", + "Nviz", +] diff --git a/gui/wxpython/photo2image/g.gui.photo2image.html b/gui/wxpython/photo2image/g.gui.photo2image.html index f958f9baf7e..af113100511 100644 --- a/gui/wxpython/photo2image/g.gui.photo2image.html +++ b/gui/wxpython/photo2image/g.gui.photo2image.html @@ -32,7 +32,7 @@

    Screenshot of g.gui.photo2image

    -Screenshot of g.gui.photo2image +Screenshot of g.gui.photo2image
    Figure: Screenshot of g.gui.photo2image
    @@ -40,7 +40,7 @@

    Screenshot of g.gui.photo2image

    For a detailed operation manual please read

    -wxGUI
    +wxGUI, wxGUI components
    diff --git a/gui/wxpython/photo2image/g.gui.photo2image.py b/gui/wxpython/photo2image/g.gui.photo2image.py index 65b4141873e..443a43f2d81 100755 --- a/gui/wxpython/photo2image/g.gui.photo2image.py +++ b/gui/wxpython/photo2image/g.gui.photo2image.py @@ -67,7 +67,7 @@ # %end """ -Module to run GCP management tool as stadalone application. +Module to run GCP management tool as standalone application. """ import os import grass.script as gs @@ -121,7 +121,7 @@ def main(): app = wx.App() - wizard = GCPWizard( + GCPWizard( parent=None, giface=StandaloneGrassInterface(), group=group, diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index 63e746794d5..d720e0a5adc 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -20,7 +20,7 @@ @author Original author Michael Barton @author Original version improved by Martin Landa -@author Rewritten by Markus Metz redesign georectfier -> GCP Manage +@author Rewritten by Markus Metz redesign georectifier -> GCP Manage @author Support for GraphicsSet added by Stepan Turek (2012) @author Yann modified: graphical replacement of i.photo.2image (was in v6 using Vask lib) @@ -336,10 +336,10 @@ def __init__( # register data structures for drawing GCP's # self.pointsToDrawTgt = self.TgtMapWindow.RegisterGraphicsToDraw( - graphicsType="point", setStatusFunc=self.SetGCPSatus + graphicsType="point", setStatusFunc=self.SetGCPStatus ) self.pointsToDrawSrc = self.SrcMapWindow.RegisterGraphicsToDraw( - graphicsType="point", setStatusFunc=self.SetGCPSatus + graphicsType="point", setStatusFunc=self.SetGCPStatus ) # connect to the map windows signals @@ -426,14 +426,13 @@ def __init__( GMessage(_("A POINTS file exists, renaming it to POINTS_BAK")) # """Make a POINTS file """ - import re try: fc = open(self.file["camera"]) fc_count = 0 for line in fc: fc_count += 1 - if re.search("NUM", line): + if "NUM" in line: storeLine = fc_count numberOfFiducial = int(line.split()[-1]) dataFiducialX = [] @@ -778,7 +777,7 @@ def SetSettings(self): self.pointsToDrawSrc.SetPropertyVal("text", textProp) self.pointsToDrawTgt.SetPropertyVal("text", copy(textProp)) - def SetGCPSatus(self, item, itemIndex): + def SetGCPStatus(self, item, itemIndex): """Before GCP is drawn, decides it's colour and whether it will be drawn. """ @@ -797,10 +796,7 @@ def SetGCPSatus(self, item, itemIndex): else: item.SetPropertyVal("hide", False) if self.highest_only: - if itemIndex == self.highest_key: - wxPen = "highest" - else: - wxPen = "default" + wxPen = "highest" if itemIndex == self.highest_key else "default" else: # noqa: PLR5501 if self.mapcoordlist[key][5] > self.rmsthresh: wxPen = "highest" @@ -1036,16 +1032,13 @@ def ReloadGCPs(self, event): targetMapWin.UpdateMap(render=False) def OnFocus(self, event): - # TODO: it is here just to remove old or obsolete beavior of base class + # TODO: it is here just to remove old or obsolete behavior of base class # gcp/MapPanel? # self.grwiz.SwitchEnv('source') pass def _onMouseLeftUpPointer(self, mapWindow, x, y): - if mapWindow == self.SrcMapWindow: - coordtype = "source" - else: - coordtype = "target" + coordtype = "source" if mapWindow == self.SrcMapWindow else "target" coord = (x, y) self.SetGCPData(coordtype, coord, self, confirm=True) @@ -1102,27 +1095,22 @@ def OnGeorect(self, event): if maptype == "raster": self.grwiz.SwitchEnv("source") - if self.clip_to_region: - flags = "ac" - else: - flags = "a" - - busy = wx.BusyInfo(_("Rectifying images, please wait..."), parent=self) - wx.GetApp().Yield() + flags = "ac" if self.clip_to_region else "a" - ret, msg = RunCommand( - "i.rectify", - parent=self, - getErrorMsg=True, - quiet=True, - group=self.xygroup, - extension=self.extension, - order=self.gr_order, - method=self.gr_method, - flags=flags, - ) + with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): + wx.GetApp().Yield() - del busy + ret, msg = RunCommand( + "i.rectify", + parent=self, + getErrorMsg=True, + quiet=True, + group=self.xygroup, + extension=self.extension, + order=self.gr_order, + method=self.gr_method, + flags=flags, + ) # provide feedback on failure if ret != 0: @@ -1130,21 +1118,19 @@ def OnGeorect(self, event): print(self.grwiz.src_map, file=sys.stderr) print(msg, file=sys.stderr) - busy = wx.BusyInfo( + with wx.BusyInfo( _("Writing output image to group, please wait..."), parent=self - ) - wx.GetApp().Yield() - - ret1, msg1 = RunCommand( - "i.group", - parent=self, - getErrorMsg=True, - quiet=False, - group=self.xygroup, - input="".join([self.grwiz.src_map.split("@")[0], self.extension]), - ) + ): + wx.GetApp().Yield() - del busy + ret1, msg1 = RunCommand( + "i.group", + parent=self, + getErrorMsg=True, + quiet=False, + group=self.xygroup, + input="".join([self.grwiz.src_map.split("@")[0], self.extension]), + ) if ret1 != 0: print("ip2i: Error in i.group", file=sys.stderr) @@ -1253,7 +1239,6 @@ def OnGROrder(self, event): elif self.gr_order == 2: minNumOfItems = 6 - diff = 6 - numOfItems # self.SetStatusText(_( # "Insufficient points, 6+ points needed for 2nd order")) @@ -1556,7 +1541,6 @@ def OnZoomToTarget(self, event): def OnZoomMenuGCP(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu @@ -2467,7 +2451,6 @@ def UpdateSettings(self): srcrender = False tgtrender = False - reload_target = False if self.new_src_map != src_map: # remove old layer layers = self.parent.grwiz.SrcMap.GetListOfLayers() @@ -2499,7 +2482,6 @@ def UpdateSettings(self): del layers[0] layers = self.parent.grwiz.TgtMap.GetListOfLayers() # self.parent.grwiz.TgtMap.DeleteAllLayers() - reload_target = True tgt_map["raster"] = self.new_tgt_map["raster"] if tgt_map["raster"] != "": diff --git a/gui/wxpython/photo2image/ip2i_mapdisplay.py b/gui/wxpython/photo2image/ip2i_mapdisplay.py index aa085f2b43a..732716a1a0c 100644 --- a/gui/wxpython/photo2image/ip2i_mapdisplay.py +++ b/gui/wxpython/photo2image/ip2i_mapdisplay.py @@ -466,7 +466,6 @@ def PrintMenu(self, event): """ Print options and output menu for map display """ - point = wx.GetMousePosition() printmenu = Menu() # Add items to the menu setup = wx.MenuItem(printmenu, wx.ID_ANY, _("Page setup")) @@ -510,7 +509,6 @@ def SaveDisplayRegion(self, event): def OnZoomMenu(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index 66ac66d9348..428ae248c87 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -42,9 +42,8 @@ import wx import wx.lib.agw.floatspin as fs -from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin - from core import globalvar +from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin if globalvar.wxPythonPhoenix: from wx import Validator @@ -52,24 +51,25 @@ from wx import PyValidator as Validator import grass.script as gs - -from core.utils import PilImageToWxImage +from core.gcmd import GError, GMessage, RunCommand +from core.utils import PilImageToWxImage, cmp from dbmgr.vinfo import VectorDBInfo -from gui_core.gselect import Select -from core.gcmd import RunCommand, GError, GMessage from gui_core.dialogs import SymbolDialog +from gui_core.gselect import Select from gui_core.wrap import ( BitmapButton, BitmapComboBox, BitmapFromImage, Button, CheckBox, + CheckListCtrlMixin, Choice, ClientDC, ColourPickerCtrl, Dialog, DirBrowseButton, EmptyBitmap, + EmptyImage, ExpandoTextCtrl, FileBrowseButton, FloatSpin, @@ -86,11 +86,44 @@ StaticText, TextCtrl, TextEntryDialog, - EmptyImage, - CheckListCtrlMixin, ) -from psmap.utils import * -from psmap.instructions import * + +# Explicit imports from psmap.instructions +from psmap.instructions import ( + Image, + Labels, + Line, + MapFrame, + Mapinfo, + NewId, + NorthArrow, + Point, + Raster, + RasterLegend, + Rectangle, + Scalebar, + Text, + Vector, + VectorLegend, + VProperties, +) + +# Explicit imports from psmap.utils +from psmap.utils import ( + AutoAdjust, + BBoxAfterRotation, + ComputeSetRegion, + PaperMapCoordinates, + PILImage, + Rect2D, + Rect2DPP, + SetResolution, + UnitConversion, + convertRGB, + getRasterType, + havePILImage, + projInfo, +) # grass.set_raise_on_error(True) @@ -1223,10 +1256,7 @@ def OnMap(self, event): if self.scaleChoice.GetSelection() == 0: self.selectedMap = self.selected - if self.rasterTypeRadio.GetValue(): - mapType = "raster" - else: - mapType = "vector" + mapType = "raster" if self.rasterTypeRadio.GetValue() else "vector" self.scale[0], self.center[0], foo = AutoAdjust( self, @@ -1275,10 +1305,7 @@ def OnScaleChoice(self, event): self.vectorTypeRadio.Show() self.drawMap.Show() self.staticBox.SetLabel(" %s " % _("Map selection")) - if self.rasterTypeRadio.GetValue(): - stype = "raster" - else: - stype = "vector" + stype = "raster" if self.rasterTypeRadio.GetValue() else "vector" self.select.SetElementList(type=stype) self.mapText.SetLabel(self.mapOrRegionText[0]) @@ -1335,10 +1362,7 @@ def OnScaleChoice(self, event): def OnElementType(self, event): """Changes data in map selection tree ctrl popup""" - if self.rasterTypeRadio.GetValue(): - mapType = "raster" - else: - mapType = "vector" + mapType = "raster" if self.rasterTypeRadio.GetValue() else "vector" self.select.SetElementList(type=mapType) if self.mapType != mapType and event is not None: self.mapType = mapType @@ -1455,10 +1479,7 @@ def update(self): ) if self.mapType == "vector": raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId: self.env["GRASS_REGION"] = gs.region_env( @@ -1529,10 +1550,7 @@ def update(self): region = gs.region(env=None) raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId: # because of resolution self.env["GRASS_REGION"] = gs.region_env( @@ -3586,7 +3604,7 @@ def _rasterLegend(self, notebook): self.Bind(wx.EVT_CHECKBOX, self.OnIsLegend, self.isRLegend) self.Bind(wx.EVT_RADIOBUTTON, self.OnDiscrete, self.discrete) self.Bind(wx.EVT_RADIOBUTTON, self.OnDiscrete, self.continuous) - ## self.Bind(wx.EVT_CHECKBOX, self.OnDefaultSize, panel.defaultSize) + # self.Bind(wx.EVT_CHECKBOX, self.OnDefaultSize, panel.defaultSize) self.Bind(wx.EVT_CHECKBOX, self.OnRange, self.range) self.rasterSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnRaster) @@ -3715,10 +3733,7 @@ def _vectorLegend(self, notebook): def sizePositionFont(self, legendType, parent, mainSizer): """Insert widgets for size, position and font control""" - if legendType == "raster": - legendDict = self.rLegendDict - else: - legendDict = self.vLegendDict + legendDict = self.rLegendDict if legendType == "raster" else self.vLegendDict panel = parent border = mainSizer @@ -4092,10 +4107,7 @@ def OnUp(self, event): self.vectorListCtrl.SetItemData(pos, idx1) self.vectorListCtrl.SetItemData(pos - 1, idx2) self.vectorListCtrl.SortItems(cmp) - if pos > 0: - selected = pos - 1 - else: - selected = 0 + selected = pos - 1 if pos > 0 else 0 self.vectorListCtrl.Select(selected) @@ -4430,11 +4442,7 @@ def updateDialog(self): else: self.rasterId = None - if raster: - currRaster = raster["raster"] - else: - currRaster = None - + currRaster = raster["raster"] if raster else None rasterType = getRasterType(map=currRaster) self.rasterCurrent.SetLabel( _("%(rast)s: type %(type)s") % {"rast": currRaster, "type": str(rasterType)} @@ -4962,10 +4970,7 @@ def _scalebarPanel(self): globalvar.IMGDIR, "scalebar-simple.png" ) for item, path in zip(["fancy", "simple"], imagePath): - if not os.path.exists(path): - bitmap = EmptyBitmap(0, 0) - else: - bitmap = wx.Bitmap(path) + bitmap = EmptyBitmap(0, 0) if not os.path.exists(path) else wx.Bitmap(path) self.sbCombo.Append(item="", bitmap=bitmap, clientData=item[0]) # self.sbCombo.Append( # item="simple", @@ -5698,8 +5703,6 @@ def updateDialog(self): y = self.unitConv.convert(value=y, fromUnit="inch", toUnit=currUnit) self.positionPanel.position["xCtrl"].SetValue("%5.3f" % x) self.positionPanel.position["yCtrl"].SetValue("%5.3f" % y) - # EN coordinates - e, n = self.textDict["east"], self.textDict["north"] self.positionPanel.position["eCtrl"].SetValue(str(self.textDict["east"])) self.positionPanel.position["nCtrl"].SetValue(str(self.textDict["north"])) @@ -5851,11 +5854,7 @@ def _imagePanel(self, notebook): panel.image["scale"].SetFormat("%f") panel.image["scale"].SetDigits(1) - if self.imageDict["scale"]: - value = float(self.imageDict["scale"]) - else: - value = 0 - + value = float(self.imageDict["scale"]) if self.imageDict["scale"] else 0 panel.image["scale"].SetValue(value) gridSizer.Add(scaleLabel, pos=(0, 0), flag=wx.ALIGN_CENTER_VERTICAL) @@ -5994,7 +5993,7 @@ def OnImageSelectionChanged(self, event): pImg = PILImage.open(file) img = PilImageToWxImage(pImg) except OSError as e: - GError(message=_("Unable to read file %s") % file) + GError(message=_("Unable to read file %s: %s") % (file, str(e))) self.ClearPreview() return self.SetSizeInfoLabel(img) @@ -6107,15 +6106,6 @@ def update(self): else: self.imageDict["XY"] = False - if self.positionPanel.position["eCtrl"].GetValue(): - e = self.positionPanel.position["eCtrl"].GetValue() - else: - self.imageDict["east"] = self.imageDict["east"] - - if self.positionPanel.position["nCtrl"].GetValue(): - n = self.positionPanel.position["nCtrl"].GetValue() - else: - self.imageDict["north"] = self.imageDict["north"] x, y = PaperMapCoordinates( mapInstr=self.instruction[self.mapId], @@ -6178,7 +6168,6 @@ def updateDialog(self): self.positionPanel.position["xCtrl"].SetValue("%5.3f" % x) self.positionPanel.position["yCtrl"].SetValue("%5.3f" % y) # EN coordinates - e, n = self.imageDict["east"], self.imageDict["north"] self.positionPanel.position["eCtrl"].SetValue(str(self.imageDict["east"])) self.positionPanel.position["nCtrl"].SetValue(str(self.imageDict["north"])) @@ -6493,15 +6482,6 @@ def update(self): else: self.pointDict["XY"] = False - if self.positionPanel.position["eCtrl"].GetValue(): - e = self.positionPanel.position["eCtrl"].GetValue() - else: - self.pointDict["east"] = self.pointDict["east"] - - if self.positionPanel.position["nCtrl"].GetValue(): - n = self.positionPanel.position["nCtrl"].GetValue() - else: - self.pointDict["north"] = self.pointDict["north"] x, y = PaperMapCoordinates( mapInstr=self.instruction[self.mapId], @@ -6557,7 +6537,6 @@ def updateDialog(self): self.positionPanel.position["xCtrl"].SetValue("%5.3f" % x) self.positionPanel.position["yCtrl"].SetValue("%5.3f" % y) # EN coordinates - e, n = self.pointDict["east"], self.pointDict["north"] self.positionPanel.position["eCtrl"].SetValue(str(self.pointDict["east"])) self.positionPanel.position["nCtrl"].SetValue(str(self.pointDict["north"])) @@ -6568,10 +6547,7 @@ def __init__(self, parent, id, settings, env, type="rectangle", coordinates=None :param coordinates: begin and end point coordinate (wx.Point, wx.Point) """ - if type == "rectangle": - title = _("Rectangle settings") - else: - title = _("Line settings") + title = _("Rectangle settings") if type == "rectangle" else _("Line settings") PsmapDialog.__init__( self, parent=parent, id=id, title=title, settings=settings, env=env ) diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index c95aad6f83b..bb71fd856a5 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -16,10 +16,9 @@ """ import os -import sys - import queue as Queue -from math import sin, cos, pi, sqrt +import sys +from math import cos, pi, sin, sqrt import wx @@ -29,25 +28,51 @@ import wx.lib.flatnotebook as FN import grass.script as gs - from core import globalvar -from gui_core.menu import Menu -from core.gconsole import CmdThread, EVT_CMD_DONE -from psmap.toolbars import PsMapToolbar -from core.gcmd import RunCommand, GError, GMessage +from core.gcmd import GError, GMessage, RunCommand +from core.gconsole import EVT_CMD_DONE, CmdThread from core.settings import UserSettings from core.utils import PilImageToWxImage -from gui_core.forms import GUI -from gui_core.widgets import GNotebook from gui_core.dialogs import HyperlinkDialog +from gui_core.forms import GUI from gui_core.ghelp import ShowAboutDialog -from gui_core.wrap import ClientDC, PseudoDC, Rect, StockCursor, EmptyBitmap -from psmap.menudata import PsMapMenuData +from gui_core.menu import Menu from gui_core.toolbars import ToolSwitcher - -from psmap.dialogs import * -from psmap.instructions import * -from psmap.utils import * +from gui_core.widgets import GNotebook +from gui_core.wrap import ClientDC, EmptyBitmap, PseudoDC, Rect, StockCursor + +from psmap.dialogs import ( + ImageDialog, + LabelsDialog, + LegendDialog, + MainVectorDialog, + MapDialog, + MapinfoDialog, + NorthArrowDialog, + PageSetupDialog, + PointDialog, + RasterDialog, + RectangleDialog, + ScalebarDialog, + TextDialog, +) +from psmap.instructions import InitMap, Instruction, NewId, SetResolution, PageSetup +from psmap.menudata import PsMapMenuData +from psmap.toolbars import PsMapToolbar +from psmap.utils import ( + AutoAdjust, + ComputeSetRegion, + GetMapBounds, + PaperMapCoordinates, + PILImage, + Rect2D, + Rect2DPP, + Rect2DPS, + UnitConversion, + convertRGB, + havePILImage, + projInfo, +) class PsMapFrame(wx.Frame): @@ -170,7 +195,6 @@ def __init__( self.getInitMap() # image path - env = gs.gisenv() self.imgName = gs.tempfile() # canvas for preview @@ -345,10 +369,7 @@ def PSFile(self, filename=None, pdf=False): temp = False regOld = gs.region(env=self.env) - if pdf: - pdfname = filename - else: - pdfname = None + pdfname = filename if pdf else None # preview or pdf if not filename or (filename and pdf): temp = True @@ -488,45 +509,44 @@ def OnCmdDone(self, event): env=self.env, ) # wx.BusyInfo does not display the message - busy = wx.BusyInfo(_("Generating preview, wait please"), parent=self) - wx.GetApp().Yield() - try: - im = PILImage.open(event.userData["filename"]) - if self.instruction[self.pageId]["Orientation"] == "Landscape": - import numpy as np - - im_array = np.array(im) - im = PILImage.fromarray(np.rot90(im_array, 3)) - im.save(self.imgName, format="PNG") - except OSError: - del busy - program = self._getGhostscriptProgramName() - dlg = HyperlinkDialog( - self, - title=_("Preview not available"), - message=_( - "Preview is not available probably because Ghostscript is not " - "installed or not on PATH." - ), - hyperlink="https://www.ghostscript.com/releases/gsdnld.html", - hyperlinkLabel=_( - "You can download {program} {arch} version here." - ).format( - program=program, - arch="64bit" if "64" in program else "32bit", - ), - ) - dlg.ShowModal() - dlg.Destroy() - return + with wx.BusyInfo(_("Generating preview, wait please"), parent=self): + wx.GetApp().Yield() + try: + im = PILImage.open(event.userData["filename"]) + if self.instruction[self.pageId]["Orientation"] == "Landscape": + import numpy as np + + im_array = np.array(im) + im = PILImage.fromarray(np.rot90(im_array, 3)) + im.save(self.imgName, format="PNG") + except OSError: + del busy + program = self._getGhostscriptProgramName() + dlg = HyperlinkDialog( + self, + title=_("Preview not available"), + message=_( + "Preview is not available probably because Ghostscript is not " + "installed or not on PATH." + ), + hyperlink="https://www.ghostscript.com/releases/gsdnld.html", + hyperlinkLabel=_( + "You can download {program} {arch} version here." + ).format( + program=program, + arch="64bit" if "64" in program else "32bit", + ), + ) + dlg.ShowModal() + dlg.Destroy() + return - self.book.SetSelection(1) - self.currentPage = 1 - rect = self.previewCanvas.ImageRect() - self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG) - self.previewCanvas.DrawImage(rect=rect) + self.book.SetSelection(1) + self.currentPage = 1 + rect = self.previewCanvas.ImageRect() + self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG) + self.previewCanvas.DrawImage(rect=rect) - del busy self.SetStatusText(_("Preview generated"), 0) gs.try_remove(event.userData["instrFile"]) @@ -546,10 +566,7 @@ def getFile(self, wildcard): s = "." + s suffix.append(s) raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId and self.instruction[rasterId]["raster"]: mapName = self.instruction[rasterId]["raster"].split("@")[0] + suffix[0] @@ -755,8 +772,6 @@ def OnAddRaster(self, event): if not self._checkMapFrameExists(type_id=id): return - ## dlg = RasterDialog(self, id = id, settings = self.instruction) - # dlg.ShowModal() if "mapNotebook" in self.openDialogs: self.openDialogs["mapNotebook"].notebook.ChangeSelection(1) else: @@ -775,8 +790,6 @@ def OnAddVect(self, event): if not self._checkMapFrameExists(type_id=id): return - ## dlg = MainVectorDialog(self, id = id, settings = self.instruction) - # dlg.ShowModal() if "mapNotebook" in self.openDialogs: self.openDialogs["mapNotebook"].notebook.ChangeSelection(2) else: @@ -1032,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 Exception: - 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""" @@ -1058,7 +1061,7 @@ def getTextExtent(self, textDict): dc.SetFont(fn) w, h, lh = dc.GetFullMultiLineTextExtent(textDict["text"]) return (w, h) - except Exception: + except (wx.PyAssertionError, ValueError, KeyError): return (0, 0) def getInitMap(self): @@ -1087,10 +1090,7 @@ def getInitMap(self): scale = mapInitRect.Get()[2] / realWidth initMap = self.instruction.FindInstructionByType("initMap") - if initMap: - id = initMap.id - else: - id = None + id = initMap.id if initMap else None if not id: id = NewId() @@ -1972,7 +1972,7 @@ def OnDragging(self, event): pdcType = "rect" lineCoords = None if r[2] < 2 or r[3] < 2: - # to avoid strange behaviour + # to avoid strange behavior return self.Draw( @@ -2081,10 +2081,7 @@ def OnDragging(self, event): instr = self.instruction[self.dragId] points = instr["where"] # moving point - if self.currentLinePoint == 0: - pPaper = points[1] - else: - pPaper = points[0] + pPaper = points[1] if self.currentLinePoint == 0 else points[0] pCanvas = self.CanvasPaperCoordinates( rect=Rect2DPS(pPaper, (0, 0)), canvasToPaper=False )[:2] @@ -2513,10 +2510,7 @@ def DrawBitmap(self, pdc, filePath, rotation, bbox): pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask=True) def DrawRotText(self, pdc, drawId, textDict, coords, bounds): - if textDict["rotate"]: - rot = float(textDict["rotate"]) - else: - rot = 0 + rot = float(textDict["rotate"]) if textDict["rotate"] else 0 if textDict["background"] != "none": background = textDict["background"] @@ -2672,16 +2666,10 @@ def UpdateMapLabel(self): """Updates map frame label""" vector = self.instruction.FindInstructionByType("vector") - if vector: - vectorId = vector.id - else: - vectorId = None + vectorId = vector.id if vector else None raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None rasterName = "None" if rasterId: diff --git a/gui/wxpython/psmap/g.gui.psmap.html b/gui/wxpython/psmap/g.gui.psmap.html index 02fc0d9960f..068b2ae6724 100644 --- a/gui/wxpython/psmap/g.gui.psmap.html +++ b/gui/wxpython/psmap/g.gui.psmap.html @@ -18,9 +18,9 @@

    DESCRIPTION

    Possible output files:

      -
    • ps.map instructions file -
    • PostScript/EPS file -
    • PDF (using ps2pdf) +
    • ps.map instructions file
    • +
    • PostScript/EPS file
    • +
    • PDF (using ps2pdf)
    @@ -38,23 +38,23 @@

    DESCRIPTION

    Currently supported ps.map instructions:
      -
    • paper -
    • maploc -
    • scale -
    • border -
    • raster -
    • colortable -
    • vpoints -
    • vlines -
    • vareas -
    • vlegend -
    • text -
    • scalebar -
    • mapinfo -
    • point -
    • line -
    • rectangle -
    • labels +
    • paper
    • +
    • maploc
    • +
    • scale
    • +
    • border
    • +
    • raster
    • +
    • colortable
    • +
    • vpoints
    • +
    • vlines
    • +
    • vareas
    • +
    • vlegend
    • +
    • text
    • +
    • scalebar
    • +
    • mapinfo
    • +
    • point
    • +
    • line
    • +
    • rectangle
    • +
    • labels

    CARTOGRAPHIC COMPOSER TOOLBAR

    @@ -203,7 +203,7 @@

    CARTOGRAPHIC COMPOSER TOOLBAR

    SEE ALSO

    - wxGUI
    + wxGUI, wxGUI components
    diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 9db64679422..dcdfb907383 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -35,17 +35,27 @@ import os import string from math import ceil -from time import strftime, localtime +from time import localtime, strftime -import wx import grass.script as gs -from grass.script.task import cmdlist_to_tuple - +import wx from core.gcmd import GError, GMessage, GWarning from core.utils import GetCmdString from dbmgr.vinfo import VectorDBInfo +from grass.script.task import cmdlist_to_tuple from gui_core.wrap import NewId as wxNewId -from psmap.utils import * + +from psmap.utils import ( # Add any additional required names from psmap.utils here + BBoxAfterRotation, + GetMapBounds, + PaperMapCoordinates, + Rect2D, + Rect2DPP, + SetResolution, + UnitConversion, + getRasterType, + projInfo, +) def NewId(): @@ -213,7 +223,7 @@ def Read(self, filename): buffer = [] continue - elif line.startswith("paper"): + if line.startswith("paper"): instruction = "paper" isBuffer = True buffer.append(line) @@ -688,7 +698,7 @@ def Read(self, instruction, text, **kwargs): if line.split()[1].lower() in {"n", "no", "none"}: instr["border"] = "n" break - elif line.split()[1].lower() in {"y", "yes"}: + if line.split()[1].lower() in {"y", "yes"}: instr["border"] = "y" elif line.startswith("width"): instr["width"] = line.split()[1] @@ -1741,7 +1751,7 @@ def EstimateHeight(self, raster, discrete, fontsize, cols=None, height=None): rinfo = gs.raster_info(raster) if rinfo["datatype"] in {"DCELL", "FCELL"}: - minim, maxim = rinfo["min"], rinfo["max"] + maxim = rinfo["max"] rows = ceil(maxim / cols) else: cat = ( diff --git a/gui/wxpython/psmap/utils.py b/gui/wxpython/psmap/utils.py index 6bb53acd9f0..bb75c0eb7d5 100644 --- a/gui/wxpython/psmap/utils.py +++ b/gui/wxpython/psmap/utils.py @@ -93,10 +93,7 @@ class UnitConversion: def __init__(self, parent=None): self.parent = parent - if self.parent: - ppi = wx.ClientDC(self.parent).GetPPI() - else: - ppi = (72, 72) + ppi = wx.ClientDC(self.parent).GetPPI() if self.parent else (72, 72) self._unitsPage = { "inch": {"val": 1.0, "tr": _("inch")}, "point": {"val": 72.0, "tr": _("point")}, @@ -323,10 +320,7 @@ def ComputeSetRegion(self, mapDict, env): centerN = mapDict["center"][1] raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId: env["GRASS_REGION"] = gs.region_env( @@ -440,6 +434,6 @@ def BBoxAfterRotation(w, h, angle): x_min = x x_max = x + wct - hst - width = int(ceil(abs(x_max) + abs(x_min))) - height = int(ceil(abs(y_max) + abs(y_min))) + width = ceil(abs(x_max) + abs(x_min)) + height = ceil(abs(y_max) + abs(y_min)) return width, height diff --git a/gui/wxpython/rdigit/controller.py b/gui/wxpython/rdigit/controller.py index 8018ee04e5c..9b70a2cc468 100644 --- a/gui/wxpython/rdigit/controller.py +++ b/gui/wxpython/rdigit/controller.py @@ -447,10 +447,7 @@ def _createNewMap(self, mapName, backgroundMap, mapType): name = mapName.split("@")[0] background = backgroundMap.split("@")[0] types = {"CELL": "int", "FCELL": "float", "DCELL": "double"} - if background: - back = background - else: - back = "null()" + back = background or "null()" try: grast.mapcalc( exp="{name} = {mtype}({back})".format( diff --git a/gui/wxpython/rdigit/g.gui.rdigit.html b/gui/wxpython/rdigit/g.gui.rdigit.html index becb12affd7..7705ef8c7be 100644 --- a/gui/wxpython/rdigit/g.gui.rdigit.html +++ b/gui/wxpython/rdigit/g.gui.rdigit.html @@ -74,9 +74,9 @@

    EXAMPLES

    SEE ALSO

    - wxGUI
    - wxGUI components,
    - r.in.poly (backend of digitizer),
    + wxGUI, + wxGUI components, + r.in.poly (backend of digitizer), g.gui.vdigit
    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/rlisetup/functions.py b/gui/wxpython/rlisetup/functions.py index fc9d3c3d202..3670a504621 100644 --- a/gui/wxpython/rlisetup/functions.py +++ b/gui/wxpython/rlisetup/functions.py @@ -18,9 +18,9 @@ class SamplingType: MMVWINC = samplingtype=moving, regionbox=mouse, shape=circle MMVWINR = samplingtype moving, regionbox=mouse, shape=rectangle - KUNITSC = samplingtype=units, regionbox=keyboard, shape=cirlce + KUNITSC = samplingtype=units, regionbox=keyboard, shape=circle KUNITSR = samplingtype=units, regionbox=keyboard, shape=rectangle - MUNITSC = samplingtype=units, regionbox=mouse, shape=cirlce + MUNITSC = samplingtype=units, regionbox=mouse, shape=circle MUNITSR = samplingtype=units, regionbox=mouse, shape=rectangle """ @@ -141,7 +141,7 @@ def sampleAreaVector( vect=vect.split("@")[0], rast=rast.split("@")[0] ) rast_name = "{pref}{cat}".format(pref=outpref, cat=cat) - # check if raster already axist + # check if raster already exists if ( len(grass.list_strings("raster", pattern=rast_name, mapset=".")) == 1 diff --git a/gui/wxpython/rlisetup/g.gui.rlisetup.html b/gui/wxpython/rlisetup/g.gui.rlisetup.html index 1dc786e0b10..ae5663bb7d6 100644 --- a/gui/wxpython/rlisetup/g.gui.rlisetup.html +++ b/gui/wxpython/rlisetup/g.gui.rlisetup.html @@ -78,76 +78,76 @@

    Usage details

    1. Choose file name and maps to use for setting: -
        -
      • Name for new configuration file(required): the name - of new configuration file
      • -
      • Raster map name to use to select areas (required): +
          +
        • Name for new configuration file(required): the name + of new configuration file
        • +
        • Raster map name to use to select areas (required): the name of raster map used for selecting sampling areas
        • -
        • Vector map to overlay (optional): name of a +
        • Vector map to overlay (optional): name of a vector map used for selecting sampling areas
        • -
        +
    2. Set the sampling frame. The sample frame is a rectangular area which contains all the areas to analyze. It can be defined in three ways: -
        -
      • Whole map layer: the sample frame is the whole map
      • -
      • Keyboard setting: the user enters the coordinates in - cells of upper left corner of sampling frame and its length in - rows and columns.
      • -
      • Draw the sample frame: the user draws the sample frame - on map using mouse.
      • -
      +
        +
      • Whole map layer: the sample frame is the whole map
      • +
      • Keyboard setting: the user enters the coordinates in + cells of upper left corner of sampling frame and its length in + rows and columns.
      • +
      • Draw the sample frame: the user draws the sample frame + on map using mouse.
      • +
    3. Set the sample areas. The sample areas are simply the areas to analyze. They can be defined in five ways (see the picture below): -
        -
      • Whole map layer: the sample area is the whole sample - frame
      • -
      • Regions: the user enters the number of areas and then - draws them using mouse.
      • -
      • Sample units: they are areas of rectangular or circular - shape. The user can define them using keyboard or mouse. -
          -
        • keyboard: the user define the shape of sample unists and - their disposition: -
            -
          • Random non overlapping: the user specifies - the number of sample units and they are placed in a - random way at runtime. It is guaranteed that the - areas do not intersect themselves.
          • -
          • Systematic contiguous: the defined sample - is placed covering the sample frame, side by side - across rows.
          • -
          • Systematic non contiguous: the same as above, - but here ever rectangle is spaced from another by - a specified number of cells.
          • -
          • Stratified random: the sample frame is - divided in n strats of rows and m strats of columns - (n and m are given by user), then the specified - number of sample areas are placed in a random way, - one for every m*n areas defined by strats.
          • -
          • Centered over sites: the sample areas - are placed into sample frame centering them on points - in site file.
          • -
          -
        • -
        • mouse: the user chooses the shape and then draws the - specified number of sample areas on map.
        • -
        +
          +
        • Whole map layer: the sample area is the whole sample + frame
        • +
        • Regions: the user enters the number of areas and then + draws them using mouse.
        • +
        • Sample units: they are areas of rectangular or circular + shape. The user can define them using keyboard or mouse. +
            +
          • keyboard: the user define the shape of sample unists and + their disposition: +
              +
            • Random non overlapping: the user specifies + the number of sample units and they are placed in a + random way at runtime. It is guaranteed that the + areas do not intersect themselves.
            • +
            • Systematic contiguous: the defined sample + is placed covering the sample frame, side by side + across rows.
            • +
            • Systematic non contiguous: the same as above, + but here ever rectangle is spaced from another by + a specified number of cells.
            • +
            • Stratified random: the sample frame is + divided in n strats of rows and m strats of columns + (n and m are given by user), then the specified + number of sample areas are placed in a random way, + one for every m*n areas defined by strats.
            • +
            • Centered over sites: the sample areas + are placed into sample frame centering them on points + in site file.
            • +
            +
          • +
          • mouse: the user chooses the shape and then draws the + specified number of sample areas on map.
          • +
        • -
        • Moving Window: the user defines a rectangular or - circular area, it is moved over all the raster increasing only - of a cell for every move(in columns if possible, if not in rows). - It produces a new raster containing the result of all analysis.
        • -
        • Select areas from the overlaid vector map: - the sample areas are defined by the vector map selected above. - For every cat in vector map, the procedure prompts the - user if they want to include it as sample area. - The resulting configuration file can be used only with the - specified raster map, and the procedure can be used only if - whole map layer is selected as sampling frame.
        • -
        +
      • Moving Window: the user defines a rectangular or + circular area, it is moved over all the raster increasing only + of a cell for every move(in columns if possible, if not in rows). + It produces a new raster containing the result of all analysis.
      • +
      • Select areas from the overlaid vector map: + the sample areas are defined by the vector map selected above. + For every cat in vector map, the procedure prompts the + user if they want to include it as sample area. + The resulting configuration file can be used only with the + specified raster map, and the procedure can be used only if + whole map layer is selected as sampling frame.
      • +
    @@ -165,7 +165,7 @@

    NOTES

    Screenshots of the wizard window frames:
    - +
     g.gui.rlisetup: First frame of wizard for selecting existing configuration files or creating a new one @@ -328,7 +328,7 @@

    REFERENCES

    SEE ALSO

    -r.li - package overview
    +r.li (package overview), r.li.daemon

    diff --git a/gui/wxpython/rlisetup/sampling_frame.py b/gui/wxpython/rlisetup/sampling_frame.py index a379ef8c09c..df2ee8f62af 100644 --- a/gui/wxpython/rlisetup/sampling_frame.py +++ b/gui/wxpython/rlisetup/sampling_frame.py @@ -315,7 +315,6 @@ def _onToolChanged(self): def _radiusDrawn(self, x, y): """When drawing finished, get region values""" mouse = self.mapWindow.mouse - item = self._registeredGraphics.GetItem(0) p1 = mouse["begin"] p2 = mouse["end"] dist, (north, east) = self.mapWindow.Distance(p1, p2, False) @@ -328,9 +327,9 @@ def _radiusDrawn(self, x, y): circle.point[0], circle.point[1], circle.radius ) self._registeredGraphics.Draw() - self.createCricle(circle) + self.createCircle(circle) - def createCricle(self, c): + def createCircle(self, c): dlg = wx.TextEntryDialog( None, "Name of sample circle region", diff --git a/gui/wxpython/rlisetup/wizard.py b/gui/wxpython/rlisetup/wizard.py index 7046fa44116..35aa3384e38 100644 --- a/gui/wxpython/rlisetup/wizard.py +++ b/gui/wxpython/rlisetup/wizard.py @@ -360,7 +360,7 @@ def _write_area(self, fil): fil.write("SAMPLEAREA -1|-1|%r|%r" % (rl, cl)) fil.write("|%s" % self.msAreaList[0].raster) fil.write("\nMOVINGWINDOW\n") - # KUNITSC = samplingtype=units, regionbox=keyboard, shape=cirlce + # KUNITSC = samplingtype=units, regionbox=keyboard, shape=circle # KUNITSR = samplingtype=units, regionbox=keyboard, shape=rectangle elif samtype in {SamplingType.KUNITSC, SamplingType.KUNITSR}: if samtype == SamplingType.KUNITSC: @@ -374,13 +374,13 @@ def _write_area(self, fil): fil.write("SAMPLEAREA -1|-1|%r|%r\n" % (rl, cl)) if self.units.distrtype == "non_overlapping": fil.write("RANDOMNONOVERLAPPING %s\n" % self.units.distr1) - elif self.units.distrtype == "systematic_contiguos": + elif self.units.distrtype == "systematic_contiguous": fil.write("SYSTEMATICCONTIGUOUS\n") elif self.units.distrtype == "stratified_random": fil.write( "STRATIFIEDRANDOM %s|%s\n" % (self.units.distr1, self.units.distr2) ) - elif self.units.distrtype == "systematic_noncontiguos": + elif self.units.distrtype == "systematic_noncontiguous": fil.write("SYSTEMATICNONCONTIGUOUS %s\n" % self.units.distr1) elif self.units.distrtype == "centered_oversites": fil.write("") @@ -388,7 +388,7 @@ def _write_area(self, fil): # elif self.samplingareapage.samplingtype == SamplingType.UNITS and # self.samplingareapage.regionbox=='mouse': - # MUNITSC = samplingtype=units, regionbox=mouse, shape=cirlce + # MUNITSC = samplingtype=units, regionbox=mouse, shape=circle # MUNITSR = samplingtype=units, regionbox=mouse, shape=rectangle elif self.samplingareapage.samplingtype in { SamplingType.MUNITSR, @@ -687,7 +687,7 @@ def OnVector(self, event): def OnLayer(self, event): try: self.vectorlayer = self.vectlayer.GetValue() - except Exception: + except AttributeError: self.vectorlayer = None next = wx.FindWindowById(wx.ID_FORWARD) next.Enable(self.CheckInput()) @@ -1434,7 +1434,7 @@ def OnDistr(self, event): self.panelSizer.Hide(self.distr2Txt) self.panelSizer.Layout() elif chosen == 1: - self.distrtype = "systematic_contiguos" + self.distrtype = "systematic_contiguous" self.distr1Label.SetLabel("") self.distr2Label.SetLabel("") self.panelSizer.Hide(self.distr1Txt) @@ -1448,7 +1448,7 @@ def OnDistr(self, event): self.panelSizer.Show(self.distr2Txt) self.panelSizer.Layout() elif chosen == 3: - self.distrtype = "systematic_noncontiguos" + self.distrtype = "systematic_noncontiguous" self.distr1Label.SetLabel(_("Insert distance between units")) self.panelSizer.Show(self.distr1Txt) self.distr2Label.SetLabel("") @@ -2182,7 +2182,7 @@ def OnEnterPage(self, event): if self.parent.units.distrtype == "non_overlapping": self.unitsmorelabel.SetLabel(_("Number sampling units:")) self.unitsmoretxt.SetLabel(self.parent.units.distr1) - elif self.parent.units.distrtype == "systematic_noncontiguos": + elif self.parent.units.distrtype == "systematic_noncontiguous": self.unitsmorelabel.SetLabel(_("Distance between units:")) self.unitsmoretxt.SetLabel(self.parent.units.distr1) elif self.parent.units.distrtype == "stratified_random": diff --git a/gui/wxpython/startup/locdownload.py b/gui/wxpython/startup/locdownload.py index 1cdadcfd316..7e24724d862 100644 --- a/gui/wxpython/startup/locdownload.py +++ b/gui/wxpython/startup/locdownload.py @@ -32,10 +32,13 @@ set_gui_path() +# flake8: noqa: E402 from core.debug import Debug from core.gthread import gThread from gui_core.wrap import Button, StaticText +# flakes8: qa + # TODO: labels (and descriptions) translatable? LOCATIONS = [ @@ -93,7 +96,7 @@ def write(self, string): heigth = self._get_heigth(string) wx.CallAfter(self.out.SetLabel, string) self._resize(heigth) - except Exception: + except wx.PyDeadObjectError: # window closed -> PyDeadObjectError pass diff --git a/gui/wxpython/timeline/frame.py b/gui/wxpython/timeline/frame.py index 7ca51cd8989..c5c54982ed3 100644 --- a/gui/wxpython/timeline/frame.py +++ b/gui/wxpython/timeline/frame.py @@ -272,10 +272,9 @@ def _draw3dFigure(self): self.axes3d.clear() self.axes3d.grid(False) # self.axes3d.grid(True) - if self.temporalType == "absolute": - convert = mdates.date2num - else: - convert = lambda x: x # noqa: E731 + convert = ( + mdates.date2num if self.temporalType == "absolute" else lambda x: x + ) # noqa: E731 colors = cycle(COLORS) plots = [] @@ -321,10 +320,9 @@ def _draw2dFigure(self): """Draws 2D plot (temporal extents)""" self.axes2d.clear() self.axes2d.grid(True) - if self.temporalType == "absolute": - convert = mdates.date2num - else: - convert = lambda x: x # noqa: E731 + convert = ( + mdates.date2num if self.temporalType == "absolute" else lambda x: x + ) # noqa: E731 colors = cycle(COLORS) @@ -520,7 +518,7 @@ def _checkDatasets(self, datasets): if len(indices) == 0: raise GException(errorMsg) - elif len(indices) >= 2: + if len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, message=_("Please specify the space time dataset <%s>.") % dataset, @@ -643,7 +641,7 @@ class DataCursor: matplotlib artist when it is selected. - Source: http://stackoverflow.com/questions/4652439/ + Source: https://stackoverflow.com/questions/4652439/ is-there-a-matplotlib-equivalent-of-matlabs-datacursormode/4674445 """ diff --git a/gui/wxpython/timeline/g.gui.timeline.html b/gui/wxpython/timeline/g.gui.timeline.html index 10f3c040ffe..443e07417b4 100644 --- a/gui/wxpython/timeline/g.gui.timeline.html +++ b/gui/wxpython/timeline/g.gui.timeline.html @@ -21,17 +21,17 @@

    DESCRIPTION

    NOTES

    g.gui.timeline requires the Python plotting library -Matplotlib. +Matplotlib.

    SEE ALSO

    - Temporal data processing
    - wxGUI
    + Temporal data processing, + wxGUI, wxGUI components

    AUTHOR

    Anna Kratochvilova, -Czech Technical University in Prague, Czech Republic +Czech Technical University in Prague, Czech Republic diff --git a/gui/wxpython/timeline/g.gui.timeline.py b/gui/wxpython/timeline/g.gui.timeline.py index 161c6832a92..3265636a3b0 100755 --- a/gui/wxpython/timeline/g.gui.timeline.py +++ b/gui/wxpython/timeline/g.gui.timeline.py @@ -50,7 +50,7 @@ def main(): from timeline.frame import TimelineFrame except ImportError as e: # TODO: why do we need this special check here, the reason of error - # is wrong intallation or something, no need to report this to the + # is wrong installation or something, no need to report this to the # user in a nice way gs.fatal(str(e)) diff --git a/gui/wxpython/tools/update_menudata.py b/gui/wxpython/tools/update_menudata.py index 2f548da3087..08897e6147d 100644 --- a/gui/wxpython/tools/update_menudata.py +++ b/gui/wxpython/tools/update_menudata.py @@ -136,10 +136,7 @@ def main(argv=None): if argv is None: argv = sys.argv - if len(argv) > 1 and argv[1] == "-d": - printDiff = True - else: - printDiff = False + printDiff = bool(len(argv) > 1 and argv[1] == "-d") if len(argv) > 1 and argv[1] == "-h": print(sys.stderr, __doc__, file=sys.stderr) diff --git a/gui/wxpython/tplot/frame.py b/gui/wxpython/tplot/frame.py index dc8eb5f6b0c..71705cc0160 100755 --- a/gui/wxpython/tplot/frame.py +++ b/gui/wxpython/tplot/frame.py @@ -212,7 +212,7 @@ def _layout(self): self.coorval = gselect.CoordinatesSelect( parent=self.controlPanelRaster, giface=self._giface ) - except Exception: + except NotImplementedError: self.coorval = TextCtrl( parent=self.controlPanelRaster, id=wx.ID_ANY, @@ -281,7 +281,7 @@ def _layout(self): self.cats = gselect.VectorCategorySelect( parent=self.controlPanelVector, giface=self._giface ) - except Exception: + except NotImplementedError: self.cats = TextCtrl( parent=self.controlPanelVector, id=wx.ID_ANY, @@ -756,10 +756,7 @@ def _writeCSV(self, x, y): """Used to write CSV file of plotted data""" import csv - if isinstance(y[0], list): - zipped = list(zip(x, *y)) - else: - zipped = list(zip(x, y)) + zipped = list(zip(x, *y)) if isinstance(y[0], list) else list(zip(x, y)) with open(self.csvpath, "w", newline="") as fi: writer = csv.writer(fi) if self.header: @@ -1032,10 +1029,10 @@ def OnRedraw(self, event=None): try: getcoors = self.coorval.coordsField.GetValue() - except Exception: + except AttributeError: try: getcoors = self.coorval.GetValue() - except Exception: + except AttributeError: getcoors = None if getcoors and getcoors != "": try: @@ -1178,7 +1175,7 @@ def _checkDatasets(self, datasets, typ): if len(indices) == 0: raise GException(errorMsg) - elif len(indices) >= 2: + if len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, message=_("Please specify the space time dataset <%s>.") % dataset, @@ -1260,7 +1257,7 @@ def SetDatasets( return try: self.coorval.coordsField.SetValue(",".join(coors)) - except Exception: + except AttributeError: self.coorval.SetValue(",".join(coors)) if self.datasetsV: vdatas = ",".join(f"{x[0]}@{x[1]}" for x in self.datasetsV) @@ -1376,7 +1373,7 @@ class DataCursor: matplotlib artist when it is selected. - Source: http://stackoverflow.com/questions/4652439/ + Source: https://stackoverflow.com/questions/4652439/ is-there-a-matplotlib-equivalent-of-matlabs-datacursormode/4674445 """ @@ -1451,7 +1448,7 @@ def __call__(self, event): """Intended to be called through "mpl_connect".""" # Rather than trying to interpolate, just display the clicked coords # This will only be called if it's within "tolerance", anyway. - x, y = event.mouseevent.xdata, event.mouseevent.ydata + x = event.mouseevent.xdata annotation = self.annotations[event.artist.axes] if x is not None: if not self.display_all: @@ -1463,7 +1460,7 @@ def __call__(self, event): for a in event.artist.get_xdata(): try: d = self.convert(a) - except Exception: + except (IndexError, ValueError): d = a xData.append(d) x = xData[np.argmin(abs(xData - x))] diff --git a/gui/wxpython/tplot/g.gui.tplot.html b/gui/wxpython/tplot/g.gui.tplot.html index 3d5a20e504f..10ddafa6245 100644 --- a/gui/wxpython/tplot/g.gui.tplot.html +++ b/gui/wxpython/tplot/g.gui.tplot.html @@ -20,7 +20,7 @@

    DESCRIPTION

  • add title to the plot, and
  • export the time series values to a CSV file (x axis data has date time string format, if you want to use for calculating simple regression model in the - R environment, + R environment, LibreOffice etc., you will obtain a different calculated formula
    y = a + b*x
    because these software packages use a reference date other than @@ -60,13 +60,13 @@

    DESCRIPTION

    NOTES

    g.gui.tplot requires the Python plotting library -Matplotlib. +Matplotlib.

    SEE ALSO

    - Temporal data processing
    - wxGUI
    + Temporal data processing, + wxGUI, wxGUI components
    diff --git a/gui/wxpython/vdigit/dialogs.py b/gui/wxpython/vdigit/dialogs.py index 9169d93faa0..3cfc8b8cbe4 100644 --- a/gui/wxpython/vdigit/dialogs.py +++ b/gui/wxpython/vdigit/dialogs.py @@ -387,7 +387,7 @@ def OnReload(self, event): # restore original list self.cats = copy.deepcopy(self.cats_orig) - # polulate list + # populate list self.itemDataMap = self.list.Populate(self.cats[self.fid], update=True) event.Skip() @@ -431,10 +431,7 @@ def ApplyChanges(self, fid): if layer not in catsCurr[1].keys() or cat not in catsCurr[1][layer]: catList.append(cat) if catList != []: - if action == "catadd": - add = True - else: - add = False + add = action == "catadd" newfid = self.digit.SetLineCats(fid, layer, catList, add) if len(self.cats.keys()) == 1: @@ -532,7 +529,7 @@ def UpdateDialog(self, query=None, cats=None): # make copy of cats (used for 'reload') self.cats_orig = copy.deepcopy(self.cats) - # polulate list + # populate list self.fid = list(self.cats.keys())[0] self.itemDataMap = self.list.Populate(self.cats[self.fid], update=True) diff --git a/gui/wxpython/vdigit/g.gui.vdigit.html b/gui/wxpython/vdigit/g.gui.vdigit.html index 7b0c7165063..d02064b997f 100644 --- a/gui/wxpython/vdigit/g.gui.vdigit.html +++ b/gui/wxpython/vdigit/g.gui.vdigit.html @@ -159,57 +159,57 @@

    DIGITIZER TOOLBAR

    • Break selected lines/boundaries at intersection
      Split - given vector line or boundary into two lines on given position - (based on v.clean, - tool=break).
    • + given vector line or boundary into two lines on given position + (based on v.clean, + tool=break).
    • Connect two selected lines/boundaries
      Connect selected - lines or boundaries, the first given line is connected to the - second one. The second line is broken if necessary on each intersection. - The lines are connected only if distance between them is not greater - than snapping threshold value.
    • + lines or boundaries, the first given line is connected to the + second one. The second line is broken if necessary on each intersection. + The lines are connected only if distance between them is not greater + than snapping threshold value.
    • Copy categories
      Copy category settings of - selected vector feature to other vector - features. Layer/category pairs of source vector features are - appended to the target feature category settings. Existing - layer/category pairs are not removed from category settings of - the target features.
    • + selected vector feature to other vector + features. Layer/category pairs of source vector features are + appended to the target feature category settings. Existing + layer/category pairs are not removed from category settings of + the target features.
    • Copy features from (background) vector map
      Make identical copy of - selected vector features. If a background vector map has been - selected from the Layer Manager, copy features from background - vector map, not from the currently modified vector map.
    • + selected vector features. If a background vector map has been + selected from the Layer Manager, copy features from background + vector map, not from the currently modified vector map.
    • Copy attributes
      Duplicate attributes settings of - selected vector feature to other vector features. New - category(ies) is appended to the target feature category - settings and attributes duplicated based on category settings - of source vector features. Existing layer/category pairs are - not removed from category settings of the target - features.
    • + selected vector feature to other vector features. New + category(ies) is appended to the target feature category + settings and attributes duplicated based on category settings + of source vector features. Existing layer/category pairs are + not removed from category settings of the target + features.
    • Feature type conversion
      Change feature type of selected - geometry features. Points are converted to centroids, - centroids to points, lines to boundaries and boundaries to - lines.
    • + geometry features. Points are converted to centroids, + centroids to points, lines to boundaries and boundaries to + lines.
    • Flip selected lines/boundaries
      Flip direction of - selected linear features (lines or boundaries).
    • + selected linear features (lines or boundaries).
    • Merge selected lines/boundaries
      Merge (at least two) - selected vector lines or boundaries. The geometry of the - merged vector lines can be changed. If the second line from - two selected lines is in opposite direction to the first, it - will be flipped. See also - module v.build.polylines.
    • + selected vector lines or boundaries. The geometry of the + merged vector lines can be changed. If the second line from + two selected lines is in opposite direction to the first, it + will be flipped. See also + module v.build.polylines.
    • Snap selected lines/boundaries (only to nodes)
      Snap - vector features in given threshold. See also - module v.clean. Note that - this tool supports only snapping to nodes. Snapping to vector - features from background vector map is not currently - supported.
    • + vector features in given threshold. See also + module v.clean. Note that + this tool supports only snapping to nodes. Snapping to vector + features from background vector map is not currently + supported.
    • Split line/boundary
      Split selected line or boundary on given position.
    • @@ -218,7 +218,7 @@

      DIGITIZER TOOLBAR

      min/max length value (linear features or dangles).
    • Z-bulk labeling of 3D lines
      Assign z coordinate values to 3D - vector lines in bounding box. This is useful for labeling contour lines.
    • + vector lines in bounding box. This is useful for labeling contour lines.
    @@ -248,9 +248,9 @@

    DIGITIZER TOOLBAR

    NOTES

    Mouse button functions:
    -
    Left - select or deselect features
    -
    Control+Left - cancel action or undo vertex when digitizing lines
    -
    Right - confirm action
    +
    Left - select or deselect features
    +
    Control+Left - cancel action or undo vertex when digitizing lines
    +
    Right - confirm action

    @@ -288,8 +288,8 @@

    REFERENCES

    SEE ALSO

    -wxGUI
    -wxGUI components + wxGUI, + wxGUI components

    diff --git a/gui/wxpython/vdigit/g.gui.vdigit.py b/gui/wxpython/vdigit/g.gui.vdigit.py index be476a03ee1..c4b4f93ae7e 100644 --- a/gui/wxpython/vdigit/g.gui.vdigit.py +++ b/gui/wxpython/vdigit/g.gui.vdigit.py @@ -84,7 +84,7 @@ def __init__(self, parent, vectorMap): ) self._initShortcuts() - # this giface issue not solved yet, we must set mapframe aferwards + # this giface issue not solved yet, we must set mapframe afterwards self._giface._mapframe = self # load vector map mapLayer = self.GetMap().AddLayer( diff --git a/gui/wxpython/vdigit/mapwindow.py b/gui/wxpython/vdigit/mapwindow.py index fed246d8d61..89ee1e84dbe 100644 --- a/gui/wxpython/vdigit/mapwindow.py +++ b/gui/wxpython/vdigit/mapwindow.py @@ -294,7 +294,7 @@ def OnLeftDownAddLine(self, event): return if self.toolbar.GetAction("type") in {"point", "centroid"}: - # add new point / centroiud + # add new point / centroid east, north = self.Pixel2Cell(self.mouse["begin"]) nfeat, fids = self.digit.AddFeature( self.toolbar.GetAction("type"), [(east, north)] @@ -834,10 +834,7 @@ def OnLeftUpVarious(self, event): self.digit.GetDisplay().SelectAreaByPoint(pos1)["area"] != -1 ) else: - if action == "moveLine": - drawSeg = True - else: - drawSeg = False + drawSeg = action == "moveLine" nselected = self.digit.GetDisplay().SelectLinesByBox( bbox=(pos1, pos2), drawSeg=drawSeg @@ -1103,10 +1100,7 @@ def _onRightUp(self, event): GError(parent=self, message=_("No vector map selected for editing.")) if mapName: - if self.toolbar.GetAction("type") == "line": - line = True - else: - line = False + line = self.toolbar.GetAction("type") == "line" if len(self.polycoords) < 2: # ignore 'one-point' lines return diff --git a/gui/wxpython/vdigit/preferences.py b/gui/wxpython/vdigit/preferences.py index aae5e993a32..2e3a0d745aa 100644 --- a/gui/wxpython/vdigit/preferences.py +++ b/gui/wxpython/vdigit/preferences.py @@ -622,10 +622,7 @@ def _createAttributesPage(self, notebook): layer = UserSettings.Get(group="vdigit", key="layer", subkey="value") mapLayer = self.parent.toolbars["vdigit"].GetLayer() tree = self.parent.tree - if tree: - item = tree.FindItemByData("maplayer", mapLayer) - else: - item = None + item = tree.FindItemByData("maplayer", mapLayer) if tree else None row = 0 for attrb in ["length", "area", "perimeter"]: # checkbox @@ -664,10 +661,7 @@ def _createAttributesPage(self, notebook): column.SetStringSelection( tree.GetLayerInfo(item, key="vdigit")["geomAttr"][attrb]["column"] ) - if attrb == "area": - type = "area" - else: - type = "length" + type = "area" if attrb == "area" else "length" unitsIdx = Units.GetUnitsIndex( type, tree.GetLayerInfo(item, key="vdigit")["geomAttr"][attrb]["units"], @@ -987,10 +981,7 @@ def UpdateSettings(self): # geometry attributes (workspace) mapLayer = self.parent.toolbars["vdigit"].GetLayer() tree = self._giface.GetLayerTree() - if tree: - item = tree.FindItemByData("maplayer", mapLayer) - else: - item = None + item = tree.FindItemByData("maplayer", mapLayer) if tree else None for key, val in self.geomAttrb.items(): checked = self.FindWindowById(val["check"]).IsChecked() column = self.FindWindowById(val["column"]).GetValue() @@ -999,11 +990,8 @@ def UpdateSettings(self): tree.SetLayerInfo(item, key="vdigit", value={"geomAttr": {}}) if checked: # enable - if key == "area": - type = key - else: - type = "length" - unitsKey = Units.GetUnitsKey(type, unitsIdx) + type_ = key if key == "area" else "length" + unitsKey = Units.GetUnitsKey(type_, unitsIdx) tree.GetLayerInfo(item, key="vdigit")["geomAttr"][key] = { "column": column, "units": unitsKey, diff --git a/gui/wxpython/vdigit/toolbars.py b/gui/wxpython/vdigit/toolbars.py index 6c5c8b21212..73bca461227 100644 --- a/gui/wxpython/vdigit/toolbars.py +++ b/gui/wxpython/vdigit/toolbars.py @@ -446,7 +446,7 @@ def _noVMapOpenForEditingErrDlg(self): return True def OnTool(self, event): - """Tool selected -> untoggles previusly selected tool in + """Tool selected -> untoggles previously selected tool in toolbar""" Debug.msg( 3, @@ -478,7 +478,7 @@ def OnTool(self, event): event.Skip() def OnAddPoint(self, event): - """Add point to the vector map Laier""" + """Add point to the vector map layer""" Debug.msg(2, "VDigitToolbar.OnAddPoint()") self.action = {"desc": "addLine", "type": "point", "id": self.addPoint} self.MapWindow.mouse["box"] = "point" @@ -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): @@ -1291,10 +1293,7 @@ def UpdateListOfLayers(self, updateTool=False): layerNameList.append(layer.GetName()) if updateTool: # update toolbar - if not self.mapLayer: - value = _("Select vector map") - else: - value = layerNameSelected + value = _("Select vector map") if not self.mapLayer else layerNameSelected if not self.comboid: if not self.tools or "selector" in self.tools: diff --git a/gui/wxpython/vdigit/wxdigit.py b/gui/wxpython/vdigit/wxdigit.py index eda912284a0..c1f777ec647 100644 --- a/gui/wxpython/vdigit/wxdigit.py +++ b/gui/wxpython/vdigit/wxdigit.py @@ -667,7 +667,7 @@ def _getLineAreaBboxCats(self, ln_id): ltype = Vect_read_line(self.poMapInfo, None, None, ln_id) if ltype == GV_CENTROID: - # TODO centroid opttimization, can be edited also its area -> it + # TODO centroid optimization, can be edited also its area -> it # will appear two times in new_ lists return self._getCentroidAreaBboxCats(ln_id) return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)] @@ -1896,10 +1896,7 @@ def _addFeature(self, ftype, coords, layer, cat, snap, threshold): modeSnap, ) - if ftype == GV_AREA: - ltype = GV_BOUNDARY - else: - ltype = ftype + ltype = GV_BOUNDARY if ftype == GV_AREA else ftype newline = Vect_write_line(self.poMapInfo, ltype, self.poPoints, self.poCats) if newline < 0: self._error.WriteLine() diff --git a/gui/wxpython/vdigit/wxdisplay.py b/gui/wxpython/vdigit/wxdisplay.py index d8e4d0a14bf..39662afb19f 100644 --- a/gui/wxpython/vdigit/wxdisplay.py +++ b/gui/wxpython/vdigit/wxdisplay.py @@ -982,15 +982,9 @@ def OpenMap(self, name, mapset, update=True, tmp=False): # open existing map if update: - if tmp: - open_fn = Vect_open_tmp_update - else: - open_fn = Vect_open_update - else: # noqa: PLR5501 - if tmp: - open_fn = Vect_open_tmp_old - else: - open_fn = Vect_open_old + open_fn = Vect_open_tmp_update if tmp else Vect_open_update + else: + open_fn = Vect_open_tmp_old if tmp else Vect_open_old ret = open_fn(self.poMapInfo, name, mapset) diff --git a/gui/wxpython/vnet/dialogs.py b/gui/wxpython/vnet/dialogs.py index 39cf2e4ae84..2979429a572 100644 --- a/gui/wxpython/vnet/dialogs.py +++ b/gui/wxpython/vnet/dialogs.py @@ -458,7 +458,7 @@ def _createParametersPage(self): # , 'turn_layer', 'turn_cat_layer']: for sel in ["input", "arc_layer", "node_layer"]: - if sel == "input": + if sel == "input": # noqa: SIM108 btn = self.addToTreeBtn # elif sel == "turn_layer": # btn = self.createTtbBtn @@ -647,11 +647,11 @@ def _updateInputDbMgrData(self): if inpLayer in browseLayers: needLayers.append(inpLayer) continue - else: - wx.BeginBusyCursor() - self.inpDbMgrData["browse"].AddLayer(inpLayer) - wx.EndBusyCursor() - needLayers.append(inpLayer) + + wx.BeginBusyCursor() + self.inpDbMgrData["browse"].AddLayer(inpLayer) + wx.EndBusyCursor() + needLayers.append(inpLayer) for layer in browseLayers: if layer not in needLayers: @@ -843,10 +843,7 @@ def _setInputData(self): def _parseMapStr(self, vectMapStr): """Create full map name (add current mapset if it is not present in name)""" mapValSpl = vectMapStr.strip().split("@") - if len(mapValSpl) > 1: - mapSet = mapValSpl[1] - else: - mapSet = grass.gisenv()["MAPSET"] + mapSet = mapValSpl[1] if len(mapValSpl) > 1 else grass.gisenv()["MAPSET"] mapName = mapValSpl[0] return mapName, mapSet @@ -1015,10 +1012,7 @@ def OnAnalysisChanged(self, event): attrCols = an_props["cmdParams"]["cols"] for col in attrCols.keys(): - if "inputField" in attrCols[col]: - colInptF = attrCols[col]["inputField"] - else: - colInptF = col + colInptF = attrCols[col].get("inputField", col) if col in skip: continue @@ -1245,8 +1239,6 @@ def __init__( wx.Dialog.__init__(self, parent, id, title, pos, size, style) self.vnet_mgr = vnet_mgr - - maxValue = 1e8 self.parent = parent self.settings = {} @@ -1985,7 +1977,6 @@ def GetSelectedIndices(self, state=wx.LIST_STATE_SELECTED): index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) if index == -1: break - else: - lastFound = index - indices.append(index) + lastFound = index + indices.append(index) return indices diff --git a/gui/wxpython/vnet/toolbars.py b/gui/wxpython/vnet/toolbars.py index 5f80e50cd9d..d31313091fe 100644 --- a/gui/wxpython/vnet/toolbars.py +++ b/gui/wxpython/vnet/toolbars.py @@ -235,6 +235,5 @@ def __init__(self, parent, vnet_mgr): self.Realize() def _toolbarData(self): - icons = {} return self._getToolbarData(()) diff --git a/gui/wxpython/vnet/vnet_core.py b/gui/wxpython/vnet/vnet_core.py index 8dda73b6770..b0ec072b2af 100644 --- a/gui/wxpython/vnet/vnet_core.py +++ b/gui/wxpython/vnet/vnet_core.py @@ -459,11 +459,6 @@ def _vnetPathRunAn(self, analysis, output, params, flags, catPts): return False mapName, mapSet = ParseMapStr(self.tmpTurnAn.GetVectMapName()) - cmdCopy = [ - "g.copy", - "vector=%s,%s" % (params["input"], mapName), - "--overwrite", - ] cmdParams.append("input=" + self.tmpTurnAn.GetVectMapName()) ret, msg, err = RunCommand( @@ -550,11 +545,6 @@ def _runTurnsAn(self, analysis, output, params, flags, catPts): # create and run commands which goes to analysis thread mapName, mapSet = ParseMapStr(self.tmpTurnAn.GetVectMapName()) - cmdCopy = [ - "g.copy", - "vector=%s,%s" % (params["input"], mapName), - "--overwrite", - ] cmdParams.append("input=" + self.tmpTurnAn.GetVectMapName()) ret, msg, err = RunCommand( @@ -580,14 +570,6 @@ def _updateTtbByGlobalCosts(self, vectMapName, tlayer): # TODO get layer number do not use it directly intervals = self.turnsData["global"].GetData() - cmdUpdGlob = [ - "v.db.update", - "map=", - self.inputData["input"].GetValue(), - "layer=%d" % tlayer, - "column=cost", - ] - dbInfo = VectorDBInfo(vectMapName) table = dbInfo.GetTable(tlayer) driver, database = dbInfo.GetDbSettings(tlayer) @@ -762,10 +744,7 @@ def _setInputParams(self, analysis, params, flags): inParams = [] for col, v in self.data.GetAnalysisProperties()["cmdParams"]["cols"].items(): - if "inputField" in v: - colInptF = v["inputField"] - else: - colInptF = col + colInptF = v.get("inputField", col) inParams.append(col + "=" + params[colInptF]) @@ -1021,7 +1000,7 @@ def NewTmpVectMapToHist(self, prefMapName): def AddTmpMapAnalysisMsg(mapName, tmp_maps): # TODO - """Wraped AddTmpVectMap""" + """Wraps AddTmpVectMap""" msg = _( "Temporary map %s already exists.\n" + "Do you want to continue in analysis and overwrite it?" diff --git a/gui/wxpython/vnet/vnet_data.py b/gui/wxpython/vnet/vnet_data.py index 3adc5fa64e9..47ffdb9a371 100644 --- a/gui/wxpython/vnet/vnet_data.py +++ b/gui/wxpython/vnet/vnet_data.py @@ -355,10 +355,8 @@ def SetPointStatus(self, item, itemIndex): item.hide = False elif len(cats) > 1: idx = self.data[itemIndex][1] - if idx == 2: # End/To/Sink point - wxPen = "used2cat" - else: - wxPen = "used1cat" + # End/To/Sink point + wxPen = "used2cat" if idx == 2 else "used1cat" else: wxPen = "used1cat" @@ -841,10 +839,7 @@ def GetRelevantParams(self, analysis): cols = self.vnetProperties[analysis]["cmdParams"]["cols"] for col, v in cols.items(): - if "inputField" in col: - colInptF = v["inputField"] - else: - colInptF = col + colInptF = v["inputField"] if "inputField" in col else col relevant_params.append(colInptF) return relevant_params @@ -900,10 +895,7 @@ def HasTmpVectMap(self, vectMapName): """ mapValSpl = vectMapName.strip().split("@") - if len(mapValSpl) > 1: - mapSet = mapValSpl[1] - else: - mapSet = grass.gisenv()["MAPSET"] + mapSet = mapValSpl[1] if len(mapValSpl) > 1 else grass.gisenv()["MAPSET"] mapName = mapValSpl[0] fullName = mapName + "@" + mapSet @@ -1195,9 +1187,8 @@ def _savePreviousHist(self, newHist, oldHist): if newHistStepsNum >= self.maxHistSteps: removedHistStep = removedHistData[line] = {} continue - else: - newHist.write("%s%s%s" % ("\n", line, "\n")) - self.histStepsNum = newHistStepsNum + newHist.write("%s%s%s" % ("\n", line, "\n")) + self.histStepsNum = newHistStepsNum elif newHistStepsNum >= self.maxHistSteps: self._parseLine(line, removedHistStep) else: @@ -1297,10 +1288,10 @@ def _getHistStepData(self, histStep): for line in hist: if not line.strip() and isSearchedHistStep: break - elif not line.strip(): + if not line.strip(): newHistStep = True continue - elif isSearchedHistStep: + if isSearchedHistStep: self._parseLine(line, histStepData) if newHistStep: @@ -1324,10 +1315,7 @@ def _parseLine(self, line, histStepData): del kv[0] idx = 0 while idx < len(kv): - if subkeyMaster: - subkey = [subkeyMaster, kv[idx]] - else: - subkey = kv[idx] + subkey = [subkeyMaster, kv[idx]] if subkeyMaster else kv[idx] value = kv[idx + 1] value = self._parseValue(value, read=True) if key not in histStepData: @@ -1376,8 +1364,8 @@ def SetValue(self, value, line, col): self.turn_data[line][col] = value def SetUTurns(self, value): - """Checked if checeBox is checed""" - useUTurns = value + """Checked if checkBox is checked""" + self.useUTurns = value def AppendRow(self, values): self.turn_data.append(values) @@ -1444,21 +1432,14 @@ def DataValidator(self, row, col, value): self.turn_data[i_row][1] = new_to_angle for i_row in inside_new: - if col == 1: - angle = new_from_angle - else: - angle = new_to_angle + angle = new_from_angle if col == 1 else new_to_angle self.turn_data[i_row][1] = angle self.turn_data[i_row][2] = angle def RemoveDataValidator(self, row): """Angle recalculation due to direction remove""" - if row == 0: - prev_row = self.GetLinesCount() - 1 - else: - prev_row = row - 1 - + prev_row = self.GetLinesCount() - 1 if row == 0 else row - 1 remove_to_angle = self.turn_data[row][2] self.turn_data[prev_row][2] = remove_to_angle diff --git a/gui/wxpython/vnet/vnet_utils.py b/gui/wxpython/vnet/vnet_utils.py index f0a354691bc..7157ac8a20e 100644 --- a/gui/wxpython/vnet/vnet_utils.py +++ b/gui/wxpython/vnet/vnet_utils.py @@ -34,10 +34,7 @@ def ParseMapStr(mapStr): """Create full map name (add current mapset if it is not present in name)""" mapValSpl = mapStr.strip().split("@") - if len(mapValSpl) > 1: - mapSet = mapValSpl[1] - else: - mapSet = grass.gisenv()["MAPSET"] + mapSet = mapValSpl[1] if len(mapValSpl) > 1 else grass.gisenv()["MAPSET"] mapName = mapValSpl[0] return mapName, mapSet @@ -133,7 +130,6 @@ def GetNearestNodeCat(e, n, layer, tresh, vectMap): vectlib.Vect_select_lines_by_box(openedMap, byref(box), vectlib.GV_POINT, List) found = 0 - dcost = 0 Cats = POINTER(vectlib.line_cats) Cats = vectlib.Vect_new_cats_struct() diff --git a/gui/wxpython/vnet/widgets.py b/gui/wxpython/vnet/widgets.py index ed1f2aa514c..d997b9c2434 100644 --- a/gui/wxpython/vnet/widgets.py +++ b/gui/wxpython/vnet/widgets.py @@ -14,7 +14,7 @@ @author Original author Michael Barton @author Original version improved by Martin Landa -@author Rewritten by Markus Metz redesign georectfier -> GCP Manage +@author Rewritten by Markus Metz redesign georectifier -> GCP Manage @author Stepan Turek (Created PointsList from GCPList) (GSoC 2012, mentor: Martin Landa) """ @@ -217,7 +217,6 @@ def GetCellValue(self, key, colName): if colNum < 0: return None - iColEd = self.dataTypes["colEditable"] if self.selIdxs[key][colNum] != -1: return self.selIdxs[key][colNum] @@ -230,7 +229,6 @@ def GetCellSelIdx(self, key, colName): :return: -1 if column does not has values to choose """ colNum = self._getColumnNum(colName) - iColEd = self.dataTypes["colEditable"] return self.selIdxs[key][colNum] def EditCellIndex(self, index, colName, cellData): diff --git a/gui/wxpython/web_services/dialogs.py b/gui/wxpython/web_services/dialogs.py index e47400cae70..bed4f57c70b 100644 --- a/gui/wxpython/web_services/dialogs.py +++ b/gui/wxpython/web_services/dialogs.py @@ -178,7 +178,7 @@ def _doLayout(self): border=5, ) - # connectin settings + # connection settings settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.VERTICAL) serverSizer = wx.FlexGridSizer(cols=3, vgap=5, hgap=5) @@ -748,7 +748,7 @@ def LoadCapFiles(self, ws_cap_files, cmd): ) def _getServerConnFromCmd(self, cmd): - """Get url/server/passwod from cmd tuple""" + """Get url/server/password from cmd tuple""" conn = {"url": "", "username": "", "password": ""} for k in conn.keys(): diff --git a/gui/wxpython/web_services/widgets.py b/gui/wxpython/web_services/widgets.py index 473a8fb58a2..db057313831 100644 --- a/gui/wxpython/web_services/widgets.py +++ b/gui/wxpython/web_services/widgets.py @@ -1,7 +1,7 @@ """ @package web_services.widgets -@brief Widgets for web services (WMS, WMTS, NasaOnEarh) +@brief Widgets for web services (WMS, WMTS, NasaOnEarth) List of classes: - widgets::WSPanel @@ -60,15 +60,14 @@ ) import grass.script as gs +from grass.pydispatch.signal import Signal rinwms_path = os.path.join(os.getenv("GISBASE"), "etc", "r.in.wms") if rinwms_path not in sys.path: sys.path.append(rinwms_path) -from wms_base import WMSDriversInfo -from srs import Srs - -from grass.pydispatch.signal import Signal +from wms_base import WMSDriversInfo # noqa:E402 +from srs import Srs # noqa:E402 class WSPanel(wx.Panel): @@ -251,14 +250,14 @@ def _advancedSettsPage(self): ) labels = {} - self.l_odrder_list = None + self.l_order_list = None if "WMS" in self.ws: labels["l_order"] = StaticBox( parent=adv_setts_panel, id=wx.ID_ANY, label=_("Order of layers in raster"), ) - self.l_odrder_list = wx.ListBox( + self.l_order_list = wx.ListBox( adv_setts_panel, id=wx.ID_ANY, choices=[], @@ -351,7 +350,7 @@ def _advancedSettsPage(self): gridSizer = wx.GridBagSizer(hgap=3, vgap=3) gridSizer.Add( - self.l_odrder_list, + self.l_order_list, pos=(0, 0), span=(4, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, @@ -384,10 +383,7 @@ def _advancedSettsPage(self): continue if k in labels or k == "o": - if k != "o": - label = labels[k] - else: - label = param + label = labels[k] if k != "o" else param gridSizer.Add( label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0) @@ -430,8 +426,8 @@ def _advancedSettsPage(self): def OnUp(self, event): """Move selected layer up""" - if self.l_odrder_list.GetSelections(): - pos = self.l_odrder_list.GetSelection() + if self.l_order_list.GetSelections(): + pos = self.l_order_list.GetSelection() if pos: self.sel_layers.insert(pos - 1, self.sel_layers.pop(pos)) if pos > 0: @@ -441,8 +437,8 @@ def OnUp(self, event): def OnDown(self, event): """Move selected to down""" - if self.l_odrder_list.GetSelections(): - pos = self.l_odrder_list.GetSelection() + if self.l_order_list.GetSelections(): + pos = self.l_order_list.GetSelection() if pos != len(self.sel_layers) - 1: self.sel_layers.insert(pos + 1, self.sel_layers.pop(pos)) if pos < len(self.sel_layers) - 1: @@ -454,10 +450,7 @@ def _updateLayerOrderList(self, selected=None): """Update order in list.""" def getlayercaption(layer): - if layer["title"]: - cap = layer["title"] - else: - cap = layer["name"] + cap = layer["title"] or layer["name"] if layer["style"]: if layer["style"]["title"]: @@ -467,14 +460,14 @@ def getlayercaption(layer): return cap layer_capts = [getlayercaption(sel_layer) for sel_layer in self.sel_layers] - self.l_odrder_list.Set(layer_capts) - if self.l_odrder_list.IsEmpty(): + self.l_order_list.Set(layer_capts) + if self.l_order_list.IsEmpty(): self.enableButtons(False) else: self.enableButtons(True) if selected is not None: - self.l_odrder_list.SetSelection(selected) - self.l_odrder_list.EnsureVisible(selected) + self.l_order_list.SetSelection(selected) + self.l_order_list.EnsureVisible(selected) def OnTransparent(self, event): checked = event.IsChecked() @@ -756,7 +749,6 @@ def OnListSelChanged(self, event): self.projs_list = [] projs_list = [] - intersect_proj = [] first = True for curr in curr_sel_ls: layer_projs = curr["cap_intf_l"].GetLayerData("srs") @@ -847,7 +839,7 @@ def _getFormats(self, layer=None): """Get formats WMS has formats defined generally for whole cap. - In WMTS and NASA OnEarh formats are defined for layer. + In WMTS and NASA OnEarth formats are defined for layer. """ formats_label = [] if layer is None: @@ -926,7 +918,7 @@ def __init__(self, parent, web_service, style, pos=wx.DefaultPosition): def LoadData(self, cap=None): """Load data into list""" - # detete first all items + # delete first all items self.DeleteAllItems() if not cap: diff --git a/gui/wxpython/wxgui.py b/gui/wxpython/wxgui.py index 447821c6724..83fed965ecd 100644 --- a/gui/wxpython/wxgui.py +++ b/gui/wxpython/wxgui.py @@ -139,10 +139,7 @@ def process_opt(opts, args): printHelp() elif o in {"-w", "--workspace"}: - if a != "": - workspaceFile = str(a) - else: - workspaceFile = args.pop(0) + workspaceFile = str(a) if a != "" else args.pop(0) return workspaceFile @@ -164,7 +161,7 @@ def main(argv=None): app = GMApp(workspaceFile) # suppress wxPython logs - q = wx.LogNull() + q = wx.LogNull() # noqa: F841 set_raise_on_error(True) # register GUI PID diff --git a/gui/wxpython/wxplot/base.py b/gui/wxpython/wxplot/base.py index dacb8270691..057894c0250 100755 --- a/gui/wxpython/wxplot/base.py +++ b/gui/wxpython/wxplot/base.py @@ -1,7 +1,7 @@ """ @package wxplot.base -@brief Base classes for iinteractive plotting using PyPlot +@brief Base classes for interactive plotting using PyPlot Classes: - base::PlotIcons @@ -30,6 +30,7 @@ from gui_core.wrap import Menu import grass.script as gs +from grass.exceptions import CalledModuleError PlotIcons = { "draw": MetaIcon(img="show", label=_("Draw/re-draw plot")), @@ -204,7 +205,7 @@ def InitRasterOpts(self, rasterList, plottype): try: ret = gs.raster_info(r) - except Exception: + except CalledModuleError: continue # if r.info cannot parse map, skip it @@ -270,7 +271,7 @@ def InitRasterPairs(self, rasterList, plottype): ret0 = gs.raster_info(rpair[0]) ret1 = gs.raster_info(rpair[1]) - except Exception: + except (IndexError, CalledModuleError): continue # if r.info cannot parse map, skip it @@ -510,7 +511,6 @@ def OnMotion(self, event): def PlotOptionsMenu(self, event): """Popup menu for plot and text options""" - point = wx.GetMousePosition() popt = Menu() # Add items to the menu settext = wx.MenuItem(popt, wx.ID_ANY, _("Text settings")) @@ -608,7 +608,6 @@ def PlotOptions(self, event): def PrintMenu(self, event): """Print options and output menu""" - point = wx.GetMousePosition() printmenu = Menu() for title, handler in ( (_("Page setup"), self.OnPageSetup), diff --git a/gui/wxpython/wxplot/histogram.py b/gui/wxpython/wxplot/histogram.py index 8cae28a5c63..b65ebd03192 100644 --- a/gui/wxpython/wxplot/histogram.py +++ b/gui/wxpython/wxplot/histogram.py @@ -97,10 +97,7 @@ def OnCreateHist(self, event): create a list of cell value and count/percent/area pairs. This is passed to plot to create a line graph of the histogram. """ - try: - self.SetCursor(StockCursor(wx.CURSOR_ARROW)) - except Exception: - pass + self.SetCursor(StockCursor(wx.CURSOR_ARROW)) self.SetGraphStyle() wx.BeginBusyCursor() diff --git a/gui/wxpython/wxplot/profile.py b/gui/wxpython/wxplot/profile.py index b4edf602e07..e0994f1a8a5 100644 --- a/gui/wxpython/wxplot/profile.py +++ b/gui/wxpython/wxplot/profile.py @@ -193,7 +193,7 @@ def SetupProfile(self): # title of window self.ptitle = _("Profile of") - # Initialize lattitude-longitude geodesic distance calculation + # Initialize latitude-longitude geodesic distance calculation if self._is_lat_lon_proj and haveCtypes: gislib.G_begin_distance_calculations() @@ -291,7 +291,6 @@ def CreateDatalist(self, raster, coords): # freezing with large, high resolution maps region = gs.region() curr_res = min(float(region["nsres"]), float(region["ewres"])) - transect_rec = 0 if self.transect_length / curr_res > 500: transect_res = self.transect_length / 500 else: @@ -486,7 +485,7 @@ def OnStats(self, event): statstr += "median: %f\n" % np.median(a) statstr += "distance along transect: %f\n\n" % self.transect_length message.append(statstr) - except Exception: + except (ValueError, TypeError, KeyError, IndexError): pass stats = PlotStatsFrame(self, id=wx.ID_ANY, message=message, title=title) diff --git a/gui/wxpython/wxplot/scatter.py b/gui/wxpython/wxplot/scatter.py index c57a3e1fac9..d87a03208e4 100644 --- a/gui/wxpython/wxplot/scatter.py +++ b/gui/wxpython/wxplot/scatter.py @@ -176,11 +176,7 @@ def CreateDatalist(self, rpair): frequency can be in cell counts, percents, or area """ datalist = [] - - if self.scattertype == "bubble": - freqflag = "cn" - else: - freqflag = "n" + freqflag = "cn" if self.scattertype == "bubble" else "n" try: ret = RunCommand( 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.aster.toar/i.aster.toar.html b/imagery/i.aster.toar/i.aster.toar.html index 7442ce91766..793d0834447 100644 --- a/imagery/i.aster.toar/i.aster.toar.html +++ b/imagery/i.aster.toar/i.aster.toar.html @@ -9,9 +9,9 @@

    DESCRIPTION

    The order of input bands is

      -
    • VNIR: 1,2,3N,3B -
    • SWIR: 4,5,6,7,8,9 -
    • TIR: 10,11,12,13,14 +
    • VNIR: 1,2,3N,3B
    • +
    • SWIR: 4,5,6,7,8,9
    • +
    • TIR: 10,11,12,13,14
    in one comma-separated list. diff --git a/imagery/i.atcorr/computations.cpp b/imagery/i.atcorr/computations.cpp index 53f8664ee06..6e5a38c5b07 100644 --- a/imagery/i.atcorr/computations.cpp +++ b/imagery/i.atcorr/computations.cpp @@ -102,14 +102,14 @@ double trunca() for (i = 0; i < 83; i++) { if (rmu[i] > 0.8) break; - k = i - 1; + k = i; } int kk = 0; for (i = 0; i < 83; i++) { if (rmu[i] > 0.94) break; - kk = i - 1; + kk = i; } double aa = @@ -118,7 +118,7 @@ double trunca() double x1 = (double)(log10(sixs_trunc.pha[kk])); double x2 = (double)acos(rmu[kk]); - for (i = kk + 1; i < 83; i++) { + for (i = kk; i < 83; i++) { double a; if (fabs(rmu[i] - 1) <= 1e-08) a = x1 - aa * x2; @@ -445,9 +445,14 @@ void os(const double tamoy, const double trmoy, const double pizmoy, /* compute position of the plane layer */ double taup = tap + trp; iplane = -1; - for (int i = 0; i <= ntp; i++) + for (int i = 0; i <= ntp; i++) { if (taup >= h[i]) iplane = i; + } + if (iplane == -1) { + G_fatal_error( + _("Position of the plane layer could not be determined")); + } /* update the layer from the end to the position to update if necessary */ @@ -1006,9 +1011,14 @@ void iso(const double tamoy, const double trmoy, const double pizmoy, /* compute position of the plane layer */ double taup = tap + trp; iplane = -1; - for (int i = 0; i <= ntp; i++) + for (int i = 0; i <= ntp; i++) { if (taup >= h[i]) iplane = i; + } + if (iplane == -1) { + G_fatal_error( + _("Position of the plane layer could not be determined")); + } /* update the layer from the end to the position to update if necessary */ diff --git a/imagery/i.atcorr/create_iwave.py b/imagery/i.atcorr/create_iwave.py index 21faa21ac2c..827b8be54c4 100644 --- a/imagery/i.atcorr/create_iwave.py +++ b/imagery/i.atcorr/create_iwave.py @@ -59,20 +59,15 @@ def read_input(csvfile): first column is wavelength values are those of the discrete band filter functions """ - infile = open(csvfile) + with open(csvfile) as infile: + # get number of bands and band names + bands = infile.readline().strip().split(",")[1:] - # get number of bands and band names - bands = infile.readline().split(",") - bands.remove(bands[0]) - bands[-1] = bands[-1].strip() - print(" > Number of bands found: %d" % len(bands)) - infile.close() + print(f" > Number of bands found: {len(bands)}") # create converter dictionary for import # fix nodata or \n - conv = {} - for b in range(len(bands)): - conv[b + 1] = lambda s: float(s or 0) + conv = {b + 1: lambda s: float(s or 0) for b in range(len(bands))} values = np.loadtxt(csvfile, delimiter=",", skiprows=1, converters=conv) @@ -87,10 +82,8 @@ def interpolate_band(values, step=2.5): and min, max wl values values must be numpy array with 2 columns """ - # removing nodata and invalid values - w = values[:, 1] >= 0 - values_clean = values[w] + values_clean = values[values[:, 1] >= 0] wavelengths = values_clean[:, 0] # 1st column of input array responses = values_clean[:, 1] # 2nd column @@ -184,25 +177,25 @@ def pretty_print(filter_f): Create pretty string out of filter function 8 values per line, with spaces, commas and all the rest """ - pstring = "" + pstring = [] for i in range(len(filter_f) + 1): if i % 8 == 0: if i != 0: value_wo_leading_zero = ("%.4f" % (filter_f[i - 1])).lstrip("0") - pstring += value_wo_leading_zero - if i > 1 and i < len(filter_f): - pstring += ", " - if i != 1: + pstring.append(value_wo_leading_zero) + if i > 1: + if i < len(filter_f): + pstring.append(", ") # trim the trailing whitespace at the end of line - pstring = pstring.rstrip() - pstring += "\n " + pstring[-1] = pstring[-1].rstrip() + pstring.append("\n ") else: value_wo_leading_zero = ("%.4f" % (filter_f[i - 1])).lstrip("0") - pstring += value_wo_leading_zero + pstring.append(value_wo_leading_zero) if i < len(filter_f): - pstring += ", " + pstring.append(", ") # trim starting \n and trailing , - return pstring.lstrip("\n").rstrip(", ") + return "".join(pstring).lstrip("\n").rstrip(", ") def write_cpp(bands, values, sensor, folder): @@ -212,6 +205,24 @@ def write_cpp(bands, values, sensor, folder): needs other functions: interpolate_bands, pretty_print """ + def get_min_wavelength(c, rthresh, fi): + """Get minimum wavelength rounded by threshold. + + :param fi: filter function + """ + while c > 0 and fi[c - 1] > rthresh: + c -= 1 + return np.ceil(li[0] * 1000 + (2.5 * c)) + + def get_max_wavelength(c, rthresh, fi): + """Get maximum wavelength rounded by threshold. + + :param fi: filter function + """ + while c < len(fi) - 1 and fi[c + 1] > rthresh: + c += 1 + return np.floor(li[0] * 1000 + (2.5 * c)) + # keep in sync with IWave::parse() rthresh = 0.01 print(" > Response peaks from interpolation to 2.5 nm steps:") @@ -225,17 +236,8 @@ def write_cpp(bands, values, sensor, folder): li = limits # Get wavelength range for spectral response in band maxresponse_idx = np.argmax(fi) - # Get minimum wavelength with spectral response - c = maxresponse_idx - while c > 0 and fi[c - 1] > rthresh: - c -= 1 - min_wavelength = np.ceil(li[0] * 1000 + (2.5 * c)) - # Get maximum wavelength with spectral response - c = maxresponse_idx - while c < len(fi) - 1 and fi[c + 1] > rthresh: - c += 1 - max_wavelength = np.floor(li[0] * 1000 + (2.5 * c)) - print(" %s (%inm - %inm)" % (bands[0], min_wavelength, max_wavelength)) + min_wavelength = get_min_wavelength(maxresponse_idx, rthresh, fi) + max_wavelength = get_max_wavelength(maxresponse_idx, rthresh, fi) else: filter_f = [] @@ -247,29 +249,17 @@ def write_cpp(bands, values, sensor, folder): # Get wavelength range for spectral response in band maxresponse_idx = np.argmax(fi) - # Get minimum wavelength with spectral response - c = maxresponse_idx - while c > 0 and fi[c - 1] > rthresh: - c -= 1 - min_wavelength = np.ceil(li[0] * 1000 + (2.5 * c)) - # Get maximum wavelength with spectral response - c = maxresponse_idx - while c < len(fi) - 1 and fi[c + 1] > rthresh: - c += 1 - max_wavelength = np.floor(li[0] * 1000 + (2.5 * c)) + min_wavelength = get_min_wavelength(maxresponse_idx, rthresh, fi) + max_wavelength = get_max_wavelength(maxresponse_idx, rthresh, fi) print(" %s (%inm - %inm)" % (bands[b], min_wavelength, max_wavelength)) # writing... outfile = open(os.path.join(folder, sensor + "_cpp_template.txt"), "w") outfile.write("/* Following filter function created using create_iwave.py */\n\n") - if len(bands) == 1: - outfile.write("void IWave::%s()\n{\n\n" % (sensor.lower())) - else: - outfile.write("void IWave::%s(int iwa)\n{\n\n" % (sensor.lower())) - # single band case if len(bands) == 1: + outfile.write("void IWave::%s()\n{\n\n" % (sensor.lower())) outfile.write(" /* %s of %s */\n" % (bands[0], sensor)) outfile.write(" static const float sr[%i] = {" % (len(filter_f))) filter_text = pretty_print(filter_f) @@ -295,6 +285,7 @@ def write_cpp(bands, values, sensor, folder): outfile.write("}\n") else: # more than 1 band + outfile.write("void IWave::%s(int iwa)\n{\n\n" % (sensor.lower())) # writing bands for b in range(len(bands)): outfile.write(" /* %s of %s */\n" % (bands[b], sensor)) @@ -305,9 +296,8 @@ def write_cpp(bands, values, sensor, folder): outfile.write(filter_text + "\n };\n\t\n") # writing band limits - for b in range(len(bands)): - inf = ", ".join(["%.4f" % i[0] for i in limits]) - sup = ", ".join(["%.4f" % i[1] for i in limits]) + inf = ", ".join(["%.4f" % i[0] for i in limits]) + sup = ", ".join(["%.4f" % i[1] for i in limits]) outfile.write(" static const float wli[%i] = {%s};\n" % (len(bands), inf)) outfile.write(" static const float wls[%i] = {%s};\n" % (len(bands), sup)) diff --git a/imagery/i.atcorr/i.atcorr.html b/imagery/i.atcorr/i.atcorr.html index 779ca7c7ef7..bf122963aba 100644 --- a/imagery/i.atcorr/i.atcorr.html +++ b/imagery/i.atcorr/i.atcorr.html @@ -837,14 +837,14 @@

    Atmospheric correction of a Sentinel-2 band

    particular scene and band. To create a 6S file, we need to obtain the following information:
      -
    • geometrical conditions, -
    • moth, day, decimal hours in GMT, decimal longitude and latitude of measurement, -
    • atmospheric model, -
    • aerosol model, -
    • visibility or aerosol optical depth, -
    • mean target elevation above sea level, -
    • sensor height and, -
    • sensor band. +
    • geometrical conditions,
    • +
    • moth, day, decimal hours in GMT, decimal longitude and latitude of measurement,
    • +
    • atmospheric model,
    • +
    • aerosol model,
    • +
    • visibility or aerosol optical depth,
    • +
    • mean target elevation above sea level,
    • +
    • sensor height and,
    • +
    • sensor band.
      @@ -944,17 +944,17 @@

      Atmospheric correction of a Sentinel-2 band

      B02 of our Sentinel 2 scene. We have to specify the following parameters:
        -
      • input = raster band to be processed, -
      • parameters = path to 6S file created in the previous step (we could also enter the values directly), -
      • output = name for the output corrected raster band, -
      • range = from 1 to the QUANTIFICATION_VALUE stored in the metadata file. It is 10000 for both Sentinel-2A and Sentinel-2B. -
      • rescale = the output range of values for the corrected bands. This is up to the user to choose, for example: 0-255, 0-1, 1-10000. +
      • input = raster band to be processed,
      • +
      • parameters = path to 6S file created in the previous step (we could also enter the values directly),
      • +
      • output = name for the output corrected raster band,
      • +
      • range = from 1 to the QUANTIFICATION_VALUE stored in the metadata file. It is 10000 for both Sentinel-2A and Sentinel-2B.
      • +
      • rescale = the output range of values for the corrected bands. This is up to the user to choose, for example: 0-255, 0-1, 1-10000.

      If the data is available, the following parameters can be specified as well:

        -
      • elevation = raster of digital elevation model, -
      • visibility = raster of visibility model. +
      • elevation = raster of digital elevation model,
      • +
      • visibility = raster of visibility model.

      Finally, this is how the command would look like to apply atmospheric @@ -987,7 +987,7 @@

      Atmospheric correction of a Landsat-7 band

      which has to be defined for the atmospheric correction. An option is to check the satellite overpass time with sun position as reported in the metadata -file (file copy; North Carolina +file (file copy; North Carolina sample dataset). In the case of the North Carolina sample dataset, these values have been stored for each channel and can be retrieved with: @@ -999,7 +999,7 @@

      Atmospheric correction of a Landsat-7 band

      If the sun position metadata are unavailable, we can also calculate them from the overpass time as follows (r.sunmask -uses SOLPOS): +uses SOLPOS):

       r.sunmask -s elev=elevation out=dummy year=2002 month=5 day=24 hour=10 min=42 sec=7 timezone=-5
      @@ -1115,20 +1115,20 @@ 

      REFERENCES

      • Vermote, E.F., Tanre, D., Deuze, J.L., Herman, M., and Morcrette, J.J., 1997, Second simulation of the satellite signal in the solar spectrum, 6S: An -overview., IEEE Trans. Geosc. and Remote Sens. 35(3):675-686. +overview., IEEE Trans. Geosc. and Remote Sens. 35(3):675-686.
      • 6S Manual: PDF1, PDF2, - and PDF3 -
      • RapidEye sensors have been provided by RapidEye AG, Germany + and PDF3
      • +
      • RapidEye sensors have been provided by RapidEye AG, Germany
      • Barsi, J.A., Markham, B.L. and Pedelty, J.A., 2011, The operational land imager: spectral response and spectral uniformity., Proc. SPIE 8153, -81530G; doi:10.1117/12.895438 +81530G; doi:10.1117/12.895438

      SEE ALSO

      diff --git a/imagery/i.biomass/i.biomass.html b/imagery/i.biomass/i.biomass.html index 21391bdb9bc..152ec3131aa 100644 --- a/imagery/i.biomass/i.biomass.html +++ b/imagery/i.biomass/i.biomass.html @@ -4,12 +4,12 @@

      DESCRIPTION

      Input:
        -
      • fPAR, the modified Photosynthetic Active Radiation for crops. -
      • Light Use Efficiency [0.0-1.0], in Uzbekistan cotton is at 1.9 most of the time. -
      • Latitude [0.0-90.0], from r.latlong. -
      • DOY [1-366]. -
      • Transmissivity of the atmosphere single-way [0.0-1.0], mostly around 0.7+ in clear sky. -
      • Water availability [0.0-1.0], possibly using direct output from i.eb.evapfr. +
      • fPAR, the modified Photosynthetic Active Radiation for crops.
      • +
      • Light Use Efficiency [0.0-1.0], in Uzbekistan cotton is at 1.9 most of the time.
      • +
      • Latitude [0.0-90.0], from r.latlong.
      • +
      • DOY [1-366].
      • +
      • Transmissivity of the atmosphere single-way [0.0-1.0], mostly around 0.7+ in clear sky.
      • +
      • Water availability [0.0-1.0], possibly using direct output from i.eb.evapfr.

      NOTES

      @@ -27,7 +27,7 @@

      REFERENCES

      [1] Bastiaanssen, W.G.M., Ali, S., 2002. A new crop yield forecasting model based on satellite measurements applied across the Indus Basin, Pakistan. Agriculture, Ecosystems and Environment, -94(3):321-340. (PDF) +94(3):321-340. (PDF)

      [2] Chemin, Y., Platonov, A., Abdullaev, I., Ul-Hassan, M. 2005. Supplementing farm level water productivity assessment by remote diff --git a/imagery/i.cluster/i.cluster.html b/imagery/i.cluster/i.cluster.html index 7ae2c73c2c3..e7cff674606 100644 --- a/imagery/i.cluster/i.cluster.html +++ b/imagery/i.cluster/i.cluster.html @@ -18,8 +18,8 @@

      DESCRIPTION

      -
      - +
      +
      @@ -207,7 +207,7 @@

      Parameters:


      Default: 17 - +
      reportfile=name
      The reportfile is an optional parameter which contains @@ -232,7 +232,7 @@

      Sampling method

      Algorithm used for i.cluster

      The algorithm uses input parameters set by the user on the diff --git a/imagery/i.eb.eta/i.eb.eta.html b/imagery/i.eb.eta/i.eb.eta.html index ff947cb1b43..0cfc9841801 100644 --- a/imagery/i.eb.eta/i.eb.eta.html +++ b/imagery/i.eb.eta/i.eb.eta.html @@ -9,10 +9,10 @@

      NOTES

      Full ETa processing will need those:
        -
      • i.vi, i.albedo, r.latlong, i.emissivity -
      • i.evapo.potrad (GRASS Addon) -
      • i.eb.netrad, i.eb.soilheatflux, i.eb.hsebal01 -
      • i.eb.evapfr, i.eb.eta +
      • i.vi, i.albedo, r.latlong, i.emissivity
      • +
      • i.evapo.potrad (GRASS Addon)
      • +
      • i.eb.netrad, i.eb.soilheatflux, i.eb.hsebal01
      • +
      • i.eb.evapfr, i.eb.eta
      (for time integration: i.evapo.time_integration) @@ -24,7 +24,7 @@

      REFERENCES

      [1] Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. -(PDF) +(PDF)

      [2] Chemin Y., Alexandridis T.A., 2001. Improving spatial resolution of ET seasonal for irrigated rice in Zhanghe, China. Asian Journal of Geoinformatics. @@ -33,12 +33,12 @@

      REFERENCES

      [3] Alexandridis T.K., Cherif I., Chemin Y., Silleos N.G., Stavrinos E., Zalidis G.C. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 2009, 1, 445-465. -(PDF) +(PDF)

      [4] Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

      SEE ALSO

      diff --git a/imagery/i.eb.evapfr/i.eb.evapfr.html b/imagery/i.eb.evapfr/i.eb.evapfr.html index 8d6354f36f9..9e745534728 100644 --- a/imagery/i.eb.evapfr/i.eb.evapfr.html +++ b/imagery/i.eb.evapfr/i.eb.evapfr.html @@ -18,7 +18,7 @@

      REFERENCES

      Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. -(PDF) +(PDF)

      Bastiaanssen, W.G.M., Molden, D.J., Makin, I.W., 2000. Remote sensing for irrigated agriculture: examples from research and @@ -32,12 +32,12 @@

      REFERENCES

      Zalidis G.C., 2009. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 1, 445-465. -(PDF) +(PDF)

      Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

      SEE ALSO

      diff --git a/imagery/i.eb.hsebal01/i.eb.hsebal01.html b/imagery/i.eb.hsebal01/i.eb.hsebal01.html index 4b6d3953e53..962c6273f67 100644 --- a/imagery/i.eb.hsebal01/i.eb.hsebal01.html +++ b/imagery/i.eb.hsebal01/i.eb.hsebal01.html @@ -8,10 +8,10 @@

      DESCRIPTION

      Full process will need those:
        -
      • i.vi, i.albedo, r.latlong, i.emissivity -
      • i.evapo.potrad (GRASS Addon) -
      • i.eb.netrad, i.eb.soilheatflux, i.eb.hsebal01 -
      • i.eb.evapfr, i.eb.eta +
      • i.vi, i.albedo, r.latlong, i.emissivity
      • +
      • i.evapo.potrad (GRASS Addon)
      • +
      • i.eb.netrad, i.eb.soilheatflux, i.eb.hsebal01
      • +
      • i.eb.evapfr, i.eb.eta
      (for time integration: i.evapo.time_integration) @@ -24,12 +24,12 @@

      DESCRIPTION

      NOTES

        -
      • z0m can be alculated by i.eb.z0m or i.eb.z0m0 (GRASS Addons). +
      • z0m can be alculated by i.eb.z0m or i.eb.z0m0 (GRASS Addons).
      • ea can be calculated with standard meteorological data.
        - eoTmin=0.6108*EXP(17.27*Tmin/(Tmin+237.3))
        - eoTmax=0.6108*EXP(17.27*Tmax/(Tmax+237.3))
        - ea=(RH/100)/((eoTmin+eoTmax)/2) -
      • t0dem = surface temperature + (altitude * 0.627 / 100) + eoTmin=0.6108*EXP(17.27*Tmin/(Tmin+237.3))
        + eoTmax=0.6108*EXP(17.27*Tmax/(Tmax+237.3))
        + ea=(RH/100)/((eoTmin+eoTmax)/2)
      • +
      • t0dem = surface temperature + (altitude * 0.627 / 100)

      REFERENCES

      @@ -37,7 +37,7 @@

      REFERENCES

      [1] Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. -(PDF) +(PDF)

      [2] Chemin Y., Alexandridis T.A., 2001. Improving spatial resolution of ET seasonal for irrigated rice in Zhanghe, China. Asian Journal of @@ -46,12 +46,12 @@

      REFERENCES

      [3] Alexandridis T.K., Cherif I., Chemin Y., Silleos N.G., Stavrinos E., Zalidis G.C. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 2009, 1, 445-465. -(PDF) +(PDF)

      [4] Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

      SEE ALSO

      diff --git a/imagery/i.eb.netrad/i.eb.netrad.html b/imagery/i.eb.netrad/i.eb.netrad.html index 306bb39c90d..c6cba3ad484 100644 --- a/imagery/i.eb.netrad/i.eb.netrad.html +++ b/imagery/i.eb.netrad/i.eb.netrad.html @@ -28,12 +28,12 @@

      REFERENCES

      densities and moisture indicators in composite terrain; a remote sensing approach under clear skies in mediterranean climates. PhD thesis, Wageningen Agricultural Univ., The Netherland, 271 pp. -(PDF) +(PDF)
    1. Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF)
    2. +(PDF)

      SEE ALSO

      diff --git a/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html b/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html index b948d827da2..ecf62af78e9 100644 --- a/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html +++ b/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html @@ -41,7 +41,7 @@

      REFERENCES

      Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. - (PDF) + (PDF)

      Chemin Y., Alexandridis T.A., 2001. Improving spatial resolution of ET seasonal for irrigated rice in Zhanghe, China. Asian Journal of Geoinformatics. 5(1):3-11,2004. @@ -49,12 +49,12 @@

      REFERENCES

      Alexandridis T.K., Cherif I., Chemin Y., Silleos N.G., Stavrinos E., Zalidis G.C. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 2009, 1, 445-465. -(PDF) +(PDF)

      Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

      SEE ALSO

      diff --git a/imagery/i.emissivity/i.emissivity.html b/imagery/i.emissivity/i.emissivity.html index 872ca4fddae..0b44b664442 100644 --- a/imagery/i.emissivity/i.emissivity.html +++ b/imagery/i.emissivity/i.emissivity.html @@ -21,7 +21,7 @@

      REFERENCES

    3. Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. - (PDF)
    4. + (PDF)
    5. Caselles, V., C. Coll, and E. Valor, 1997. Land surface emissivity and temperature determination in the whole HAPEX-Sahel area from AVHRR data. International Journal of Remote @@ -29,7 +29,7 @@

      REFERENCES

    6. Rubio, E., V. Caselles, and C. Badenas, 1997. Emissivity measurements of several soils and vegetation types in the 8-14 µm wave band: Analysis of two field methods. Remote Sensing of - Environment 59(3): 490-521. + Environment 59(3): 490-521.
    7. SEE ALSO

      diff --git a/imagery/i.evapo.pm/i.evapo.pm.html b/imagery/i.evapo.pm/i.evapo.pm.html index b9f5f66d8e9..efa25bfed44 100644 --- a/imagery/i.evapo.pm/i.evapo.pm.html +++ b/imagery/i.evapo.pm/i.evapo.pm.html @@ -18,9 +18,9 @@

      DESCRIPTION

      Land and water surfaces are idenfyied by Vh:

        -
      • where Vh gt 0 vegetation is present and evapotranspiration is calculated; -
      • where Vh = 0 bare ground is present and evapotranspiration is calculated; -
      • where Vh lt 0 water surface is present and evaporation is calculated. +
      • where Vh gt 0 vegetation is present and evapotranspiration is calculated;
      • +
      • where Vh = 0 bare ground is present and evapotranspiration is calculated;
      • +
      • where Vh lt 0 water surface is present and evaporation is calculated.

      For more details on the algorithms see [1,2,3]. @@ -46,7 +46,7 @@

      NOTES

      REFERENCES

      [1] Cannata M., 2006. - GIS embedded approach for Free & Open Source Hydrological Modelling. PhD thesis, Department of Geodesy and Geomatics, Polytechnic of Milan, Italy. + GIS embedded approach for Free & Open Source Hydrological Modelling. PhD thesis, Department of Geodesy and Geomatics, Polytechnic of Milan, Italy.

      [2] Allen, R.G., L.S. Pereira, D. Raes, and M. Smith. 1998. Crop Evapotranspiration: Guidelines for computing crop water requirements. @@ -73,9 +73,8 @@

      AUTHORS

      Original version of program: The HydroFOSS project, 2006, IST-SUPSI. (http://istgis.ist.supsi.ch:8001/geomatica/index.php?id=1) - -
      Massimiliano Cannata, Scuola Universitaria Professionale della Svizzera Italiana - Istituto Scienze della Terra -
      Maria A. Brovelli, Politecnico di Milano - Polo regionale di Como -
      +Massimiliano Cannata, Scuola Universitaria Professionale della Svizzera Italiana - Istituto Scienze della Terra +
      +Maria A. Brovelli, Politecnico di Milano - Polo regionale di Como

      Contact: Massimiliano Cannata diff --git a/imagery/i.evapo.pt/i.evapo.pt.html b/imagery/i.evapo.pt/i.evapo.pt.html index cd890e425ee..10887a5bb50 100644 --- a/imagery/i.evapo.pt/i.evapo.pt.html +++ b/imagery/i.evapo.pt/i.evapo.pt.html @@ -12,13 +12,13 @@

      NOTES

      Alpha values:

      • 1.32 for estimates from vegetated areas as a result of the increase in -surface roughness (Morton, 1983; Brutsaert and Stricker, 1979) +surface roughness (Morton, 1983; Brutsaert and Stricker, 1979)
      • 1.26 is applicable in humid climates (De Bruin and Keijman, 1979; Stewart and Rouse, 1976; Shuttleworth and Calder, 1979), and temperate -hardwood swamps (Munro, 1979) +hardwood swamps (Munro, 1979)
      • 1.74 has been recommended for estimating potential evapotranspiration in more arid regions (ASCE, 1990). This worked well in Greece with University -of Thessaloniki. +of Thessaloniki.
      Alpha values extracted from: diff --git a/imagery/i.evapo.time/i.evapo.time.html b/imagery/i.evapo.time/i.evapo.time.html index c0aa1bdac15..15b5bb17b34 100644 --- a/imagery/i.evapo.time/i.evapo.time.html +++ b/imagery/i.evapo.time/i.evapo.time.html @@ -5,17 +5,17 @@

      DESCRIPTION

      Inputs:
        -
      • ETa images -
      • ETa images DOY (Day of Year) -
      • ETo images -
      • ETo DOYmin as a single value +
      • ETa images
      • +
      • ETa images DOY (Day of Year)
      • +
      • ETo images
      • +
      • ETo DOYmin as a single value
      Method:
        -
      1. each ETa pixel is divided by the same day ETo and become ETrF -
      2. each ETrF pixel is multiplied by the ETo sum for the representative days -
      3. Sum all n temporal [ETrF*ETo_sum] pixels to make a summed(ET) in [DOYmin;DOYmax] +
      4. each ETa pixel is divided by the same day ETo and become ETrF
      5. +
      6. each ETrF pixel is multiplied by the ETo sum for the representative days
      7. +
      8. Sum all n temporal [ETrF*ETo_sum] pixels to make a summed(ET) in [DOYmin;DOYmax]
      representative days calculation: @@ -35,8 +35,8 @@

      NOTES

      n=0 for ETo_val in Eto[1] Eto[2] ... do - r.mapcalc "eto$n = $ETo_val" - `expr n = n + 1` + r.mapcalc "eto$n = $ETo_val" + `expr n = n + 1` done diff --git a/imagery/i.fft/i.fft.html b/imagery/i.fft/i.fft.html index abb7453af82..26782835c5c 100644 --- a/imagery/i.fft/i.fft.html +++ b/imagery/i.fft/i.fft.html @@ -40,12 +40,12 @@

      REFERENCES

      • M. Frigo and S. G. Johnson (1998): "FFTW: An Adaptive Software Architecture -for the FFT". See www.FFTW.org: FFTW is a C subroutine library +for the FFT". See www.FFTW.org: FFTW is a C subroutine library for computing the Discrete Fourier Transform (DFT) in one or more -dimensions, of both real and complex data, and of arbitrary input size. -
      • John A. Richards, 1986. Remote Sensing Digital Image Analysis, Springer-Verlag. +dimensions, of both real and complex data, and of arbitrary input size.
      • +
      • John A. Richards, 1986. Remote Sensing Digital Image Analysis, Springer-Verlag.
      • Personal communication, between program author and Ali R. Vali, -Space Research Center, University of Texas, Austin, 1990. +Space Research Center, University of Texas, Austin, 1990.

      SEE ALSO

      diff --git a/imagery/i.gensig/i.gensig.html b/imagery/i.gensig/i.gensig.html index 97db7777447..b878fc41f73 100644 --- a/imagery/i.gensig/i.gensig.html +++ b/imagery/i.gensig/i.gensig.html @@ -60,7 +60,7 @@

      Parameters

      image.

      -

      subgroup=name +
      subgroup=name
      subgroup containing image files

      @@ -108,13 +108,13 @@

      NOTES

        -
      • Line 1: version number (currently always 1) -
      • Line 2: text label -
      • Line 3: Space separated list of semantic labels -
      • Line 4: text label of class -
      • Line 5: number of points in class -
      • Line 6: mean values per band of the class -
      • Line 7-12: (semi)-matrix of band-band covariance +
      • Line 1: version number (currently always 1)
      • +
      • Line 2: text label
      • +
      • Line 3: Space separated list of semantic labels
      • +
      • Line 4: text label of class
      • +
      • Line 5: number of points in class
      • +
      • Line 6: mean values per band of the class
      • +
      • Line 7-12: (semi)-matrix of band-band covariance

      SEE ALSO

      diff --git a/imagery/i.gensig/testsuite/test_i_gensig.py b/imagery/i.gensig/testsuite/test_i_gensig.py index d75e3da2af4..836550fd1e6 100644 --- a/imagery/i.gensig/testsuite/test_i_gensig.py +++ b/imagery/i.gensig/testsuite/test_i_gensig.py @@ -92,9 +92,13 @@ def tearDownClass(cls): """Remove the temporary region and generated data""" cls.del_temp_region() shutil.rmtree(cls.sig_dir1, ignore_errors=True) - cls.runModule("g.remove", flags="f", type="raster", name=cls.b1, quiet=True) - cls.runModule("g.remove", flags="f", type="raster", name=cls.b2, quiet=True) - cls.runModule("g.remove", flags="f", type="raster", name=cls.train, quiet=True) + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=(cls.b1, cls.b2, cls.train), + quiet=True, + ) def test_creation(self): """Test creating a signature""" diff --git a/imagery/i.gensigset/i.gensigset.html b/imagery/i.gensigset/i.gensigset.html index 3c5c170dceb..5db3efa5802 100644 --- a/imagery/i.gensigset/i.gensigset.html +++ b/imagery/i.gensigset/i.gensigset.html @@ -206,13 +206,13 @@

      WARNINGS

      REFERENCES

      diff --git a/imagery/i.ifft/i.ifft.html b/imagery/i.ifft/i.ifft.html index 028f81f5895..eee7bc54e06 100644 --- a/imagery/i.ifft/i.ifft.html +++ b/imagery/i.ifft/i.ifft.html @@ -23,7 +23,7 @@

      REFERENCES

      • M. Frigo and S. G. Johnson (1998): "FFTW: An Adaptive Software -Architecture for the FFT". See www.fftw.org: +Architecture for the FFT". See www.fftw.org: FFTW is a C subroutine library for computing the Discrete Fourier Transform (DFT) in one or more dimensions, of both real and complex data, and of arbitrary input size.
      • diff --git a/imagery/i.landsat.toar/i.landsat.toar.html b/imagery/i.landsat.toar/i.landsat.toar.html index 821f7cb4cfe..4a792c26274 100644 --- a/imagery/i.landsat.toar/i.landsat.toar.html +++ b/imagery/i.landsat.toar/i.landsat.toar.html @@ -235,7 +235,7 @@

        DOS1 example

        Calculation of reflectance values from DN using DOS1 (metadata obtained -from p016r035_7x20020524.met.gz): +from p016r035_7x20020524.met.gz):
         i.landsat.toar input=lsat7_2002. output=lsat7_2002_toar. sensor=tm7 \
        diff --git a/imagery/i.maxlik/testsuite/test_i_maxlik.py b/imagery/i.maxlik/testsuite/test_i_maxlik.py
        index e7fbf6c1a79..2245d0d6d58 100644
        --- a/imagery/i.maxlik/testsuite/test_i_maxlik.py
        +++ b/imagery/i.maxlik/testsuite/test_i_maxlik.py
        @@ -163,13 +163,12 @@ def tearDownClass(cls):
                 cls.del_temp_region()
                 shutil.rmtree(cls.sig_dir1, ignore_errors=True)
                 shutil.rmtree(cls.sig_dir2, ignore_errors=True)
        -        cls.runModule("g.remove", flags="f", type="raster", name=cls.b1, quiet=True)
        -        cls.runModule("g.remove", flags="f", type="raster", name=cls.b2, quiet=True)
                 cls.runModule(
        -            "g.remove", flags="f", type="raster", name=cls.v1_class, quiet=True
        -        )
        -        cls.runModule(
        -            "g.remove", flags="f", type="raster", name=cls.v2_class, quiet=True
        +            "g.remove",
        +            flags="f",
        +            type="raster",
        +            name=(cls.b1, cls.b2, cls.v1_class, cls.v2_class),
        +            quiet=True,
                 )
                 cls.runModule("g.remove", flags="f", type="group", name=cls.group, quiet=True)
         
        diff --git a/imagery/i.modis.qc/i.modis.qc.html b/imagery/i.modis.qc/i.modis.qc.html
        index 64553966a27..3147a006bd1 100644
        --- a/imagery/i.modis.qc/i.modis.qc.html
        +++ b/imagery/i.modis.qc/i.modis.qc.html
        @@ -514,10 +514,10 @@ 

        TODO

        REFERENCES

          -
        • MODIS Products +
        • MODIS Products
        • Vermote E.F., Kotchenova S.Y., Ray J.P. MODIS Surface Reflectance User's Guide. Version 1.2. June 2008. MODIS Land Surface Reflectance Science Computing Facility. - Homepage + Homepage

        SEE ALSO

        diff --git a/imagery/i.ortho.photo/README b/imagery/i.ortho.photo/README index bc8313ce304..51260299d5b 100644 --- a/imagery/i.ortho.photo/README +++ b/imagery/i.ortho.photo/README @@ -49,7 +49,7 @@ Workflow description: Open Source GIS: A GRASS GIS Approach, Second Edition, 2004 by Markus Neteler and Helena Mitasova, Chapter 10 – PROCESSING OF AERIAL PHOTOS -http://grassbook.org/extra/sample-chapter/ +https://grassbook.org/extra/sample-chapter/ --> PDF ###################################################################### diff --git a/imagery/i.ortho.photo/i.ortho.camera/i.ortho.camera.html b/imagery/i.ortho.photo/i.ortho.camera/i.ortho.camera.html index 535ef8e03a7..3159e4812b2 100644 --- a/imagery/i.ortho.photo/i.ortho.camera/i.ortho.camera.html +++ b/imagery/i.ortho.photo/i.ortho.camera/i.ortho.camera.html @@ -24,12 +24,12 @@

        DESCRIPTION

         
        -	CAMERA NAME:               camera name______
        -	CAMERA IDENTIFICATION:     identification___
        -	CALIBRATED FOCAL LENGTH mm.:_________________
        -	POINT OF SYMMETRY (X)   mm.:_________________
        -	POINT OF SYMMETRY (Y)   mm.:_________________
        -	MAXIMUM NUMBER OF FIDUCIALS:_________________
        +    CAMERA NAME:               camera name______
        +    CAMERA IDENTIFICATION:     identification___
        +    CALIBRATED FOCAL LENGTH mm.:_________________
        +    POINT OF SYMMETRY (X)   mm.:_________________
        +    POINT OF SYMMETRY (Y)   mm.:_________________
        +    MAXIMUM NUMBER OF FIDUCIALS:_________________
         
            AFTER COMPLETING ALL ANSWERS, HIT <ESC> TO CONTINUE
                        (OR <Ctrl-C> TO CANCEL)
        @@ -73,20 +73,20 @@ 

        DESCRIPTION

        Please provide the following information

        -	Fid#	FID ID		  X          Y
        -
        -	1__	_____		0.0___	0.0___
        -	2__	_____		0.0___	0.0___
        -	3__	_____		0.0___	0.0___
        -	4__	_____		0.0___	0.0___
        -	5__	_____		0.0___	0.0___
        -	6__	_____		0.0___	0.0___
        -	7__	_____		0.0___	0.0___
        -	8__	_____		0.0___	0.0___
        -	9__	_____		0.0___	0.0___
        -	10_	_____		0.0___	0.0___
        -
        -		     next:  end__
        +    Fid#    FID ID          X          Y
        +
        +    1__    _____        0.0___    0.0___
        +    2__    _____        0.0___    0.0___
        +    3__    _____        0.0___    0.0___
        +    4__    _____        0.0___    0.0___
        +    5__    _____        0.0___    0.0___
        +    6__    _____        0.0___    0.0___
        +    7__    _____        0.0___    0.0___
        +    8__    _____        0.0___    0.0___
        +    9__    _____        0.0___    0.0___
        +    10_    _____        0.0___    0.0___
        +
        +             next:  end__
         
              AFTER COMPLETING ALL ANSWERS, HIT <ESC> TO CONTINUE
                             (OR <Ctrl-C> TO CANCEL)
        diff --git a/imagery/i.ortho.photo/i.ortho.init/i.ortho.init.html b/imagery/i.ortho.photo/i.ortho.init/i.ortho.init.html
        index 5da40c86344..a9e86ab2a0b 100644
        --- a/imagery/i.ortho.photo/i.ortho.init/i.ortho.init.html
        +++ b/imagery/i.ortho.photo/i.ortho.init/i.ortho.init.html
        @@ -19,9 +19,8 @@ 

        DESCRIPTION

        parameters. During the imagery program, i.photo.rectify, the initial camera exposure station file is used for computation of the ortho-rectification parameters. If no initial camera exposure station file exist, the default -values are computed from the control points file created in g.gui.image2target. - +values are computed from the control points file created in +g.gui.image2target.

        @@ -29,19 +28,19 @@

        DESCRIPTION

                 Please provide the following information
         
        -	INITIAL XC: Meters                __________
        -	INITIAL YC: Meters                __________
        -	INITIAL ZC: Meters                __________
        -	INITIAL omega (pitch) degrees:    __________
        -	INITIAL phi  (roll) degrees:      __________
        -	INITIAL kappa  (yaw) degrees:     __________
        +    INITIAL XC: Meters                __________
        +    INITIAL YC: Meters                __________
        +    INITIAL ZC: Meters                __________
        +    INITIAL omega (pitch) degrees:    __________
        +    INITIAL phi  (roll) degrees:      __________
        +    INITIAL kappa  (yaw) degrees:     __________
         
        -	Standard Deviation XC: Meters     __________
        -	Standard Deviation YC: Meters     __________
        -	Standard Deviation ZC: Meters     __________
        -	Std. Dev. omega (pitch) degrees:  __________
        -	Std. Dev. phi  (roll) degrees:    __________
        -	Std. Dev. kappa  (yaw) degrees:   __________
        +    Standard Deviation XC: Meters     __________
        +    Standard Deviation YC: Meters     __________
        +    Standard Deviation ZC: Meters     __________
        +    Std. Dev. omega (pitch) degrees:  __________
        +    Std. Dev. phi  (roll) degrees:    __________
        +    Std. Dev. kappa  (yaw) degrees:   __________
         
                 Use these values at run time? (1=yes, 0=no)
         
        @@ -55,9 +54,9 @@ 

        DESCRIPTION

        exposure.
          -
        • X: East aircraft position; -
        • Y: North aircraft position; -
        • Z: Flight altitude above sea level +
        • X: East aircraft position;
        • +
        • Y: North aircraft position;
        • +
        • Z: Flight altitude above sea level

        @@ -68,12 +67,12 @@

        DESCRIPTION

        • Omega (pitch): Raising or lowering of the aircraft's front (turning - around the wings' axis); + around the wings' axis);
        • Phi (roll): Raising or lowering of the wings (turning around the - aircraft's axis); + aircraft's axis);
        • Kappa (yaw): Rotation needed to align the aerial photo to true north: needs to be denoted as +90 degree for clockwise turn and -90 degree for - a counterclockwise turn. + a counterclockwise turn.

        diff --git a/imagery/i.ortho.photo/i.ortho.photo/i.ortho.photo.html b/imagery/i.ortho.photo/i.ortho.photo/i.ortho.photo.html index c7ce061b01d..4e64c5a2b5e 100644 --- a/imagery/i.ortho.photo/i.ortho.photo/i.ortho.photo.html +++ b/imagery/i.ortho.photo/i.ortho.photo/i.ortho.photo.html @@ -11,7 +11,7 @@

        DESCRIPTION

        • Initialization Options
            -
          1. Create/Modify imagery group to be orthorectified: +
          2. Create/Modify imagery group to be orthorectified: i.group
          3. Select/Modify target project (formerly known as location) and mapset for orthorectification: i.ortho.target
          4. @@ -23,7 +23,7 @@

            DESCRIPTION

          5. Transformation Parameters Computation
              -
            1. Compute image-to-photo transformation: +
            2. Compute image-to-photo transformation: g.gui.photo2image
            3. Initialize parameters of camera: i.ortho.init
            4. @@ -34,7 +34,7 @@

              DESCRIPTION

            5. Ortho-rectification
                -
              1. Ortho-rectify imagery group: +
              2. Ortho-rectify imagery group: i.ortho.rectify
            6. @@ -229,7 +229,7 @@

              EXAMPLE

            7. Y: North aircraft position;
            8. Z: Flight height above surface;
            9. Omega (pitch): Raising or lowering of the aircraft's front - (turning around the wings' axis);
            10. + (turning around the wings' axis);
            11. Phi (roll): Raising or lowering of the wings (turning around the aircraft's axis);
            12. Kappa (yaw): Rotation needed to align the aerial photo to diff --git a/imagery/i.ortho.photo/i.ortho.rectify/i.ortho.rectify.html b/imagery/i.ortho.photo/i.ortho.rectify/i.ortho.rectify.html index 96a649d8b8e..607e53f70bc 100644 --- a/imagery/i.ortho.photo/i.ortho.rectify/i.ortho.rectify.html +++ b/imagery/i.ortho.photo/i.ortho.rectify/i.ortho.rectify.html @@ -1,4 +1,4 @@ -

              DESCRIPTION

              +

              DESCRIPTION

              i.photo.rectify rectifies an image by using the image to photo coordinate transformation matrix created by g.gui.photo2image @@ -44,7 +44,7 @@

              DESCRIPTION

              i.ortho.photo, an interactive terminal is used to determine the options. -

              Interactive mode

              +

              Interactive mode

              You are first asked if all images within the imagery group should be rectified. If this option is not chosen, you are asked to specify for each image within the imagery group whether it should be rectified or not. @@ -89,19 +89,19 @@

              Interactive mode

              The last prompt will ask you about the amount of memory to be used by i.photo.rectify. -

              SEE ALSO

              +

              SEE ALSO

              -i.ortho.photo
              -i.ortho.camera
              -g.gui.photo2image
              -g.gui.image2target
              -i.ortho.init
              +i.ortho.photo, +i.ortho.camera, +g.gui.photo2image, +g.gui.image2target, +i.ortho.init, i.rectify
              -

              AUTHORS

              +

              AUTHORS

              Mike Baba, DBA Systems, Inc.
              Updated rectification and elevation map to FP 1/2002 Markus Neteler
              diff --git a/imagery/i.ortho.photo/i.ortho.target/i.ortho.target.html b/imagery/i.ortho.photo/i.ortho.target/i.ortho.target.html index 312cff5599d..07a4c5c6a2e 100644 --- a/imagery/i.ortho.photo/i.ortho.target/i.ortho.target.html +++ b/imagery/i.ortho.photo/i.ortho.target/i.ortho.target.html @@ -1,22 +1,21 @@ -

              DESCRIPTION

              +

              DESCRIPTION

              -i.ortho.target sets the image group target project (location) and mapset -

              +i.ortho.target sets the image group target project (location) and mapset. -

              SEE ALSO

              +

              SEE ALSO

              -i.ortho.photo
              -i.ortho.elev
              -i.ortho.camera
              -g.gui.photo2image
              -g.gui.image2target
              -i.ortho.init
              +i.ortho.photo, +i.ortho.elev, +i.ortho.camera, +g.gui.photo2image, +g.gui.image2target, +i.ortho.init, i.ortho.rectify
              -

              AUTHOR

              +

              AUTHOR

              Mike Baba, DBA Systems, Inc.
              GRASS development team, 2017 diff --git a/imagery/i.ortho.photo/lib/TODO b/imagery/i.ortho.photo/lib/TODO index 792cb581378..df02ac3cf5d 100644 --- a/imagery/i.ortho.photo/lib/TODO +++ b/imagery/i.ortho.photo/lib/TODO @@ -30,4 +30,4 @@ Possibly a lot is already done in lib/image3/ ? ----------------- See also -http://trac.osgeo.org/grass/wiki/Grass7Planning +https://trac.osgeo.org/grass/wiki/Grass7Planning diff --git a/imagery/i.pca/main.c b/imagery/i.pca/main.c index 427cf5f8730..8cc6c4f58fe 100644 --- a/imagery/i.pca/main.c +++ b/imagery/i.pca/main.c @@ -314,6 +314,7 @@ static int calc_mu_cov(int *fds, double **covar, double *mu, double *stddev, DCELL **rowbuf = (DCELL **)G_malloc(bands * sizeof(DCELL *)); double **sum2 = (double **)G_calloc(bands, sizeof(double *)); double *sumsq, *sd, *sum; + int ret = 1; if (stddev) { sumsq = (double *)G_calloc(bands, sizeof(double)); @@ -358,8 +359,10 @@ static int calc_mu_cov(int *fds, double **covar, double *mu, double *stddev, } G_percent(1, 1, 1); - if (count < 2) - return 0; + if (count < 2) { + ret = 0; + goto free_exit; + } for (i = 0; i < bands; i++) { if (stddev) { @@ -378,22 +381,21 @@ static int calc_mu_cov(int *fds, double **covar, double *mu, double *stddev, if (j != i) covar[j][i] = covar[i][j]; } - - G_free(sum2[i]); - G_free(rowbuf[i]); } for (i = 0; i < bands; i++) mu[i] = sum[i] / count; +free_exit: + for (i = 0; i < bands; i++) { + G_free(sum2[i]); + G_free(rowbuf[i]); + } G_free(rowbuf); - G_free(sum2); - if (sd) - G_free(sd); - if (sumsq) - G_free(sumsq); + G_free(sd); + G_free(sumsq); - return 1; + return ret; } static int write_pca(double **eigmat, double *mu, double *stddev, int *inp_fd, @@ -571,6 +573,8 @@ static int write_pca(double **eigmat, double *mu, double *stddev, int *inp_fd, G_free(min); G_free(max); G_free(old_range); + G_free(pcs); + G_free(out_fd); return 0; } diff --git a/imagery/i.rectify/i.rectify.html b/imagery/i.rectify/i.rectify.html index 6451c8c9be9..b8c21b0b7ef 100644 --- a/imagery/i.rectify/i.rectify.html +++ b/imagery/i.rectify/i.rectify.html @@ -11,8 +11,8 @@

              DESCRIPTION

              are first, second, and third order polynomial and thin plate spline. Thin plate spline is recommended for ungeoreferenced satellite imagery where ground control points (GCPs) are included. Examples are -NOAA/AVHRR -and ENVISAT +NOAA/AVHRR +and ENVISAT imagery which include throusands of GCPs.

              @@ -66,11 +66,11 @@

              Coordinate transformation

              Linear affine transformation (1st order transformation)

              -
              x' = ax + by + c -
              y' = Ax + By + C +
              x' = ax + by + c +
              y' = Ax + By + C
              -The a,b,c,A,B,C are determined by least squares regression +The a, b, c, A, B, C are determined by least squares regression based on the control points entered. This transformation applies scaling, translation and rotation. It is NOT a general purpose rubber-sheeting like TPS, nor is it ortho-photo @@ -144,9 +144,9 @@

              Resampling method

              In the bilinear, cubic and lanczos methods, if any of the surrounding cells used to interpolate the new cell value are NULL, the resulting cell will be NULL, even if the nearest cell is not NULL. This will cause some thinning along NULL borders, -such as the coasts of land areas in a DEM. The bilinear_f, cubic_f and lanczos_f -interpolation methods can be used if thinning along NULL edges is not desired. -These methods "fall back" to simpler interpolation methods along NULL borders. +such as the coasts of land areas in a DEM. The bilinear_f, cubic_f +and lanczos_f interpolation methods can be used if thinning along NULL edges is +not desired. These methods "fall back" to simpler interpolation methods along NULL borders. That is, from lanczos to cubic to bilinear to nearest.

              If nearest neighbor assignment is used, the output map has the same raster format as the input map. If any of the other interpolations is used, the @@ -179,7 +179,9 @@

              SEE ALSO

              v.proj, i.group, i.target -
              + +
              + Ground Control Points Manager diff --git a/imagery/i.segment/i.segment.html b/imagery/i.segment/i.segment.html index e30f21d3743..43d5e5fde68 100644 --- a/imagery/i.segment/i.segment.html +++ b/imagery/i.segment/i.segment.html @@ -100,11 +100,11 @@

              Goodness of Fit

              Mean shift

              Mean shift image segmentation consists of 2 steps: anisotrophic filtering and 2. clustering. For anisotrophic filtering new cell values -are calculated from all pixels not farther than hs pixels away +are calculated from all pixels not farther than radius pixels away from the current pixel and with a spectral difference not larger than hr. That means that pixels that are too different from the current pixel are not considered in the calculation of new pixel values. -hs and hr are the spatial and spectral (range) bandwidths +radius and hr are the spatial and spectral (range) bandwidths for anisotrophic filtering. Cell values are iteratively recalculated (shifted to the segment's mean) until the maximum number of iterations is reached or until the largest shift is smaller than threshold. @@ -251,8 +251,6 @@

              Functionality

        Use of Segmentation Results

          -
        • Improve the optional output from this module, or better yet, add a -module for i.segment.metrics.
        • Providing updates to i.maxlik to ensure the segmentation output can be used as input for the existing classification functionality.
        • @@ -277,6 +275,9 @@

          REFERENCES

          SEE ALSO

          +i.segment.stats (addon), +i.segment.uspo (addon), +i.segment.hierarchical (addon) g.gui.iclass, i.group, i.maxlik, diff --git a/imagery/i.signatures/i.signatures.html b/imagery/i.signatures/i.signatures.html index 403269ec84c..7f3ba1920e7 100644 --- a/imagery/i.signatures/i.signatures.html +++ b/imagery/i.signatures/i.signatures.html @@ -1,6 +1,6 @@

          DESCRIPTION

          -i.signatures module allows to manage signature files: +i.signatures module allows managing signature files:
          • "sig" – generated by i.gensig for i.maxlik
          • diff --git a/imagery/i.smap/i.smap.html b/imagery/i.smap/i.smap.html index 14a883efc28..4a57e900378 100644 --- a/imagery/i.smap/i.smap.html +++ b/imagery/i.smap/i.smap.html @@ -10,18 +10,17 @@

            DESCRIPTION

            i.smap has two modes of operation. The first mode -is the sequential maximum a posteriori (SMAP) mode -[1,2]. The SMAP +is the sequential maximum a posteriori (SMAP) mode (see +Bouman and Shapiro, 1992; Bouman and Shapiro, 1994). The SMAP segmentation algorithm attempts to improve segmentation accuracy by segmenting the image into regions rather than -segmenting each pixel separately -(see NOTES). +segmenting each pixel separately (see NOTES below).

            The second mode is the more conventional maximum likelihood (ML) classification which classifies each pixel separately, but requires somewhat less computation. This mode is selected with -the -m flag (see below). +the -m flag (see below).

            OPTIONS

            @@ -30,9 +29,7 @@

            Flags:

            -m
            Use maximum likelihood estimation (instead of smap). -Normal operation is to use SMAP estimation (see -NOTES). - +Normal operation is to use SMAP estimation (see NOTES below).

            Parameters:

            @@ -57,7 +54,7 @@

            Parameters:

            statistics) for the classes to be identified in the image. This signature file is produced by the program i.gensigset -(see NOTES). +(see NOTES below).
            blocksize=value @@ -102,7 +99,7 @@

            Parameters:

            -

            NOTES

            +

            NOTES

            The SMAP algorithm exploits the fact that nearby pixels in an image are likely to have the same class. It works by @@ -129,8 +126,9 @@

            NOTES

            The module i.smap does not support MASKed or NULL cells. Therefore it might be necessary to create a copy of the classification results -using e.g. r.mapcalc: -

            +using e.g. r.mapcalc:
            +

            +

             r.mapcalc "MASKed_map = classification_results"
             
            @@ -198,16 +196,16 @@

            REFERENCES

          • C. Bouman and M. Shapiro, "Multispectral Image Segmentation using a Multiscale Image Model", Proc. of IEEE Int'l Conf. on Acoust., Speech and Sig. Proc., -pp. III-565 - III-568, San Francisco, California, March 23-26, 1992. +pp. III-565 - III-568, San Francisco, California, March 23-26, 1992.
          • C. Bouman and M. Shapiro 1994, "A Multiscale Random Field Model for Bayesian Image Segmentation", IEEE Trans. on Image Processing., 3(2), 162-177" -(PDF) +(PDF)
          • McCauley, J.D. and B.A. Engel 1995, "Comparison of Scene Segmentations: SMAP, ECHO and Maximum Likelihood", -IEEE Trans. on Geoscience and Remote Sensing, 33(6): 1313-1316. +IEEE Trans. on Geoscience and Remote Sensing, 33(6): 1313-1316.

          SEE ALSO

          @@ -216,10 +214,10 @@

          SEE ALSO

          r.support for setting semantic labels,
          -i.group for creating groups and subgroups +i.group for creating groups and subgroups,
          r.mapcalc -to copy classification result in order to cut out MASKed subareas +to copy classification result in order to cut out MASKed subareas,
          i.gensigset to generate the signature file required by this program diff --git a/imagery/i.topo.corr/main.c b/imagery/i.topo.corr/main.c index 1f2b7988d26..42422117063 100644 --- a/imagery/i.topo.corr/main.c +++ b/imagery/i.topo.corr/main.c @@ -114,7 +114,10 @@ int main(int argc, char *argv[]) Rast_get_window(&window); azimuth = atof(azim->answer); /* Warning: make buffers and output after set window */ - strcpy(dem.name, base->answer); + if (G_strlcpy(dem.name, base->answer, sizeof(dem.name)) >= + sizeof(dem.name)) { + G_fatal_error(_("DEM name <%s> is too long"), base->answer); + } /* Set window to DEM file */ Rast_get_window(&window); Rast_get_cellhd(dem.name, "", &hd_dem); @@ -122,7 +125,10 @@ int main(int argc, char *argv[]) dem.fd = Rast_open_old(dem.name, ""); dem.type = Rast_get_map_type(dem.fd); /* Open and buffer of the output file */ - strcpy(out.name, output->answer); + if (G_strlcpy(out.name, output->answer, sizeof(out.name)) >= + sizeof(out.name)) { + G_fatal_error(_("Output name <%s> is too long"), output->answer); + } out.fd = Rast_open_new(output->answer, DCELL_TYPE); out.rast = Rast_allocate_buf(out.type); /* Open and buffer of the elevation file */ @@ -169,7 +175,11 @@ int main(int argc, char *argv[]) for (i = 0; input->answers[i] != NULL; i++) { G_message(_("Band %s: "), input->answers[i]); /* Abre fichero de bandas y el de salida */ - strcpy(band.name, input->answers[i]); + if (G_strlcpy(band.name, input->answers[i], sizeof(band.name)) >= + sizeof(band.name)) { + G_fatal_error(_("Band name <%s> is too long"), + input->answers[i]); + } Rast_get_cellhd(band.name, "", &hd_band); Rast_set_window( &hd_band); /* Antes de out_open y allocate para mismo size */ diff --git a/imagery/i.vi/evi2.c b/imagery/i.vi/evi2.c index c56ad2f62e0..502fba957ab 100644 --- a/imagery/i.vi/evi2.c +++ b/imagery/i.vi/evi2.c @@ -7,7 +7,7 @@ * 2-band enhanced vegetation index without a blue band and its application to * AVHRR data Proc. SPIE 6679, Remote Sensing and Modeling of Ecosystems for * Sustainability IV, 667905 (October 09, 2007) doi:10.1117/12.734933 - * http://dx.doi.org/10.1117/12.734933 + * https://doi.org/10.1117/12.734933 */ double e_vi2(double redchan, double nirchan) { diff --git a/imagery/i.vi/i.vi.html b/imagery/i.vi/i.vi.html index 7e600600678..38786a22abc 100644 --- a/imagery/i.vi/i.vi.html +++ b/imagery/i.vi/i.vi.html @@ -134,7 +134,7 @@

          Vegetation Indices

          vegetation index without a blue band and its application to AVHRR data. Proc. SPIE 6679, Remote Sensing and Modeling of Ecosystems for Sustainability IV, 667905 (october 09, 2007) -doi:10.1117/12.734933). +doi:10.1117/12.734933).
           evi2( redchan, nirchan )
          @@ -150,7 +150,7 @@ 

          Vegetation Indices

          Gitelson, Anatoly A.; Kaufman, Yoram J.; Merzlyak, Mark N. (1996) Use of a green channel in remote sensing of global vegetation from EOS- MODIS, Remote Sensing of Environment 58 (3), 289-298. -doi:10.1016/s0034-4257(96)00072-7 +doi:10.1016/s0034-4257(96)00072-7
           gari( redchan, nirchan, bluechan, greenchan )
          @@ -508,7 +508,7 @@ 

          Preparation: DN to reflectance

          Calculation of reflectance values from DN using DOS1 (metadata obtained -from p016r035_7x20020524.met.gz): +from p016r035_7x20020524.met.gz):

          @@ -584,9 +584,9 @@ 

          NOTES

          Written by Terrill W. Ray, Div. of Geological and Planetary Sciences, California Institute of Technology, email: terrill@mars1.gps.caltech.edu

          Snail Mail: Terrill Ray
          - Division of Geological and Planetary Sciences
          - Caltech, Mail Code 170-25
          - Pasadena, CA 91125 + Division of Geological and Planetary Sciences
          + Caltech, Mail Code 170-25
          + Pasadena, CA 91125

          REFERENCES

          @@ -596,8 +596,8 @@

          REFERENCES

          densities and moisture indicators in composite terrain; a remote sensing approach under clear skies in mediterranean climates. PhD thesis, Wageningen Agricultural Univ., The Netherland, 271 pp. -(PDF) -
        • Index DataBase: List of available Indices
        • +(PDF) +
        • Index DataBase: List of available Indices

        SEE ALSO

        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/imagery/i.vi/testsuite/test_vi.py b/imagery/i.vi/testsuite/test_vi.py index 0c383417257..b2160f924ed 100644 --- a/imagery/i.vi/testsuite/test_vi.py +++ b/imagery/i.vi/testsuite/test_vi.py @@ -26,14 +26,12 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - cls.runModule("g.remove", flags="f", type="raster", name="ipvi") - cls.runModule("g.remove", flags="f", type="raster", name="ndwi") - cls.runModule("g.remove", flags="f", type="raster", name="dvi") - cls.runModule("g.remove", flags="f", type="raster", name="sr") - cls.runModule("g.remove", flags="f", type="raster", name="evi") - cls.runModule("g.remove", flags="f", type="raster", name="evi2") - cls.runModule("g.remove", flags="f", type="raster", name="gari") - cls.runModule("g.remove", flags="f", type="raster", name="gemi") + cls.runModule( + "g.remove", + flags="f", + type="raster", + name="ipvi,ndwi,dvi,sr,evi,evi2,gari,gemi", + ) cls.del_temp_region() def test_vinameipvi(self): diff --git a/imagery/i.zc/i.zc.html b/imagery/i.zc/i.zc.html index b962c9b7b8d..f3dec69e4a1 100644 --- a/imagery/i.zc/i.zc.html +++ b/imagery/i.zc/i.zc.html @@ -13,16 +13,16 @@

        NOTES

        The procedure to find the "edges" in the image is as follows:
          -
        1. The Fourier transform of the image is taken, +
        2. The Fourier transform of the image is taken,
        3. The Fourier transform of the Laplacian of a two-dimensional -Gaussian function is used to filter the transformed image, -
        4. The result is run through an inverse Fourier transform, +Gaussian function is used to filter the transformed image,
        5. +
        6. The result is run through an inverse Fourier transform,
        7. The resulting image is traversed in search of places where the image -changes from positive to negative or from negative to positive, +changes from positive to negative or from negative to positive,
        8. Each cell in the map where the value crosses zero (with a change in value greater than the threshold value) is marked as an edge and an orientation is assigned to it. -The resulting raster map layer is output. +The resulting raster map layer is output.
        The width= parameter determines the x-y extent of the diff --git a/imagery/imageryintro.html b/imagery/imageryintro.html index 4b80951af9e..a9c93696632 100644 --- a/imagery/imageryintro.html +++ b/imagery/imageryintro.html @@ -2,6 +2,21 @@

        Image processing in general

        +GRASS GIS provides a powerful suite of tools for the processing and +analysis of geospatial raster data, including satellite imagery and +aerial photography. Its image processing capabilities encompass a broad +range of preprocessing operations, such as data import, georeferencing, +radiometric calibration, and atmospheric correction. It is particularly +suited for handling Earth observation data, enabling the analysis of +multispectral and temporal datasets. GRASS GIS supports advanced +functionalities such as image classification, sensor fusion, and point +cloud statistics. The calculation of vegetation indices further enables +analyses of environmental, agricultural, and land cover dynamics. An +extensive collection of +addons +further enhances its image processing capabilities, particularly in the +context of Earth observation and remote sensing applications. + Digital numbers and physical values (reflection/radiance-at-sensor):

        Satellite imagery is commonly stored in Digital Numbers (DN) for @@ -44,7 +59,7 @@

        Image processing in general

        using the DOS correction method. The more accurate way is using i.atcorr (which supports many satellite sensors). The atmospherically corrected sensor data represent -surface reflectance, +surface reflectance, which ranges theoretically from 0% to 100%. Note that this level of data correction is the proper level of correction to calculate vegetation indices. @@ -61,10 +76,10 @@

        Image processing in general

        As a general rule in GRASS:
        1. Raster/imagery output maps have their bounds and resolution equal - to those of the current region. + to those of the current region.
        2. Raster/imagery input maps are automatically cropped/padded and rescaled (using nearest-neighbor resampling) to match the current - region. + region.
        @@ -99,7 +114,7 @@

        Semantic label information

        a different group with identical semantic labels.
        -
        +
        New enhanced classification workflow involving semantic labels. @@ -192,12 +207,12 @@

        Image classification

      • Combined radiometric/geometric (segmentation based) classification:
      • Object-oriented classification:
      @@ -231,8 +246,8 @@

      Radiometric corrections

      Time series processing

      -GRASS also offers support for time series processing (r.series). Statistics can be derived from a +GRASS also offers support for time series processing +(r.series). Statistics can be derived from a set of coregistered input maps such as multitemporal satellite data. The common univariate statistics and also linear regression can be calculated. @@ -278,4 +293,5 @@

      See also

    8. Introduction into temporal data processing
    9. Database management
    10. Projections and spatial transformations
    11. +
    12. Graphical User Interface
    13. diff --git a/include/Make/DB.make b/include/Make/DB.make index a8ed51536f3..797da921ee5 100644 --- a/include/Make/DB.make +++ b/include/Make/DB.make @@ -10,7 +10,7 @@ include $(MODULE_TOPDIR)/include/Make/Compile.make dbmi: $(DBDRIVERDIR)/$(PGM)$(EXE) db_html -db_html: $(HTMLDIR)/grass-$(PGM).html $(MANDIR)/grass-$(PGM).$(MANSECT) +db_html: $(HTMLDIR)/grass-$(PGM).html $(MANDIR)/grass-$(PGM).$(MANSECT) # $(MDDIR)/source/grass-$(PGM).md $(DBDRIVERDIR)/$(PGM)$(EXE): $(ARCH_OBJS) $(DEPENDENCIES) $(call linker) diff --git a/include/Make/Doxyfile_arch_html.in b/include/Make/Doxyfile_arch_html.in index 3f1e828494c..4c60088412a 100644 --- a/include/Make/Doxyfile_arch_html.in +++ b/include/Make/Doxyfile_arch_html.in @@ -18,7 +18,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -573,7 +573,7 @@ LAYOUT_FILE = # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# https://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. @@ -644,7 +644,7 @@ INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -851,7 +851,7 @@ REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -946,7 +946,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. +# see https://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. @@ -1337,7 +1337,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. +# https://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain diff --git a/include/Make/Doxyfile_arch_latex.in b/include/Make/Doxyfile_arch_latex.in index 1962073feec..25f6ac1592f 100644 --- a/include/Make/Doxyfile_arch_latex.in +++ b/include/Make/Doxyfile_arch_latex.in @@ -18,7 +18,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -573,7 +573,7 @@ LAYOUT_FILE = # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# https://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. @@ -644,7 +644,7 @@ INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -851,7 +851,7 @@ REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -946,7 +946,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. +# see https://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. @@ -1337,7 +1337,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. +# https://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain diff --git a/include/Make/Grass.make b/include/Make/Grass.make index 137a45d1955..17ce25fcb71 100644 --- a/include/Make/Grass.make +++ b/include/Make/Grass.make @@ -59,6 +59,7 @@ DOCSDIR = $(ARCH_DISTDIR)/docs ETC = $(ARCH_DISTDIR)/etc GUIDIR = $(ARCH_DISTDIR)/gui HTMLDIR = $(ARCH_DISTDIR)/docs/html +MDDIR = $(ARCH_DISTDIR)/docs/mkdocs SCRIPTDIR = $(ARCH_DISTDIR)/scripts MSG_DIR = $(ARCH_DISTDIR)/etc/msgs MO_DIR = $(ARCH_DISTDIR)/locale diff --git a/include/Make/GuiScript.make b/include/Make/GuiScript.make index dbbc7609882..7451e2b693d 100644 --- a/include/Make/GuiScript.make +++ b/include/Make/GuiScript.make @@ -10,6 +10,8 @@ include $(MODULE_TOPDIR)/include/Make/HtmlRules.make MODULES := $(patsubst g.gui.%.py,%,$(wildcard g.gui.*.py)) CMDHTML := $(patsubst %,$(HTMLDIR)/g.gui.%.html,$(MODULES)) GUIHTML := $(patsubst %,$(HTMLDIR)/wxGUI.%.html,$(MODULES)) +CMDMAN := $(patsubst %,$(MDDIR)/source/g.gui.%.md,$(MODULES)) +GUIMAN := $(patsubst %,$(MDDIR)/source/wxGUI.%.md,$(MODULES)) ifdef MINGW SCRIPTEXT = .py BATFILES := $(patsubst %,$(BIN)/g.gui.%.bat,$(MODULES)) @@ -19,26 +21,40 @@ BATFILES = endif PYFILES := $(patsubst %,$(SCRIPTDIR)/g.gui.%$(SCRIPTEXT),$(MODULES)) -guiscript: $(IMGDST) $(PYFILES) $(BATFILES) +guiscript: $(IMGDST) $(IMGDST_MD) $(PYFILES) $(BATFILES) # we cannot use cross-compiled g.parser for generating html files ifndef CROSS_COMPILING $(MAKE) $(CMDHTML) -rm -f g.gui.*.tmp.html $(MAKE) $(GUIHTML) +# $(MAKE) $(CMDMAN) +# $(MAKE) $(GUIMAN) endif $(HTMLDIR)/g.gui.%.html: g.gui.%.html g.gui.%.tmp.html | $(HTMLDIR) VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) MODULE_TOPDIR=$(MODULE_TOPDIR) \ $(PYTHON) $(GISBASE)/utils/mkhtml.py g.gui.$* $(GRASS_VERSION_DATE) > $@ +$(MDDIR)/source/g.gui.%.md: g.gui.%.md g.gui.%.tmp.md | $(MDDIR) + VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) MODULE_TOPDIR=$(MODULE_TOPDIR) \ + $(PYTHON) $(GISBASE)/utils/mkmarkdown.py g.gui.$* $(GRASS_VERSION_DATE) > $@ + $(HTMLDIR)/wxGUI.%.html: g.gui.%.html | $(HTMLDIR) -rm -f g.gui.$*.tmp.html VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) MODULE_TOPDIR=$(MODULE_TOPDIR) \ $(PYTHON) $(GISBASE)/utils/mkhtml.py g.gui.$* $(GRASS_VERSION_DATE) > $@ +$(MDDIR)/source/wxGUI.%.md: g.gui.%.md | $(MDDIR) + -rm -f g.gui.$*.tmp.md + VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) MODULE_TOPDIR=$(MODULE_TOPDIR) \ + $(PYTHON) $(GISBASE)/utils/mkmarkdown.py g.gui.$* $(GRASS_VERSION_DATE) > $@ + g.gui.%.tmp.html: $(SCRIPTDIR)/g.gui.% $(call htmldesc,$<,$@) +g.gui.%.tmp.md: $(SCRIPTDIR)/g.gui.% + $(call mddesc,$<,$@) + $(SCRIPTDIR)/g.gui.%$(SCRIPTEXT): g.gui.%.py | $(SCRIPTDIR) $(INSTALL) $< $@ diff --git a/include/Make/Html.make b/include/Make/Html.make index fa736d3405a..335c841e149 100644 --- a/include/Make/Html.make +++ b/include/Make/Html.make @@ -7,19 +7,26 @@ $(HTMLDIR)/%.html: %.html %.tmp.html $(HTMLSRC) $(IMGDST) | $(HTMLDIR) VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) MODULE_TOPDIR=$(MODULE_TOPDIR) \ $(PYTHON) $(GISBASE)/utils/mkhtml.py $* > $@ +$(MDDIR)/source/%.md: %.md %.tmp.md $(HTMLSRC) $(IMGDST_MD) | $(MDDIR) + VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) MODULE_TOPDIR=$(MODULE_TOPDIR) \ + $(PYTHON) $(GISBASE)/utils/mkmarkdown.py $* > $@ + $(MANDIR)/%.$(MANSECT): $(HTMLDIR)/%.html $(HTML2MAN) "$<" "$@" %.tmp.html: $(HTMLSRC) if [ "$(HTMLSRC)" != "" ] ; then $(call htmldesc,$<,$@) ; fi +%.tmp.md: $(HTMLSRC) + if [ "$(HTMLSRC)" != "" ] ; then $(call mddesc,$<,$@) ; fi + ifdef CROSS_COMPILING html: else -html: $(HTMLDIR)/$(PGM).html $(MANDIR)/$(PGM).$(MANSECT) +html: $(HTMLDIR)/$(PGM).html $(MANDIR)/$(PGM).$(MANSECT) # $(MDDIR)/source/$(PGM).md endif diff --git a/include/Make/HtmlRules.make b/include/Make/HtmlRules.make index 0c79a05a2ad..cdeaf317b98 100644 --- a/include/Make/HtmlRules.make +++ b/include/Make/HtmlRules.make @@ -3,13 +3,20 @@ htmldesc = $(call run_grass,$(1) --html-description < /dev/null | grep -v '\|\| ' > $(2)) +mddesc = $(call run_grass,$(1) --md-description < /dev/null > $(2)) + IMGSRC := $(wildcard *.png) $(wildcard *.jpg) $(wildcard *.gif) IMGDST := $(patsubst %,$(HTMLDIR)/%,$(IMGSRC)) +IMGDST_MD := $(patsubst %,$(MDDIR)/source/%,$(IMGSRC)) ifneq ($(strip $(IMGDST)),) .SECONDARY: $(IMGDST) endif +ifneq ($(strip $(IMGDST_MD)),) +.SECONDARY: $(IMGDST_MD) +endif + $(HTMLDIR)/%.png: %.png | $(HTMLDIR) $(INSTALL_DATA) $< $@ @@ -18,3 +25,12 @@ $(HTMLDIR)/%.jpg: %.jpg | $(HTMLDIR) $(HTMLDIR)/%.gif: %.gif | $(HTMLDIR) $(INSTALL_DATA) $< $@ + +$(MDDIR)/source/%.png: %.png | $(MDDIR) + $(INSTALL_DATA) $< $@ + +$(MDDIR)/source/%.jpg: %.jpg | $(MDDIR) + $(INSTALL_DATA) $< $@ + +$(MDDIR)/source/%.gif: %.gif | $(MDDIR) + $(INSTALL_DATA) $< $@ diff --git a/include/Make/NoHtml.make b/include/Make/NoHtml.make index 915d2912c30..5742ff6268f 100644 --- a/include/Make/NoHtml.make +++ b/include/Make/NoHtml.make @@ -2,5 +2,8 @@ $(HTMLDIR)/$(PGM).html: @echo no HTML documentation available +$(MDDIR)/source/$(PGM).md: + @echo no Markdown documentation available + $(MANDIR)/$(PGM).$(MANSECT): @echo no manual page available diff --git a/include/Make/Rules.make b/include/Make/Rules.make index 3681c667a02..9e765fab7a4 100644 --- a/include/Make/Rules.make +++ b/include/Make/Rules.make @@ -6,7 +6,7 @@ first: pre default ARCH_DIRS = $(ARCH_DISTDIR) $(ARCH_BINDIR) $(ARCH_INCDIR) $(ARCH_LIBDIR) \ $(BIN) $(ETC) \ $(DRIVERDIR) $(DBDRIVERDIR) $(FONTDIR) $(DOCSDIR) $(HTMLDIR) \ - $(MANBASEDIR) $(MANDIR) $(UTILSDIR) + $(MDDIR) $(MDDIR)/source $(MANBASEDIR) $(MANDIR) $(UTILSDIR) pre: | $(ARCH_DIRS) diff --git a/include/grass/config.h.in b/include/grass/config.h.in index 2451d8cc2b8..8e5eb161a45 100644 --- a/include/grass/config.h.in +++ b/include/grass/config.h.in @@ -152,9 +152,6 @@ /* Define to 1 if PDAL exists. */ #undef HAVE_PDAL -/* Define to 1 if PDAL NoFilenameWriter is present. */ -#undef HAVE_PDAL_NOFILENAMEWRITER - /* Define to 1 if glXCreateGLXPixmap exists. */ #undef HAVE_PIXMAPS diff --git a/include/grass/defs/dbmi.h b/include/grass/defs/dbmi.h index c5bf648414f..5af0476849d 100644 --- a/include/grass/defs/dbmi.h +++ b/include/grass/defs/dbmi.h @@ -386,10 +386,12 @@ const char *db_whoami(void); void db_zero(void *, int); void db_zero_string(dbString *); unsigned int db_sizeof_string(const dbString *); -int db_set_login(const char *, const char *, const char *, const char *); +int db_set_login(const char *, const char *, const char *, const char *, + const char *, const char *, int); int db_set_login2(const char *, const char *, const char *, const char *, const char *, const char *, int); -int db_get_login(const char *, const char *, const char **, const char **); +int db_get_login(const char *, const char *, const char **, const char **, + const char **, const char **); int db_get_login2(const char *, const char *, const char **, const char **, const char **, const char **); int db_get_login_dump(FILE *); diff --git a/include/grass/defs/gprojects.h b/include/grass/defs/gprojects.h index 7ab5e47ddd6..e96200c1480 100644 --- a/include/grass/defs/gprojects.h +++ b/include/grass/defs/gprojects.h @@ -65,7 +65,7 @@ void GPJ_free_ellps(struct gpj_ellps *); #ifndef HAVE_PROJ_H /* PROJ.4's private datastructures copied from projects.h as removed from upstream; pending better solution. see: - http://trac.osgeo.org/proj/ticket/98 */ + https://trac.osgeo.org/proj/ticket/98 */ int pj_factors(LP, void *, double, struct FACTORS *); 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/include/grass/gprojects.h b/include/grass/gprojects.h index 7872d6cb4b6..35f795d87ad 100644 --- a/include/grass/gprojects.h +++ b/include/grass/gprojects.h @@ -112,7 +112,7 @@ struct gpj_ellps { #ifndef HAVE_PROJ_H /* PROJ.4's private datastructures copied from projects.h as removed from upstream; pending better solution. see: - http://trac.osgeo.org/proj/ticket/98 */ + https://trac.osgeo.org/proj/ticket/98 */ /* In PROJ 5, the 'struct FACTORS' is back in as 'struct P5_FACTORS', * and old 'struct LP' is now back in as 'PJ_UV' */ diff --git a/include/grass/iostream/ami_sort_impl.h b/include/grass/iostream/ami_sort_impl.h index bdd466d2b62..ebe22358da8 100644 --- a/include/grass/iostream/ami_sort_impl.h +++ b/include/grass/iostream/ami_sort_impl.h @@ -112,7 +112,7 @@ size_t makeRun_Block(AMI_STREAM *instream, T *data, unsigned int run_size, once, it reads it in blocks, sorts each block and then merges the blocks together. Note: it is not in place! it allocates another array of same size as data, writes the sorted run into it and - deteles data, and replaces data with outdata */ + deletes data, and replaces data with outdata */ template void makeRun(AMI_STREAM *instream, T *&data, int run_size, Compare *cmp) { diff --git a/include/grass/iostream/replacementHeap.h b/include/grass/iostream/replacementHeap.h index 485d4cef99b..30c309cdda2 100644 --- a/include/grass/iostream/replacementHeap.h +++ b/include/grass/iostream/replacementHeap.h @@ -101,10 +101,10 @@ class ReplacementHeap { public: // allocate array mergeHeap and the runs in runList - ReplacementHeap(size_t arity, queue *runList); + ReplacementHeap(size_t arity, queue *runList); // delete array mergeHeap - ~ReplacementHeap(); + ~ReplacementHeap(); // is heap empty? int empty() const { return (size == 0); } @@ -159,7 +159,7 @@ ReplacementHeap::ReplacementHeap(size_t g_arity, /*****************************************************************/ template -ReplacementHeap::~ReplacementHeap() +ReplacementHeap::~ReplacementHeap() { if (!empty()) { diff --git a/include/grass/iostream/replacementHeapBlock.h b/include/grass/iostream/replacementHeapBlock.h index c1596d67585..f4614eb838b 100644 --- a/include/grass/iostream/replacementHeapBlock.h +++ b/include/grass/iostream/replacementHeapBlock.h @@ -102,10 +102,10 @@ class ReplacementHeapBlock { public: // allocate array mergeHeap, where the streams are stored in runList - ReplacementHeapBlock(queue *> *runList); + ReplacementHeapBlock(queue *> *runList); // delete array mergeHeap - ~ReplacementHeapBlock(); + ~ReplacementHeapBlock(); // is heap empty? int empty() const { return (size == 0); } @@ -161,7 +161,7 @@ ReplacementHeapBlock::ReplacementHeapBlock( /*****************************************************************/ template -ReplacementHeapBlock::~ReplacementHeapBlock() +ReplacementHeapBlock::~ReplacementHeapBlock() { if (!empty()) { 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/btree2/Makefile b/lib/btree2/Makefile index 84dda646327..627fc259bce 100644 --- a/lib/btree2/Makefile +++ b/lib/btree2/Makefile @@ -7,6 +7,7 @@ MOD_OBJS := $(filter-out try.o,$(AUTO_OBJS)) LIB = BTREE2 include $(MODULE_TOPDIR)/include/Make/Lib.make +include $(MODULE_TOPDIR)/include/Make/Doxygen.make HEADERS := $(ARCH_INCDIR)/kdtree.h @@ -17,3 +18,5 @@ headers: $(HEADERS) $(ARCH_INCDIR)/kdtree.h: kdtree.h $(INSTALL_DATA) $< $@ + +DOXNAME = btree2 diff --git a/lib/btree2/btree2.dox b/lib/btree2/btree2lib.dox similarity index 98% rename from lib/btree2/btree2.dox rename to lib/btree2/btree2lib.dox index 5f6b7515e0d..6e4d00b0eda 100644 --- a/lib/btree2/btree2.dox +++ b/lib/btree2/btree2lib.dox @@ -1,4 +1,4 @@ -/*! \page btree2 btree2 library +/*! \page btree2 GRASS Btree2 and k-d tree libraries \tableofcontents diff --git a/lib/cairodriver/cairodriver.dox b/lib/cairodriver/cairodriver.dox index d7ce1ab60e2..ca3ac067e06 100644 --- a/lib/cairodriver/cairodriver.dox +++ b/lib/cairodriver/cairodriver.dox @@ -11,7 +11,7 @@ output, see Cairo website for details. GRASS Cairo display %driver was originally written by Lars Ahlzen (announcement). +href="https://lists.osgeo.org/pipermail/grass-dev/2007-October/033524.html">announcement). \section cairofunctions List of functions diff --git a/lib/cluster/c_exec.c b/lib/cluster/c_exec.c index abc53d32fe5..043c67475c3 100644 --- a/lib/cluster/c_exec.c +++ b/lib/cluster/c_exec.c @@ -1,7 +1,7 @@ /*! \file cluster/c_exec.c - \brief Cluster library - Exectute clusterring + \brief Cluster library - Execute clusterring (C) 2001-2009 by the GRASS Development Team diff --git a/lib/db/README b/lib/db/README deleted file mode 100644 index 7268b4e182f..00000000000 --- a/lib/db/README +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** - * - * MODULE: DBMI library - * AUTHOR(S): Joel Jones (CERL/UIUC) - * Radim Blazek , - * Brad Douglas , - * Glynn Clements , - * Roberto Flor, Hamish Bowman , - * Markus Neteler , - * Huidae Cho , - * Paul Kelly , - * Martin Landa , - * Moritz Lennert , - * Daniel Calvelo Aros , - * Bernhard Reiter , - * Alex Shevlakov - * PURPOSE: database management functions for modules and drivers - * COPYRIGHT: (C) 2003-2006 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. - * - *****************************************************************************/ - -DBMI Library - -Original author: Joel Jones (jjones * zorro.cecer.army.mil | jjones * uiuc.edu ) - Ref: http://lists.osgeo.org/pipermail/grass-dev/1995-February/002015.html - -Directory contents: - -dbmi: DataBase Management Interface (db_*() functions) - dbmi_base: contains functions for modules, drivers (../../db/drivers/) - dbmi_client: contains functions for modules - dbmi_driver: contains functions for drivers (../../db/drivers/) - -sqlp: SQL parser library -stubs: stubs for unimplemented DB functions - -The DBMI drivers are stored in -../../db/drivers/ - -The DBMI user modules are stored in -../../db/base/ - -NOTE: - Please read db/drivers/README - -To generate dbmi_driver/dbstubs.h automatically, run './mk_dbstubs_h.sh' in -dbmi_driver/ directory. diff --git a/lib/db/README.md b/lib/db/README.md new file mode 100644 index 00000000000..227d628fa48 --- /dev/null +++ b/lib/db/README.md @@ -0,0 +1,59 @@ +## DBMI library + +### Purpose + +Database management functions for modules and drivers. + +### Authors + +Original author: + +- Joel Jones (CERL/UIUC) (jjones zorro.cecer.army.mil) + +Ref: + +Further authors: + +- Radim Blazek (radim.blazek gmail.com) +- Brad Douglas (rez touchofmadness.com) +- Glynn Clements (glynn gclements.plus.com) +- Roberto Flor, Hamish Bowman (hamish_b yahoo.com) +- Markus Neteler (neteler itc.it) +- Huidae Cho (grass4u gmail.com) +- Paul Kelly (paul-grass stjohnspoint.co.uk) +- Martin Landa (landa.martin gmail.com) +- Moritz Lennert (mlennert club.worldonline.be) +- Daniel Calvelo Aros (dca.gis gmail.com) +- Bernhard Reiter (bernhard intevation.de) +- Alex Shevlakov (sixote yahoo.com) + +### Copyright + +(C) 2003-2024 by the GRASS Development Team + +### License + +This program is free software under the GNU General Public +License (>=v2). Read the file COPYING that comes with GRASS +for details. + +### Directory contents + +- `dbmi/`: DataBase Management Interface (`db_*()` functions) + - `dbmi_base/`: contains functions for modules, drivers (`../../db/drivers/`) + - `dbmi_client/`: contains functions for modules + - `dbmi_driver/`: contains functions for drivers (`../../db/drivers/`) +- `sqlp/`: SQL parser library +- `stubs/`: stubs for unimplemented DB functions + +The DBMI drivers are stored in +`../../db/drivers/` + +The DBMI user modules are stored in +`../../db/base/` + +NOTE: +Please read db/drivers/README.md + +To generate `dbmi_driver/dbstubs.h` automatically, run `./mk_dbstubs_h.sh` in +`dbmi_driver/` directory (GRASS GIS 6). diff --git a/lib/db/dbmi_base/connect.c b/lib/db/dbmi_base/connect.c index 780d929dd3a..ced282405bd 100644 --- a/lib/db/dbmi_base/connect.c +++ b/lib/db/dbmi_base/connect.c @@ -87,11 +87,11 @@ int db_get_connection(dbConnection *connection) connection->group = (char *)G_getenv_nofatal2("DB_GROUP", G_VAR_MAPSET); /* try to get user/password */ - db_get_login2(connection->driverName, connection->databaseName, - (const char **)&(connection->user), - (const char **)&(connection->password), - (const char **)&(connection->hostName), - (const char **)&(connection->port)); + db_get_login(connection->driverName, connection->databaseName, + (const char **)&(connection->user), + (const char **)&(connection->password), + (const char **)&(connection->hostName), + (const char **)&(connection->port)); return DB_OK; } diff --git a/lib/db/dbmi_base/default_name.c b/lib/db/dbmi_base/default_name.c index f9904651a06..839060b44d9 100644 --- a/lib/db/dbmi_base/default_name.c +++ b/lib/db/dbmi_base/default_name.c @@ -123,7 +123,7 @@ int db_set_default_connection(void) * that here?) or $MAPSET/sqlite/mapname.sql as with dbf? */ - /* http://www.sqlite.org/lockingv3.html + /* https://www.sqlite.org/lockingv3.html * When SQLite creates a journal file on Unix, it opens the * directory that contains that file and calls fsync() on the * directory, in an effort to push the directory information to disk. diff --git a/lib/db/dbmi_base/login.c b/lib/db/dbmi_base/login.c index d79fc84e6cf..9c865233d2c 100644 --- a/lib/db/dbmi_base/login.c +++ b/lib/db/dbmi_base/login.c @@ -253,22 +253,23 @@ static int set_login(const char *driver, const char *database, const char *user, /*! \brief Set login parameters for driver/database - \deprecated Use db_set_login2() instead. - - \todo: GRASS 8: to be replaced by db_set_login2(). - \param driver driver name \param database database name \param user user name \param password password string + \param host host name + \param port + \param overwrite TRUE to overwrite existing connections \return DB_OK on success \return DB_FAILED on failure */ -int db_set_login(const char *driver, const char *database, const char *user, - const char *password) +int db_set_login2(const char *driver, const char *database, const char *user, + const char *password, const char *host, const char *port, + int overwrite) { - return set_login(driver, database, user, password, NULL, NULL, FALSE); + return db_set_login(driver, database, user, password, host, port, + overwrite); } /*! @@ -285,9 +286,9 @@ int db_set_login(const char *driver, const char *database, const char *user, \return DB_OK on success \return DB_FAILED on failure */ -int db_set_login2(const char *driver, const char *database, const char *user, - const char *password, const char *host, const char *port, - int overwrite) +int db_set_login(const char *driver, const char *database, const char *user, + const char *password, const char *host, const char *port, + int overwrite) { return set_login(driver, database, user, password, host, port, overwrite); } @@ -346,22 +347,20 @@ static int get_login(const char *driver, const char *database, If driver/database is not found, output arguments are set to NULL. - \deprecated Use db_set_login2() instead. - - \todo: GRASS 8: to be replaced by db_set_login2(). - \param driver driver name \param database database name (can be NULL) \param[out] user name \param[out] password string + \param[out] host name + \param[out] port \return DB_OK on success \return DB_FAILED on failure */ -int db_get_login(const char *driver, const char *database, const char **user, - const char **password) +int db_get_login2(const char *driver, const char *database, const char **user, + const char **password, const char **host, const char **port) { - return get_login(driver, database, user, password, NULL, NULL); + return db_get_login(driver, database, user, password, host, port); } /*! @@ -379,8 +378,8 @@ int db_get_login(const char *driver, const char *database, const char **user, \return DB_OK on success \return DB_FAILED on failure */ -int db_get_login2(const char *driver, const char *database, const char **user, - const char **password, const char **host, const char **port) +int db_get_login(const char *driver, const char *database, const char **user, + const char **password, const char **host, const char **port) { return get_login(driver, database, user, password, host, port); } diff --git a/lib/db/dbmi_client/c_update.c b/lib/db/dbmi_client/c_update.c index 9a8a0d6e4cd..399f19d8155 100644 --- a/lib/db/dbmi_client/c_update.c +++ b/lib/db/dbmi_client/c_update.c @@ -1,7 +1,7 @@ /*! * \file db/dbmi_client/c_update.c * - * \brief DBMI Library (client) - update statemets + * \brief DBMI Library (client) - update statements * * (C) 1999-2008 by the GRASS Development Team * diff --git a/lib/db/dbmi_driver/d_update.c b/lib/db/dbmi_driver/d_update.c index 5d601679082..ed7a501a7c4 100644 --- a/lib/db/dbmi_driver/d_update.c +++ b/lib/db/dbmi_driver/d_update.c @@ -1,7 +1,7 @@ /*! * \file db/dbmi_driver/d_update.c * - * \brief DBMI Library (driver) - update statemets + * \brief DBMI Library (driver) - update statements * * (C) 1999-2008 by the GRASS Development Team * diff --git a/lib/db/dbmilib.dox b/lib/db/dbmilib.dox index fdbac5fab36..0c85715e7f0 100644 --- a/lib/db/dbmilib.dox +++ b/lib/db/dbmilib.dox @@ -15,10 +15,10 @@ Interface) with its integrated drivers. At time of this writing following DBMI drivers for attribute storage are available: - DBF: xBase files (default) - - ODBC: to interface from http://www.unixodbc.org - - PostgreSQL driver (note that PostgreSQL can also be accessed through ODBC): http://www.postgresql.org + - ODBC: to interface from https://www.unixodbc.org + - PostgreSQL driver (note that PostgreSQL can also be accessed through ODBC): https://www.postgresql.org - mySQL: http://mysql.com/ - - SQLite: http://www.sqlite.org + - SQLite: https://www.sqlite.org These drivers are compiled depending on present DB related libraries and 'configure' settings. Only the DBF driver is always compiled. The diff --git a/lib/db/sqlp/README b/lib/db/sqlp/README deleted file mode 100644 index 9a23b0925e8..00000000000 --- a/lib/db/sqlp/README +++ /dev/null @@ -1,18 +0,0 @@ -sqlp is SQL parser library - -sqp is intended as library for simple dbmi drivers (like dbf, txt). -yac.y and lex.l was originally stolen from unixODBC 3/2001 and modified. - -An input may be subset of SQL statements. Currently supported: -SELECT FROM WHERE -INSERT INTO -UPDATE WHERE -DELETE FROM WHERE -CREATE TABLE -DROP TABLE -[...] - -New types have to be added in yac.y, lex.l, print.c and -../../../include/sqlp.h . -In ./test/ is a test program to the the SQL parser (see -README there). diff --git a/lib/db/sqlp/README.md b/lib/db/sqlp/README.md new file mode 100644 index 00000000000..852126fb157 --- /dev/null +++ b/lib/db/sqlp/README.md @@ -0,0 +1,24 @@ +## SQL parser library + +sqlp is the SQL parser library. + +sqp is intended as library for simple dbmi drivers (like dbf, txt). +`yac.y` and `lex.l` was originally stolen from unixODBC 3/2001 and modified. + +An input may be subset of SQL statements. Currently supported: + +```sql +SELECT FROM WHERE +INSERT INTO +UPDATE WHERE +DELETE FROM WHERE +CREATE TABLE +DROP TABLE +[...] +``` + +New types have to be added in `yac.y`, `lex.l`, `print.c` and +`../../../include/sqlp.h`. + +In `./test/` is a test program to the the SQL parser (see +README.md there). diff --git a/lib/db/sqlp/sql.html b/lib/db/sqlp/sql.html index 730d0462c2a..a2dc32da2a5 100644 --- a/lib/db/sqlp/sql.html +++ b/lib/db/sqlp/sql.html @@ -9,9 +9,9 @@ attribute table.

      GRASS GIS supports various RDBMS -(Relational +(Relational database management system) and embedded databases. SQL -(Structured Query +(Structured Query Language) queries are directly passed to the underlying database system. The set of supported SQL commands depends on the RDMBS and database driver selected. @@ -29,25 +29,25 @@

      Database drivers

      Fig.: Land use/land cover clustering of LANDSAT scene (simplified)
      - + - + - + - + - +
      sqliteData storage in SQLite database files (default DB backend)http://sqlite.org/
      https://sqlite.org/
      dbfData storage in DBF files http://shapelib.maptools.org/dbf_api.html
      pgData storage in PostgreSQL RDBMShttp://postgresql.org/
      https://postgresql.org/
      mysqlData storage in MySQL RDBMShttp://mysql.org/
      https://www.mysql.org/
      odbcData storage via UnixODBC (PostgreSQL, Oracle, etc.)http://www.unixodbc.org/
      https://www.unixodbc.org/
      ogrData storage in OGR fileshttp://gdal.org/
      https://gdal.org/

      NOTES

      @@ -237,4 +237,4 @@

      SEE ALSO

      AUTHOR

      -Radmin Blazek +Radim Blazek diff --git a/lib/db/sqlp/test/README b/lib/db/sqlp/test/README deleted file mode 100644 index d703f03bd0c..00000000000 --- a/lib/db/sqlp/test/README +++ /dev/null @@ -1,6 +0,0 @@ -Test of sql parser library. - -sqlptest reads sql statements (one per row) from standard -input and writes results of parser to standard output. - -Some test statemets are in ./test diff --git a/lib/db/sqlp/test/README.md b/lib/db/sqlp/test/README.md new file mode 100644 index 00000000000..a6aae0fe947 --- /dev/null +++ b/lib/db/sqlp/test/README.md @@ -0,0 +1,6 @@ +## Test of SQL parser library + +`sqlptest` reads SQL statements (one per row) from standard +input and writes results of parser to standard output. + +Some test statements are in `./test`. diff --git a/lib/fonts/fonts/cyrilc.hmp b/lib/fonts/fonts/cyrilc.hmp index 12b63015753..c1d5c6f5086 100644 --- a/lib/fonts/fonts/cyrilc.hmp +++ b/lib/fonts/fonts/cyrilc.hmp @@ -19,4 +19,4 @@ 2801 2802 2823 2805 2806 2821 2804 2822 2809 2810 2811 2812 2813 2814 2815 2816 2832 2817 2818 2819 2820 2807 2803 2829 -2828 2808 2825 2830 2826 2824 2827 2832 +2828 2808 2825 2830 2826 2824 2827 2832 diff --git a/lib/fonts/fonts/fonts.table b/lib/fonts/fonts/fonts.table index d4d8486b5fa..f897f10384d 100644 --- a/lib/fonts/fonts/fonts.table +++ b/lib/fonts/fonts/fonts.table @@ -1,16 +1,16 @@ # # Descriptive Names for GRASS Stroke Fonts # -# This file maps a descriptive name to each font file, for use in the +# This file maps a descriptive name to each font file, for use in the # description field in the fontcap table (generated by g.mkfontcap). # # Format: Each line contains the filename followed by the vertical bar # character | and then the descriptive name. # -# Note that this file is used purely for the purpose of specifying +# Note that this file is used purely for the purpose of specifying # descriptive names for the Stroke fonts in this directory. # $GISBASE/etc/fontcap contains the list of fonts available to the GRASS -# display drivers, and any changes must be reflected there before they are +# display drivers, and any changes must be reflected there before they are # available for use - g.mkfontcap can do this automatically. # cyrilc.hmp|Cyrillic diff --git a/lib/gis/area_poly1.c b/lib/gis/area_poly1.c index 9d06690f970..a165876a229 100644 --- a/lib/gis/area_poly1.c +++ b/lib/gis/area_poly1.c @@ -186,7 +186,7 @@ double G_ellipsoid_polygon_area(const double *lon, const double *lat, int n) area = -area; /* kludge - if polygon circles the south pole the area will be - * computed as if it cirlced the north pole. The correction is + * computed as if it circled the north pole. The correction is * the difference between total surface area of the earth and * the "north pole" area. */ 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/copy_dir.c b/lib/gis/copy_dir.c index 226e25a5a39..8babbc2e964 100644 --- a/lib/gis/copy_dir.c +++ b/lib/gis/copy_dir.c @@ -141,8 +141,10 @@ int G_recursive_copy(const char *src, const char *dst) sprintf(path, "%s/%s", src, dp->d_name); sprintf(path2, "%s/%s", dst, dp->d_name); - if (G_recursive_copy(path, path2) != 0) + if (G_recursive_copy(path, path2) != 0) { + closedir(dirp); return 1; + } } closedir(dirp); diff --git a/lib/gis/debug.c b/lib/gis/debug.c index 034ab8dc690..b0d42260528 100644 --- a/lib/gis/debug.c +++ b/lib/gis/debug.c @@ -72,8 +72,6 @@ int G_debug(int level, const char *msg, ...) G_init_debug(); if (grass_debug_level >= level) { - va_start(ap, msg); - filen = getenv("GRASS_DEBUG_FILE"); if (filen != NULL) { fd = fopen(filen, "a"); @@ -87,14 +85,14 @@ int G_debug(int level, const char *msg, ...) } fprintf(fd, "D%d/%d: ", level, grass_debug_level); + va_start(ap, msg); vfprintf(fd, msg, ap); + va_end(ap); fprintf(fd, "\n"); fflush(fd); if (filen != NULL) fclose(fd); - - va_end(ap); } return 1; 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/lz4.c b/lib/gis/lz4.c index 1575be2c481..b2540a90438 100644 --- a/lib/gis/lz4.c +++ b/lib/gis/lz4.c @@ -1,6 +1,6 @@ /* LZ4 - Fast LZ compression algorithm - Copyright (C) 2011-2017, Yann Collet. + Copyright (C) 2011-2023, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -8,9 +8,9 @@ modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -28,17 +28,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 - */ + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ /*-************************************ * Tuning parameters **************************************/ /* * LZ4_HEAPMODE : - * Select how default compression functions will allocate memory for their hash - * table, in memory stack (0:default, fastest), or in memory heap (1:requires + * Select how stateless compression functions like `LZ4_compress_default()` + * allocate memory for their hash table, + * in memory stack (0:default, fastest), or in memory heap (1:requires * malloc()). */ #ifndef LZ4_HEAPMODE @@ -46,10 +47,16 @@ #endif /* - * ACCELERATION_DEFAULT : + * LZ4_ACCELERATION_DEFAULT : * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 */ -#define ACCELERATION_DEFAULT 1 +#define LZ4_ACCELERATION_DEFAULT 1 +/* + * LZ4_ACCELERATION_MAX : + * Any "acceleration" value higher than this threshold + * get treated as LZ4_ACCELERATION_MAX instead (fix #876) + */ +#define LZ4_ACCELERATION_MAX 65537 /*-************************************ * CPU Feature Detection @@ -58,20 +65,16 @@ * By default, access to unaligned memory is controlled by `memcpy()`, which is * safe and portable. Unfortunately, on some target/compiler combinations, the * generated assembly is sub-optimal. The below switch allow to select different - * access method for improved performance. - * Method 0 (default) : use `memcpy()`. Safe and portable. - * Method 1 : `__packed` statement. It depends on compiler extension - * (ie, not portable). - * This method is safe if your compiler supports it, and *generally* - * as fast or faster than `memcpy`. - * Method 2 : direct access. This method is portable but violate C standard. - * It can generate buggy code on targets which assembly generation - * depends on alignment. But in some circumstances, it's the only - * known way to get the most performance (ie GCC + ARMv6) - * See + * access method for improved performance. Method 0 (default) : use `memcpy()`. + * Safe and portable. Method 1 : `__packed` statement. It depends on compiler + * extension (ie, not portable). This method is safe if your compiler supports + * it, and *generally* as fast or faster than `memcpy`. Method 2 : direct + * access. This method is portable but violate C standard. It can generate buggy + * code on targets which assembly generation depends on alignment. But in some + * circumstances, it's the only known way to get the most performance (ie GCC + + * ARMv6) See * https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html - * for details. - * Prefer these methods in priority order (0 > 1 > 2) + * for details. Prefer these methods in priority order (0 > 1 > 2) */ #ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */ #if defined(__GNUC__) && \ @@ -79,7 +82,8 @@ defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \ defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)) #define LZ4_FORCE_MEMORY_ACCESS 2 -#elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__) +#elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__) || \ + defined(_MSC_VER) #define LZ4_FORCE_MEMORY_ACCESS 1 #endif #endif @@ -92,36 +96,58 @@ #if defined(_MSC_VER) && \ defined(_WIN32_WCE) /* Visual Studio for WinCE doesn't support Hardware \ bit count */ +#undef LZ4_FORCE_SW_BITCOUNT /* avoid double def */ #define LZ4_FORCE_SW_BITCOUNT #endif /*-************************************ * Dependency **************************************/ -#define LZ4_STATIC_LINKING_ONLY +/* + * LZ4_SRC_INCLUDED: + * Amalgamation flag, whether lz4.c is included + */ +#ifndef LZ4_SRC_INCLUDED +#define LZ4_SRC_INCLUDED 1 +#endif + +#ifndef LZ4_DISABLE_DEPRECATE_WARNINGS #define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to \ LZ4_decompress_safe_withPrefix64k */ +#endif + +#ifndef LZ4_STATIC_LINKING_ONLY +#define LZ4_STATIC_LINKING_ONLY +#endif #include "lz4.h" /* see also "memory routines" below */ /*-************************************ * Compiler Options **************************************/ -#ifdef _MSC_VER /* Visual Studio */ -#include +#if defined(_MSC_VER) && (_MSC_VER >= 1400) /* Visual Studio 2005+ */ +#include /* only present in VS2005+ */ #pragma warning( \ disable : 4127) /* disable: C4127: conditional expression is constant */ -#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) \ - */ +#pragma warning( \ + disable : 6237) /* disable: C6237: conditional expression is always 0 */ +#pragma warning( \ + disable : 6239) /* disable: C6239: ( && ) \ + always evaluates to the result of */ +#pragma warning( \ + disable : 6240) /* disable: C6240: ( && ) \ + always evaluates to the result of */ +#pragma warning(disable : 6326) /* disable: C6326: Potential comparison of a \ + constant with another constant */ #endif /* _MSC_VER */ #ifndef LZ4_FORCE_INLINE -#ifdef _MSC_VER /* Visual Studio */ +#if defined(_MSC_VER) && !defined(__clang__) /* MSVC */ #define LZ4_FORCE_INLINE static __forceinline #else #if defined(__cplusplus) || \ defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -#ifdef __GNUC__ +#if defined(__GNUC__) || defined(__clang__) #define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) #else #define LZ4_FORCE_INLINE static inline @@ -132,8 +158,8 @@ #endif /* _MSC_VER */ #endif /* LZ4_FORCE_INLINE */ -/* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE - * Gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy, +/* LZ4_FORCE_O2 and LZ4_FORCE_INLINE + * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8, * together with a simple 8-byte copy loop as a fall-back path. * However, this optimization hurts the decompression speed by >30%, * because the execution does not go to the optimized loop @@ -141,18 +167,19 @@ * before going to the fall-back path become useless overhead. * This optimization happens only with the -O3 flag, and -O2 generates * a simple 8-byte copy loop. - * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy + * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8 * functions are annotated with __attribute__((optimize("O2"))), - * and also LZ4_wildCopy is forcibly inlined, so that the O2 attribute - * of LZ4_wildCopy does not affect the compression speed. + * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute + * of LZ4_wildCopy8 does not affect the compression speed. */ -#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) -#define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize("O2"))) -#define LZ4_FORCE_O2_INLINE_GCC_PPC64LE \ - __attribute__((optimize("O2"))) LZ4_FORCE_INLINE +#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && \ + !defined(__clang__) +#define LZ4_FORCE_O2 __attribute__((optimize("O2"))) +#undef LZ4_FORCE_INLINE +#define LZ4_FORCE_INLINE \ + static __inline __attribute__((optimize("O2"), always_inline)) #else -#define LZ4_FORCE_O2_GCC_PPC64LE -#define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static +#define LZ4_FORCE_O2 #endif #if (defined(__GNUC__) && (__GNUC__ >= 3)) || \ @@ -170,19 +197,135 @@ #define unlikely(expr) expect((expr) != 0, 0) #endif +/* Should the alignment test prove unreliable, for some reason, + * it can be disabled by setting LZ4_ALIGN_TEST to 0 */ +#ifndef LZ4_ALIGN_TEST /* can be externally provided */ +#define LZ4_ALIGN_TEST 1 +#endif + /*-************************************ * Memory routines **************************************/ + +/*! LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION : + * Disable relatively high-level LZ4/HC functions that use dynamic memory + * allocation functions (malloc(), calloc(), free()). + * + * Note that this is a compile-time switch. And since it disables + * public/stable LZ4 v1 API functions, we don't recommend using this + * symbol to generate a library for distribution. + * + * The following public functions are removed when this symbol is defined. + * - lz4 : LZ4_createStream, LZ4_freeStream, + * LZ4_createStreamDecode, LZ4_freeStreamDecode, LZ4_create + * (deprecated) + * - lz4hc : LZ4_createStreamHC, LZ4_freeStreamHC, + * LZ4_createHC (deprecated), LZ4_freeHC (deprecated) + * - lz4frame, lz4file : All LZ4F_* functions + */ +#if defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) +#define ALLOC(s) lz4_error_memory_allocation_is_disabled +#define ALLOC_AND_ZERO(s) lz4_error_memory_allocation_is_disabled +#define FREEMEM(p) lz4_error_memory_allocation_is_disabled +#elif defined(LZ4_USER_MEMORY_FUNCTIONS) +/* memory management functions can be customized by user project. + * Below functions must exist somewhere in the Project + * and be available at link time */ +void *LZ4_malloc(size_t s); +void *LZ4_calloc(size_t n, size_t s); +void LZ4_free(void *p); +#define ALLOC(s) LZ4_malloc(s) +#define ALLOC_AND_ZERO(s) LZ4_calloc(1, s) +#define FREEMEM(p) LZ4_free(p) +#else #include /* malloc, calloc, free */ #define ALLOC(s) malloc(s) #define ALLOC_AND_ZERO(s) calloc(1, s) #define FREEMEM(p) free(p) +#endif + +#if !LZ4_FREESTANDING #include /* memset, memcpy */ -#define MEM_INIT(p, v, s) memset((p), (v), (s)) +#endif +#if !defined(LZ4_memset) +#define LZ4_memset(p, v, s) memset((p), (v), (s)) +#endif +#define MEM_INIT(p, v, s) LZ4_memset((p), (v), (s)) + +/*-************************************ + * Common Constants + **************************************/ +#define MINMATCH 4 + +#define WILDCOPYLENGTH 8 +#define LASTLITERALS \ + 5 /* see ../doc/lz4_Block_format.md#parsing-restrictions \ + */ +#define MFLIMIT 12 /* see ../doc/lz4_Block_format.md#parsing-restrictions */ +#define MATCH_SAFEGUARD_DISTANCE \ + ((2 * WILDCOPYLENGTH) - \ + MINMATCH) /* ensure it's possible to write 2 x wildcopyLength without \ + overflowing output buffer */ +#define FASTLOOP_SAFE_DISTANCE 64 +static const int LZ4_minLength = (MFLIMIT + 1); + +#define KB *(1 << 10) +#define MB *(1 << 20) +#define GB *(1U << 30) + +#define LZ4_DISTANCE_ABSOLUTE_MAX 65535 +#if (LZ4_DISTANCE_MAX > \ + LZ4_DISTANCE_ABSOLUTE_MAX) /* max supported by LZ4 format */ +#error "LZ4_DISTANCE_MAX is too big : must be <= 65535" +#endif + +#define ML_BITS 4 +#define ML_MASK ((1U << ML_BITS) - 1) +#define RUN_BITS (8 - ML_BITS) +#define RUN_MASK ((1U << RUN_BITS) - 1) + +/*-************************************ + * Error detection + **************************************/ +#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 1) +#include +#else +#ifndef assert +#define assert(condition) ((void)0) +#endif +#endif + +#define LZ4_STATIC_ASSERT(c) \ + { \ + enum { LZ4_static_assert = 1 / (int)(!!(c)) }; \ + } /* use after variable declarations */ + +#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 2) +#include +static int g_debuglog_enable = 1; +#define DEBUGLOG(l, ...) \ + { \ + if ((g_debuglog_enable) && (l <= LZ4_DEBUG)) { \ + fprintf(stderr, __FILE__ " %i: ", __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } \ + } +#else +#define DEBUGLOG(l, ...) \ + { \ + } /* disabled */ +#endif + +static int LZ4_isAligned(const void *ptr, size_t alignment) +{ + return ((size_t)ptr & (alignment - 1)) == 0; +} /*-************************************ - * Basic Types + * Types **************************************/ +#include #if defined(__cplusplus) || \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) #include @@ -193,6 +336,9 @@ typedef int32_t S32; typedef uint64_t U64; typedef uintptr_t uptrval; #else +#if UINT_MAX != 4294967295UL +#error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4" +#endif typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; @@ -207,9 +353,41 @@ typedef U64 reg_t; /* 64-bits in x32 mode */ typedef size_t reg_t; /* 32-bits in x32 mode */ #endif +typedef enum { + notLimited = 0, + limitedOutput = 1, + fillOutput = 2 +} limitedOutput_directive; + /*-************************************ * Reading and writing into memory **************************************/ + +/** + * LZ4 relies on memcpy with a constant size being inlined. In freestanding + * environments, the compiler can't assume the implementation of memcpy() is + * standard compliant, so it can't apply its specialized memcpy() inlining + * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze + * memcpy() as if it were standard compliant, so it can inline it in + * freestanding environments. This is needed when decompressing the Linux + * Kernel, for example. + */ +#if !defined(LZ4_memcpy) +#if defined(__GNUC__) && (__GNUC__ >= 4) +#define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size) +#else +#define LZ4_memcpy(dst, src, size) memcpy(dst, src, size) +#endif +#endif + +#if !defined(LZ4_memmove) +#if defined(__GNUC__) && (__GNUC__ >= 4) +#define LZ4_memmove __builtin_memmove +#else +#define LZ4_memmove memmove +#endif +#endif + static unsigned LZ4_isLittleEndian(void) { const union { @@ -219,6 +397,13 @@ static unsigned LZ4_isLittleEndian(void) return one.c[0]; } +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#define LZ4_PACK(__Declaration__) __Declaration__ __attribute__((__packed__)) +#elif defined(_MSC_VER) +#define LZ4_PACK(__Declaration__) \ + __pragma(pack(push, 1)) __Declaration__ __pragma(pack(pop)) +#endif + #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS == 2) /* lie to the compiler about data alignment; use with caution */ @@ -226,12 +411,10 @@ static U16 LZ4_read16(const void *memPtr) { return *(const U16 *)memPtr; } - static U32 LZ4_read32(const void *memPtr) { return *(const U32 *)memPtr; } - static reg_t LZ4_read_ARCH(const void *memPtr) { return *(const reg_t *)memPtr; @@ -241,7 +424,6 @@ static void LZ4_write16(void *memPtr, U16 value) { *(U16 *)memPtr = value; } - static void LZ4_write32(void *memPtr, U32 value) { *(U32 *)memPtr = value; @@ -252,71 +434,63 @@ static void LZ4_write32(void *memPtr, U32 value) /* __pack instructions are safer, but compiler specific, hence potentially * problematic for some compilers */ /* currently only defined for gcc and icc */ -typedef union { - U16 u16; - U32 u32; - reg_t uArch; -} __attribute__((packed)) unalign; +LZ4_PACK(typedef struct { U16 u16; }) LZ4_unalign16; +LZ4_PACK(typedef struct { U32 u32; }) LZ4_unalign32; +LZ4_PACK(typedef struct { reg_t uArch; }) LZ4_unalignST; static U16 LZ4_read16(const void *ptr) { - return ((const unalign *)ptr)->u16; + return ((const LZ4_unalign16 *)ptr)->u16; } - static U32 LZ4_read32(const void *ptr) { - return ((const unalign *)ptr)->u32; + return ((const LZ4_unalign32 *)ptr)->u32; } - static reg_t LZ4_read_ARCH(const void *ptr) { - return ((const unalign *)ptr)->uArch; + return ((const LZ4_unalignST *)ptr)->uArch; } static void LZ4_write16(void *memPtr, U16 value) { - ((unalign *)memPtr)->u16 = value; + ((LZ4_unalign16 *)memPtr)->u16 = value; } - static void LZ4_write32(void *memPtr, U32 value) { - ((unalign *)memPtr)->u32 = value; + ((LZ4_unalign32 *)memPtr)->u32 = value; } -#else /* safe and portable access through memcpy() */ +#else /* safe and portable access using memcpy() */ static U16 LZ4_read16(const void *memPtr) { U16 val; - - memcpy(&val, memPtr, sizeof(val)); + LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static U32 LZ4_read32(const void *memPtr) { U32 val; - - memcpy(&val, memPtr, sizeof(val)); + LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static reg_t LZ4_read_ARCH(const void *memPtr) { reg_t val; - - memcpy(&val, memPtr, sizeof(val)); + LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static void LZ4_write16(void *memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + LZ4_memcpy(memPtr, &value, sizeof(value)); } static void LZ4_write32(void *memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + LZ4_memcpy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ @@ -328,10 +502,22 @@ static U16 LZ4_readLE16(const void *memPtr) } else { const BYTE *p = (const BYTE *)memPtr; + return (U16)((U16)p[0] | (p[1] << 8)); + } +} - return (U16)((U16)p[0] + (p[1] << 8)); +#ifdef LZ4_STATIC_LINKING_ONLY_ENDIANNESS_INDEPENDENT_OUTPUT +static U32 LZ4_readLE32(const void *memPtr) +{ + if (LZ4_isLittleEndian()) { + return LZ4_read32(memPtr); + } + else { + const BYTE *p = (const BYTE *)memPtr; + return (U32)p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); } } +#endif static void LZ4_writeLE16(void *memPtr, U16 value) { @@ -340,7 +526,6 @@ static void LZ4_writeLE16(void *memPtr, U16 value) } else { BYTE *p = (BYTE *)memPtr; - p[0] = (BYTE)value; p[1] = (BYTE)(value >> 8); } @@ -348,74 +533,129 @@ static void LZ4_writeLE16(void *memPtr, U16 value) /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ -LZ4_FORCE_O2_INLINE_GCC_PPC64LE -void LZ4_wildCopy(void *dstPtr, const void *srcPtr, void *dstEnd) +LZ4_FORCE_INLINE +void LZ4_wildCopy8(void *dstPtr, const void *srcPtr, void *dstEnd) { BYTE *d = (BYTE *)dstPtr; const BYTE *s = (const BYTE *)srcPtr; BYTE *const e = (BYTE *)dstEnd; do { - memcpy(d, s, 8); + LZ4_memcpy(d, s, 8); d += 8; s += 8; } while (d < e); } -/*-************************************ - * Common Constants - **************************************/ -#define MINMATCH 4 +static const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4}; +static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3}; -#define WILDCOPYLENGTH 8 -#define LASTLITERALS 5 -#define MFLIMIT (WILDCOPYLENGTH + MINMATCH) -static const int LZ4_minLength = (MFLIMIT + 1); +#ifndef LZ4_FAST_DEC_LOOP +#if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64 +#define LZ4_FAST_DEC_LOOP 1 +#elif defined(__aarch64__) && defined(__APPLE__) +#define LZ4_FAST_DEC_LOOP 1 +#elif defined(__aarch64__) && !defined(__clang__) +/* On non-Apple aarch64, we disable this optimization for clang because + * on certain mobile chipsets, performance is reduced with clang. For + * more information refer to https://github.com/lz4/lz4/pull/707 */ +#define LZ4_FAST_DEC_LOOP 1 +#else +#define LZ4_FAST_DEC_LOOP 0 +#endif +#endif -#define KB *(1 << 10) -#define MB *(1 << 20) -#define GB *(1U << 30) +#if LZ4_FAST_DEC_LOOP + +LZ4_FORCE_INLINE void LZ4_memcpy_using_offset_base(BYTE *dstPtr, + const BYTE *srcPtr, + BYTE *dstEnd, + const size_t offset) +{ + assert(srcPtr + offset == dstPtr); + if (offset < 8) { + LZ4_write32(dstPtr, 0); /* silence an msan warning when offset==0 */ + dstPtr[0] = srcPtr[0]; + dstPtr[1] = srcPtr[1]; + dstPtr[2] = srcPtr[2]; + dstPtr[3] = srcPtr[3]; + srcPtr += inc32table[offset]; + LZ4_memcpy(dstPtr + 4, srcPtr, 4); + srcPtr -= dec64table[offset]; + dstPtr += 8; + } + else { + LZ4_memcpy(dstPtr, srcPtr, 8); + dstPtr += 8; + srcPtr += 8; + } -#define MAXD_LOG 16 -#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) + LZ4_wildCopy8(dstPtr, srcPtr, dstEnd); +} -#define ML_BITS 4 -#define ML_MASK ((1U << ML_BITS) - 1) -#define RUN_BITS (8 - ML_BITS) -#define RUN_MASK ((1U << RUN_BITS) - 1) +/* customized variant of memcpy, which can overwrite up to 32 bytes beyond + * dstEnd this version copies two times 16 bytes (instead of one time 32 bytes) + * because it must be compatible with offsets >= 16. */ +LZ4_FORCE_INLINE void LZ4_wildCopy32(void *dstPtr, const void *srcPtr, + void *dstEnd) +{ + BYTE *d = (BYTE *)dstPtr; + const BYTE *s = (const BYTE *)srcPtr; + BYTE *const e = (BYTE *)dstEnd; -/*-************************************ - * Error detection - **************************************/ -#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 1) -#include -#else -#ifndef assert -#define assert(condition) ((void)0) -#endif -#endif + do { + LZ4_memcpy(d, s, 16); + LZ4_memcpy(d + 16, s + 16, 16); + d += 32; + s += 32; + } while (d < e); +} -#define LZ4_STATIC_ASSERT(c) \ - { \ - enum { LZ4_static_assert = 1 / (int)(!!(c)) }; \ - } /* use after variable declarations */ +/* LZ4_memcpy_using_offset() presumes : + * - dstEnd >= dstPtr + MINMATCH + * - there is at least 12 bytes available to write after dstEnd */ +LZ4_FORCE_INLINE void LZ4_memcpy_using_offset(BYTE *dstPtr, const BYTE *srcPtr, + BYTE *dstEnd, const size_t offset) +{ + BYTE v[8]; -#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 2) -#include -static int g_debuglog_enable = 1; + assert(dstEnd >= dstPtr + MINMATCH); -#define DEBUGLOG(l, ...) \ - { \ - if ((g_debuglog_enable) && (l <= LZ4_DEBUG)) { \ - fprintf(stderr, __FILE__ ": "); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, " \n"); \ - } \ + switch (offset) { + case 1: + MEM_INIT(v, *srcPtr, 8); + break; + case 2: + LZ4_memcpy(v, srcPtr, 2); + LZ4_memcpy(&v[2], srcPtr, 2); +#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier \ + */ +#pragma warning(push) +#pragma warning( \ + disable : 6385) /* warning C6385: Reading invalid data from 'v'. */ +#endif + LZ4_memcpy(&v[4], v, 4); +#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier \ + */ +#pragma warning(pop) +#endif + break; + case 4: + LZ4_memcpy(v, srcPtr, 4); + LZ4_memcpy(&v[4], srcPtr, 4); + break; + default: + LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset); + return; } -#else -#define DEBUGLOG(l, ...) \ - { \ - } /* disabled */ + + LZ4_memcpy(dstPtr, v, 8); + dstPtr += 8; + while (dstPtr < dstEnd) { + LZ4_memcpy(dstPtr, v, 8); + dstPtr += 8; + } +} #endif /*-************************************ @@ -423,64 +663,89 @@ static int g_debuglog_enable = 1; **************************************/ static unsigned LZ4_NbCommonBytes(reg_t val) { + assert(val != 0); if (LZ4_isLittleEndian()) { if (sizeof(val) == 8) { -#if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) +#if defined(_MSC_VER) && (_MSC_VER >= 1800) && \ + (defined(_M_AMD64) && !defined(_M_ARM64EC)) && \ + !defined(LZ4_FORCE_SW_BITCOUNT) +/*-************************************************************************************************* + * ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications + *on ARM64 Windows 11. The ARM64EC ABI does not support AVX/AVX2/AVX512 + *instructions, nor their relevant intrinsics including _tzcnt_u64. Therefore, + *we need to neuter the _tzcnt_u64 code path for ARM64EC. + ****************************************************************************************************/ +#if defined(__clang__) && (__clang_major__ < 10) + /* Avoid undefined clang-cl intrinsics issue. + * See https://github.com/lz4/lz4/pull/1017 for details. */ + return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3; +#else + /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */ + return (unsigned)_tzcnt_u64(val) >> 3; +#endif +#elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; - _BitScanForward64(&r, (U64)val); - return (int)(r >> 3); -#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && \ + return (unsigned)r >> 3; +#elif (defined(__clang__) || \ + (defined(__GNUC__) && \ + ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); + return (unsigned)__builtin_ctzll((U64)val) >> 3; #else - static const int DeBruijnBytePos[64] = { - 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, - 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, - 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, - 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7}; - return DeBruijnBytePos[((U64)((val & -(long long)val) * - 0x0218A392CDABBD3FULL)) >> - 58]; + const U64 m = 0x0101010101010101ULL; + val ^= val - 1; + return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56); #endif } - else { /* 32 bits */ -#if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + else /* 32 bits */ { +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r; - _BitScanForward(&r, (U32)val); - return (int)(r >> 3); -#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && \ - !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); + return (unsigned)r >> 3; +#elif (defined(__clang__) || \ + (defined(__GNUC__) && \ + ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (unsigned)__builtin_ctz((U32)val) >> 3; #else - static const int DeBruijnBytePos[32] = { - 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, - 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1}; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> - 27]; + const U32 m = 0x01010101; + return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24; #endif } } - else { /* Big Endian CPU */ - if (sizeof(val) == 8) { /* 64-bits */ -#if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - - _BitScanReverse64(&r, val); - return (unsigned)(r >> 3); -#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && \ - !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); + else /* Big Endian CPU */ { + if (sizeof(val) == 8) { +#if (defined(__clang__) || \ + (defined(__GNUC__) && \ + ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (unsigned)__builtin_clzll((U64)val) >> 3; +#else +#if 1 + /* this method is probably faster, + * but adds a 128 bytes lookup table */ + static const unsigned char ctz7_tab[128] = { + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, + 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, + 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, + 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, + 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, + 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, + 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + }; + U64 const mask = 0x0101010101010101ULL; + U64 const t = (((val >> 8) - mask) | val) & mask; + return ctz7_tab[(t * 0x0080402010080402ULL) >> 57]; #else + /* this method doesn't consume memory space like the previous one, + * but it contains several branches, + * that may end up slowing execution */ static const U32 by32 = - sizeof(val) * - 4; /* 32 on 64 bits (goal), 16 on 32 bits. - Just to avoid some static analyzer complaining about shift - by 32 on 32-bits target. Note that this code path is never - triggered in 32-bits mode. */ + sizeof(val) * 4; /* 32 on 64 bits (goal), 16 on 32 bits. +Just to avoid some static analyzer complaining about shift by 32 on 32-bits +target. Note that this code path is never triggered in 32-bits mode. */ unsigned r; - if (!(val >> by32)) { r = 4; } @@ -497,30 +762,21 @@ static unsigned LZ4_NbCommonBytes(reg_t val) } r += (!val); return r; +#endif #endif } - else { /* 32 bits */ -#if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - - _BitScanReverse(&r, (unsigned long)val); - return (unsigned)(r >> 3); -#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && \ + else /* 32 bits */ { +#if (defined(__clang__) || \ + (defined(__GNUC__) && \ + ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); + return (unsigned)__builtin_clz((U32)val) >> 3; #else - unsigned r; - - if (!(val >> 16)) { - r = 2; - val >>= 8; - } - else { - r = 0; - val >>= 24; - } - r += (!val); - return r; + val >>= 8; + val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) | + (val + 0x00FF0000)) >> + 24; + return (unsigned)val ^ 3; #endif } } @@ -534,7 +790,6 @@ unsigned LZ4_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *pInLimit) if (likely(pIn < pInLimit - (STEPSIZE - 1))) { reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); - if (!diff) { pIn += STEPSIZE; pMatch += STEPSIZE; @@ -546,7 +801,6 @@ unsigned LZ4_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *pInLimit) while (likely(pIn < pInLimit - (STEPSIZE - 1))) { reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); - if (!diff) { pIn += STEPSIZE; pMatch += STEPSIZE; @@ -571,7 +825,6 @@ unsigned LZ4_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *pInLimit) } #ifndef LZ4_COMMONDEFS_ONLY - /*-************************************ * Local Constants **************************************/ @@ -582,11 +835,6 @@ static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run /*-************************************ * Local Structures and types **************************************/ -typedef enum { - notLimited = 0, - limitedOutput = 1, - fillOutput = 2 -} limitedOutput_directive; typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; /** @@ -602,10 +850,10 @@ typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere * else in memory, starting at ctx->dictionary with length * ctx->dictSize. - * - usingDictCtx : Like usingExtDict, but everything concerning the preceding - * content is in a separate context, pointed to by - * ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table - * entries in the current context that refer to positions + * - usingDictCtx : Everything concerning the preceding content is + * in a separate context, pointed to by ctx->dictCtx. + * ctx->dictionary, ctx->dictSize, and table entries + * in the current context that refer to positions * preceding the beginning of the current compression are * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx * ->dictSize describe the location and size of the preceding @@ -620,9 +868,6 @@ typedef enum { } dict_directive; typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; -typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; -typedef enum { full = 0, partial = 1 } earlyEnd_directive; - /*-************************************ * Local Utils **************************************/ @@ -630,26 +875,43 @@ int LZ4_versionNumber(void) { return LZ4_VERSION_NUMBER; } - const char *LZ4_versionString(void) { return LZ4_VERSION_STRING; } - int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } - int LZ4_sizeofState(void) { - return LZ4_STREAMSIZE; + return sizeof(LZ4_stream_t); +} + +/*-**************************************** + * Internal Definitions, used only in Tests + *******************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +int LZ4_compress_forceExtDict(LZ4_stream_t *LZ4_dict, const char *source, + char *dest, int srcSize); + +int LZ4_decompress_safe_forceExtDict(const char *source, char *dest, + int compressedSize, int maxOutputSize, + const void *dictStart, size_t dictSize); +int LZ4_decompress_safe_partial_forceExtDict( + const char *source, char *dest, int compressedSize, int targetOutputSize, + int dstCapacity, const void *dictStart, size_t dictSize); +#if defined(__cplusplus) } +#endif /*-****************************** * Compression functions ********************************/ -static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { if (tableType == byU16) return ((sequence * 2654435761U) >> @@ -658,16 +920,17 @@ static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) return ((sequence * 2654435761U) >> ((MINMATCH * 8) - LZ4_HASHLOG)); } -static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { - static const U64 prime5bytes = 889523592379ULL; - static const U64 prime8bytes = 11400714785074694791ULL; const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG + 1 : LZ4_HASHLOG; - - if (LZ4_isLittleEndian()) + if (LZ4_isLittleEndian()) { + const U64 prime5bytes = 889523592379ULL; return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); - else + } + else { + const U64 prime8bytes = 11400714785074694791ULL; return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); + } } LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void *const p, @@ -675,72 +938,81 @@ LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void *const p, { if ((sizeof(reg_t) == 8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + +#ifdef LZ4_STATIC_LINKING_ONLY_ENDIANNESS_INDEPENDENT_OUTPUT + return LZ4_hash4(LZ4_readLE32(p), tableType); +#else return LZ4_hash4(LZ4_read32(p), tableType); +#endif } -static void LZ4_putIndexOnHash(U32 idx, U32 h, void *tableBase, - tableType_t const tableType) +LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void *tableBase, + tableType_t const tableType) { switch (tableType) { - default: /* fallthrough */ - case clearedTable: /* fallthrough */ - case byPtr: { /* illegal! */ + default: /* fallthrough */ + case clearedTable: { /* illegal! */ assert(0); return; } + case byPtr: { + const BYTE **hashTable = (const BYTE **)tableBase; + hashTable[h] = NULL; + return; + } case byU32: { U32 *hashTable = (U32 *)tableBase; - - hashTable[h] = idx; + hashTable[h] = 0; return; } case byU16: { U16 *hashTable = (U16 *)tableBase; - - assert(idx < 65536); - hashTable[h] = (U16)idx; + hashTable[h] = 0; return; } } } -static void LZ4_putPositionOnHash(const BYTE *p, U32 h, void *tableBase, - tableType_t const tableType, - const BYTE *srcBase) +LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void *tableBase, + tableType_t const tableType) { switch (tableType) { - case clearedTable: { /* illegal! */ + default: /* fallthrough */ + case clearedTable: /* fallthrough */ + case byPtr: { /* illegal! */ assert(0); return; } - case byPtr: { - const BYTE **hashTable = (const BYTE **)tableBase; - - hashTable[h] = p; - return; - } case byU32: { U32 *hashTable = (U32 *)tableBase; - - hashTable[h] = (U32)(p - srcBase); + hashTable[h] = idx; return; } case byU16: { U16 *hashTable = (U16 *)tableBase; - - hashTable[h] = (U16)(p - srcBase); + assert(idx < 65536); + hashTable[h] = (U16)idx; return; } } } +/* LZ4_putPosition*() : only used in byPtr mode */ +LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE *p, U32 h, + void *tableBase, + tableType_t const tableType) +{ + const BYTE **const hashTable = (const BYTE **)tableBase; + assert(tableType == byPtr); + (void)tableType; + hashTable[h] = p; +} + LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE *p, void *tableBase, - tableType_t tableType, - const BYTE *srcBase) + tableType_t tableType) { U32 const h = LZ4_hashPosition(p, tableType); - - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); + LZ4_putPositionOnHash(p, h, tableBase, tableType); } /* LZ4_getIndexOnHash() : @@ -749,19 +1021,17 @@ LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE *p, void *tableBase, * Assumption 1 : only valid if tableType == byU32 or byU16. * Assumption 2 : h is presumed valid (within limits of hash table) */ -static U32 LZ4_getIndexOnHash(U32 h, const void *tableBase, - tableType_t tableType) +LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void *tableBase, + tableType_t tableType) { LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); if (tableType == byU32) { const U32 *const hashTable = (const U32 *)tableBase; - assert(h < (1U << (LZ4_MEMORY_USAGE - 2))); return hashTable[h]; } if (tableType == byU16) { const U16 *const hashTable = (const U16 *)tableBase; - assert(h < (1U << (LZ4_MEMORY_USAGE - 1))); return hashTable[h]; } @@ -770,34 +1040,21 @@ static U32 LZ4_getIndexOnHash(U32 h, const void *tableBase, } static const BYTE *LZ4_getPositionOnHash(U32 h, const void *tableBase, - tableType_t tableType, - const BYTE *srcBase) + tableType_t tableType) { - if (tableType == byPtr) { + assert(tableType == byPtr); + (void)tableType; + { const BYTE *const *hashTable = (const BYTE *const *)tableBase; - return hashTable[h]; } - if (tableType == byU32) { - const U32 *const hashTable = (const U32 *)tableBase; - - return hashTable[h] + srcBase; - } - { - const U16 *const hashTable = (const U16 *)tableBase; - - return hashTable[h] + srcBase; - } /* default, to ensure a return */ } -LZ4_FORCE_INLINE const BYTE *LZ4_getPosition(const BYTE *p, - const void *tableBase, - tableType_t tableType, - const BYTE *srcBase) +LZ4_FORCE_INLINE const BYTE * +LZ4_getPosition(const BYTE *p, const void *tableBase, tableType_t tableType) { U32 const h = LZ4_hashPosition(p, tableType); - - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); + return LZ4_getPositionOnHash(h, tableBase, tableType); } LZ4_FORCE_INLINE void LZ4_prepareTable(LZ4_stream_t_internal *const cctx, @@ -808,25 +1065,27 @@ LZ4_FORCE_INLINE void LZ4_prepareTable(LZ4_stream_t_internal *const cctx, * therefore safe to use no matter what mode we're in. Otherwise, we figure * out if it's safe to leave as is or whether it needs to be reset. */ - if (cctx->tableType != clearedTable) { - if (cctx->tableType != tableType || - (tableType == byU16 && - cctx->currentOffset + inputSize >= 0xFFFFU) || - (tableType == byU32 && cctx->currentOffset > 1 GB) || + if ((tableType_t)cctx->tableType != clearedTable) { + assert(inputSize >= 0); + if ((tableType_t)cctx->tableType != tableType || + ((tableType == byU16) && + cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU) || + ((tableType == byU32) && cctx->currentOffset > 1 GB) || tableType == byPtr || inputSize >= 4 KB) { DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx); MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE); cctx->currentOffset = 0; - cctx->tableType = clearedTable; + cctx->tableType = (U32)clearedTable; } else { DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)"); } } - /* Adding a gap, so all previous entries are > MAX_DISTANCE back, is faster - * than compressing without a gap. However, compressing with - * currentOffset == 0 is faster still, so we preserve that case. + /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, + * is faster than compressing without a gap. + * However, compressing with currentOffset == 0 is faster still, + * so we preserve that case. */ if (cctx->currentOffset != 0 && tableType == byU32) { DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset"); @@ -839,16 +1098,21 @@ LZ4_FORCE_INLINE void LZ4_prepareTable(LZ4_stream_t_internal *const cctx, cctx->dictSize = 0; } -/** LZ4_compress_generic() : - inlined, to ensure branches are decided at compilation time */ -LZ4_FORCE_INLINE int LZ4_compress_generic( +/** LZ4_compress_generic_validated() : + * inlined, to ensure branches are decided at compilation time. + * The following conditions are presumed already validated: + * - source != NULL + * - inputSize > 0 + */ +LZ4_FORCE_INLINE int LZ4_compress_generic_validated( LZ4_stream_t_internal *const cctx, const char *const source, char *const dest, const int inputSize, - int *inputConsumed, /* only written when outputLimited == fillOutput */ - const int maxOutputSize, const limitedOutput_directive outputLimited, + int *inputConsumed, /* only written when outputDirective == fillOutput */ + const int maxOutputSize, const limitedOutput_directive outputDirective, const tableType_t tableType, const dict_directive dictDirective, - const dictIssue_directive dictIssue, const U32 acceleration) + const dictIssue_directive dictIssue, const int acceleration) { + int result; const BYTE *ip = (const BYTE *)source; U32 const startIndex = cctx->currentOffset; @@ -864,13 +1128,13 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with - index in current context */ + indexes in current context */ int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ - const BYTE *const dictEnd = dictionary + dictSize; + const BYTE *const dictEnd = dictionary ? dictionary + dictSize : dictionary; const BYTE *anchor = (const BYTE *)source; const BYTE *const iend = ip + inputSize; const BYTE *const mflimitPlusOne = iend - MFLIMIT + 1; @@ -878,7 +1142,8 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( /* the dictCtx currentOffset is indexed on the start of the dictionary, * while a dictionary in the current context precedes the currentOffset */ - const BYTE *dictBase = dictDirective == usingDictCtx + const BYTE *dictBase = (dictionary == NULL) ? NULL + : (dictDirective == usingDictCtx) ? dictionary + dictSize - dictCtx->currentOffset : dictionary + dictSize - startIndex; @@ -888,18 +1153,20 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( U32 offset = 0; U32 forwardH; - DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, - tableType); - /* Init conditions */ - if (outputLimited == fillOutput && maxOutputSize < 1) - return 0; /* Impossible to store anything */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) - return 0; /* Unsupported inputSize, too large (or negative) */ - if ((tableType == byU16) && (inputSize >= LZ4_64Klimit)) - return 0; /* Size too large (not within 64K limit) */ + DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", + inputSize, tableType); + assert(ip != NULL); + if (tableType == byU16) + assert(inputSize < + LZ4_64Klimit); /* Size too large (not within 64K limit) */ if (tableType == byPtr) assert(dictDirective == noDict); /* only supported use case with byPtr */ + /* If init conditions are not met, we don't have to mark stream + * as having dirty context, since no action was taken yet */ + if (outputDirective == fillOutput && maxOutputSize < 1) { + return 0; + } /* Impossible to store anything */ assert(acceleration >= 1); lowLimit = @@ -916,31 +1183,38 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( cctx->dictSize += (U32)inputSize; } cctx->currentOffset += (U32)inputSize; - cctx->tableType = tableType; + cctx->tableType = (U32)tableType; if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ /* First Byte */ - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - ip++; - forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ + { + U32 const h = LZ4_hashPosition(ip, tableType); + if (tableType == byPtr) { + LZ4_putPositionOnHash(ip, h, cctx->hashTable, byPtr); + } + else { + LZ4_putIndexOnHash(startIndex, h, cctx->hashTable, tableType); + } + } + ip++; + forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ for (;;) { const BYTE *match; BYTE *token; + const BYTE *filledIp; /* Find a match */ if (tableType == byPtr) { const BYTE *forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - + int step = 1; + int searchMatchNb = acceleration << LZ4_skipTrigger; do { U32 const h = forwardH; - ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); @@ -949,20 +1223,18 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( goto _last_literals; assert(ip < mflimitPlusOne); - match = - LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType); forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType); - } while ((match + MAX_DISTANCE < ip) || + } while ((match + LZ4_DISTANCE_MAX < ip) || (LZ4_read32(match) != LZ4_read32(ip))); } else { /* byU32, byU16 */ const BYTE *forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - + int step = 1; + int searchMatchNb = acceleration << LZ4_skipTrigger; do { U32 const h = forwardH; U32 const current = (U32)(forwardIp - base); @@ -1002,6 +1274,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( "startIndex=%5u", matchIndex, startIndex); assert(startIndex - matchIndex >= MINMATCH); + assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; } @@ -1016,16 +1289,20 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); - if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) - continue; /* match outside of valid area */ + DEBUGLOG(7, "candidate at pos=%u (offset=%u \n", matchIndex, + current - matchIndex); + if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { + continue; + } /* match outside of valid area */ assert(matchIndex < current); - if ((tableType != byU16) && - (matchIndex + MAX_DISTANCE < current)) - continue; /* too far */ - if (tableType == byU16) - assert((current - matchIndex) <= - MAX_DISTANCE); /* too_far presumed impossible with - byU16 */ + if (((tableType != byU16) || + (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX)) && + (matchIndex + LZ4_DISTANCE_MAX < current)) { + continue; + } /* too far */ + assert( + (current - matchIndex) <= + LZ4_DISTANCE_MAX); /* match now expected within distance */ if (LZ4_read32(match) == LZ4_read32(ip)) { if (maybe_extMem) @@ -1037,36 +1314,41 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( } /* Catch up */ - while (((ip > anchor) & (match > lowLimit)) && - (unlikely(ip[-1] == match[-1]))) { - ip--; - match--; + filledIp = ip; + assert(ip > anchor); /* this is always true as ip has been advanced + before entering the main loop */ + if ((match > lowLimit) && unlikely(ip[-1] == match[-1])) { + do { + ip--; + match--; + } while (((ip > anchor) & (match > lowLimit)) && + (unlikely(ip[-1] == match[-1]))); } /* Encode Literals */ { unsigned const litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited == + if ((outputDirective == limitedOutput) && /* Check output buffer overflow */ (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength / 255) > - olimit))) - return 0; - if ((outputLimited == fillOutput) && - (unlikely( - op + (litLength + 240) / 255 /* litlen */ + - litLength /* literals */ + 2 /* offset */ + - 1 /* token */ + MFLIMIT - MINMATCH - /* min last literals so last match is <= end - MFLIMIT */ - > olimit))) { + olimit))) { + return 0; /* cannot compress within `dst` budget. Stored indexes + in hash table are nonetheless fine */ + } + if ((outputDirective == fillOutput) && + (unlikely(op + (litLength + 240) / 255 /* litlen */ + + litLength /* literals */ + 2 /* offset */ + + 1 /* token */ + MFLIMIT - + MINMATCH /* min last literals so last match is <= + end - MFLIMIT */ + > olimit))) { op--; goto _last_literals; } if (litLength >= RUN_MASK) { - int len = (int)litLength - RUN_MASK; - + unsigned len = litLength - RUN_MASK; *token = (RUN_MASK << ML_BITS); for (; len >= 255; len -= 255) *op++ = 255; @@ -1076,7 +1358,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( *token = (BYTE)(litLength << ML_BITS); /* Copy Literals */ - LZ4_wildCopy(op, anchor, op + litLength); + LZ4_wildCopy8(op, anchor, op + litLength); op += litLength; DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i", (int)(anchor - (const BYTE *)source), litLength, @@ -1095,9 +1377,10 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( * higher 4-bits for literal length supposed already written */ - if ((outputLimited == fillOutput) && - (op + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH - /* min last literals so last match is <= end - MFLIMIT */ + if ((outputDirective == fillOutput) && + (op + 2 /* offset */ + 1 /* token */ + MFLIMIT - + MINMATCH /* min last literals so last match is <= end - MFLIMIT + */ > olimit)) { /* the match was too close to the end, rewind and go to last * literals */ @@ -1109,14 +1392,14 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( if (maybe_extMem) { /* static test */ DEBUGLOG(6, " with offset=%u (ext if > %i)", offset, (int)(ip - (const BYTE *)source)); - assert(offset <= MAX_DISTANCE && offset > 0); + assert(offset <= LZ4_DISTANCE_MAX && offset > 0); LZ4_writeLE16(op, (U16)offset); op += 2; } else { DEBUGLOG(6, " with offset=%u (same segment)", (U32)(ip - match)); - assert(ip - match <= MAX_DISTANCE); + assert(ip - match <= LZ4_DISTANCE_MAX); LZ4_writeLE16(op, (U16)(ip - match)); op += 2; } @@ -1129,12 +1412,11 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( dictDirective == usingDictCtx) && (lowLimit == dictionary) /* match within extDict */) { const BYTE *limit = ip + (dictEnd - match); - assert(dictEnd > match); if (limit > matchlimit) limit = matchlimit; matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); - ip += MINMATCH + matchCode; + ip += (size_t)matchCode + MINMATCH; if (ip == limit) { unsigned const more = LZ4_count(limit, (const BYTE *)source, matchlimit); @@ -1148,24 +1430,43 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( else { matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); - ip += MINMATCH + matchCode; + ip += (size_t)matchCode + MINMATCH; DEBUGLOG(6, " with matchLength=%u", matchCode + MINMATCH); } - if ((outputLimited) && /* Check output buffer overflow */ - (unlikely(op + (1 + LASTLITERALS) + (matchCode >> 8) > + if ((outputDirective) && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode + 240) / 255 > olimit))) { - if (outputLimited == limitedOutput) - return 0; - if (outputLimited == fillOutput) { + if (outputDirective == fillOutput) { /* Match description too long : reduce it */ U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + - ((U32)(olimit - op) - 2 - 1 - LASTLITERALS) * 255; + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255; ip -= matchCode - newMatchCode; + assert(newMatchCode < matchCode); matchCode = newMatchCode; + if (unlikely(ip <= filledIp)) { + /* We have already filled up to filledIp so if ip ends + * up less than filledIp we have positions in the hash + * table beyond the current position. This is a problem + * if we reuse the hash table. So we have to remove + * these positions from the hash table. + */ + const BYTE *ptr; + DEBUGLOG(5, "Clearing %u positions", + (U32)(filledIp - ip)); + for (ptr = ip; ptr <= filledIp; ++ptr) { + U32 const h = LZ4_hashPosition(ptr, tableType); + LZ4_clearHash(h, cctx->hashTable, tableType); + } + } + } + else { + assert(outputDirective == limitedOutput); + return 0; /* cannot compress within `dst` budget. Stored + indexes in hash table are nonetheless fine */ } } if (matchCode >= ML_MASK) { @@ -1183,6 +1484,9 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( else *token += (BYTE)(matchCode); } + /* Ensure we have enough space for the last literals. */ + assert( + !(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit)); anchor = ip; @@ -1191,14 +1495,23 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( break; /* Fill table */ - LZ4_putPosition(ip - 2, cctx->hashTable, tableType, base); + { + U32 const h = LZ4_hashPosition(ip - 2, tableType); + if (tableType == byPtr) { + LZ4_putPositionOnHash(ip - 2, h, cctx->hashTable, byPtr); + } + else { + U32 const idx = (U32)((ip - 2) - base); + LZ4_putIndexOnHash(idx, h, cctx->hashTable, tableType); + } + } /* Test next position */ if (tableType == byPtr) { - match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - if ((match + MAX_DISTANCE >= ip) && + match = LZ4_getPosition(ip, cctx->hashTable, tableType); + LZ4_putPosition(ip, cctx->hashTable, tableType); + if ((match + LZ4_DISTANCE_MAX >= ip) && (LZ4_read32(match) == LZ4_read32(ip))) { token = op++; *token = 0; @@ -1214,6 +1527,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( if (dictDirective == usingDictCtx) { if (matchIndex < startIndex) { /* there was no match, try the dictionary */ + assert(tableType == byU32); matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); match = dictBase + matchIndex; @@ -1229,6 +1543,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( } else if (dictDirective == usingExtDict) { if (matchIndex < startIndex) { + assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; /* required for match length counter */ @@ -1246,9 +1561,10 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( assert(matchIndex < current); if (((dictIssue == dictSmall) ? (matchIndex >= prefixIdxLimit) : 1) && - ((tableType == byU16) + (((tableType == byU16) && + (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 - : (matchIndex + MAX_DISTANCE >= current)) && + : (matchIndex + LZ4_DISTANCE_MAX >= current)) && (LZ4_read32(match) == LZ4_read32(ip))) { token = op++; *token = 0; @@ -1269,20 +1585,24 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( /* Encode Last Literals */ { size_t lastRun = (size_t)(iend - anchor); - - if ((outputLimited) && /* Check output buffer overflow */ + if ((outputDirective) && /* Check output buffer overflow */ (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > olimit)) { - if (outputLimited == fillOutput) { + if (outputDirective == fillOutput) { /* adapt lastRun to fill 'dst' */ - lastRun = (olimit - op) - 1; - lastRun -= (lastRun + 240) / 255; + assert(olimit >= op); + lastRun = (size_t)(olimit - op) - 1 /*token*/; + lastRun -= (lastRun + 256 - RUN_MASK) / + 256; /*additional length tokens*/ + } + else { + assert(outputDirective == limitedOutput); + return 0; /* cannot compress within `dst` budget. Stored indexes + in hash table are nonetheless fine */ } - if (outputLimited == limitedOutput) - return 0; } + DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun); if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; for (; accumulator >= 255; accumulator -= 255) *op++ = 255; @@ -1291,28 +1611,72 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( else { *op++ = (BYTE)(lastRun << ML_BITS); } - memcpy(op, anchor, lastRun); + LZ4_memcpy(op, anchor, lastRun); ip = anchor + lastRun; op += lastRun; } - if (outputLimited == fillOutput) { + if (outputDirective == fillOutput) { *inputConsumed = (int)(((const char *)ip) - source); } + result = (int)(((char *)op) - dest); + assert(result > 0); DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", - inputSize, (int)(((char *)op) - dest)); - return (int)(((char *)op) - dest); + inputSize, result); + return result; +} + +/** LZ4_compress_generic() : + * inlined, to ensure branches are decided at compilation time; + * takes care of src == (NULL, 0) + * and forward the rest to LZ4_compress_generic_validated */ +LZ4_FORCE_INLINE int LZ4_compress_generic( + LZ4_stream_t_internal *const cctx, const char *const src, char *const dst, + const int srcSize, + int *inputConsumed, /* only written when outputDirective == fillOutput */ + const int dstCapacity, const limitedOutput_directive outputDirective, + const tableType_t tableType, const dict_directive dictDirective, + const dictIssue_directive dictIssue, const int acceleration) +{ + DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i", srcSize, + dstCapacity); + + if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { + return 0; + } /* Unsupported srcSize, too large (or negative) */ + if (srcSize == 0) { /* src == NULL supported if srcSize == 0 */ + if (outputDirective != notLimited && dstCapacity <= 0) + return 0; /* no output, can't write anything */ + DEBUGLOG(5, "Generating an empty block"); + assert(outputDirective == notLimited || dstCapacity >= 1); + assert(dst != NULL); + dst[0] = 0; + if (outputDirective == fillOutput) { + assert(inputConsumed != NULL); + *inputConsumed = 0; + } + return 1; + } + assert(src != NULL); + + return LZ4_compress_generic_validated( + cctx, src, dst, srcSize, + inputConsumed, /* only written into if outputDirective == fillOutput */ + dstCapacity, outputDirective, tableType, dictDirective, dictIssue, + acceleration); } int LZ4_compress_fast_extState(void *state, const char *source, char *dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t_internal *ctx = &((LZ4_stream_t *)state)->internal_donotuse; - + LZ4_stream_t_internal *const ctx = + &LZ4_initStream(state, sizeof(LZ4_stream_t))->internal_donotuse; + assert(ctx != NULL); if (acceleration < 1) - acceleration = ACCELERATION_DEFAULT; - LZ4_resetStream((LZ4_stream_t *)state); + acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) + acceleration = LZ4_ACCELERATION_MAX; if (maxOutputSize >= LZ4_compressBound(inputSize)) { if (inputSize < LZ4_64Klimit) { return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, @@ -1321,7 +1685,7 @@ int LZ4_compress_fast_extState(void *state, const char *source, char *dest, } else { const tableType_t tableType = - ((sizeof(void *) == 4) && ((uptrval)source > MAX_DISTANCE)) + ((sizeof(void *) == 4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32; return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, @@ -1331,14 +1695,13 @@ int LZ4_compress_fast_extState(void *state, const char *source, char *dest, } else { if (inputSize < LZ4_64Klimit) { - ; return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); } else { const tableType_t tableType = - ((sizeof(void *) == 4) && ((uptrval)source > MAX_DISTANCE)) + ((sizeof(void *) == 4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32; return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, @@ -1361,15 +1724,17 @@ int LZ4_compress_fast_extState_fastReset(void *state, const char *src, char *dst, int srcSize, int dstCapacity, int acceleration) { - LZ4_stream_t_internal *ctx = &((LZ4_stream_t *)state)->internal_donotuse; - + LZ4_stream_t_internal *const ctx = + &((LZ4_stream_t *)state)->internal_donotuse; if (acceleration < 1) - acceleration = ACCELERATION_DEFAULT; + acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) + acceleration = LZ4_ACCELERATION_MAX; + assert(ctx != NULL); if (dstCapacity >= LZ4_compressBound(srcSize)) { if (srcSize < LZ4_64Klimit) { const tableType_t tableType = byU16; - LZ4_prepareTable(ctx, srcSize, tableType); if (ctx->currentOffset) { return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, @@ -1384,7 +1749,7 @@ int LZ4_compress_fast_extState_fastReset(void *state, const char *src, } else { const tableType_t tableType = - ((sizeof(void *) == 4) && ((uptrval)src > MAX_DISTANCE)) + ((sizeof(void *) == 4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; LZ4_prepareTable(ctx, srcSize, tableType); @@ -1396,7 +1761,6 @@ int LZ4_compress_fast_extState_fastReset(void *state, const char *src, else { if (srcSize < LZ4_64Klimit) { const tableType_t tableType = byU16; - LZ4_prepareTable(ctx, srcSize, tableType); if (ctx->currentOffset) { return LZ4_compress_generic( @@ -1411,7 +1775,7 @@ int LZ4_compress_fast_extState_fastReset(void *state, const char *src, } else { const tableType_t tableType = - ((sizeof(void *) == 4) && ((uptrval)src > MAX_DISTANCE)) + ((sizeof(void *) == 4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; LZ4_prepareTable(ctx, srcSize, tableType); @@ -1422,23 +1786,21 @@ int LZ4_compress_fast_extState_fastReset(void *state, const char *src, } } -int LZ4_compress_fast(const char *source, char *dest, int inputSize, - int maxOutputSize, int acceleration) +int LZ4_compress_fast(const char *src, char *dest, int srcSize, int dstCapacity, + int acceleration) { int result; - #if (LZ4_HEAPMODE) - LZ4_stream_t *ctxPtr = - ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ - + LZ4_stream_t *const ctxPtr = (LZ4_stream_t *)ALLOC( + sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ if (ctxPtr == NULL) return 0; #else LZ4_stream_t ctx; LZ4_stream_t *const ctxPtr = &ctx; #endif - result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, - maxOutputSize, acceleration); + result = LZ4_compress_fast_extState(ctxPtr, src, dest, srcSize, dstCapacity, + acceleration); #if (LZ4_HEAPMODE) FREEMEM(ctxPtr); @@ -1446,83 +1808,78 @@ int LZ4_compress_fast(const char *source, char *dest, int inputSize, return result; } -int LZ4_compress_default(const char *source, char *dest, int inputSize, - int maxOutputSize) -{ - return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); -} - -/* hidden debug function */ -/* strangely enough, gcc generates faster code when this function is - * uncommented, even if unused */ -int LZ4_compress_fast_force(const char *source, char *dest, int inputSize, - int maxOutputSize, int acceleration) +int LZ4_compress_default(const char *src, char *dst, int srcSize, + int dstCapacity) { - LZ4_stream_t ctx; - - LZ4_resetStream(&ctx); - - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, - inputSize, NULL, maxOutputSize, - limitedOutput, byU16, noDict, noDictIssue, - acceleration); - else - return LZ4_compress_generic( - &ctx.internal_donotuse, source, dest, inputSize, NULL, - maxOutputSize, limitedOutput, sizeof(void *) == 8 ? byU32 : byPtr, - noDict, noDictIssue, acceleration); + return LZ4_compress_fast(src, dst, srcSize, dstCapacity, 1); } /* Note!: This function leaves the stream in an unclean/broken state! * It is not safe to subsequently use the same state with a _fastReset() or * _continue() call without resetting it. */ -static int LZ4_compress_destSize_extState(LZ4_stream_t *state, const char *src, - char *dst, int *srcSizePtr, - int targetDstSize) +static int LZ4_compress_destSize_extState_internal(LZ4_stream_t *state, + const char *src, char *dst, + int *srcSizePtr, + int targetDstSize, + int acceleration) { - LZ4_resetStream(state); + void *const s = LZ4_initStream(state, sizeof(*state)); + assert(s != NULL); + (void)s; if (targetDstSize >= LZ4_compressBound( *srcSizePtr)) { /* compression success is guaranteed */ return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, - targetDstSize, 1); + targetDstSize, acceleration); } else { if (*srcSizePtr < LZ4_64Klimit) { - return LZ4_compress_generic( - &state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, - targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1); + return LZ4_compress_generic(&state->internal_donotuse, src, dst, + *srcSizePtr, srcSizePtr, targetDstSize, + fillOutput, byU16, noDict, noDictIssue, + acceleration); } else { - tableType_t const tableType = - ((sizeof(void *) == 4) && ((uptrval)src > MAX_DISTANCE)) + tableType_t const addrMode = + ((sizeof(void *) == 4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; - return LZ4_compress_generic( - &state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, - targetDstSize, fillOutput, tableType, noDict, noDictIssue, 1); + return LZ4_compress_generic(&state->internal_donotuse, src, dst, + *srcSizePtr, srcSizePtr, targetDstSize, + fillOutput, addrMode, noDict, + noDictIssue, acceleration); } } } +int LZ4_compress_destSize_extState(void *state, const char *src, char *dst, + int *srcSizePtr, int targetDstSize, + int acceleration) +{ + int const r = LZ4_compress_destSize_extState_internal( + (LZ4_stream_t *)state, src, dst, srcSizePtr, targetDstSize, + acceleration); + /* clean the state on exit */ + LZ4_initStream(state, sizeof(LZ4_stream_t)); + return r; +} + int LZ4_compress_destSize(const char *src, char *dst, int *srcSizePtr, int targetDstSize) { #if (LZ4_HEAPMODE) - LZ4_stream_t *ctx = (LZ4_stream_t *)ALLOC( + LZ4_stream_t *const ctx = (LZ4_stream_t *)ALLOC( sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ - if (ctx == NULL) return 0; #else LZ4_stream_t ctxBody; - LZ4_stream_t *ctx = &ctxBody; + LZ4_stream_t *const ctx = &ctxBody; #endif - int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, - targetDstSize); + int result = LZ4_compress_destSize_extState_internal( + ctx, src, dst, srcSizePtr, targetDstSize, 1); #if (LZ4_HEAPMODE) FREEMEM(ctx); @@ -1534,25 +1891,53 @@ int LZ4_compress_destSize(const char *src, char *dst, int *srcSizePtr, * Streaming functions ********************************/ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_stream_t *LZ4_createStream(void) { - LZ4_stream_t *lz4s = (LZ4_stream_t *)ALLOC(sizeof(LZ4_stream_t)); - - LZ4_STATIC_ASSERT( - LZ4_STREAMSIZE >= - sizeof(LZ4_stream_t_internal)); /* A compilation error here means - LZ4_STREAMSIZE is not large enough */ + LZ4_stream_t *const lz4s = (LZ4_stream_t *)ALLOC(sizeof(LZ4_stream_t)); + LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal)); DEBUGLOG(4, "LZ4_createStream %p", lz4s); if (lz4s == NULL) return NULL; - LZ4_resetStream(lz4s); + LZ4_initStream(lz4s, sizeof(*lz4s)); return lz4s; } +#endif +static size_t LZ4_stream_t_alignment(void) +{ +#if LZ4_ALIGN_TEST + typedef struct { + char c; + LZ4_stream_t t; + } t_a; + return sizeof(t_a) - sizeof(LZ4_stream_t); +#else + return 1; /* effectively disabled */ +#endif +} + +LZ4_stream_t *LZ4_initStream(void *buffer, size_t size) +{ + DEBUGLOG(5, "LZ4_initStream"); + if (buffer == NULL) { + return NULL; + } + if (size < sizeof(LZ4_stream_t)) { + return NULL; + } + if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) + return NULL; + MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal)); + return (LZ4_stream_t *)buffer; +} + +/* resetStream is now deprecated, + * prefer initStream() which is more general */ void LZ4_resetStream(LZ4_stream_t *LZ4_stream) { DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream); - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal)); } void LZ4_resetStream_fast(LZ4_stream_t *ctx) @@ -1560,6 +1945,7 @@ void LZ4_resetStream_fast(LZ4_stream_t *ctx) LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32); } +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) int LZ4_freeStream(LZ4_stream_t *LZ4_stream) { if (!LZ4_stream) @@ -1568,15 +1954,18 @@ int LZ4_freeStream(LZ4_stream_t *LZ4_stream) FREEMEM(LZ4_stream); return (0); } +#endif +typedef enum { _ld_fast, _ld_slow } LoadDict_mode_e; #define HASH_UNIT sizeof(reg_t) -int LZ4_loadDict(LZ4_stream_t *LZ4_dict, const char *dictionary, int dictSize) +int LZ4_loadDict_internal(LZ4_stream_t *LZ4_dict, const char *dictionary, + int dictSize, LoadDict_mode_e _ld) { - LZ4_stream_t_internal *dict = &LZ4_dict->internal_donotuse; + LZ4_stream_t_internal *const dict = &LZ4_dict->internal_donotuse; const tableType_t tableType = byU32; const BYTE *p = (const BYTE *)dictionary; const BYTE *const dictEnd = p + dictSize; - const BYTE *base; + U32 idx32; DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict); @@ -1593,56 +1982,97 @@ int LZ4_loadDict(LZ4_stream_t *LZ4_dict, const char *dictionary, int dictSize) * there are only valid offsets in the window, which allows an optimization * in LZ4_compress_fast_continue() where it uses noDictIssue even when the * dictionary isn't a full 64k. */ - - if ((dictEnd - p) > 64 KB) - p = dictEnd - 64 KB; - base = dictEnd - 64 KB - dict->currentOffset; - dict->dictionary = p; - dict->dictSize = (U32)(dictEnd - p); dict->currentOffset += 64 KB; - dict->tableType = tableType; if (dictSize < (int)HASH_UNIT) { return 0; } + if ((dictEnd - p) > 64 KB) + p = dictEnd - 64 KB; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->tableType = (U32)tableType; + idx32 = dict->currentOffset - dict->dictSize; + while (p <= dictEnd - HASH_UNIT) { - LZ4_putPosition(p, dict->hashTable, tableType, base); + U32 const h = LZ4_hashPosition(p, tableType); + /* Note: overwriting => favors positions end of dictionary */ + LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType); p += 3; + idx32 += 3; + } + + if (_ld == _ld_slow) { + /* Fill hash table with additional references, to improve compression + * capability */ + p = dict->dictionary; + idx32 = dict->currentOffset - dict->dictSize; + while (p <= dictEnd - HASH_UNIT) { + U32 const h = LZ4_hashPosition(p, tableType); + U32 const limit = dict->currentOffset - 64 KB; + if (LZ4_getIndexOnHash(h, dict->hashTable, tableType) <= limit) { + /* Note: not overwriting => favors positions beginning of + * dictionary */ + LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType); + } + p++; + idx32++; + } } - return dict->dictSize; + return (int)dict->dictSize; +} + +int LZ4_loadDict(LZ4_stream_t *LZ4_dict, const char *dictionary, int dictSize) +{ + return LZ4_loadDict_internal(LZ4_dict, dictionary, dictSize, _ld_fast); } -void LZ4_attach_dictionary(LZ4_stream_t *working_stream, - const LZ4_stream_t *dictionary_stream) +int LZ4_loadDictSlow(LZ4_stream_t *LZ4_dict, const char *dictionary, + int dictSize) { - if (dictionary_stream != NULL) { + return LZ4_loadDict_internal(LZ4_dict, dictionary, dictSize, _ld_slow); +} + +void LZ4_attach_dictionary(LZ4_stream_t *workingStream, + const LZ4_stream_t *dictionaryStream) +{ + const LZ4_stream_t_internal *dictCtx = + (dictionaryStream == NULL) ? NULL + : &(dictionaryStream->internal_donotuse); + + DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)", workingStream, + dictionaryStream, dictCtx != NULL ? dictCtx->dictSize : 0); + + if (dictCtx != NULL) { /* If the current offset is zero, we will never look in the * external dictionary context, since there is no value a table * entry can take that indicate a miss. In that case, we need * to bump the offset to something non-zero. */ - if (working_stream->internal_donotuse.currentOffset == 0) { - working_stream->internal_donotuse.currentOffset = 64 KB; + if (workingStream->internal_donotuse.currentOffset == 0) { + workingStream->internal_donotuse.currentOffset = 64 KB; + } + + /* Don't actually attach an empty dictionary. + */ + if (dictCtx->dictSize == 0) { + dictCtx = NULL; } - working_stream->internal_donotuse.dictCtx = - &(dictionary_stream->internal_donotuse); - } - else { - working_stream->internal_donotuse.dictCtx = NULL; } + workingStream->internal_donotuse.dictCtx = dictCtx; } static void LZ4_renormDictT(LZ4_stream_t_internal *LZ4_dict, int nextSize) { - if (LZ4_dict->currentOffset + nextSize > + assert(nextSize >= 0); + if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */ /* rescale hash table */ U32 const delta = LZ4_dict->currentOffset - 64 KB; const BYTE *dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; int i; - DEBUGLOG(4, "LZ4_renormDictT"); for (i = 0; i < LZ4_HASH_SIZE_U32; i++) { if (LZ4_dict->hashTable[i] < delta) @@ -1662,45 +2092,55 @@ int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, const char *source, int acceleration) { const tableType_t tableType = byU32; - LZ4_stream_t_internal *streamPtr = &LZ4_stream->internal_donotuse; - const BYTE *dictEnd = streamPtr->dictionary + streamPtr->dictSize; + LZ4_stream_t_internal *const streamPtr = &LZ4_stream->internal_donotuse; + const char *dictEnd = + streamPtr->dictSize + ? (const char *)streamPtr->dictionary + streamPtr->dictSize + : NULL; - DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i)", inputSize); + DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)", + inputSize, streamPtr->dictSize); - if (streamPtr->initCheck) - return 0; /* Uninitialized structure detected */ - LZ4_renormDictT(streamPtr, inputSize); /* avoid index overflow */ + LZ4_renormDictT(streamPtr, inputSize); /* fix index overflow */ if (acceleration < 1) - acceleration = ACCELERATION_DEFAULT; + acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) + acceleration = LZ4_ACCELERATION_MAX; /* invalidate tiny dictionaries */ - if ((streamPtr->dictSize - 1 < 4) /* intentional underflow */ - && (dictEnd != (const BYTE *)source)) { + if ((streamPtr->dictSize < 4) /* tiny dictionary : not enough for a hash */ + && (dictEnd != source) /* prefix mode */ + && (inputSize > 0) /* tolerance : don't lose history, in case next + invocation would use prefix mode */ + && (streamPtr->dictCtx == NULL) /* usingDictCtx */ + ) { DEBUGLOG( 5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary); + /* remove dictionary existence from history, to employ faster prefix + * mode */ streamPtr->dictSize = 0; streamPtr->dictionary = (const BYTE *)source; - dictEnd = (const BYTE *)source; + dictEnd = source; } /* Check overlapping input/dictionary space */ { - const BYTE *sourceEnd = (const BYTE *)source + inputSize; - - if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { + const char *const sourceEnd = source + inputSize; + if ((sourceEnd > (const char *)streamPtr->dictionary) && + (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; - streamPtr->dictionary = dictEnd - streamPtr->dictSize; + streamPtr->dictionary = (const BYTE *)dictEnd - streamPtr->dictSize; } } /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE *)source) { + if (dictEnd == source) { if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) return LZ4_compress_generic(streamPtr, source, dest, inputSize, @@ -1717,7 +2157,6 @@ int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, const char *source, /* external dictionary mode */ { int result; - if (streamPtr->dictCtx) { /* We depend here on the fact that dictCtx'es (produced by * LZ4_loadDict) guarantee that their tables contain no references @@ -1730,7 +2169,7 @@ int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, const char *source, * cost to copy the dictionary's tables into the active context, * so that the compression loop is only looking into one table. */ - memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t)); + LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr)); result = LZ4_compress_generic( streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, @@ -1743,7 +2182,7 @@ int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, const char *source, acceleration); } } - else { + else { /* small data <= 4 KB */ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { result = LZ4_compress_generic( @@ -1768,7 +2207,7 @@ int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, const char *source, int LZ4_compress_forceExtDict(LZ4_stream_t *LZ4_dict, const char *source, char *dest, int srcSize) { - LZ4_stream_t_internal *streamPtr = &LZ4_dict->internal_donotuse; + LZ4_stream_t_internal *const streamPtr = &LZ4_dict->internal_donotuse; int result; LZ4_renormDictT(streamPtr, srcSize); @@ -1793,22 +2232,33 @@ int LZ4_compress_forceExtDict(LZ4_stream_t *LZ4_dict, const char *source, /*! LZ4_saveDict() : * If previously compressed data block is not guaranteed to remain available at - * its memory location, save it into a safer place (char* safeBuffer). Note : - * you don't need to call LZ4_loadDict() afterwards, dictionary is immediately - * usable, you can therefore call LZ4_compress_fast_continue(). Return : saved - * dictionary size in bytes (necessarily <= dictSize), or 0 if error. + * its memory location, save it into a safer place (char* safeBuffer). Note : no + * need to call LZ4_loadDict() afterwards, dictionary is immediately usable, one + * can therefore call LZ4_compress_fast_continue() right after. + * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if + * error. */ int LZ4_saveDict(LZ4_stream_t *LZ4_dict, char *safeBuffer, int dictSize) { LZ4_stream_t_internal *const dict = &LZ4_dict->internal_donotuse; - const BYTE *const previousDictEnd = dict->dictionary + dict->dictSize; - if ((U32)dictSize > 64 KB) - dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ - if ((U32)dictSize > dict->dictSize) - dictSize = dict->dictSize; + DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, + safeBuffer); - memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + if ((U32)dictSize > 64 KB) { + dictSize = 64 KB; + } /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) { + dictSize = (int)dict->dictSize; + } + + if (safeBuffer == NULL) + assert(dictSize == 0); + if (dictSize > 0) { + const BYTE *const previousDictEnd = dict->dictionary + dict->dictSize; + assert(dict->dictionary); + LZ4_memmove(safeBuffer, previousDictEnd - dictSize, (size_t)dictSize); + } dict->dictionary = (const BYTE *)safeBuffer; dict->dictSize = (U32)dictSize; @@ -1816,316 +2266,797 @@ int LZ4_saveDict(LZ4_stream_t *LZ4_dict, char *safeBuffer, int dictSize) return dictSize; } -/*-***************************** +/*-******************************* * Decompression functions - *******************************/ + ********************************/ + +typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive; + +#undef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +/* variant for decompress_unsafe() + * does not know end of input + * presumes input is well formed + * note : will consume at least one byte */ +static size_t read_long_length_no_check(const BYTE **pp) +{ + size_t b, l = 0; + do { + b = **pp; + (*pp)++; + l += b; + } while (b == 255); + DEBUGLOG(6, "read_long_length_no_check: +length=%zu using %zu input bytes", + l, l / 255 + 1) + return l; +} + +/* core decoder variant for LZ4_decompress_fast*() + * for legacy support only : these entry points are deprecated. + * - Presumes input is correctly formed (no defense vs malformed inputs) + * - Does not know input size (presume input buffer is "large enough") + * - Decompress a full block (only) + * @return : nb of bytes read from input. + * Note : this variant is not optimized for speed, just for maintenance. + * the goal is to remove support of decompress_fast*() variants by v2.0 + **/ +LZ4_FORCE_INLINE int LZ4_decompress_unsafe_generic( + const BYTE *const istart, BYTE *const ostart, int decompressedSize, + + size_t prefixSize, + const BYTE *const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note: =0 if dictStart==NULL */ +) +{ + const BYTE *ip = istart; + BYTE *op = (BYTE *)ostart; + BYTE *const oend = ostart + decompressedSize; + const BYTE *const prefixStart = ostart - prefixSize; + + DEBUGLOG(5, "LZ4_decompress_unsafe_generic"); + if (dictStart == NULL) + assert(dictSize == 0); + + while (1) { + /* start new sequence */ + unsigned token = *ip++; + + /* literals */ + { + size_t ll = token >> ML_BITS; + if (ll == 15) { + /* long literal length */ + ll += read_long_length_no_check(&ip); + } + if ((size_t)(oend - op) < ll) + return -1; /* output buffer overflow */ + LZ4_memmove(op, ip, ll); /* support in-place decompression */ + op += ll; + ip += ll; + if ((size_t)(oend - op) < MFLIMIT) { + if (op == oend) + break; /* end of block */ + DEBUGLOG( + 5, + "invalid: literals end at distance %zi from end of block", + oend - op); + /* incorrect end of block : + * last match must start at least MFLIMIT==12 bytes before end + * of output block */ + return -1; + } + } + + /* match */ + { + size_t ml = token & 15; + size_t const offset = LZ4_readLE16(ip); + ip += 2; + + if (ml == 15) { + /* long literal length */ + ml += read_long_length_no_check(&ip); + } + ml += MINMATCH; + + if ((size_t)(oend - op) < ml) + return -1; /* output buffer overflow */ + + { + const BYTE *match = op - offset; + + /* out of range */ + if (offset > (size_t)(op - prefixStart) + dictSize) { + DEBUGLOG(6, "offset out of range"); + return -1; + } + + /* check special case : extDict */ + if (offset > (size_t)(op - prefixStart)) { + /* extDict scenario */ + const BYTE *const dictEnd = dictStart + dictSize; + const BYTE *extMatch = + dictEnd - (offset - (size_t)(op - prefixStart)); + size_t const extml = (size_t)(dictEnd - extMatch); + if (extml > ml) { + /* match entirely within extDict */ + LZ4_memmove(op, extMatch, ml); + op += ml; + ml = 0; + } + else { + /* match split between extDict & prefix */ + LZ4_memmove(op, extMatch, extml); + op += extml; + ml -= extml; + } + match = prefixStart; + } + + /* match copy - slow variant, supporting overlap copy */ + { + size_t u; + for (u = 0; u < ml; u++) { + op[u] = match[u]; + } + } + } + op += ml; + if ((size_t)(oend - op) < LASTLITERALS) { + DEBUGLOG( + 5, "invalid: match ends at distance %zi from end of block", + oend - op); + /* incorrect end of block : + * last match must stop at least LASTLITERALS==5 bytes before + * end of output block */ + return -1; + } + } /* match */ + } /* main loop */ + return (int)(ip - istart); +} + +/* Read the variable-length literal or match length. + * + * @ip : input pointer + * @ilimit : position after which if length is not decoded, the input is + *necessarily corrupted. + * @initial_check - check ip >= ipmax before start of loop. Returns + *initial_error if so. + * @error (output) - error code. Must be set to 0 before call. + **/ +typedef size_t Rvl_t; +static const Rvl_t rvl_error = (Rvl_t)(-1); +LZ4_FORCE_INLINE Rvl_t read_variable_length(const BYTE **ip, const BYTE *ilimit, + int initial_check) +{ + Rvl_t s, length = 0; + assert(ip != NULL); + assert(*ip != NULL); + assert(ilimit != NULL); + if (initial_check && unlikely((*ip) >= ilimit)) { /* read limit reached */ + return rvl_error; + } + s = **ip; + (*ip)++; + length += s; + if (unlikely((*ip) > ilimit)) { /* read limit reached */ + return rvl_error; + } + /* accumulator overflow detection (32-bit mode only) */ + if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1) / 2))) { + return rvl_error; + } + if (likely(s != 255)) + return length; + do { + s = **ip; + (*ip)++; + length += s; + if (unlikely((*ip) > ilimit)) { /* read limit reached */ + return rvl_error; + } + /* accumulator overflow detection (32-bit mode only) */ + if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1) / 2))) { + return rvl_error; + } + } while (s == 255); + + return length; +} + /*! LZ4_decompress_generic() : * This generic decompression function covers all use cases. * It shall be instantiated several times, using different sets of directives. * Note that it is important for performance that this function really get * inlined, in order to remove useless branches during compilation optimization. */ -LZ4_FORCE_O2_GCC_PPC64LE LZ4_FORCE_INLINE int LZ4_decompress_generic( +LZ4_FORCE_INLINE int LZ4_decompress_generic( const char *const src, char *const dst, int srcSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is - `dstCapacity` */ - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ + int outputSize, /* If endOnInput==endOnInputSize, this value is + `dstCapacity` */ + + earlyEnd_directive partialDecoding, /* full, partial */ + dict_directive dict, /* noDict, withPrefix64k, usingExtDict */ const BYTE *const lowPrefix, /* always <= dst, == dst when no prefix */ const BYTE *const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note : = 0 if noDict */ ) { - const BYTE *ip = (const BYTE *)src; - const BYTE *const iend = ip + srcSize; - - BYTE *op = (BYTE *)dst; - BYTE *const oend = op + outputSize; - BYTE *cpy; - BYTE *oexit = op + targetOutputSize; - - const BYTE *const dictEnd = (const BYTE *)dictStart + dictSize; - const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4}; - const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3}; - - const int safeDecode = (endOnInput == endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); - - /* Set up the "end" pointers for the shortcut. */ - const BYTE *const shortiend = - iend - (endOnInput ? 14 : 8) /*maxLL */ - 2 /*offset */; - const BYTE *const shortoend = - oend - (endOnInput ? 14 : 8) /*maxLL */ - 18 /*maxML */; - - DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i)", srcSize); - - /* Special cases */ - if ((partialDecoding) && (oexit > oend - MFLIMIT)) - oexit = - oend - - MFLIMIT; /* targetOutputSize too high => just decode everything */ - if ((endOnInput) && (unlikely(outputSize == 0))) - return ((srcSize == 1) && (*ip == 0)) ? 0 - : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize == 0))) - return (*ip == 0 ? 1 : -1); - if ((endOnInput) && unlikely(srcSize == 0)) + if ((src == NULL) || (outputSize < 0)) { return -1; + } + + { + const BYTE *ip = (const BYTE *)src; + const BYTE *const iend = ip + srcSize; + + BYTE *op = (BYTE *)dst; + BYTE *const oend = op + outputSize; + BYTE *cpy; + + const BYTE *const dictEnd = + (dictStart == NULL) ? NULL : dictStart + dictSize; + + const int checkOffset = (dictSize < (int)(64 KB)); + + /* Set up the "end" pointers for the shortcut. */ + const BYTE *const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/; + const BYTE *const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/; - /* Main Loop : decode sequences */ - while (1) { const BYTE *match; size_t offset; + unsigned token; + size_t length; - unsigned const token = *ip++; - size_t length = token >> ML_BITS; /* literal length */ + DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, + outputSize); - assert(!endOnInput || ip <= iend); /* ip < iend before the increment */ + /* Special cases */ + assert(lowPrefix <= op); + if (unlikely(outputSize == 0)) { + /* Empty output buffer */ + if (partialDecoding) + return 0; + return ((srcSize == 1) && (*ip == 0)) ? 0 : -1; + } + if (unlikely(srcSize == 0)) { + return -1; + } - /* A two-stage shortcut for the most common case: - * 1) If the literal length is 0..14, and there is enough space, - * enter the shortcut and copy 16 bytes on behalf of the literals - * (in the fast mode, only 8 bytes can be safely copied this way). - * 2) Further if the match length is 4..18, copy 18 bytes in a similar - * manner; but we ensure that there's enough space in the output for - * those 18 bytes earlier, upon entering the shortcut (in other words, - * there is a combined check for both stages). - */ - if ((endOnInput ? length != RUN_MASK : length <= 8) - /* strictly "less than" on input, to re-enter the loop with at least - one byte */ - && likely((endOnInput ? ip < shortiend : 1) & (op <= shortoend))) { - /* Copy the literals */ - memcpy(op, ip, endOnInput ? 16 : 8); - op += length; - ip += length; - - /* The second stage: prepare for match copying, decode full info. - * If it doesn't work out, the info won't be wasted. */ - length = token & ML_MASK; /* match length */ + /* LZ4_FAST_DEC_LOOP: + * designed for modern OoO performance cpus, + * where copying reliably 32-bytes is preferable to an unpredictable + * branch. note : fast loop may show a regression for some client arm + * chips. */ +#if LZ4_FAST_DEC_LOOP + if ((oend - op) < FASTLOOP_SAFE_DISTANCE) { + DEBUGLOG(6, "move to safe decode loop"); + goto safe_decode; + } + + /* Fast loop : decode sequences as long as output < + * oend-FASTLOOP_SAFE_DISTANCE */ + DEBUGLOG(6, "using fast decode loop"); + while (1) { + /* Main fastloop assertion: We can always wildcopy + * FASTLOOP_SAFE_DISTANCE */ + assert(oend - op >= FASTLOOP_SAFE_DISTANCE); + assert(ip < iend); + token = *ip++; + length = token >> ML_BITS; /* literal length */ + DEBUGLOG(7, "blockPos%6u: litLength token = %u", + (unsigned)(op - (BYTE *)dst), (unsigned)length); + + /* decode literal length */ + if (length == RUN_MASK) { + size_t const addl = + read_variable_length(&ip, iend - RUN_MASK, 1); + if (addl == rvl_error) { + DEBUGLOG(6, "error reading long literal length"); + goto _output_error; + } + length += addl; + if (unlikely((uptrval)(op) + length < (uptrval)(op))) { + goto _output_error; + } /* overflow detection */ + if (unlikely((uptrval)(ip) + length < (uptrval)(ip))) { + goto _output_error; + } /* overflow detection */ + + /* copy literals */ + LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); + if ((op + length > oend - 32) || (ip + length > iend - 32)) { + goto safe_literal_copy; + } + LZ4_wildCopy32(op, ip, op + length); + ip += length; + op += length; + } + else if (ip <= iend - (16 + 1 /*max lit + offset + nextToken*/)) { + /* We don't need to check oend, since we check it once for each + * loop below */ + DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", + (unsigned)length); + /* Literals can only be <= 14, but hope compilers optimize + * better when copy by a register size */ + LZ4_memcpy(op, ip, 16); + ip += length; + op += length; + } + else { + goto safe_literal_copy; + } + + /* get offset */ offset = LZ4_readLE16(ip); ip += 2; + DEBUGLOG(6, "blockPos%6u: offset = %u", + (unsigned)(op - (BYTE *)dst), (unsigned)offset); match = op - offset; + assert(match <= op); /* overflow check */ + + /* get matchlength */ + length = token & ML_MASK; + DEBUGLOG(7, " match length token = %u (len==%u)", (unsigned)length, + (unsigned)length + MINMATCH); + + if (length == ML_MASK) { + size_t const addl = + read_variable_length(&ip, iend - LASTLITERALS + 1, 0); + if (addl == rvl_error) { + DEBUGLOG(5, "error reading long match length"); + goto _output_error; + } + length += addl; + length += MINMATCH; + DEBUGLOG(7, " long match length == %u", (unsigned)length); + if (unlikely((uptrval)(op) + length < (uptrval)op)) { + goto _output_error; + } /* overflow detection */ + if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { + goto safe_match_copy; + } + } + else { + length += MINMATCH; + if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { + DEBUGLOG(7, "moving to safe_match_copy (ml==%u)", + (unsigned)length); + goto safe_match_copy; + } - /* Do not deal with overlapping matches. */ - if ((length != ML_MASK) && (offset >= 8) && - (dict == withPrefix64k || match >= lowPrefix)) { - /* Copy the match. */ - memcpy(op + 0, match + 0, 8); - memcpy(op + 8, match + 8, 8); - memcpy(op + 16, match + 16, 2); - op += length + MINMATCH; - /* Both stages worked, load the next token. */ - continue; + /* Fastpath check: skip LZ4_wildCopy32 when true */ + if ((dict == withPrefix64k) || (match >= lowPrefix)) { + if (offset >= 8) { + assert(match >= lowPrefix); + assert(match <= op); + assert(op + 18 <= oend); + + LZ4_memcpy(op, match, 8); + LZ4_memcpy(op + 8, match + 8, 8); + LZ4_memcpy(op + 16, match + 16, 2); + op += length; + continue; + } + } } - /* The second stage didn't work out, but the info is ready. - * Propel it right to the point of match copying. */ - goto _copy_match; - } + if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { + DEBUGLOG(5, "Error : pos=%zi, offset=%zi => outside buffers", + op - lowPrefix, op - match); + goto _output_error; + } + /* match starting within external dictionary */ + if ((dict == usingExtDict) && (match < lowPrefix)) { + assert(dictEnd != NULL); + if (unlikely(op + length > oend - LASTLITERALS)) { + if (partialDecoding) { + DEBUGLOG(7, "partialDecoding: dictionary match, close " + "to dstEnd"); + length = MIN(length, (size_t)(oend - op)); + } + else { + DEBUGLOG(6, "end-of-block condition violated") + goto _output_error; + } + } - /* decode literal length */ - if (length == RUN_MASK) { - unsigned s; + if (length <= (size_t)(lowPrefix - match)) { + /* match fits entirely within external dictionary : just + * copy */ + LZ4_memmove(op, dictEnd - (lowPrefix - match), length); + op += length; + } + else { + /* match stretches into both external dictionary and current + * block */ + size_t const copySize = (size_t)(lowPrefix - match); + size_t const restSize = length - copySize; + LZ4_memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > + (size_t)(op - lowPrefix)) { /* overlap copy */ + BYTE *const endOfMatch = op + restSize; + const BYTE *copyFrom = lowPrefix; + while (op < endOfMatch) { + *op++ = *copyFrom++; + } + } + else { + LZ4_memcpy(op, lowPrefix, restSize); + op += restSize; + } + } + continue; + } - if (unlikely(endOnInput ? ip >= iend - RUN_MASK : 0)) - goto _output_error; /* overflow detection */ - do { - s = *ip++; - length += s; - } while (likely(endOnInput ? ip < iend - RUN_MASK : 1) & - (s == 255)); - if ((safeDecode) && - unlikely((uptrval)(op) + length < (uptrval)(op))) - goto _output_error; /* overflow detection */ - if ((safeDecode) && - unlikely((uptrval)(ip) + length < (uptrval)(ip))) - goto _output_error; /* overflow detection */ - } + /* copy match within block */ + cpy = op + length; - /* copy literals */ - cpy = op + length; - if (((endOnInput) && - ((cpy > (partialDecoding ? oexit : oend - MFLIMIT)) || - (ip + length > iend - (2 + 1 + LASTLITERALS)))) || - ((!endOnInput) && (cpy > oend - WILDCOPYLENGTH))) { - if (partialDecoding) { - if (cpy > oend) - goto _output_error; /* Error : write attempt beyond end of - output buffer */ - if ((endOnInput) && (ip + length > iend)) - goto _output_error; /* Error : read attempt beyond end of - input buffer */ + assert((op <= oend) && (oend - op >= 32)); + if (unlikely(offset < 16)) { + LZ4_memcpy_using_offset(op, match, cpy, offset); } else { - if ((!endOnInput) && (cpy != oend)) - goto _output_error; /* Error : block decoding must stop - exactly there */ - if ((endOnInput) && ((ip + length != iend) || (cpy > oend))) - goto _output_error; /* Error : input must be consumed */ + LZ4_wildCopy32(op, match, cpy); } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ + + op = cpy; /* wildcopy correction */ } - LZ4_wildCopy(op, ip, cpy); - ip += length; - op = cpy; + safe_decode: +#endif - /* get offset */ - offset = LZ4_readLE16(ip); - ip += 2; - match = op - offset; + /* Main Loop : decode remaining sequences where output < + * FASTLOOP_SAFE_DISTANCE */ + DEBUGLOG(6, "using safe decode loop"); + while (1) { + assert(ip < iend); + token = *ip++; + length = token >> ML_BITS; /* literal length */ + DEBUGLOG(7, "blockPos%6u: litLength token = %u", + (unsigned)(op - (BYTE *)dst), (unsigned)length); + + /* A two-stage shortcut for the most common case: + * 1) If the literal length is 0..14, and there is enough space, + * enter the shortcut and copy 16 bytes on behalf of the literals + * (in the fast mode, only 8 bytes can be safely copied this way). + * 2) Further if the match length is 4..18, copy 18 bytes in a + * similar manner; but we ensure that there's enough space in the + * output for those 18 bytes earlier, upon entering the shortcut (in + * other words, there is a combined check for both stages). + */ + if ((length != RUN_MASK) + /* strictly "less than" on input, to re-enter the loop with at + least one byte */ + && likely((ip < shortiend) & (op <= shortoend))) { + /* Copy the literals */ + LZ4_memcpy(op, ip, 16); + op += length; + ip += length; + + /* The second stage: prepare for match copying, decode full + * info. If it doesn't work out, the info won't be wasted. */ + length = token & ML_MASK; /* match length */ + DEBUGLOG(7, "blockPos%6u: matchLength token = %u (len=%u)", + (unsigned)(op - (BYTE *)dst), (unsigned)length, + (unsigned)length + 4); + offset = LZ4_readLE16(ip); + ip += 2; + match = op - offset; + assert(match <= op); /* check overflow */ + + /* Do not deal with overlapping matches. */ + if ((length != ML_MASK) && (offset >= 8) && + (dict == withPrefix64k || match >= lowPrefix)) { + /* Copy the match. */ + LZ4_memcpy(op + 0, match + 0, 8); + LZ4_memcpy(op + 8, match + 8, 8); + LZ4_memcpy(op + 16, match + 16, 2); + op += length + MINMATCH; + /* Both stages worked, load the next token. */ + continue; + } - /* get matchlength */ - length = token & ML_MASK; + /* The second stage didn't work out, but the info is ready. + * Propel it right to the point of match copying. */ + goto _copy_match; + } - _copy_match: - if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) - goto _output_error; /* Error : offset outside buffers */ - LZ4_write32( - op, - (U32) - offset); /* costs ~1%; silence an msan warning when offset==0 */ + /* decode literal length */ + if (length == RUN_MASK) { + size_t const addl = + read_variable_length(&ip, iend - RUN_MASK, 1); + if (addl == rvl_error) { + goto _output_error; + } + length += addl; + if (unlikely((uptrval)(op) + length < (uptrval)(op))) { + goto _output_error; + } /* overflow detection */ + if (unlikely((uptrval)(ip) + length < (uptrval)(ip))) { + goto _output_error; + } /* overflow detection */ + } - if (length == ML_MASK) { - unsigned s; +#if LZ4_FAST_DEC_LOOP + safe_literal_copy: +#endif + /* copy literals */ + cpy = op + length; + + LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); + if ((cpy > oend - MFLIMIT) || + (ip + length > iend - (2 + 1 + LASTLITERALS))) { + /* We've either hit the input parsing restriction or the output + * parsing restriction. In the normal scenario, decoding a full + * block, it must be the last sequence, otherwise it's an error + * (invalid input or dimensions). In partialDecoding scenario, + * it's necessary to ensure there is no buffer overflow. + */ + if (partialDecoding) { + /* Since we are partial decoding we may be in this block + * because of the output parsing restriction, which is not + * valid since the output buffer is allowed to be + * undersized. + */ + DEBUGLOG(7, "partialDecoding: copying literals, close to " + "input or output end") + DEBUGLOG(7, "partialDecoding: literal length = %u", + (unsigned)length); + DEBUGLOG( + 7, "partialDecoding: remaining space in dstBuffer : %i", + (int)(oend - op)); + DEBUGLOG( + 7, "partialDecoding: remaining space in srcBuffer : %i", + (int)(iend - ip)); + /* Finishing in the middle of a literals segment, + * due to lack of input. + */ + if (ip + length > iend) { + length = (size_t)(iend - ip); + cpy = op + length; + } + /* Finishing in the middle of a literals segment, + * due to lack of output space. + */ + if (cpy > oend) { + cpy = oend; + assert(op <= oend); + length = (size_t)(oend - op); + } + } + else { + /* We must be on the last sequence (or invalid) because of + * the parsing limitations so check that we exactly consume + * the input and don't overrun the output buffer. + */ + if ((ip + length != iend) || (cpy > oend)) { + DEBUGLOG(5, "should have been last run of literals") + DEBUGLOG(5, "ip(%p) + length(%i) = %p != iend (%p)", ip, + (int)length, ip + length, iend); + DEBUGLOG(5, "or cpy(%p) > (oend-MFLIMIT)(%p)", cpy, + oend - MFLIMIT); + DEBUGLOG(5, + "after writing %u bytes / %i bytes available", + (unsigned)(op - (BYTE *)dst), outputSize); + goto _output_error; + } + } + LZ4_memmove(op, ip, + length); /* supports overlapping memory regions, for + in-place decompression scenarios */ + ip += length; + op += length; + /* Necessarily EOF when !partialDecoding. + * When partialDecoding, it is EOF if we've either + * filled the output buffer or + * can't proceed with reading an offset for following match. + */ + if (!partialDecoding || (cpy == oend) || (ip >= (iend - 2))) { + break; + } + } + else { + LZ4_wildCopy8(op, ip, + cpy); /* can overwrite up to 8 bytes beyond cpy */ + ip += length; + op = cpy; + } - do { - s = *ip++; - if ((endOnInput) && (ip > iend - LASTLITERALS)) + /* get offset */ + offset = LZ4_readLE16(ip); + ip += 2; + match = op - offset; + + /* get matchlength */ + length = token & ML_MASK; + DEBUGLOG(7, "blockPos%6u: matchLength token = %u", + (unsigned)(op - (BYTE *)dst), (unsigned)length); + + _copy_match: + if (length == ML_MASK) { + size_t const addl = + read_variable_length(&ip, iend - LASTLITERALS + 1, 0); + if (addl == rvl_error) { goto _output_error; - length += s; - } while (s == 255); - if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) - goto _output_error; /* overflow detection */ - } - length += MINMATCH; + } + length += addl; + if (unlikely((uptrval)(op) + length < (uptrval)op)) + goto _output_error; /* overflow detection */ + } + length += MINMATCH; - /* check external dictionary */ - if ((dict == usingExtDict) && (match < lowPrefix)) { - if (unlikely(op + length > oend - LASTLITERALS)) - goto _output_error; /* doesn't respect parsing restriction */ +#if LZ4_FAST_DEC_LOOP + safe_match_copy: +#endif + if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) + goto _output_error; /* Error : offset outside buffers */ + /* match starting within external dictionary */ + if ((dict == usingExtDict) && (match < lowPrefix)) { + assert(dictEnd != NULL); + if (unlikely(op + length > oend - LASTLITERALS)) { + if (partialDecoding) + length = MIN(length, (size_t)(oend - op)); + else + goto _output_error; /* doesn't respect parsing + restriction */ + } - if (length <= (size_t)(lowPrefix - match)) { - /* match can be copied as a single segment from external - * dictionary */ - memmove(op, dictEnd - (lowPrefix - match), length); - op += length; + if (length <= (size_t)(lowPrefix - match)) { + /* match fits entirely within external dictionary : just + * copy */ + LZ4_memmove(op, dictEnd - (lowPrefix - match), length); + op += length; + } + else { + /* match stretches into both external dictionary and current + * block */ + size_t const copySize = (size_t)(lowPrefix - match); + size_t const restSize = length - copySize; + LZ4_memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > + (size_t)(op - lowPrefix)) { /* overlap copy */ + BYTE *const endOfMatch = op + restSize; + const BYTE *copyFrom = lowPrefix; + while (op < endOfMatch) + *op++ = *copyFrom++; + } + else { + LZ4_memcpy(op, lowPrefix, restSize); + op += restSize; + } + } + continue; } - else { - /* match encompass external dictionary and current block */ - size_t const copySize = (size_t)(lowPrefix - match); - size_t const restSize = length - copySize; - - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ - BYTE *const endOfMatch = op + restSize; - const BYTE *copyFrom = lowPrefix; - - while (op < endOfMatch) - *op++ = *copyFrom++; + assert(match >= lowPrefix); + + /* copy match within block */ + cpy = op + length; + + /* partialDecoding : may end anywhere within the block */ + assert(op <= oend); + if (partialDecoding && (cpy > oend - MATCH_SAFEGUARD_DISTANCE)) { + size_t const mlen = MIN(length, (size_t)(oend - op)); + const BYTE *const matchEnd = match + mlen; + BYTE *const copyEnd = op + mlen; + if (matchEnd > op) { /* overlap copy */ + while (op < copyEnd) { + *op++ = *match++; + } } else { - memcpy(op, lowPrefix, restSize); - op += restSize; + LZ4_memcpy(op, match, mlen); } + op = copyEnd; + if (op == oend) { + break; + } + continue; } - continue; - } - /* copy match within block */ - cpy = op + length; - if (unlikely(offset < 8)) { - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += inc32table[offset]; - memcpy(op + 4, match, 4); - match -= dec64table[offset]; - } - else { - memcpy(op, match, 8); - match += 8; - } - op += 8; - - if (unlikely(cpy > oend - 12)) { - BYTE *const oCopyLimit = oend - (WILDCOPYLENGTH - 1); - - if (cpy > oend - LASTLITERALS) - goto _output_error; /* Error : last LASTLITERALS bytes must be - literals (uncompressed) */ - if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; + if (unlikely(offset < 8)) { + LZ4_write32(op, 0); /* silence msan warning when offset==0 */ + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += inc32table[offset]; + LZ4_memcpy(op + 4, match, 4); + match -= dec64table[offset]; } - while (op < cpy) - *op++ = *match++; - } - else { - memcpy(op, match, 8); - if (length > 16) - LZ4_wildCopy(op + 8, match + 8, cpy); + else { + LZ4_memcpy(op, match, 8); + match += 8; + } + op += 8; + + if (unlikely(cpy > oend - MATCH_SAFEGUARD_DISTANCE)) { + BYTE *const oCopyLimit = oend - (WILDCOPYLENGTH - 1); + if (cpy > oend - LASTLITERALS) { + goto _output_error; + } /* Error : last LASTLITERALS bytes must be literals + (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy8(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op < cpy) { + *op++ = *match++; + } + } + else { + LZ4_memcpy(op, match, 8); + if (length > 16) { + LZ4_wildCopy8(op + 8, match + 8, cpy); + } + } + op = cpy; /* wildcopy correction */ } - op = cpy; /* correction */ - } - /* end of decoding */ - if (endOnInput) + /* end of decoding */ + DEBUGLOG(5, "decoded %i bytes", (int)(((char *)op) - dst)); return (int)(((char *)op) - dst); /* Nb of output bytes decoded */ - else - return (int)(((const char *)ip) - src); /* Nb of input bytes read */ - /* Overflow error detected */ -_output_error: - return (int)(-(((const char *)ip) - src)) - 1; + /* Overflow error detected */ + _output_error: + return (int)(-(((const char *)ip) - src)) - 1; + } } /*===== Instantiate the API decoding functions. =====*/ -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 int LZ4_decompress_safe(const char *source, char *dest, int compressedSize, int maxDecompressedSize) { return LZ4_decompress_generic(source, dest, compressedSize, - maxDecompressedSize, endOnInputSize, full, 0, + maxDecompressedSize, decode_full_block, noDict, (BYTE *)dest, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE -int LZ4_decompress_safe_partial(const char *source, char *dest, - int compressedSize, int targetOutputSize, - int maxDecompressedSize) +LZ4_FORCE_O2 +int LZ4_decompress_safe_partial(const char *src, char *dst, int compressedSize, + int targetOutputSize, int dstCapacity) { - return LZ4_decompress_generic( - source, dest, compressedSize, maxDecompressedSize, endOnInputSize, - partial, targetOutputSize, noDict, (BYTE *)dest, NULL, 0); + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity, + partial_decode, noDict, (BYTE *)dst, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 int LZ4_decompress_fast(const char *source, char *dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, withPrefix64k, - (BYTE *)dest - 64 KB, NULL, 0); + DEBUGLOG(5, "LZ4_decompress_fast"); + return LZ4_decompress_unsafe_generic((const BYTE *)source, (BYTE *)dest, + originalSize, 0, NULL, 0); } /*===== Instantiate a few more decoding cases, used more than once. =====*/ -LZ4_FORCE_O2_GCC_PPC64LE /* Exported, an obsolete API function. */ +LZ4_FORCE_O2 /* Exported, an obsolete API function. */ int LZ4_decompress_safe_withPrefix64k(const char *source, char *dest, int compressedSize, int maxOutputSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, withPrefix64k, + decode_full_block, withPrefix64k, + (BYTE *)dest - 64 KB, NULL, 0); +} + +LZ4_FORCE_O2 +static int LZ4_decompress_safe_partial_withPrefix64k(const char *source, + char *dest, + int compressedSize, + int targetOutputSize, + int dstCapacity) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + partial_decode, withPrefix64k, (BYTE *)dest - 64 KB, NULL, 0); } @@ -2133,43 +3064,62 @@ LZ4_FORCE_O2_GCC_PPC64LE /* Exported, an obsolete API function. */ int LZ4_decompress_fast_withPrefix64k(const char *source, char *dest, int originalSize) { - /* LZ4_decompress_fast doesn't validate match offsets, - * and thus serves well with any prefixed dictionary. */ - return LZ4_decompress_fast(source, dest, originalSize); + return LZ4_decompress_unsafe_generic((const BYTE *)source, (BYTE *)dest, + originalSize, 64 KB, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 static int LZ4_decompress_safe_withSmallPrefix(const char *source, char *dest, int compressedSize, int maxOutputSize, size_t prefixSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, noDict, + decode_full_block, noDict, (BYTE *)dest - prefixSize, NULL, 0); } -LZ4_FORCE_O2_GCC_PPC64LE /* Exported under another name, for tests/fullbench.c - */ -#define LZ4_decompress_safe_extDict LZ4_decompress_safe_forceExtDict - int - LZ4_decompress_safe_extDict(const char *source, char *dest, - int compressedSize, int maxOutputSize, - const void *dictStart, size_t dictSize) +LZ4_FORCE_O2 +static int LZ4_decompress_safe_partial_withSmallPrefix( + const char *source, char *dest, int compressedSize, int targetOutputSize, + int dstCapacity, size_t prefixSize) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + partial_decode, noDict, + (BYTE *)dest - prefixSize, NULL, 0); +} + +LZ4_FORCE_O2 +int LZ4_decompress_safe_forceExtDict(const char *source, char *dest, + int compressedSize, int maxOutputSize, + const void *dictStart, size_t dictSize) { - return LZ4_decompress_generic( - source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, - usingExtDict, (BYTE *)dest, (const BYTE *)dictStart, dictSize); + DEBUGLOG(5, "LZ4_decompress_safe_forceExtDict"); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + decode_full_block, usingExtDict, (BYTE *)dest, + (const BYTE *)dictStart, dictSize); +} + +LZ4_FORCE_O2 +int LZ4_decompress_safe_partial_forceExtDict( + const char *source, char *dest, int compressedSize, int targetOutputSize, + int dstCapacity, const void *dictStart, size_t dictSize) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + partial_decode, usingExtDict, (BYTE *)dest, + (const BYTE *)dictStart, dictSize); } -LZ4_FORCE_O2_GCC_PPC64LE +LZ4_FORCE_O2 static int LZ4_decompress_fast_extDict(const char *source, char *dest, int originalSize, const void *dictStart, size_t dictSize) { - return LZ4_decompress_generic( - source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, - (BYTE *)dest, (const BYTE *)dictStart, dictSize); + return LZ4_decompress_unsafe_generic((const BYTE *)source, (BYTE *)dest, + originalSize, 0, + (const BYTE *)dictStart, dictSize); } /* The "double dictionary" mode, for use with e.g. ring buffers: the first part @@ -2183,37 +3133,30 @@ int LZ4_decompress_safe_doubleDict(const char *source, char *dest, size_t dictSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, usingExtDict, + decode_full_block, usingExtDict, (BYTE *)dest - prefixSize, (const BYTE *)dictStart, dictSize); } -LZ4_FORCE_INLINE -int LZ4_decompress_fast_doubleDict(const char *source, char *dest, - int originalSize, size_t prefixSize, - const void *dictStart, size_t dictSize) -{ - return LZ4_decompress_generic( - source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, - (BYTE *)dest - prefixSize, (const BYTE *)dictStart, dictSize); -} - /*===== streaming decompression functions =====*/ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_streamDecode_t *LZ4_createStreamDecode(void) { - LZ4_streamDecode_t *lz4s = - (LZ4_streamDecode_t *)ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); - return lz4s; + LZ4_STATIC_ASSERT(sizeof(LZ4_streamDecode_t) >= + sizeof(LZ4_streamDecode_t_internal)); + return (LZ4_streamDecode_t *)ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); } int LZ4_freeStreamDecode(LZ4_streamDecode_t *LZ4_stream) { - if (!LZ4_stream) - return 0; /* support free on NULL */ + if (LZ4_stream == NULL) { + return 0; + } /* support free on NULL */ FREEMEM(LZ4_stream); return 0; } +#endif /*! LZ4_setStreamDecode() : * Use this function to instruct where to find the dictionary. @@ -2225,9 +3168,14 @@ int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, const char *dictionary, int dictSize) { LZ4_streamDecode_t_internal *lz4sd = &LZ4_streamDecode->internal_donotuse; - lz4sd->prefixSize = (size_t)dictSize; - lz4sd->prefixEnd = (const BYTE *)dictionary + dictSize; + if (dictSize) { + assert(dictionary != NULL); + lz4sd->prefixEnd = (const BYTE *)dictionary + dictSize; + } + else { + lz4sd->prefixEnd = (const BYTE *)dictionary; + } lz4sd->externalDict = NULL; lz4sd->extDictSize = 0; return 1; @@ -2256,14 +3204,14 @@ int LZ4_decoderRingBufferSize(int maxBlockSize) } /* - *_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" - mode. Previously decoded blocks must still be available at the memory position - where they were decoded. If it's not possible, save the relevant part of - decoded data into a safe buffer, and indicate where it stands using - LZ4_setStreamDecode() - */ -LZ4_FORCE_O2_GCC_PPC64LE +*_continue() : + These decoding functions allow decompression of multiple blocks in +"streaming" mode. Previously decoded blocks must still be available at the +memory position where they were decoded. If it's not possible, save the relevant +part of decoded data into a safe buffer, and indicate where it stands using +LZ4_setStreamDecode() +*/ +LZ4_FORCE_O2 int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest, int compressedSize, int maxOutputSize) @@ -2278,7 +3226,7 @@ int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize); if (result <= 0) return result; - lz4sd->prefixSize = result; + lz4sd->prefixSize = (size_t)result; lz4sd->prefixEnd = (BYTE *)dest + result; } else if (lz4sd->prefixEnd == (BYTE *)dest) { @@ -2295,54 +3243,58 @@ int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; - lz4sd->prefixSize += result; + lz4sd->prefixSize += (size_t)result; lz4sd->prefixEnd += result; } else { /* The buffer wraps around, or they're switching to another buffer. */ lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_safe_extDict(source, dest, compressedSize, - maxOutputSize, lz4sd->externalDict, - lz4sd->extDictSize); + result = LZ4_decompress_safe_forceExtDict( + source, dest, compressedSize, maxOutputSize, lz4sd->externalDict, + lz4sd->extDictSize); if (result <= 0) return result; - lz4sd->prefixSize = result; + lz4sd->prefixSize = (size_t)result; lz4sd->prefixEnd = (BYTE *)dest + result; } return result; } -LZ4_FORCE_O2_GCC_PPC64LE -int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, - const char *source, char *dest, - int originalSize) +LZ4_FORCE_O2 int +LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, + const char *source, char *dest, int originalSize) { - LZ4_streamDecode_t_internal *lz4sd = &LZ4_streamDecode->internal_donotuse; + LZ4_streamDecode_t_internal *const lz4sd = + (assert(LZ4_streamDecode != NULL), + &LZ4_streamDecode->internal_donotuse); int result; + DEBUGLOG(5, "LZ4_decompress_fast_continue (toDecodeSize=%i)", originalSize); + assert(originalSize >= 0); + if (lz4sd->prefixSize == 0) { + DEBUGLOG(5, "first invocation : no prefix nor extDict"); assert(lz4sd->extDictSize == 0); result = LZ4_decompress_fast(source, dest, originalSize); if (result <= 0) return result; - lz4sd->prefixSize = originalSize; + lz4sd->prefixSize = (size_t)originalSize; lz4sd->prefixEnd = (BYTE *)dest + originalSize; } else if (lz4sd->prefixEnd == (BYTE *)dest) { - if (lz4sd->prefixSize >= 64 KB - 1 || lz4sd->extDictSize == 0) - result = LZ4_decompress_fast(source, dest, originalSize); - else - result = LZ4_decompress_fast_doubleDict( - source, dest, originalSize, lz4sd->prefixSize, - lz4sd->externalDict, lz4sd->extDictSize); + DEBUGLOG(5, "continue using existing prefix"); + result = LZ4_decompress_unsafe_generic( + (const BYTE *)source, (BYTE *)dest, originalSize, lz4sd->prefixSize, + lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; - lz4sd->prefixSize += originalSize; + lz4sd->prefixSize += (size_t)originalSize; lz4sd->prefixEnd += originalSize; } else { + DEBUGLOG(5, "prefix becomes extDict"); lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_fast_extDict(source, dest, originalSize, @@ -2350,7 +3302,7 @@ int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, lz4sd->extDictSize); if (result <= 0) return result; - lz4sd->prefixSize = originalSize; + lz4sd->prefixSize = (size_t)originalSize; lz4sd->prefixEnd = (BYTE *)dest + originalSize; } @@ -2358,11 +3310,11 @@ int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, } /* - Advanced decoding functions : - *_usingDict() : - These decoding functions work the same as "_continue" ones, - the dictionary must be explicitly provided within parameters - */ +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters +*/ int LZ4_decompress_safe_usingDict(const char *source, char *dest, int compressedSize, int maxOutputSize, @@ -2371,14 +3323,42 @@ int LZ4_decompress_safe_usingDict(const char *source, char *dest, if (dictSize == 0) return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize); if (dictStart + dictSize == dest) { - if (dictSize >= 64 KB - 1) + if (dictSize >= 64 KB - 1) { return LZ4_decompress_safe_withPrefix64k( source, dest, compressedSize, maxOutputSize); - return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, - maxOutputSize, dictSize); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_withSmallPrefix( + source, dest, compressedSize, maxOutputSize, (size_t)dictSize); } - return LZ4_decompress_safe_extDict(source, dest, compressedSize, - maxOutputSize, dictStart, dictSize); + assert(dictSize >= 0); + return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, + maxOutputSize, dictStart, + (size_t)dictSize); +} + +int LZ4_decompress_safe_partial_usingDict(const char *source, char *dest, + int compressedSize, + int targetOutputSize, int dstCapacity, + const char *dictStart, int dictSize) +{ + if (dictSize == 0) + return LZ4_decompress_safe_partial(source, dest, compressedSize, + targetOutputSize, dstCapacity); + if (dictStart + dictSize == dest) { + if (dictSize >= 64 KB - 1) { + return LZ4_decompress_safe_partial_withPrefix64k( + source, dest, compressedSize, targetOutputSize, dstCapacity); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_withSmallPrefix( + source, dest, compressedSize, targetOutputSize, dstCapacity, + (size_t)dictSize); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_forceExtDict( + source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, + (size_t)dictSize); } int LZ4_decompress_fast_usingDict(const char *source, char *dest, @@ -2386,9 +3366,12 @@ int LZ4_decompress_fast_usingDict(const char *source, char *dest, int dictSize) { if (dictSize == 0 || dictStart + dictSize == dest) - return LZ4_decompress_fast(source, dest, originalSize); + return LZ4_decompress_unsafe_generic((const BYTE *)source, (BYTE *)dest, + originalSize, (size_t)dictSize, + NULL, 0); + assert(dictSize >= 0); return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, - dictSize); + (size_t)dictSize); } /*=************************************************* @@ -2400,25 +3383,20 @@ int LZ4_compress_limitedOutput(const char *source, char *dest, int inputSize, { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } - -int LZ4_compress(const char *source, char *dest, int inputSize) +int LZ4_compress(const char *src, char *dest, int srcSize) { - return LZ4_compress_default(source, dest, inputSize, - LZ4_compressBound(inputSize)); + return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize)); } - int LZ4_compress_limitedOutput_withState(void *state, const char *src, char *dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } - int LZ4_compress_withState(void *state, const char *src, char *dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } - int LZ4_compress_limitedOutput_continue(LZ4_stream_t *LZ4_stream, const char *src, char *dst, int srcSize, int dstCapacity) @@ -2426,7 +3404,6 @@ int LZ4_compress_limitedOutput_continue(LZ4_stream_t *LZ4_stream, return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1); } - int LZ4_compress_continue(LZ4_stream_t *LZ4_stream, const char *source, char *dest, int inputSize) { @@ -2435,17 +3412,15 @@ int LZ4_compress_continue(LZ4_stream_t *LZ4_stream, const char *source, } /* - These decompression functions are deprecated and should no longer be used. - They are only provided here for compatibility with older user programs. - - LZ4_uncompress is totally equivalent to LZ4_decompress_fast - - LZ4_uncompress_unknownOutputSize is totally equivalent to - LZ4_decompress_safe - */ +These decompression functions are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is totally equivalent to LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe +*/ int LZ4_uncompress(const char *source, char *dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } - int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize) { @@ -2456,7 +3431,7 @@ int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int LZ4_sizeofStreamState(void) { - return LZ4_STREAMSIZE; + return sizeof(LZ4_stream_t); } int LZ4_resetStreamState(void *state, char *inputBuffer) @@ -2466,11 +3441,13 @@ int LZ4_resetStreamState(void *state, char *inputBuffer) return 0; } +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) void *LZ4_create(char *inputBuffer) { (void)inputBuffer; return LZ4_createStream(); } +#endif char *LZ4_slideInputBuffer(void *state) { diff --git a/lib/gis/lz4.h b/lib/gis/lz4.h index 9ab16d35e0e..e2230ea4a54 100644 --- a/lib/gis/lz4.h +++ b/lib/gis/lz4.h @@ -1,37 +1,37 @@ /* * LZ4 - Fast LZ compression algorithm * Header File - * Copyright (C) 2011-2017, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 - */ + * Copyright (C) 2011-2023, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ #if defined(__cplusplus) extern "C" { #endif @@ -45,27 +45,32 @@ extern "C" { /** Introduction - LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s + LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core, scalable with multi-cores CPU. It features an extremely fast decoder, with speed in multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. The LZ4 compression library provides in-memory compression and decompression - functions. Compression can be done in: + functions. It gives full buffer control to user. Compression can be done in: - a single step (described as Simple Functions) - a single step, reusing a context (described in Advanced Functions) - unbounded multiple steps (described as Streaming compression) - lz4.h provides block compression functions. It gives full buffer control to - user. Decompressing an lz4-compressed block also requires metadata (such as - compressed size). Each application is free to encode such metadata in - whichever way it wants. - - An additional format, called LZ4 frame specification - (doc/lz4_Frame_format.md), take care of encoding standard metadata alongside - LZ4-compressed blocks. If your application requires interoperability, it's - recommended to use it. A library is provided to take care of it, see - lz4frame.h. + lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md). + Decompressing such a compressed block requires additional metadata. + Exact metadata depends on exact decompression function. + For the typical case of LZ4_decompress_safe(), + metadata includes block's compressed size, and maximum bound of decompressed + size. Each application is free to encode and pass such metadata in whichever + way it wants. + + lz4.h only handle blocks, it can not generate Frames. + + Blocks are different from Frames (doc/lz4_Frame_format.md). + Frames bundle both blocks and metadata in a specified manner. + Embedding metadata is required for compressed data to be self-contained and + portable. Frame format is delivered through a companion API, declared in + lz4frame.h. The `lz4` CLI can only manage frames. */ /*^*************************************************************** @@ -87,21 +92,50 @@ extern "C" { #if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT == 1) #define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY #elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT == 1) -#define LZ4LIB_API \ - __declspec(dllimport) \ - LZ4LIB_VISIBILITY /* It isn't required but allows generating better \ - code, saving a function pointer load from the IAT \ - and an indirect jump. */ +#define LZ4LIB_API \ + __declspec(dllimport) \ + LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, \ + saving a function pointer load from the IAT and an \ + indirect jump.*/ #else #define LZ4LIB_API LZ4LIB_VISIBILITY #endif +/*! LZ4_FREESTANDING : + * When this macro is set to 1, it enables "freestanding mode" that is + * suitable for typical freestanding environment which doesn't support + * standard C library. + * + * - LZ4_FREESTANDING is a compile-time switch. + * - It requires the following macros to be defined: + * LZ4_memcpy, LZ4_memmove, LZ4_memset. + * - It only enables LZ4/HC functions which don't use heap. + * All LZ4F_* functions are not supported. + * - See tests/freestanding.c to check its basic setup. + */ +#if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1) +#define LZ4_HEAPMODE 0 +#define LZ4HC_HEAPMODE 0 +#define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1 +#if !defined(LZ4_memcpy) +#error "LZ4_FREESTANDING requires macro 'LZ4_memcpy'." +#endif +#if !defined(LZ4_memset) +#error "LZ4_FREESTANDING requires macro 'LZ4_memset'." +#endif +#if !defined(LZ4_memmove) +#error "LZ4_FREESTANDING requires macro 'LZ4_memmove'." +#endif +#elif !defined(LZ4_FREESTANDING) +#define LZ4_FREESTANDING 0 +#endif + /*------ Version ------*/ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MINOR \ - 8 /* for new (non-breaking) interface capabilities \ + 10 /* for new (non-breaking) interface capabilities \ */ -#define LZ4_VERSION_RELEASE 2 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER \ (LZ4_VERSION_MAJOR * 100 * 100 + LZ4_VERSION_MINOR * 100 + \ @@ -110,55 +144,84 @@ extern "C" { #define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE #define LZ4_QUOTE(str) #str #define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) -#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) - -LZ4LIB_API int LZ4_versionNumber(void); -/**< library version number; useful to check dll version */ +#define LZ4_VERSION_STRING \ + LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) /* requires v1.7.3+ */ -LZ4LIB_API const char *LZ4_versionString( - void); /**< library version string; unseful to check dll version */ +LZ4LIB_API int +LZ4_versionNumber(void); /**< library version number; useful to check dll + version; requires v1.3.0+ */ +LZ4LIB_API const char * +LZ4_versionString(void); /**< library version string; useful to check dll + version; requires v1.7.5+ */ /*-************************************ - * Tuning parameter + * Tuning memory usage **************************************/ /*! * LZ4_MEMORY_USAGE : + * Can be selected at compile time, by setting LZ4_MEMORY_USAGE. * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> - * 64KB; 20 -> 1MB; etc.) Increasing memory usage improves compression ratio - * Reduced memory usage may improve speed, thanks to cache effect - * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + * 64KB; 20 -> 1MB) Increasing memory usage improves compression ratio, + * generally at the cost of speed. Reduced memory usage may improve speed at the + * cost of ratio, thanks to better cache locality. Default value is 14, for + * 16KB, which nicely fits into most L1 caches. */ #ifndef LZ4_MEMORY_USAGE -#define LZ4_MEMORY_USAGE 14 +#define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT +#endif + +/* These are absolute limits, they should not be changed by users */ +#define LZ4_MEMORY_USAGE_MIN 10 +#define LZ4_MEMORY_USAGE_DEFAULT 14 +#define LZ4_MEMORY_USAGE_MAX 20 + +#if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN) +#error "LZ4_MEMORY_USAGE is too small !" +#endif + +#if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX) +#error "LZ4_MEMORY_USAGE is too large !" #endif /*-************************************ * Simple Functions **************************************/ /*! LZ4_compress_default() : - Compresses 'srcSize' bytes from buffer 'src' - into already allocated 'dst' buffer of size 'dstCapacity'. - Compression is guaranteed to succeed if 'dstCapacity' >= - LZ4_compressBound(srcSize). It also runs faster, so it's a recommended - setting. If the function cannot compress 'src' into a more limited 'dst' - budget, compression stops *immediately*, and the function result is zero. - Note : as a consequence, 'dst' content is not valid. - Note 2 : This function is protected against buffer overflow scenarios (never - writes outside 'dst' buffer, nor read outside 'source' buffer). srcSize : max - supported value is LZ4_MAX_INPUT_SIZE. dstCapacity : size of buffer 'dst' - (which must be already allocated) return : the number of bytes written into - buffer 'dst' (necessarily <= dstCapacity) or 0 if compression fails */ + * Compresses 'srcSize' bytes from buffer 'src' + * into already allocated 'dst' buffer of size 'dstCapacity'. + * Compression is guaranteed to succeed if 'dstCapacity' >= + * LZ4_compressBound(srcSize). It also runs faster, so it's a recommended + * setting. If the function cannot compress 'src' into a more limited 'dst' + * budget, compression stops *immediately*, and the function result is zero. In + * which case, 'dst' content is undefined (invalid). srcSize : max supported + * value is LZ4_MAX_INPUT_SIZE. dstCapacity : size of buffer 'dst' (which must + * be already allocated) + * @return : the number of bytes written into buffer 'dst' (necessarily <= + * dstCapacity) or 0 if compression fails Note : This function is protected + * against buffer overflow scenarios (never writes outside 'dst' buffer, nor + * read outside 'source' buffer). + */ LZ4LIB_API int LZ4_compress_default(const char *src, char *dst, int srcSize, int dstCapacity); /*! LZ4_decompress_safe() : - compressedSize : is the exact complete size of the compressed block. - dstCapacity : is the size of destination buffer, which must be already - allocated. return : the number of bytes decompressed into destination buffer - (necessarily <= dstCapacity) If destination buffer is not large enough, - decoding will stop and output an error code (negative value). If the source - stream is detected malformed, the function will stop decoding and return a - negative result. This function is protected against malicious data packets. + * @compressedSize : is the exact complete size of the compressed block. + * @dstCapacity : is the size of destination buffer (which must be already + * allocated), presumed an upper bound of decompressed size. + * @return : the number of bytes decompressed into destination buffer + * (necessarily <= dstCapacity) If destination buffer is not large enough, + * decoding will stop and output an error code (negative value). If the source + * stream is detected malformed, the function will stop decoding and return a + * negative result. Note 1 : This function is protected against malicious data + * packets : it will never writes outside 'dst' buffer, nor read outside + * 'source' buffer, even if the compressed block is maliciously modified to + * order the decoder to do these actions. In such case, the decoder stops + * immediately, and considers the compressed block malformed. Note 2 : + * compressedSize and dstCapacity must be provided to the function, the + * compressed block does not contain them. The implementation is free to send / + * store / derive this information in whichever way is most beneficial. If there + * is a need for a different format which bundles together both compressed data + * and its metadata, consider looking at lz4frame.h instead. */ LZ4LIB_API int LZ4_decompress_safe(const char *src, char *dst, int compressedSize, int dstCapacity); @@ -172,9 +235,8 @@ LZ4LIB_API int LZ4_decompress_safe(const char *src, char *dst, ? 0 \ : (isize) + ((isize) / 255) + 16) -/*! - LZ4_compressBound() : - Provides the maximum size that LZ4 compression may output in a "worst case" +/*! LZ4_compressBound() : + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) This function is primarily useful for memory allocation purposes (destination buffer size). Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack @@ -183,79 +245,95 @@ LZ4LIB_API int LZ4_decompress_safe(const char *src, char *dst, supported value is LZ4_MAX_INPUT_SIZE return : maximum output size in a "worst case" scenario or 0, if input size is incorrect (too large or negative) - */ +*/ LZ4LIB_API int LZ4_compressBound(int inputSize); -/*! - LZ4_compress_fast() : - Same as LZ4_compress_default(), but allows selection of "acceleration" +/*! LZ4_compress_fast() : + Same as LZ4_compress_default(), but allows selection of "acceleration" factor. The larger the acceleration value, the faster the algorithm, but also the lesser the compression. It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. An acceleration value of "1" is the same as regular LZ4_compress_default() Values <= 0 will be - replaced by ACCELERATION_DEFAULT (currently == 1, see lz4.c). - */ + replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c). Values > + LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == + 65537, see lz4.c). +*/ LZ4LIB_API int LZ4_compress_fast(const char *src, char *dst, int srcSize, int dstCapacity, int acceleration); -/*! - LZ4_compress_fast_extState() : - Same compression function, just using an externally allocated memory space to - store compression state. Use LZ4_sizeofState() to know how much memory must - be allocated, and allocate it on 8-bytes boundaries (using malloc() - typically). Then, provide it as 'void* state' to compression function. +/*! LZ4_compress_fast_extState() : + * Same as LZ4_compress_fast(), using an externally allocated memory space for + * its state. Use LZ4_sizeofState() to know how much memory must be allocated, + * and allocate it on 8-bytes boundaries (using `malloc()` typically). + * Then, provide this buffer as `void* state` to compression function. */ LZ4LIB_API int LZ4_sizeofState(void); LZ4LIB_API int LZ4_compress_fast_extState(void *state, const char *src, char *dst, int srcSize, int dstCapacity, int acceleration); -/*! - LZ4_compress_destSize() : - Reverse the logic : compresses as much data as possible from 'src' buffer - into already allocated buffer 'dst' of size 'targetDestSize'. - This function either compresses the entire 'src' content into 'dst' if it's - large enough, or fill 'dst' buffer completely with as much data as possible - from 'src'. *srcSizePtr : will be modified to indicate how many bytes where - read from 'src' to fill 'dst'. New value is necessarily <= old value. return - : Nb bytes written into 'dst' (necessarily <= targetDestSize) or 0 if - compression fails +/*! LZ4_compress_destSize() : + * Reverse the logic : compresses as much data as possible from 'src' buffer + * into already allocated buffer 'dst', of size >= 'dstCapacity'. + * This function either compresses the entire 'src' content into 'dst' if it's + * large enough, or fill 'dst' buffer completely with as much data as possible + * from 'src'. note: acceleration parameter is fixed to "default". + * + * *srcSizePtr : in+out parameter. Initially contains size of input. + * Will be modified to indicate how many bytes where read from + * 'src' to fill 'dst'. New value is necessarily <= input value. + * @return : Nb bytes written into 'dst' (necessarily <= dstCapacity) + * or 0 if compression fails. + * + * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed in v1.9.2+): + * the produced compressed content could, in specific circumstances, + * require to be decompressed into a destination buffer larger + * by at least 1 byte than the content to decompress. + * If an application uses `LZ4_compress_destSize()`, + * it's highly recommended to update liblz4 to v1.9.2 or better. + * If this can't be done or ensured, + * the receiving decompression function should provide + * a dstCapacity which is > decompressedSize, by at least 1 byte. + * See https://github.com/lz4/lz4/issues/859 for details */ LZ4LIB_API int LZ4_compress_destSize(const char *src, char *dst, int *srcSizePtr, int targetDstSize); -/*! - LZ4_decompress_fast() : **unsafe!** - This function is a bit faster than LZ4_decompress_safe(), - but it may misbehave on malformed input because it doesn't perform full - validation of compressed data. originalSize : is the uncompressed size to - regenerate Destination buffer must be already allocated, and its size must be - >= 'originalSize' bytes. return : number of bytes read from source buffer (== - compressed size). If the source stream is detected malformed, the function - stops decoding and return a negative result. note : This function is only - usable if the originalSize of uncompressed data is known in advance. The - caller should also check that all the compressed input has been consumed - properly, i.e. that the return value matches the size of the buffer with - compressed input. The function never writes past the output buffer. However, - since it doesn't know its 'src' size, it may read past the intended input. - Also, because match offsets are not validated during decoding, reads from - 'src' may underflow. Use this function in trusted environment **only**. - */ -LZ4LIB_API int LZ4_decompress_fast(const char *src, char *dst, - int originalSize); - -/*! - LZ4_decompress_safe_partial() : - This function decompress a compressed block of size 'srcSize' at position - 'src' into destination buffer 'dst' of size 'dstCapacity'. The function will - decompress a minimum of 'targetOutputSize' bytes, and stop after that. - However, it's not accurate, and may write more than 'targetOutputSize' (but - always <= dstCapacity). - @return : the number of bytes decoded in the destination buffer (necessarily - <= dstCapacity) Note : this number can also be < targetOutputSize, if - compressed block contains less data. Therefore, always control how many bytes - were decoded. If source stream is detected malformed, function returns a - negative result. This function is protected against malicious data packets. +/*! LZ4_decompress_safe_partial() : + * Decompress an LZ4 compressed block, of size 'srcSize' at position 'src', + * into destination buffer 'dst' of size 'dstCapacity'. + * Up to 'targetOutputSize' bytes will be decoded. + * The function stops decoding on reaching this objective. + * This can be useful to boost performance + * whenever only the beginning of a block is required. + * + * @return : the number of bytes decoded in `dst` (necessarily <= + * targetOutputSize) If source stream is detected malformed, function returns a + * negative result. + * + * Note 1 : @return can be < targetOutputSize, if compressed block contains + * less data. + * + * Note 2 : targetOutputSize must be <= dstCapacity + * + * Note 3 : this function effectively stops decoding on reaching + * targetOutputSize, so dstCapacity is kind of redundant. This is because in + * older versions of this function, decoding operation would still write + * complete sequences. Therefore, there was no guarantee that it would stop + * writing at exactly targetOutputSize, it could write more bytes, though only + * up to dstCapacity. Some "margin" used to be required for this operation to + * work properly. Thankfully, this is no longer necessary. The function + * nonetheless keeps the same signature, in an effort to preserve API + * compatibility. + * + * Note 4 : If srcSize is the exact size of the block, + * then targetOutputSize can be any value, + * including larger than the block's decompressed size. + * The function will, at most, generate block's decompressed size. + * + * Note 5 : If srcSize is _larger_ than block's compressed size, + * then targetOutputSize **MUST** be <= block's decompressed size. + * Otherwise, *silent corruption will occur*. */ LZ4LIB_API int LZ4_decompress_safe_partial(const char *src, char *dst, int srcSize, int targetOutputSize, @@ -266,45 +344,144 @@ LZ4LIB_API int LZ4_decompress_safe_partial(const char *src, char *dst, ***********************************************/ typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ -/*! LZ4_createStream() and LZ4_freeStream() : - * LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. - * LZ4_freeStream() releases its memory. - */ +/*! + Note about RC_INVOKED + + - RC_INVOKED is predefined symbol of rc.exe (the resource compiler which is + part of MSVC/Visual Studio). + https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros + + - Since rc.exe is a legacy compiler, it truncates long symbol (> 30 chars) + and reports warning "RC4011: identifier truncated". + + - To eliminate the warning, we surround long preprocessor symbol with + "#if !defined(RC_INVOKED) ... #endif" block that means + "skip this block when rc.exe is trying to read it". +*/ +#if !defined( \ + RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros \ + */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_stream_t *LZ4_createStream(void); LZ4LIB_API int LZ4_freeStream(LZ4_stream_t *streamPtr); +#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ +#endif -/*! LZ4_resetStream() : - * An LZ4_stream_t structure can be allocated once and re-used multiple times. - * Use this function to start compressing a new stream. +/*! LZ4_resetStream_fast() : v1.9.0+ + * Use this to prepare an LZ4_stream_t for a new chain of dependent blocks + * (e.g., LZ4_compress_fast_continue()). + * + * An LZ4_stream_t must be initialized once before usage. + * This is automatically done when created by LZ4_createStream(). + * However, should the LZ4_stream_t be simply declared on stack (for example), + * it's necessary to initialize it first, using LZ4_initStream(). + * + * After init, start any new stream with LZ4_resetStream_fast(). + * A same LZ4_stream_t can be re-used multiple times consecutively + * and compress multiple streams, + * provided that it starts each new stream with LZ4_resetStream_fast(). + * + * LZ4_resetStream_fast() is much faster than LZ4_initStream(), + * but is not compatible with memory regions containing garbage data. + * + * Note: it's only useful to call LZ4_resetStream_fast() + * in the context of streaming compression. + * The *extState* functions perform their own resets. + * Invoking LZ4_resetStream_fast() before is redundant, and even + * counterproductive. */ -LZ4LIB_API void LZ4_resetStream(LZ4_stream_t *streamPtr); +LZ4LIB_API void LZ4_resetStream_fast(LZ4_stream_t *streamPtr); /*! LZ4_loadDict() : - * Use this function to load a static dictionary into LZ4_stream_t. - * Any previous data will be forgotten, only 'dictionary' will remain in - * memory. Loading a size of 0 is allowed, and is the same as reset. - * @return : dictionary size, in bytes (necessarily <= 64 KB) + * Use this function to reference a static dictionary into LZ4_stream_t. + * The dictionary must remain available during compression. + * LZ4_loadDict() triggers a reset, so any previous data will be forgotten. + * The same dictionary will have to be loaded on decompression side for + * successful decoding. Dictionary are useful for better compression of small + * data (KB range). While LZ4 itself accepts any input as dictionary, dictionary + * efficiency is also a topic. When in doubt, employ the Zstandard's Dictionary + * Builder. Loading a size of 0 is allowed, and is the same as reset. + * @return : loaded dictionary size, in bytes (note: only the last 64 KB are + * loaded) */ LZ4LIB_API int LZ4_loadDict(LZ4_stream_t *streamPtr, const char *dictionary, int dictSize); +/*! LZ4_loadDictSlow() : v1.10.0+ + * Same as LZ4_loadDict(), + * but uses a bit more cpu to reference the dictionary content more thoroughly. + * This is expected to slightly improve compression ratio. + * The extra-cpu cost is likely worth it if the dictionary is re-used across + * multiple sessions. + * @return : loaded dictionary size, in bytes (note: only the last 64 KB are + * loaded) + */ +LZ4LIB_API int LZ4_loadDictSlow(LZ4_stream_t *streamPtr, const char *dictionary, + int dictSize); + +/*! LZ4_attach_dictionary() : stable since v1.10.0 + * + * This allows efficient re-use of a static dictionary multiple times. + * + * Rather than re-loading the dictionary buffer into a working context before + * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a + * working LZ4_stream_t, this function introduces a no-copy setup mechanism, + * in which the working stream references @dictionaryStream in-place. + * + * Several assumptions are made about the state of @dictionaryStream. + * Currently, only states which have been prepared by LZ4_loadDict() or + * LZ4_loadDictSlow() should be expected to work. + * + * Alternatively, the provided @dictionaryStream may be NULL, + * in which case any existing dictionary stream is unset. + * + * If a dictionary is provided, it replaces any pre-existing stream history. + * The dictionary contents are the only history that can be referenced and + * logically immediately precede the data compressed in the first subsequent + * compression call. + * + * The dictionary will only remain attached to the working stream through the + * first compression call, at the end of which it is cleared. + * @dictionaryStream stream (and source buffer) must remain in-place / + * accessible / unchanged through the completion of the compression session. + * + * Note: there is no equivalent LZ4_attach_*() method on the decompression side + * because there is no initialization cost, hence no need to share the cost + * across multiple sessions. To decompress LZ4 blocks using dictionary, attached + * or not, just employ the regular LZ4_setStreamDecode() for streaming, or the + * stateless LZ4_decompress_safe_usingDict() for one-shot decompression. + */ +LZ4LIB_API void LZ4_attach_dictionary(LZ4_stream_t *workingStream, + const LZ4_stream_t *dictionaryStream); + /*! LZ4_compress_fast_continue() : * Compress 'src' content using data from previously compressed blocks, for * better compression ratio. 'dst' buffer must be already allocated. If * dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to * succeed, and runs faster. * - * Important : The previous 64KB of compressed data is assumed to remain - * present and unmodified in memory! - * - * Special 1 : When input is a double-buffer, they can have any size, including - * < 64 KB. Make sure that buffers are separated by at least one byte. This way, - * each block only depends on previous block. Special 2 : If input buffer is a - * ring-buffer, it can have any size, including < 64 KB. - * * @return : size of compressed block * or 0 if there is an error (typically, cannot fit into 'dst'). - * After an error, the stream status is invalid, it can only be reset or freed. + * + * Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new + * block. Each block has precise boundaries. Each block must be decompressed + * separately, calling LZ4_decompress_*() with relevant metadata. It's not + * possible to append blocks together and expect a single invocation of + * LZ4_decompress_*() to decompress them together. + * + * Note 2 : The previous 64KB of source data is __assumed__ to remain present, + * unmodified, at same address in memory ! + * + * Note 3 : When input is structured as a double-buffer, each buffer can have + * any size, including < 64 KB. Make sure that buffers are separated, by at + * least one byte. This construction ensures that each block only depends on + * previous block. + * + * Note 4 : If input buffer is a ring-buffer, it can have any size, including < + * 64 KB. + * + * Note 5 : After an error, the stream status is undefined (invalid), it can + * only be reset or freed. */ LZ4LIB_API int LZ4_compress_fast_continue(LZ4_stream_t *streamPtr, const char *src, char *dst, @@ -332,13 +509,19 @@ typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */ * creation / destruction of streaming decompression tracking context. * A tracking context can be re-used multiple times. */ +#if !defined( \ + RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros \ + */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_streamDecode_t *LZ4_createStreamDecode(void); LZ4LIB_API int LZ4_freeStreamDecode(LZ4_streamDecode_t *LZ4_stream); +#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ +#endif /*! LZ4_setStreamDecode() : * An LZ4_streamDecode_t context can be allocated once and re-used multiple * times. Use this function to start decompression of a new stream of blocks. A - * dictionary can optionnally be set. Use NULL or size 0 for a reset order. + * dictionary can optionally be set. Use NULL or size 0 for a reset order. * Dictionary is presumed stable : it must remain accessible and unmodified * during next decompression. * @return : 1 if OK, 0 if error @@ -346,7 +529,7 @@ LZ4LIB_API int LZ4_freeStreamDecode(LZ4_streamDecode_t *LZ4_stream); LZ4LIB_API int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, const char *dictionary, int dictSize); -/*! LZ4_decoderRingBufferSize() : v1.8.2 +/*! LZ4_decoderRingBufferSize() : v1.8.2+ * Note : in a ring buffer scenario (optional), * blocks are presumed decompressed next to each other * up to the moment there is not enough remaining space for next block @@ -358,16 +541,31 @@ LZ4LIB_API int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, * or 0 if there is an error (invalid maxBlockSize). */ LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize); -#define LZ4_DECODER_RING_BUFFER_SIZE(mbs) \ - (65536 + 14 + (mbs)) /* for static allocation; mbs presumed valid */ - -/*! LZ4_decompress_*_continue() : - * These decoding functions allow decompression of consecutive blocks in - * "streaming" mode. A block is an unsplittable entity, it must be presented - * entirely to a decompression function. Decompression functions only accepts - * one block at a time. The last 64KB of previously decoded data *must* remain - * available and unmodified at the memory position where they were decoded. If - * less than 64KB of data has been decoded, all the data must be present. +#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) \ + (65536 + 14 + \ + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */ + +/*! LZ4_decompress_safe_continue() : + * This decoding function allows decompression of consecutive blocks in + * "streaming" mode. The difference with the usual independent blocks is that + * new blocks are allowed to find references into former blocks. + * A block is an unsplittable entity, and must be presented entirely to the + * decompression function. LZ4_decompress_safe_continue() only accepts one block + * at a time. It's modeled after `LZ4_decompress_safe()` and behaves similarly. + * + * @LZ4_streamDecode : decompression state, tracking the position in memory of + * past data + * @compressedSize : exact complete size of one compressed block. + * @dstCapacity : size of destination buffer (which must be already allocated), + * must be an upper bound of decompressed size. + * @return : number of bytes decompressed into destination buffer (necessarily + * <= dstCapacity) If destination buffer is not large enough, decoding will stop + * and output an error code (negative value). If the source stream is detected + * malformed, the function will stop decoding and return a negative result. + * + * The last 64KB of previously decoded data *must* remain available and + * unmodified at the memory position where they were previously decoded. If less + * than 64KB of data has been decoded, all the data must be present. * * Special : if decompression side sets a ring buffer, it must respect one of * the following conditions : @@ -397,130 +595,185 @@ LZ4LIB_API int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *src, char *dst, int srcSize, int dstCapacity); -LZ4LIB_API int -LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, - const char *src, char *dst, int originalSize); -/*! LZ4_decompress_*_usingDict() : - * These decoding functions work the same as +/*! LZ4_decompress_safe_usingDict() : + * Works the same as * a combination of LZ4_setStreamDecode() followed by - * LZ4_decompress_*_continue() They are stand-alone, and don't need an - * LZ4_streamDecode_t structure. Dictionary is presumed stable : it must remain - * accessible and unmodified during next decompression. + * LZ4_decompress_safe_continue() However, it's stateless: it doesn't need any + * LZ4_streamDecode_t state. Dictionary is presumed stable : it must remain + * accessible and unmodified during decompression. Performance tip : + * Decompression speed can be substantially increased when dst == dictStart + + * dictSize. */ LZ4LIB_API int LZ4_decompress_safe_usingDict(const char *src, char *dst, - int srcSize, int dstCapcity, - const char *dictStart, - int dictSize); -LZ4LIB_API int LZ4_decompress_fast_usingDict(const char *src, char *dst, - int originalSize, + int srcSize, int dstCapacity, const char *dictStart, int dictSize); -/*^********************************************** +/*! LZ4_decompress_safe_partial_usingDict() : + * Behaves the same as LZ4_decompress_safe_partial() + * with the added ability to specify a memory segment for past data. + * Performance tip : Decompression speed can be substantially increased + * when dst == dictStart + dictSize. + */ +LZ4LIB_API int LZ4_decompress_safe_partial_usingDict( + const char *src, char *dst, int compressedSize, int targetOutputSize, + int maxOutputSize, const char *dictStart, int dictSize); + +#endif /* LZ4_H_2983827168210 */ + +/*^************************************* * !!!!!! STATIC LINKING ONLY !!!!!! - ***********************************************/ + ***************************************/ -/*-************************************ - * Unstable declarations - ************************************** - * Declarations in this section should be considered unstable. - * Use at your own peril, etc., etc. - * They may be removed in the future. - * Their signatures may change. - **************************************/ +/*-**************************************************************************** + * Experimental section + * + * Symbols declared in this section must be considered unstable. Their + * signatures or semantics may change, or they may be removed altogether in the + * future. They are therefore only safe to depend on when the caller is + * statically linked against the library. + * + * To protect against unsafe usage, not only are the declarations guarded, + * the definitions are hidden by default + * when building LZ4 as a shared/dynamic library. + * + * In order to access these declarations, + * define LZ4_STATIC_LINKING_ONLY in your application + * before including LZ4's headers. + * + * In order to make their implementations accessible dynamically, you must + * define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library. + ******************************************************************************/ #ifdef LZ4_STATIC_LINKING_ONLY -/*! LZ4_resetStream_fast() : - * Use this, like LZ4_resetStream(), to prepare a context for a new chain of - * calls to a streaming API (e.g., LZ4_compress_fast_continue()). - * - * Note: - * Using this in advance of a non- streaming-compression function is redundant, - * and potentially bad for performance, since they all perform their own custom - * reset internally. - * - * Differences from LZ4_resetStream(): - * When an LZ4_stream_t is known to be in a internally coherent state, - * it can often be prepared for a new compression with almost no work, only - * sometimes falling back to the full, expensive reset that is always required - * when the stream is in an indeterminate state (i.e., the reset performed by - * LZ4_resetStream()). - * - * LZ4_streams are guaranteed to be in a valid state when: - * - returned from LZ4_createStream() - * - reset by LZ4_resetStream() - * - memset(stream, 0, sizeof(LZ4_stream_t)), though this is discouraged - * - the stream was in a valid state and was reset by LZ4_resetStream_fast() - * - the stream was in a valid state and was then used in any compression call - * that returned success - * - the stream was in an indeterminate state and was used in a compression - * call that fully reset the state (e.g., LZ4_compress_fast_extState()) and - * that returned success - * - * When a stream isn't known to be in a valid state, it is not safe to pass to - * any fastReset or streaming function. It must first be cleansed by the full - * LZ4_resetStream(). - */ -LZ4LIB_API void LZ4_resetStream_fast(LZ4_stream_t *streamPtr); +#ifndef LZ4_STATIC_3504398509 +#define LZ4_STATIC_3504398509 + +#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS +#define LZ4LIB_STATIC_API LZ4LIB_API +#else +#define LZ4LIB_STATIC_API +#endif /*! LZ4_compress_fast_extState_fastReset() : * A variant of LZ4_compress_fast_extState(). * - * Using this variant avoids an expensive initialization step. It is only safe - * to call if the state buffer is known to be correctly initialized already - * (see above comment on LZ4_resetStream_fast() for a definition of "correctly - * initialized"). From a high level, the difference is that this function - * initializes the provided state with a call to something like - * LZ4_resetStream_fast() while LZ4_compress_fast_extState() starts with a - * call to LZ4_resetStream(). + * Using this variant avoids an expensive initialization step. + * It is only safe to call if the state buffer is known to be correctly + * initialized already (see above comment on LZ4_resetStream_fast() for a + * definition of "correctly initialized"). From a high level, the difference is + * that this function initializes the provided state with a call to something + * like LZ4_resetStream_fast() while LZ4_compress_fast_extState() starts with a + * call to LZ4_resetStream(). */ -LZ4LIB_API int LZ4_compress_fast_extState_fastReset(void *state, - const char *src, char *dst, - int srcSize, - int dstCapacity, - int acceleration); +LZ4LIB_STATIC_API int +LZ4_compress_fast_extState_fastReset(void *state, const char *src, char *dst, + int srcSize, int dstCapacity, + int acceleration); + +/*! LZ4_compress_destSize_extState() : introduced in v1.10.0 + * Same as LZ4_compress_destSize(), but using an externally allocated state. + * Also: exposes @acceleration + */ +int LZ4_compress_destSize_extState(void *state, const char *src, char *dst, + int *srcSizePtr, int targetDstSize, + int acceleration); -/*! LZ4_attach_dictionary() : - * This is an experimental API that allows for the efficient use of a - * static dictionary many times. +/*! In-place compression and decompression * - * Rather than re-loading the dictionary buffer into a working context before - * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a - * working LZ4_stream_t, this function introduces a no-copy setup mechanism, - * in which the working stream references the dictionary stream in-place. + * It's possible to have input and output sharing the same buffer, + * for highly constrained memory environments. + * In both cases, it requires input to lay at the end of the buffer, + * and decompression to start at beginning of the buffer. + * Buffer size must feature some margin, hence be larger than final size. * - * Several assumptions are made about the state of the dictionary stream. - * Currently, only streams which have been prepared by LZ4_loadDict() should - * be expected to work. + * |<------------------------buffer--------------------------------->| + * |<-----------compressed data--------->| + * |<-----------decompressed size------------------>| + * |<----margin---->| * - * Alternatively, the provided dictionary stream pointer may be NULL, in which - * case any existing dictionary stream is unset. + * This technique is more useful for decompression, + * since decompressed size is typically larger, + * and margin is short. * - * If a dictionary is provided, it replaces any pre-existing stream history. - * The dictionary contents are the only history that can be referenced and - * logically immediately precede the data compressed in the first subsequent - * compression call. + * In-place decompression will work inside any buffer + * which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize). + * This presumes that decompressedSize > compressedSize. + * Otherwise, it means compression actually expanded data, + * and it would be more efficient to store such data with a flag indicating it's + * not compressed. This can happen when data is not compressible (already + * compressed, or encrypted). * - * The dictionary will only remain attached to the working stream through the - * first compression call, at the end of which it is cleared. The dictionary - * stream (and source buffer) must remain in-place / accessible / unchanged - * through the completion of the first compression call on the stream. + * For in-place compression, margin is larger, as it must be able to cope with + * both history preservation, requiring input data to remain unmodified up to + * LZ4_DISTANCE_MAX, and data expansion, which can happen when input is not + * compressible. As a consequence, buffer size requirements are much higher, and + * memory savings offered by in-place compression are more limited. + * + * There are ways to limit this cost for compression : + * - Reduce history size, by modifying LZ4_DISTANCE_MAX. + * Note that it is a compile-time constant, so all compressions will apply + * this limit. Lower values will reduce compression ratio, except when + * input_size < LZ4_DISTANCE_MAX, so it's a reasonable trick when inputs are + * known to be small. + * - Require the compressor to deliver a "maximum compressed size". + * This is the `dstCapacity` parameter in `LZ4_compress*()`. + * When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can + * fail, in which case, the return code will be 0 (zero). The caller must be + * ready for these cases to happen, and typically design a backup scheme to send + * data uncompressed. The combination of both techniques can significantly + * reduce the amount of margin required for in-place compression. + * + * In-place compression can work in any buffer + * which size is >= (maxCompressedSize) + * with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed + * compression success. LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both + * maxCompressedSize and LZ4_DISTANCE_MAX, so it's possible to reduce memory + * requirements by playing with them. */ -LZ4LIB_API void LZ4_attach_dictionary(LZ4_stream_t *working_stream, - const LZ4_stream_t *dictionary_stream); +#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) \ + (((compressedSize) >> 8) + 32) +#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) \ + ((decompressedSize) + \ + LZ4_DECOMPRESS_INPLACE_MARGIN( \ + decompressedSize)) /**< note: presumes that compressedSize < \ + decompressedSize. note2: margin is \ + overestimated a bit, since it could use \ + compressedSize instead */ + +#ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at \ + compile time */ +#define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */ #endif -/*-************************************ - * Private definitions - ************************************** - * Do not use these definitions. - * They are exposed to allow static allocation of `LZ4_stream_t` and - *`LZ4_streamDecode_t`. Using these definitions will expose code to API and/or +#define LZ4_COMPRESS_INPLACE_MARGIN \ + (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by \ + srcSize when it's smaller */ +#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) \ + ((maxCompressedSize) + \ + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally \ + LZ4_COMPRESSBOUND(inputSize), but can be \ + set to any lower value, with the risk \ + that compression can fail (return code \ + 0(zero)) */ + +#endif /* LZ4_STATIC_3504398509 */ +#endif /* LZ4_STATIC_LINKING_ONLY */ + +#ifndef LZ4_H_98237428734687 +#define LZ4_H_98237428734687 + +/*-************************************************************ + * Private Definitions + ************************************************************** + * Do not use these definitions directly. + * They are only exposed to allow static allocation of `LZ4_stream_t` and + *`LZ4_streamDecode_t`. Accessing members will expose user code to API and/or *ABI break in future versions of the library. - **************************************/ + **************************************************************/ #define LZ4_HASHLOG (LZ4_MEMORY_USAGE - 2) #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) #define LZ4_HASH_SIZE_U32 \ @@ -529,75 +782,74 @@ LZ4LIB_API void LZ4_attach_dictionary(LZ4_stream_t *working_stream, #if defined(__cplusplus) || \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) #include - -typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; -struct LZ4_stream_t_internal { - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint16_t initCheck; - uint16_t tableType; - const uint8_t *dictionary; - const LZ4_stream_t_internal *dictCtx; - uint32_t dictSize; -}; - -typedef struct { - const uint8_t *externalDict; - size_t extDictSize; - const uint8_t *prefixEnd; - size_t prefixSize; -} LZ4_streamDecode_t_internal; - +typedef int8_t LZ4_i8; +typedef uint8_t LZ4_byte; +typedef uint16_t LZ4_u16; +typedef uint32_t LZ4_u32; #else +typedef signed char LZ4_i8; +typedef unsigned char LZ4_byte; +typedef unsigned short LZ4_u16; +typedef unsigned int LZ4_u32; +#endif + +/*! LZ4_stream_t : + * Never ever use below internal definitions directly ! + * These definitions are not API/ABI safe, and may change in future versions. + * If you need static allocation, declare or allocate an LZ4_stream_t object. + **/ typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; struct LZ4_stream_t_internal { - unsigned int hashTable[LZ4_HASH_SIZE_U32]; - unsigned int currentOffset; - unsigned short initCheck; - unsigned short tableType; - const unsigned char *dictionary; + LZ4_u32 hashTable[LZ4_HASH_SIZE_U32]; + const LZ4_byte *dictionary; const LZ4_stream_t_internal *dictCtx; - unsigned int dictSize; + LZ4_u32 currentOffset; + LZ4_u32 tableType; + LZ4_u32 dictSize; + /* Implicit padding to ensure structure is aligned */ }; +#define LZ4_STREAM_MINSIZE \ + ((1UL << (LZ4_MEMORY_USAGE)) + \ + 32) /* static size, for inter-version compatibility */ +union LZ4_stream_u { + char minStateSize[LZ4_STREAM_MINSIZE]; + LZ4_stream_t_internal internal_donotuse; +}; /* previously typedef'd to LZ4_stream_t */ + +/*! LZ4_initStream() : v1.9.0+ + * An LZ4_stream_t structure must be initialized at least once. + * This is automatically done when invoking LZ4_createStream(), + * but it's not when the structure is simply declared on stack (for example). + * + * Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t. + * It can also initialize any arbitrary buffer of sufficient size, + * and will @return a pointer of proper type upon initialization. + * + * Note : initialization fails if size and alignment conditions are not + *respected. In which case, the function will @return NULL. Note2: An + *LZ4_stream_t structure guarantees correct alignment and size. Note3: Before + *v1.9.0, use LZ4_resetStream() instead + **/ +LZ4LIB_API LZ4_stream_t *LZ4_initStream(void *stateBuffer, size_t size); + +/*! LZ4_streamDecode_t : + * Never ever use below internal definitions directly ! + * These definitions are not API/ABI safe, and may change in future versions. + * If you need static allocation, declare or allocate an LZ4_streamDecode_t + *object. + **/ typedef struct { - const unsigned char *externalDict; + const LZ4_byte *externalDict; + const LZ4_byte *prefixEnd; size_t extDictSize; - const unsigned char *prefixEnd; size_t prefixSize; } LZ4_streamDecode_t_internal; -#endif - -/*! - * LZ4_stream_t : - * information structure to track an LZ4 stream. - * init this structure before first use. - * note : only use in association with static linking ! - * this definition is not API/ABI safe, - * it may change in a future version ! - */ -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE - 3)) + 4) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) -union LZ4_stream_u { - unsigned long long table[LZ4_STREAMSIZE_U64]; - LZ4_stream_t_internal internal_donotuse; -}; /* previously typedef'd to LZ4_stream_t */ - -/*! - * LZ4_streamDecode_t : - * information structure to track an LZ4 stream during decompression. - * init this structure using LZ4_setStreamDecode (or memset()) before first use - * note : only use in association with static linking ! - * this definition is not API/ABI safe, - * and may change in a future version ! - */ -#define LZ4_STREAMDECODESIZE_U64 4 -#define LZ4_STREAMDECODESIZE \ - (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +#define LZ4_STREAMDECODE_MINSIZE 32 union LZ4_streamDecode_u { - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + char minStateSize[LZ4_STREAMDECODE_MINSIZE]; LZ4_streamDecode_t_internal internal_donotuse; }; /* previously typedef'd to LZ4_streamDecode_t */ @@ -606,36 +858,41 @@ union LZ4_streamDecode_u { **************************************/ /*! Deprecation warnings - Should deprecation warnings be a problem, - it is generally possible to disable them, - typically with -Wno-deprecated-declarations for gcc - or _CRT_SECURE_NO_WARNINGS in Visual. - Otherwise, it's also possible to define LZ4_DISABLE_DEPRECATE_WARNINGS */ + * + * Deprecated functions make the compiler generate a warning when invoked. + * This is meant to invite users to update their source code. + * Should deprecation warnings be a problem, it is generally possible to + * disable them, typically with -Wno-deprecated-declarations for gcc or + * _CRT_SECURE_NO_WARNINGS in Visual. + * + * Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS + * before including the header file. + */ #ifdef LZ4_DISABLE_DEPRECATE_WARNINGS #define LZ4_DEPRECATED(message) /* disable deprecation warnings */ #else -#define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #if defined(__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ #define LZ4_DEPRECATED(message) [[deprecated(message)]] -#elif (LZ4_GCC_VERSION >= 405) || defined(__clang__) -#define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) -#elif (LZ4_GCC_VERSION >= 301) -#define LZ4_DEPRECATED(message) __attribute__((deprecated)) #elif defined(_MSC_VER) #define LZ4_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__clang__) || \ + (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45)) +#define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) +#elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31) +#define LZ4_DEPRECATED(message) __attribute__((deprecated)) #else #pragma message( \ - "WARNING: You need to implement LZ4_DEPRECATED for this compiler") -#define LZ4_DEPRECATED(message) + "WARNING: LZ4_DEPRECATED needs custom implementation for this compiler") +#define LZ4_DEPRECATED(message) /* disabled */ #endif #endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ -/* Obsolete compression functions */ +/*! Obsolete compression functions (since v1.7.3) */ LZ4_DEPRECATED("use LZ4_compress_default() instead") -LZ4LIB_API int LZ4_compress(const char *source, char *dest, int sourceSize); +LZ4LIB_API int LZ4_compress(const char *src, char *dest, int srcSize); LZ4_DEPRECATED("use LZ4_compress_default() instead") -LZ4LIB_API int LZ4_compress_limitedOutput(const char *source, char *dest, - int sourceSize, int maxOutputSize); +LZ4LIB_API int LZ4_compress_limitedOutput(const char *src, char *dest, + int srcSize, int maxOutputSize); LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState(void *state, const char *source, char *dest, int inputSize); @@ -654,14 +911,15 @@ int LZ4_compress_limitedOutput_continue(LZ4_stream_t *LZ4_streamPtr, const char *source, char *dest, int inputSize, int maxOutputSize); -/* Obsolete decompression functions */ +/*! Obsolete decompression functions (since v1.8.0) */ LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress(const char *source, char *dest, int outputSize); LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize); -/* Obsolete streaming functions; degraded functionality; do not use! +/* Obsolete streaming functions (since v1.7.0) + * degraded functionality; do not use! * * In order to perform streaming compression, these functions depended on data * that is no longer tracked in the state. They have been preserved as well as @@ -679,7 +937,7 @@ LZ4LIB_API int LZ4_resetStreamState(void *state, char *inputBuffer); LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char *LZ4_slideInputBuffer(void *state); -/* Obsolete streaming decoding functions */ +/*! Obsolete streaming decoding functions (since v1.7.0) */ LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k(const char *src, char *dst, @@ -688,7 +946,64 @@ LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k(const char *src, char *dst, int originalSize); -#endif /* LZ4_H_2983827168210 */ +/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) : + * These functions used to be faster than LZ4_decompress_safe(), + * but this is no longer the case. They are now slower. + * This is because LZ4_decompress_fast() doesn't know the input size, + * and therefore must progress more cautiously into the input buffer to not + * read beyond the end of block. On top of that `LZ4_decompress_fast()` is not + * protected vs malformed or malicious inputs, making it a security liability. + * As a consequence, LZ4_decompress_fast() is strongly discouraged, and + * deprecated. + * + * The last remaining LZ4_decompress_fast() specificity is that + * it can decompress a block without knowing its compressed size. + * Such functionality can be achieved in a more secure manner + * by employing LZ4_decompress_safe_partial(). + * + * Parameters: + * originalSize : is the uncompressed size to regenerate. + * `dst` must be already allocated, its size must be >= + * 'originalSize' bytes. + * @return : number of bytes read from source buffer (== compressed size). + * The function expects to finish at block's end exactly. + * If the source stream is detected malformed, the function stops + * decoding and returns a negative result. note : LZ4_decompress_fast*() + * requires originalSize. Thanks to this information, it never writes past the + * output buffer. However, since it doesn't know its 'src' size, it may read an + * unknown amount of input, past input buffer bounds. Also, since match offsets + * are not validated, match reads from 'src' may underflow too. These issues + * never happen if input (compressed) data is correct. But they may happen if + * input data is invalid (error or intentional tampering). As a consequence, use + * these functions in trusted environments with trusted data **only**. + */ +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using " + "LZ4_decompress_safe_partial() instead") +LZ4LIB_API int LZ4_decompress_fast(const char *src, char *dst, + int originalSize); +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider migrating " + "towards LZ4_decompress_safe_continue() instead. " + "Note that the contract will change (requires block's " + "compressed size, instead of decompressed size)") +LZ4LIB_API int +LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, + const char *src, char *dst, int originalSize); +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using " + "LZ4_decompress_safe_partial_usingDict() instead") +LZ4LIB_API int LZ4_decompress_fast_usingDict(const char *src, char *dst, + int originalSize, + const char *dictStart, + int dictSize); + +/*! LZ4_resetStream() : + * An LZ4_stream_t structure must be initialized at least once. + * This is done with LZ4_initStream(), or LZ4_resetStream(). + * Consider switching to LZ4_initStream(), + * invoking LZ4_resetStream() will trigger deprecation warnings in the future. + */ +LZ4LIB_API void LZ4_resetStream(LZ4_stream_t *streamPtr); + +#endif /* LZ4_H_98237428734687 */ #if defined(__cplusplus) } diff --git a/lib/gis/parser_rest_md.c b/lib/gis/parser_rest_md.c index 551c72b40e7..eada518c236 100644 --- a/lib/gis/parser_rest_md.c +++ b/lib/gis/parser_rest_md.c @@ -4,7 +4,7 @@ \brief GIS Library - Argument parsing functions (reStructuredText and Markdown output) - (C) 2012-2023 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. @@ -20,6 +20,8 @@ #include "parser_local_proto.h" +#define MD_NEWLINE " " + static void usage_rest_md(bool rest); static void print_flag(const char *key, const char *label, const char *description, bool rest); @@ -41,7 +43,6 @@ void usage_rest_md(bool rest) struct Option *opt; struct Flag *flag; const char *type; - char *header = NULL; int new_prompt = 0; new_prompt = G__uses_new_gisprompt(); @@ -51,35 +52,17 @@ void usage_rest_md(bool rest) if (!st->pgm_name) st->pgm_name = "??"; - /* main header */ - G_asprintf(&header, "%s - GRASS GIS manual", st->pgm_name); - if (rest) { - size_t s; - fprintf(stdout, "%s\n", header); - for (s = 0; s < strlen(header); s++) { - fprintf(stdout, "="); - } - fprintf(stdout, "\n"); - } - else { - fprintf(stdout, "# %s\n", header); - } - fprintf(stdout, "\n"); + /* print metadata used by man/build*.py */ + fprintf(stdout, "---\n"); + fprintf(stdout, "name: %s\n", st->pgm_name); + fprintf(stdout, "description: %s\n", st->module_info.description); + fprintf(stdout, "keywords: "); + G__print_keywords(stdout, NULL, FALSE); + fprintf(stdout, "\n---\n\n"); - /* GRASS GIS logo */ - if (rest) { - fprintf(stdout, ".. image:: grass_logo.png\n"); - fprintf(stdout, " :align: center\n"); - fprintf(stdout, " :alt: GRASS logo\n"); - } - else { - fprintf(stdout, "![GRASS logo](./grass_logo.png)\n"); - } - /* horizontal line */ - fprintf(stdout, "\n---"); - if (rest) - fprintf(stdout, "-"); - fprintf(stdout, "\n\n"); + /* main header */ + if (!rest) + fprintf(stdout, "# %s\n\n", st->pgm_name); /* header - GRASS module */ if (!rest) @@ -88,7 +71,7 @@ void usage_rest_md(bool rest) if (rest) fprintf(stdout, "----"); fprintf(stdout, "\n"); - fprintf(stdout, "**%s**", st->pgm_name); + fprintf(stdout, "***%s***", st->pgm_name); if (st->module_info.label || st->module_info.description) fprintf(stdout, " - "); @@ -130,13 +113,13 @@ void usage_rest_md(bool rest) } fprintf(stdout, "**%s**", st->pgm_name); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); if (rest) fprintf(stdout, "| "); fprintf(stdout, "**%s --help**", st->pgm_name); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); if (rest) fprintf(stdout, "| "); @@ -219,7 +202,7 @@ void usage_rest_md(bool rest) while (st->n_flags && flag != NULL) { print_flag(&flag->key, flag->label, flag->description, rest); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); flag = flag->next_flag; } @@ -228,21 +211,21 @@ void usage_rest_md(bool rest) _("Allow output files to overwrite existing files"), rest); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); } } print_flag("help", NULL, _("Print usage summary"), rest); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); print_flag("verbose", NULL, _("Verbose module output"), rest); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); print_flag("quiet", NULL, _("Quiet module output"), rest); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); print_flag("ui", NULL, _("Force launching GUI dialog"), rest); fprintf(stdout, "\n"); @@ -263,7 +246,7 @@ void usage_rest_md(bool rest) opt = opt->next_opt; if (opt != NULL) { if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); } fprintf(stdout, "\n"); } @@ -284,7 +267,7 @@ void print_flag(const char *key, const char *label, const char *description, fprintf(stdout, "-"); fprintf(stdout, "-%s**", key); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); if (label != NULL) { if (rest) @@ -292,13 +275,15 @@ void print_flag(const char *key, const char *label, const char *description, print_escaped(stdout, "\t", rest); print_escaped(stdout, label, rest); if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); } - if (rest) - fprintf(stdout, "| "); - print_escaped(stdout, "\t", rest); - print_escaped(stdout, description, rest); + if (description != NULL) { + if (rest) + fprintf(stdout, "| "); + print_escaped(stdout, "\t", rest); + print_escaped(stdout, description, rest); + } } void print_option(const struct Option *opt, bool rest, char *image_spec_rest) @@ -341,7 +326,7 @@ void print_option(const struct Option *opt, bool rest, char *image_spec_rest) fprintf(stdout, " **[required]**"); } if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); if (opt->label) { if (rest) @@ -352,7 +337,7 @@ void print_option(const struct Option *opt, bool rest, char *image_spec_rest) if (opt->description) { if (opt->label) { if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); } if (rest) @@ -363,7 +348,7 @@ void print_option(const struct Option *opt, bool rest, char *image_spec_rest) if (opt->options) { if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); if (rest) fprintf(stdout, "| "); @@ -375,7 +360,7 @@ void print_option(const struct Option *opt, bool rest, char *image_spec_rest) if (opt->def) { if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); if (rest) fprintf(stdout, "| "); @@ -394,7 +379,7 @@ void print_option(const struct Option *opt, bool rest, char *image_spec_rest) while (opt->opts[i]) { if (opt->descs[i]) { if (!rest) - fprintf(stdout, "\\"); + fprintf(stdout, MD_NEWLINE); fprintf(stdout, "\n"); char *thumbnails = NULL; if (opt->gisprompt) { @@ -518,7 +503,7 @@ void print_escaped_for_md_keywords(FILE *f, const char *str) str_s = G_store(str); G_strip(str_s); - /* HTML link only for second keyword */ + /* HTML link only for second keyword = topic */ if (st->n_keys > 1 && strcmp(st->module_info.keywords[1], str) == 0) { const char *s; @@ -532,7 +517,7 @@ void print_escaped_for_md_keywords(FILE *f, const char *str) fputc(*s, f); } } - fprintf(f, ".html)"); + fprintf(f, ".md)"); } else { /* first and other than second keyword */ if (st->n_keys > 0 && strcmp(st->module_info.keywords[0], str) == 0) { @@ -547,13 +532,14 @@ void print_escaped_for_md_keywords(FILE *f, const char *str) fputc(*s, f); } } - fprintf(f, ".html)"); + fprintf(f, ".md)"); } else { - /* keyword index */ + /* keyword index, mkdocs expects dash */ char *str_link; - str_link = G_str_replace(str_s, " ", "%20"); - fprintf(f, "[%s](keywords.html#%s)", str_s, str_link); + str_link = G_str_replace(str_s, " ", "-"); + G_str_to_lower(str_link); + fprintf(f, "[%s](keywords.md#%s)", str_s, str_link); G_free(str_link); } } 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/gis/testsuite/test_gis_lib_getl.py b/lib/gis/testsuite/test_gis_lib_getl.py index 98092955ab2..72e8992ad39 100644 --- a/lib/gis/testsuite/test_gis_lib_getl.py +++ b/lib/gis/testsuite/test_gis_lib_getl.py @@ -5,7 +5,6 @@ import ctypes import pathlib -import platform import unittest import grass.lib.gis as libgis diff --git a/lib/gmath/gmathlib.dox b/lib/gmath/gmathlib.dox index a404595de04..77b516b8ebd 100644 --- a/lib/gmath/gmathlib.dox +++ b/lib/gmath/gmathlib.dox @@ -464,8 +464,8 @@ implemented.

      Getting BLAS/LAPACK (one package) if not already provided by the system: -
      http://www.netlib.org/lapack/ -
      http://netlib.bell-labs.com/netlib/master/readme.html +
      https://www.netlib.org/lapack/ +
      https://netlib.bell-labs.com/netlib/master/readme.html

      Pre-compiled binaries of LAPACK/BLAS are provided on many Linux diff --git a/lib/gpde/n_arrays_io.c b/lib/gpde/n_arrays_io.c index eae8a9065c6..5836df00754 100644 --- a/lib/gpde/n_arrays_io.c +++ b/lib/gpde/n_arrays_io.c @@ -150,6 +150,7 @@ N_array_2d *N_read_rast_to_array_2d(char *name, N_array_2d *array) /* Close file */ Rast_close(map); + G_free(rast); return data; } @@ -219,6 +220,9 @@ void N_write_array_2d_to_rast(N_array_2d *array, char *name) /* Close file */ Rast_close(map); + G_free(rast); + G_free(frast); + G_free(drast); } /* ******************** 3D ARRAY FUNCTIONS *********************** */ diff --git a/lib/gpde/n_les_assemble.c b/lib/gpde/n_les_assemble.c index 0d90e09c4f7..fb08ed8046d 100644 --- a/lib/gpde/n_les_assemble.c +++ b/lib/gpde/n_les_assemble.c @@ -875,6 +875,8 @@ int N_les_integrate_dirichlet_2d(N_les *les, N_geom_data *geom, count++; } } + G_free(dvect1); + G_free(dvect2); return 0; } diff --git a/lib/htmldriver/htmldriver.html b/lib/htmldriver/htmldriver.html index 3e14f240805..81036978dc2 100644 --- a/lib/htmldriver/htmldriver.html +++ b/lib/htmldriver/htmldriver.html @@ -54,14 +54,14 @@

      Environment variables

      (default is CLIENT):
      CLIENT    Netscape/IE client-side - image map (NAME="map").
      + image map (NAME="map").
      APACHE    Apache/NCSA server-side image - map.
      + map.
      RAW -         Raw url and polygon - vertices (url  x1  y1  x2  y2  - .....), suitable for conversion to CERN server format, or - any other format with user supplied conversion program.
      +         Raw url and polygon + vertices (url  x1  y1  x2  y2  + .....), suitable for conversion to CERN server format, or + any other format with user supplied conversion program.
    14. GRASS_RENDER_FILE=filename
      @@ -185,7 +185,9 @@

      SEE ALSO

      PNG driver, HTML driver, variables -

      + +

      + d.rast, d.vect, d.mon, diff --git a/lib/imagery/testsuite/test_imagery_sigfile.py b/lib/imagery/testsuite/test_imagery_sigfile.py index 8d0e288561d..731ef047063 100644 --- a/lib/imagery/testsuite/test_imagery_sigfile.py +++ b/lib/imagery/testsuite/test_imagery_sigfile.py @@ -349,9 +349,12 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.del_temp_region() - cls.runModule("g.remove", flags="f", type="raster", name=cls.map1) - cls.runModule("g.remove", flags="f", type="raster", name=cls.map2) - cls.runModule("g.remove", flags="f", type="raster", name=cls.map3) + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=(cls.map1, cls.map2, cls.map3), + ) def test_symmetric_complete_difference(self): # Prepare imagery group reference struct diff --git a/lib/imagery/testsuite/test_imagery_sigsetfile.py b/lib/imagery/testsuite/test_imagery_sigsetfile.py index d526e920885..80be7c0d3a5 100644 --- a/lib/imagery/testsuite/test_imagery_sigsetfile.py +++ b/lib/imagery/testsuite/test_imagery_sigsetfile.py @@ -242,9 +242,12 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.del_temp_region() - cls.runModule("g.remove", flags="f", type="raster", name=cls.map1) - cls.runModule("g.remove", flags="f", type="raster", name=cls.map2) - cls.runModule("g.remove", flags="f", type="raster", name=cls.map3) + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=(cls.map1, cls.map2, cls.map3), + ) def test_symmetric_complete_difference(self): # Prepare imagery group reference struct diff --git a/lib/init/Makefile b/lib/init/Makefile index f6983faada3..2db853fce95 100644 --- a/lib/init/Makefile +++ b/lib/init/Makefile @@ -47,8 +47,9 @@ ifneq ($(strip $(MINGW)),) endif HTMLFILES := $(wildcard *.html) +MDFILES := $(wildcard *.md) -default: $(FILES) $(patsubst %,$(HTMLDIR)/%,$(HTMLFILES)) +default: $(FILES) $(patsubst %,$(HTMLDIR)/%,$(HTMLFILES)) $(patsubst %,$(MDDIR)/source/%,$(MDFILES)) ifneq ($(strip $(MINGW)),) $(ARCH_BINDIR)/$(START_UP): grass.sh diff --git a/lib/init/grass.html b/lib/init/grass.html index 5b2d918fb12..736be547716 100644 --- a/lib/init/grass.html +++ b/lib/init/grass.html @@ -183,10 +183,10 @@

      User Interface Environment Variable

      determines the user interface to use. The following is the hierarchy from highest precedence to lowest.
        -
      1. Command line argument -
      2. Environment variable GRASS_GUI -
      3. Value set in $HOME/.grass8/rc (GUI) -
      4. Default value - gui +
      5. Command line argument
      6. +
      7. Environment variable GRASS_GUI
      8. +
      9. Value set in $HOME/.grass8/rc (GUI)
      10. +
      11. Default value - gui

      Python Environment Variables

      diff --git a/lib/init/grass.py b/lib/init/grass.py index 5c0d8132103..a1e50af63bb 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -125,7 +125,7 @@ def clean_env(): write_gisrc(env_new, gisrc) -def is_debug(): +def is_debug() -> bool: """Returns True if we are in debug mode For debug messages use ``debug()``. @@ -133,13 +133,8 @@ def is_debug(): global _DEBUG if _DEBUG is not None: return _DEBUG - _DEBUG = os.getenv("GRASS_DEBUG") # translate to bool (no or empty variable means false) - if _DEBUG: - _DEBUG = True - else: - _DEBUG = False - return _DEBUG + return bool(os.getenv("GRASS_DEBUG")) def debug(msg): @@ -553,10 +548,7 @@ def write_gisrc(kv, filename, append=False): def add_mapset_to_gisrc(gisrc, grassdb, location, mapset): - if os.access(gisrc, os.R_OK): - kv = read_gisrc(gisrc) - else: - kv = {} + kv = read_gisrc(gisrc) if os.access(gisrc, os.R_OK) else {} kv["GISDBASE"] = grassdb kv["LOCATION_NAME"] = location kv["MAPSET"] = mapset @@ -564,10 +556,7 @@ def add_mapset_to_gisrc(gisrc, grassdb, location, mapset): def add_last_mapset_to_gisrc(gisrc, last_mapset_path): - if os.access(gisrc, os.R_OK): - kv = read_gisrc(gisrc) - else: - kv = {} + kv = read_gisrc(gisrc) if os.access(gisrc, os.R_OK) else {} kv["LAST_MAPSET_PATH"] = last_mapset_path write_gisrc(kv, gisrc) @@ -1026,7 +1015,7 @@ def load_env(grass_env_file): # Regular expression for lines starting with "export var=val" (^export # lines below). Environment variables should start with a-zA-Z or _. # \1 and \2 are a variable name and its value, respectively. - export_re = re.compile("^export[ \t]+([a-zA-Z_]+[a-zA-Z0-9_]*)=(.*?)[ \t]*$") + export_re = re.compile(r"^export[ \t]+([a-zA-Z_]+[a-zA-Z0-9_]*)=(.*?)[ \t]*$") for line in readfile(grass_env_file).splitlines(): # match ^export lines @@ -1333,11 +1322,8 @@ def get_shell(): sh = os.path.basename(sh) else: # If SHELL is not set, see if there is Bash and use it. - if shutil.which("bash"): - sh = "bash" - else: - # Fallback to sh if there is no Bash on path. - sh = "sh" + # Fallback to sh if there is no Bash on path. + sh = "bash" if shutil.which("bash") else "sh" # Ensure the variable is set. os.environ["SHELL"] = sh @@ -1651,11 +1637,8 @@ def sh_like_startup(location, location_name, grass_env_file, sh): else: f.write("test -r ~/.alias && . ~/.alias\n") - if os.getenv("ISISROOT"): - # GRASS GIS and ISIS blend - grass_name = "ISIS-GRASS" - else: - grass_name = "GRASS" + # GRASS GIS and ISIS blend + grass_name = "GRASS" if not os.getenv("ISISROOT") else "ISIS-GRASS" if sh == "zsh": f.write("setopt PROMPT_SUBST\n") diff --git a/lib/init/helptext.html b/lib/init/helptext.html index d988b6b0376..4a14dd52df1 100644 --- a/lib/init/helptext.html +++ b/lib/init/helptext.html @@ -62,7 +62,7 @@

      GRASS started in the default project, now what?

      Creating a New project with the Project Wizard

      If you know the CRS of your data or study area, -you can fill EPSG code +you can fill EPSG code or description and Project Wizard finds appropriate CRS from a predefined list of projections. @@ -97,4 +97,6 @@

      See also

      - List of EPSG codes (Database of worldwide coordinate systems) + List of EPSG codes (Database of worldwide coordinate systems), + CRS Explorer - PROJ codes, and + EPSG Geodetic Parameter Dataset diff --git a/lib/init/variables.html b/lib/init/variables.html index 6fd10d7f173..b7704c5537b 100644 --- a/lib/init/variables.html +++ b/lib/init/variables.html @@ -222,14 +222,14 @@

      List of selected (GRASS related) shell environment variables

      it may be set to either
      • standard - sets percentage output and message - formatting style to standard formatting,
      • + formatting style to standard formatting,
      • gui - sets percentage output and message formatting - style to GUI formatting,
      • + style to GUI formatting,
      • silent - disables percentage output and error - messages,
      • + messages,
      • plain - sets percentage output and message - formatting style to ASCII output without rewinding control - characters.
      • + formatting style to ASCII output without rewinding control + characters.
      GRASS_MOUSE_BUTTON
      @@ -316,12 +316,11 @@

      List of selected (GRASS related) shell environment variables

      may be set to either:
      • keep - the temporary vector map is not deleted when - closing the map. + closing the map.
      • move - the temporary vector map is moved to the current mapset when closing the map.
      • delete - the temporary vector map is deleted when - closing the map. -
      • + closing the map.
      Default value is keep. @@ -392,12 +391,12 @@

      List of selected (GRASS related) shell environment variables

      TMPDIR, TEMP, TMP
      [Various GRASS GIS commands and wxGUI]
      - - The default wxGUI temporary directory is chosen from a - platform-dependent list, but the user can control the selection of - this directory by setting one of the TMPDIR, TEMP or TMP - environment variables Hence the wxGUI uses $TMPDIR if it is set, - then $TEMP, otherwise /tmp.
      + + The default wxGUI temporary directory is chosen from a + platform-dependent list, but the user can control the selection of + this directory by setting one of the TMPDIR, TEMP or TMP + environment variables Hence the wxGUI uses $TMPDIR if it is set, + then $TEMP, otherwise /tmp.

      List of selected GRASS environment variables for rendering

      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/pngdriver/pngdriver.html b/lib/pngdriver/pngdriver.html index d0eab9f4125..1b1f6b2a2cb 100644 --- a/lib/pngdriver/pngdriver.html +++ b/lib/pngdriver/pngdriver.html @@ -99,7 +99,9 @@

      SEE ALSO

      PS driver, HTML driver, variables -

      + +

      + d.rast, d.vect, d.mon, diff --git a/lib/psdriver/psdriver.html b/lib/psdriver/psdriver.html index 3cc9bf7404f..31af82fae88 100644 --- a/lib/psdriver/psdriver.html +++ b/lib/psdriver/psdriver.html @@ -85,7 +85,9 @@

      SEE ALSO

      PNG driver, HTML driver, variables -

      +
      +

      + d.rast, d.vect, d.mon, 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/raster/put_title.c b/lib/raster/put_title.c index 8d0d4f0b43f..346bf12f23d 100644 --- a/lib/raster/put_title.c +++ b/lib/raster/put_title.c @@ -35,6 +35,7 @@ int Rast_put_cell_title(const char *name, const char *title) if (!out) { fclose(in); G_warning(_("G_put_title - can't create a temp file")); + G_free(tempfile); return -1; } @@ -52,12 +53,15 @@ int Rast_put_cell_title(const char *name, const char *title) if (line < 3) { G_warning(_("category information for [%s] in [%s] invalid"), name, mapset); + remove(tempfile); + G_free(tempfile); return -1; } in = fopen(tempfile, "r"); if (!in) { G_warning(_("G_put_title - can't reopen temp file")); + G_free(tempfile); return -1; } @@ -66,6 +70,8 @@ int Rast_put_cell_title(const char *name, const char *title) fclose(in); G_warning(_("can't write category information for [%s] in [%s]"), name, mapset); + remove(tempfile); + G_free(tempfile); return -1; } @@ -75,6 +81,7 @@ int Rast_put_cell_title(const char *name, const char *title) fclose(in); fclose(out); remove(tempfile); + G_free(tempfile); return 1; } diff --git a/lib/raster3d/index.c b/lib/raster3d/index.c index a73e12219c0..6ddbbb083a6 100644 --- a/lib/raster3d/index.c +++ b/lib/raster3d/index.c @@ -37,6 +37,7 @@ static int Rast3d_readIndex(RASTER3D_Map *map) if (indexLength == map->indexLongNbytes * map->nTiles) { if (read(map->data_fd, tmp, indexLength) != indexLength) { Rast3d_error("Rast3d_readIndex: can't read file"); + Rast3d_free(tmp); return 0; } } @@ -52,6 +53,7 @@ static int Rast3d_readIndex(RASTER3D_Map *map) tmp2 = Rast3d_malloc(indexLength); if (tmp2 == NULL) { Rast3d_error("Rast3d_readIndex: error in Rast3d_malloc"); + Rast3d_free(tmp); return 0; } } @@ -60,6 +62,8 @@ static int Rast3d_readIndex(RASTER3D_Map *map) if (read(map->data_fd, tmp2, indexLength) != indexLength) { Rast3d_error("Rast3d_readIndex: can't read file"); + Rast3d_free(tmp); + Rast3d_free(tmp2); return 0; } @@ -117,6 +121,7 @@ int Rast3d_flush_index(RASTER3D_Map *map) indexLength = map->nTiles * sizeof(long); if (write(map->data_fd, tmp, indexLength) != indexLength) { Rast3d_error("Rast3d_flush_index: can't write file"); + Rast3d_free(tmp); return 0; } 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/buffer2.c b/lib/vector/Vlib/buffer2.c index 102b1ca350b..ce628d761ef 100644 --- a/lib/vector/Vlib/buffer2.c +++ b/lib/vector/Vlib/buffer2.c @@ -118,7 +118,7 @@ static void elliptic_tangent(double x, double y, double da, double db, /* * !!! This is not line in GRASS' sense. See - * http://en.wikipedia.org/wiki/Line_%28mathematics%29 + * https://en.wikipedia.org/wiki/Line_%28mathematics%29 */ static void line_coefficients(double x1, double y1, double x2, double y2, double *a, double *b, double *c) 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/lib/vector/Vlib/close.c b/lib/vector/Vlib/close.c index 573d75068b0..7e80e876393 100644 --- a/lib/vector/Vlib/close.c +++ b/lib/vector/Vlib/close.c @@ -98,7 +98,7 @@ int Vect_close(struct Map_info *Map) Vect_copy_map_dblinks(Map, &Out, TRUE); /* afterwords, dblinks must be removed from temporary map otherwise when deleting temporary map also original - attribute tables would be deteled */ + attribute tables would be deleted */ Vect_map_del_dblink(Map, -1); /* delete db links for all layers */ if (0 != Vect_copy_map_lines_field( diff --git a/lib/vector/Vlib/copy.c b/lib/vector/Vlib/copy.c index bde7e577c8b..779b5ed4a0f 100644 --- a/lib/vector/Vlib/copy.c +++ b/lib/vector/Vlib/copy.c @@ -82,6 +82,8 @@ int Vect_copy_map_lines_field(struct Map_info *In, int field, struct Map_info *Out) { int ret, format, topo; + const char *geometry_type = NULL; + const char *map_name = NULL; if (Vect_level(In) < 1) G_fatal_error( @@ -127,24 +129,30 @@ int Vect_copy_map_lines_field(struct Map_info *In, int field, /* copy features */ ret += copy_lines_2(In, field, topo, Out); - if (topo == TOPO_NONE && + if (topo == TOPO_NONE) { /* check output feature type, centroids can be exported as * points; boundaries as linestrings */ - strcmp(Vect_get_finfo_geometry_type(Out), "polygon") == 0) { - /* copy areas - external formats and simple features access only */ - ret += Vect__copy_areas(In, field, Out); + geometry_type = Vect_get_finfo_geometry_type(Out); + if (geometry_type && strcmp(geometry_type, "polygon") == 0) { + /* copy areas - external formats and simple features access only + */ + ret += Vect__copy_areas(In, field, Out); + } + G_free((void *)geometry_type); } } else { /* -> copy features on level 1 */ - if (topo == TOPO_NONE) + if (topo == TOPO_NONE) { + map_name = Vect_get_full_name(In); G_warning(_("Vector map <%s> not open on topological level. " "Areas will be skipped!"), - Vect_get_full_name(In)); + map_name); + G_free((void *)map_name); + } ret += copy_lines_1(In, field, Out); } - return ret > 0 ? 1 : 0; } @@ -161,6 +169,7 @@ int Vect_copy_map_lines_field(struct Map_info *In, int field, int copy_lines_1(struct Map_info *In, int field, struct Map_info *Out) { int ret, type; + const char *map_name = NULL; struct line_pnts *Points; struct line_cats *Cats; @@ -174,8 +183,9 @@ int copy_lines_1(struct Map_info *In, int field, struct Map_info *Out) while (TRUE) { type = Vect_read_next_line(In, Points, Cats); if (type == -1) { - G_warning(_("Unable to read vector map <%s>"), - Vect_get_full_name(In)); + map_name = Vect_get_full_name(In); + G_warning(_("Unable to read vector map <%s>"), map_name); + G_free((void *)map_name); ret = 1; break; } @@ -193,7 +203,6 @@ int copy_lines_1(struct Map_info *In, int field, struct Map_info *Out) Vect_write_line(Out, type, Points, Cats); } - Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); @@ -220,6 +229,7 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) struct line_cats *Cats, *CCats; const char *ftype = NULL; + const char *map_name = NULL; Points = Vect_new_line_struct(); CPoints = Vect_new_line_struct(); @@ -251,8 +261,9 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) G_percent(i, nlines, 2); type = Vect_read_line(In, Points, Cats, i); if (type == -1) { - G_warning(_("Unable to read vector map <%s>"), - Vect_get_full_name(In)); + map_name = Vect_get_full_name(In); + G_warning(_("Unable to read vector map <%s>"), map_name); + G_free((void *)map_name); ret = 1; break; /* free allocated space and return */ } @@ -364,7 +375,8 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) if (-1 == Vect_write_line(Out, type, Points, Cats)) { G_warning(_("Writing new feature failed")); - return 1; + ret = 1; + goto free_exit; } } @@ -372,12 +384,13 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) G_important_message( _("%d features without category or from different layer skipped"), nskipped); - +free_exit: Vect_destroy_line_struct(Points); Vect_destroy_line_struct(CPoints); Vect_destroy_line_struct(NPoints); Vect_destroy_cats_struct(Cats); Vect_destroy_cats_struct(CCats); + G_free((void *)ftype); return ret; } @@ -496,6 +509,7 @@ int is_isle(struct Map_info *Map, int area) int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) { int i, area, nareas, cat, isle, nisles, nparts_alloc, nskipped; + int ret = 0; struct line_pnts **Points; struct line_cats *Cats; @@ -567,7 +581,8 @@ int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) if (0 > V2__write_area_sfa(Out, (const struct line_pnts **)Points, nisles + 1, Cats)) { G_warning(_("Writing area %d failed"), area); - return -1; + ret = -1; + goto free_exit; } } #ifdef HAVE_POSTGRES @@ -575,7 +590,8 @@ int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) if (0 > V2__update_area_pg(Out, (const struct line_pnts **)Points, nisles + 1, cat)) { G_warning(_("Writing area %d failed"), area); - return -1; + ret = -1; + goto free_exit; } } #endif @@ -587,11 +603,13 @@ int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) nskipped); /* free allocated space for isles */ +free_exit: for (i = 0; i < nparts_alloc; i++) Vect_destroy_line_struct(Points[i]); Vect_destroy_cats_struct(Cats); + G_free(Points); - return 0; + return ret; } /*! @@ -615,6 +633,7 @@ int Vect_copy_tables(struct Map_info *In, struct Map_info *Out, int field) { int i, n, type; struct field_info *Fi; + const char *map_name = NULL; n = Vect_get_num_dblinks(In); @@ -631,20 +650,23 @@ int Vect_copy_tables(struct Map_info *In, struct Map_info *Out, int field) In->dblnk->field[i].number); return -1; } - if (field > 0 && Fi->number != field) + if (field > 0 && Fi->number != field) { + Vect_destroy_field_info(Fi); continue; + } if (Vect_copy_table(In, Out, Fi->number, Fi->number, Fi->name, type) != 0) { - + map_name = Vect_get_full_name(In); G_warning( _("Unable to copy table <%s> for layer %d from <%s> to <%s>"), - Fi->table, Fi->number, Vect_get_full_name(In), - Vect_get_name(Out)); + Fi->table, Fi->number, map_name, Vect_get_name(Out)); + G_free((void *)map_name); + Vect_destroy_field_info(Fi); return -1; } + Vect_destroy_field_info(Fi); } - return 0; } @@ -729,10 +751,10 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, int field_in, int field_out, const char *field_name, int type, int *cats, int ncats) { - int ret; + int ret = 0; struct field_info *Fi, *Fin; const char *name, *key; - dbDriver *driver; + dbDriver *driver = NULL; G_debug(2, "Vect_copy_table_by_cats(): field_in = %d field_out = %d", field_in, field_out); @@ -757,7 +779,7 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, if (ret == -1) { G_warning(_("Unable to add database link for vector map <%s>"), Out->name); - return -1; + goto free_exit; } if (cats) @@ -770,7 +792,8 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, Fin->table, key, cats, ncats); if (ret == DB_FAILED) { G_warning(_("Unable to copy table <%s>"), Fin->table); - return -1; + ret = -1; + goto free_exit; } driver = db_start_driver_open_database(Fin->driver, @@ -779,22 +802,30 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, if (!driver) { G_warning(_("Unable to open database <%s> with driver <%s>"), Fin->database, Fin->driver); - return -1; + ret = -1; + goto free_exit; } /* do not allow duplicate keys */ if (db_create_index2(driver, Fin->table, Fi->key) != DB_OK) { G_warning(_("Unable to create index")); - return -1; + ret = -1; + goto close_db_free_exit; } if (db_grant_on_table(driver, Fin->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) { G_warning(_("Unable to grant privileges on table <%s>"), Fin->table); - return -1; + ret = -1; + goto close_db_free_exit; } +close_db_free_exit: db_close_database_shutdown_driver(driver); - return 0; +free_exit: + Vect_destroy_field_info(Fi); + Vect_destroy_field_info(Fin); + + return ret; } diff --git a/lib/vector/Vlib/dbcolumns.c b/lib/vector/Vlib/dbcolumns.c index e3cf915a9ec..f0c6f5bc514 100644 --- a/lib/vector/Vlib/dbcolumns.c +++ b/lib/vector/Vlib/dbcolumns.c @@ -154,7 +154,7 @@ const char *Vect_get_column_names_types(struct Map_info *Map, int field) dbHandle handle; dbString table_name; dbTable *table; - const char **col_type_names; + char **col_type_names; char *list; num_dblinks = Vect_get_num_dblinks(Map); @@ -180,16 +180,21 @@ const char *Vect_get_column_names_types(struct Map_info *Map, int field) ncols = db_get_table_number_of_columns(table); col_type_names = G_malloc(ncols * sizeof(char *)); for (col = 0; col < ncols; col++) { - char buf[256]; + col_type_names[col] = (char *)G_calloc(256, sizeof(char)); - sprintf(buf, "%s(%s)", + sprintf(col_type_names[col], "%s(%s)", db_get_column_name(db_get_table_column(table, col)), db_sqltype_name( db_get_column_sqltype(db_get_table_column(table, col)))); - col_type_names[col] = buf; } - if ((list = G_str_concat(col_type_names, ncols, ",", BUFF_MAX)) == NULL) + + if ((list = G_str_concat((const char **)col_type_names, ncols, ",", + BUFF_MAX)) == NULL) list = G_store(""); + + for (col = 0; col < ncols; col++) { + G_free(col_type_names[col]); + } G_free(col_type_names); G_debug(3, "%s", list); diff --git a/lib/vector/Vlib/legal_vname.c b/lib/vector/Vlib/legal_vname.c index cd2aa0f14ba..f51df6ace66 100644 --- a/lib/vector/Vlib/legal_vname.c +++ b/lib/vector/Vlib/legal_vname.c @@ -32,7 +32,7 @@ int Vect_legal_filename(const char *s) { /* full list of SQL keywords available at - http://www.postgresql.org/docs/8.2/static/sql-keywords-appendix.html + https://www.postgresql.org/docs/8.2/static/sql-keywords-appendix.html */ static const char *keywords[] = {"and", "or", "not", NULL}; char buf[GNAME_MAX]; diff --git a/lib/vector/Vlib/open_pg.c b/lib/vector/Vlib/open_pg.c index 7db0113be99..293291066c2 100644 --- a/lib/vector/Vlib/open_pg.c +++ b/lib/vector/Vlib/open_pg.c @@ -535,11 +535,11 @@ void connect_db(struct Format_info_pg *pg_info) /* try connection settings for given database first, then try * any settings defined for pg driver */ - db_get_login2("pg", dbname, &user, &passwd, &host, &port); + db_get_login("pg", dbname, &user, &passwd, &host, &port); /* any settings defined for pg driver disabled - can cause problems when running multiple local/remote db clusters if (strlen(dbname) > 0 && !user && !passwd) - db_get_login2("pg", NULL, &user, &passwd, &host, &port); + db_get_login("pg", NULL, &user, &passwd, &host, &port); */ if (user || passwd || host || port) { char conninfo[DB_SQL_MAX]; diff --git a/lib/vector/Vlib/remove_duplicates.c b/lib/vector/Vlib/remove_duplicates.c index e15f7ccedb3..6fd90166a85 100644 --- a/lib/vector/Vlib/remove_duplicates.c +++ b/lib/vector/Vlib/remove_duplicates.c @@ -197,6 +197,11 @@ void Vect_remove_duplicates(struct Map_info *Map, int type, } } G_verbose_message(_("Removed duplicates: %d"), ndupl); + Vect_destroy_line_struct(APoints); + Vect_destroy_line_struct(BPoints); + Vect_destroy_cats_struct(ACats); + Vect_destroy_cats_struct(BCats); + Vect_destroy_boxlist(List); } /*! diff --git a/lib/vector/Vlib/write_sfa.c b/lib/vector/Vlib/write_sfa.c index 75754dd7645..3b7f1af6339 100644 --- a/lib/vector/Vlib/write_sfa.c +++ b/lib/vector/Vlib/write_sfa.c @@ -339,6 +339,7 @@ void V2__add_line_to_topo_sfa(struct Map_info *Map, int line, G_debug(3, "V2__add_line_to_topo_sfa(): line = %d npoints = %d", line, points->n_points); + first = TRUE; plus = &(Map->plus); Line = plus->Line[line]; type = Line->type; diff --git a/lib/vector/vectorascii.html b/lib/vector/vectorascii.html index 0fd6fbf5444..cae0ecef5a6 100644 --- a/lib/vector/vectorascii.html +++ b/lib/vector/vectorascii.html @@ -82,12 +82,12 @@ Acceptable formats:
      key: D=Degrees; M=Minutes; S=Seconds; h=Hemisphere (N,S,E,W)
        -
      • (+/-)DDD.DDDDD -
      • DDDh -
      • DDD:MMh -
      • DDD:MM.MMMMMh -
      • DDD:MM:SSh -
      • DDD:MM:SS.SSSSSh +
      • (+/-)DDD.DDDDD
      • +
      • DDDh
      • +
      • DDD:MMh
      • +
      • DDD:MM.MMMMMh
      • +
      • DDD:MM:SSh
      • +
      • DDD:MM:SS.SSSSSh

      EXAMPLES

      diff --git a/lib/vector/vectorlib_pg.dox b/lib/vector/vectorlib_pg.dox index c3a072c6a14..d95b3dec1c2 100644 --- a/lib/vector/vectorlib_pg.dox +++ b/lib/vector/vectorlib_pg.dox @@ -10,14 +10,14 @@ by GRASS Development Team (https://grass.osgeo.org) write PostGIS data directly without any external library (like in the case of \ref vlibOgr). GRASS-PostGIS data provider is implemented using libpq +href="https://www.postgresql.org/docs/9.2/static/libpq.html">libpq library. Note that GRASS-PostGIS data provider is compiled only when GRASS is configured with --with-postgres switch. See the trac +href="https://trac.osgeo.org/grass/wiki/Grass7/VectorLib/PostGISInterface">trac page for more info. \section vlibFn List of functions diff --git a/locale/po/grassmods_ar.po b/locale/po/grassmods_ar.po index b21aefa5d0b..3c4c68d45f8 100644 --- a/locale/po/grassmods_ar.po +++ b/locale/po/grassmods_ar.po @@ -35230,7 +35230,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -40743,7 +40743,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -51689,7 +51689,7 @@ msgstr "كتابة ملف جديد...\n" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -71377,7 +71377,7 @@ msgid "Either or must be given" msgstr "طبقتين يجب تحديدهم" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_bn.po b/locale/po/grassmods_bn.po index 17a11f251b8..53b06dd272f 100644 --- a/locale/po/grassmods_bn.po +++ b/locale/po/grassmods_bn.po @@ -32646,7 +32646,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37639,7 +37639,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47629,7 +47629,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_cs.po b/locale/po/grassmods_cs.po index c6f5f75df4c..0b4d04a2008 100644 --- a/locale/po/grassmods_cs.po +++ b/locale/po/grassmods_cs.po @@ -33469,7 +33469,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38799,7 +38799,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -49461,7 +49461,7 @@ msgstr "Exportují se prvky s kategorií..." #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -68271,7 +68271,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_de.po b/locale/po/grassmods_de.po index 8603cfda94d..2a168b388ca 100644 --- a/locale/po/grassmods_de.po +++ b/locale/po/grassmods_de.po @@ -33833,7 +33833,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -39230,7 +39230,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Löst Grenzen zwischen benachbarten Flächen mit gleicher Kategorienummer oder " @@ -50003,7 +50003,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -68907,7 +68907,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_el.po b/locale/po/grassmods_el.po index 5b07d819bd2..c285d2d7d10 100644 --- a/locale/po/grassmods_el.po +++ b/locale/po/grassmods_el.po @@ -32820,7 +32820,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37938,7 +37938,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48176,7 +48176,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -66429,7 +66429,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_es.po b/locale/po/grassmods_es.po index 676e7382c2d..8a0188b6448 100644 --- a/locale/po/grassmods_es.po +++ b/locale/po/grassmods_es.po @@ -34627,7 +34627,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -40162,7 +40162,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Disuelve contornos entre áreas adyacentes que comparten un número de " @@ -51266,7 +51266,7 @@ msgstr "Conviritiendo reglas de color en categorías..." #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -70595,7 +70595,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_fi.po b/locale/po/grassmods_fi.po index 15504ea84ae..be1a87cd456 100644 --- a/locale/po/grassmods_fi.po +++ b/locale/po/grassmods_fi.po @@ -32664,7 +32664,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37662,7 +37662,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47677,7 +47677,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65889,7 +65889,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_fr.po b/locale/po/grassmods_fr.po index f13cc33269f..3225a9d712b 100644 --- a/locale/po/grassmods_fr.po +++ b/locale/po/grassmods_fr.po @@ -1578,8 +1578,8 @@ msgid "" "Unable to convert input map coordinate reference system to GRASS format; " "cannot create new project." msgstr "" -"Impossible de convertir la projection de la couche en entrée au format GRASS " -"; impossible de créer le nouveau projet" +"Impossible de convertir la projection de la couche en entrée au format " +"GRASS ; impossible de créer le nouveau projet" #: ../raster/r.external/proj.c:140 ../raster/r.in.gdal/main.c:1035 #: ../raster/r.in.gdal/proj.c:139 ../vector/v.in.lidar/main.c:522 @@ -1638,7 +1638,7 @@ msgstr "Le PROJ_INFO du jeu de données est : \n" #: ../raster/r.in.lidar/projection.c:89 ../raster3d/r3.in.lidar/projection.c:90 #: ../vector/v.in.lidar/projection.c:87 ../vector/v.external/proj.c:360 #: ../vector/v.in.pdal/projection.c:87 ../vector/v.in.ogr/proj.c:492 -#, c-format, fuzzy +#, fuzzy, c-format msgid "" "\n" "In case of no significant differences in the coordinate reference system " @@ -4444,7 +4444,7 @@ msgid "unable to open input file <%s>" msgstr "" #: ../raster/r.quant/read_rules.c:89 -#, c-format, fuzzy +#, fuzzy, c-format msgid "" "\n" "Enter the rule or 'help' for the format description or 'end' to exit:\n" @@ -4561,7 +4561,7 @@ msgid "Failed to set raster attribute table" msgstr "" #: ../raster/r.out.gdal/main.c:51 -#, c-format, fuzzy +#, fuzzy, c-format msgid "Supported formats:\n" msgstr "Formats supportés :\n" @@ -12802,7 +12802,7 @@ msgid "Amount of memory cannot be negative." msgstr "Maximum de mémoire à utiliser (en MB)" #: ../raster/r.viewshed/main.cpp:616 -#, c-format, fuzzy +#, fuzzy, c-format msgid " Converting %d to %d MB" msgstr " Conversion de %d en %d MB" @@ -23481,12 +23481,12 @@ msgid "Region%s" msgstr "" #: ../imagery/i.cluster/main.c:261 -#, c-format, fuzzy +#, fuzzy, c-format msgid " North: %12.2f East: %12.2f%s" msgstr " Nord : %12.2f Est : %12.2f%s" #: ../imagery/i.cluster/main.c:263 -#, c-format, fuzzy +#, fuzzy, c-format msgid " South: %12.2f West: %12.2f%s" msgstr " Sud : %12.2f Ouest : %12.2f%s" @@ -23496,7 +23496,7 @@ msgid " Res: %12.2f Res: %12.2f%s" msgstr "" #: ../imagery/i.cluster/main.c:267 -#, c-format, fuzzy +#, fuzzy, c-format msgid " Rows: %12d Cols: %12d Cells: %d%s" msgstr " Lignes : %12d Colonnes : %12d Cellules : %d%s" @@ -23526,17 +23526,17 @@ msgid " Minimum class size: %d%s" msgstr "" #: ../imagery/i.cluster/main.c:278 -#, c-format, fuzzy +#, fuzzy, c-format msgid " Minimum class separation: %f%s" msgstr " Séparation minimale des classes : %f%s" #: ../imagery/i.cluster/main.c:280 -#, c-format, fuzzy +#, fuzzy, c-format msgid " Percent convergence: %f%s" msgstr " Pourcentage de convergence : %f%s" #: ../imagery/i.cluster/main.c:282 -#, c-format, fuzzy +#, fuzzy, c-format msgid " Maximum number of iterations: %d%s" msgstr " Nombre maximum d'itérations : %d%s" @@ -28076,7 +28076,7 @@ msgid "Lists all database drivers." msgstr "Lister tous les pilotes de bases de données." #: ../db/db.execute/main.c:55 ../db/db.select/main.c:62 -#, c-format, fuzzy +#, fuzzy, c-format msgid "Unable to open file <%s>: %s" msgstr "Impossible d'ouvrir le fichier <%s> : %s" @@ -28981,7 +28981,7 @@ msgid "The password was stored in file (%s%cdblogin)" msgstr "" #: ../db/db.select/main.c:104 -#, c-format, fuzzy +#, fuzzy, c-format msgid "Test %s." msgstr "Test %s." @@ -33949,7 +33949,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -39447,7 +39447,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Fusionne des contours entre surfaces adjacentes partageant un attribut ou " @@ -50333,7 +50333,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -57802,7 +57802,7 @@ msgstr "" #: ../vector/v.vol.rst/user1.c:586 ../vector/v.vol.rst/user1.c:640 #: ../vector/v.vol.rst/user1.c:694 ../vector/v.vol.rst/user1.c:748 #: ../vector/v.vol.rst/user1.c:802 -#, c-format, fuzzy +#, fuzzy, c-format msgid "Error closing output file %s" msgstr "Erreur en fermant le fichier de sortie %s" @@ -66437,7 +66437,7 @@ msgid "" msgstr "" #: ../display/d.vect.thematic/main.c:515 -#, c-format, fuzzy +#, fuzzy, c-format msgid "" "\n" "Total number of records: %.0f\n" @@ -68934,7 +68934,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_hu.po b/locale/po/grassmods_hu.po index 193acc17813..0cad5773fea 100644 --- a/locale/po/grassmods_hu.po +++ b/locale/po/grassmods_hu.po @@ -32714,7 +32714,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37770,7 +37770,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47888,7 +47888,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -66112,7 +66112,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_id_ID.po b/locale/po/grassmods_id_ID.po index c7159086153..df950915b12 100644 --- a/locale/po/grassmods_id_ID.po +++ b/locale/po/grassmods_id_ID.po @@ -32626,7 +32626,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37619,7 +37619,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47609,7 +47609,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65729,7 +65729,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_it.po b/locale/po/grassmods_it.po index 3120ef6c35b..53af5452a54 100644 --- a/locale/po/grassmods_it.po +++ b/locale/po/grassmods_it.po @@ -33636,7 +33636,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38964,7 +38964,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Dissolve i confini tra aree adiacenti che condividono categorie o attributi " @@ -49678,7 +49678,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -68276,7 +68276,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ja.po b/locale/po/grassmods_ja.po index 3444ccaf5db..c4aa7ebd561 100644 --- a/locale/po/grassmods_ja.po +++ b/locale/po/grassmods_ja.po @@ -33121,7 +33121,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38412,7 +38412,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -49018,7 +49018,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -67358,7 +67358,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ko.po b/locale/po/grassmods_ko.po index 5e3acc44adc..09064eb9df8 100644 --- a/locale/po/grassmods_ko.po +++ b/locale/po/grassmods_ko.po @@ -33006,7 +33006,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38236,7 +38236,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48700,7 +48700,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -67003,7 +67003,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_lv.po b/locale/po/grassmods_lv.po index 717f25bac27..cd5cf65275a 100644 --- a/locale/po/grassmods_lv.po +++ b/locale/po/grassmods_lv.po @@ -33073,7 +33073,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38284,7 +38284,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48739,7 +48739,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -67248,7 +67248,7 @@ msgid "Either or must be given" msgstr "2 līmeņiem jābūt norādītiem" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ml.po b/locale/po/grassmods_ml.po index 201460df7bb..cfe442a427e 100644 --- a/locale/po/grassmods_ml.po +++ b/locale/po/grassmods_ml.po @@ -32646,7 +32646,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37639,7 +37639,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47629,7 +47629,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_pl.po b/locale/po/grassmods_pl.po index 8edda3da8e1..ce0193ce676 100644 --- a/locale/po/grassmods_pl.po +++ b/locale/po/grassmods_pl.po @@ -33222,7 +33222,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38510,7 +38510,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Usuwa granice pomiędzy sąsiadującymi obszarami o tej samej kategorii lub " @@ -49108,7 +49108,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -67713,7 +67713,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_pt.po b/locale/po/grassmods_pt.po index 63404997a1a..a22f945601b 100644 --- a/locale/po/grassmods_pt.po +++ b/locale/po/grassmods_pt.po @@ -33030,7 +33030,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38260,7 +38260,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48676,7 +48676,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -67030,7 +67030,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_pt_BR.po b/locale/po/grassmods_pt_BR.po index 673f09c2d8c..a40e9100d63 100644 --- a/locale/po/grassmods_pt_BR.po +++ b/locale/po/grassmods_pt_BR.po @@ -33360,7 +33360,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38650,7 +38650,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -49178,7 +49178,7 @@ msgstr "Convertendo regras de cores em categorias..." #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -68320,7 +68320,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ro.po b/locale/po/grassmods_ro.po index 46ac81a4b36..4f49bec89f3 100644 --- a/locale/po/grassmods_ro.po +++ b/locale/po/grassmods_ro.po @@ -33065,7 +33065,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38269,7 +38269,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Se dizolvă limitele dintre arealele adiacente un număr comun de categorii " @@ -48737,7 +48737,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -67214,7 +67214,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ru.po b/locale/po/grassmods_ru.po index cc9bdc51a78..87d6bbad54e 100644 --- a/locale/po/grassmods_ru.po +++ b/locale/po/grassmods_ru.po @@ -32900,7 +32900,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38055,7 +38055,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48284,7 +48284,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -66746,7 +66746,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_si.po b/locale/po/grassmods_si.po index 7f42447aee9..2acdb89fbfe 100644 --- a/locale/po/grassmods_si.po +++ b/locale/po/grassmods_si.po @@ -32646,7 +32646,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37639,7 +37639,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47629,7 +47629,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_sl.po b/locale/po/grassmods_sl.po index e2b72f76d56..c1f78896be4 100644 --- a/locale/po/grassmods_sl.po +++ b/locale/po/grassmods_sl.po @@ -35453,7 +35453,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -40975,7 +40975,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -51966,7 +51966,7 @@ msgstr "Uporabljam koordinate središča sloja\n" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -71740,7 +71740,7 @@ msgid "Either or must be given" msgstr "Uporabiš lahko ali 'from_table' ali 'select'" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ta.po b/locale/po/grassmods_ta.po index d76c586fc00..05719977a92 100644 --- a/locale/po/grassmods_ta.po +++ b/locale/po/grassmods_ta.po @@ -32662,7 +32662,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37669,7 +37669,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47684,7 +47684,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65897,7 +65897,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_th.po b/locale/po/grassmods_th.po index bb0898b05f1..65e557c85d9 100644 --- a/locale/po/grassmods_th.po +++ b/locale/po/grassmods_th.po @@ -32774,7 +32774,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37894,7 +37894,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48103,7 +48103,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -66270,7 +66270,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_tr.po b/locale/po/grassmods_tr.po index 6e58f486013..ecb42b13505 100644 --- a/locale/po/grassmods_tr.po +++ b/locale/po/grassmods_tr.po @@ -33009,7 +33009,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38276,7 +38276,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48802,7 +48802,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -67181,7 +67181,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_uk.po b/locale/po/grassmods_uk.po index 8bf34d792ef..65b9178e653 100644 --- a/locale/po/grassmods_uk.po +++ b/locale/po/grassmods_uk.po @@ -32686,7 +32686,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37679,7 +37679,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47669,7 +47669,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -66059,7 +66059,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_vi.po b/locale/po/grassmods_vi.po index bfe8eb81909..49b0683b187 100644 --- a/locale/po/grassmods_vi.po +++ b/locale/po/grassmods_vi.po @@ -32777,7 +32777,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37924,7 +37924,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48138,7 +48138,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -66307,7 +66307,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_zh.po b/locale/po/grassmods_zh.po index f5926443d90..cccf638e84a 100644 --- a/locale/po/grassmods_zh.po +++ b/locale/po/grassmods_zh.po @@ -32927,7 +32927,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -38146,7 +38146,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -48560,7 +48560,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -66768,7 +66768,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_zh_CN.po b/locale/po/grassmods_zh_CN.po index 9ba4d09e886..455581b506d 100644 --- a/locale/po/grassmods_zh_CN.po +++ b/locale/po/grassmods_zh_CN.po @@ -32627,7 +32627,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37620,7 +37620,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47610,7 +47610,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65730,7 +65730,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grasswxpy_ar.po b/locale/po/grasswxpy_ar.po index e0cd184896d..0475f287e81 100644 --- a/locale/po/grasswxpy_ar.po +++ b/locale/po/grasswxpy_ar.po @@ -7568,7 +7568,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12909,7 +12909,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14244,7 +14244,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14314,7 +14314,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14934,10 +14934,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17919,17 +17915,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_bn.po b/locale/po/grasswxpy_bn.po index 27ab019eb1f..76ade0c0e31 100644 --- a/locale/po/grasswxpy_bn.po +++ b/locale/po/grasswxpy_bn.po @@ -7576,7 +7576,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12919,7 +12919,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14254,7 +14254,7 @@ msgstr "ত্রুটি" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14324,7 +14324,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14944,10 +14944,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17930,17 +17926,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_cs.po b/locale/po/grasswxpy_cs.po index f4d64a7cf4a..24423cf5314 100644 --- a/locale/po/grasswxpy_cs.po +++ b/locale/po/grasswxpy_cs.po @@ -7757,7 +7757,7 @@ msgstr "Rozloží společné hranice " #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Rozloží hranice mezi sousedícími plochami, sdílejícími společné číslo " @@ -13205,7 +13205,7 @@ msgid "Zoom to saved region extents" msgstr "Přiblížit na uložený region" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Nastavit výpočetní region podle pojmenovaného regionu" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14598,7 +14598,7 @@ msgstr "Chyba:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Nelze vykonat příkaz: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14668,7 +14668,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15316,10 +15316,6 @@ msgstr "Nastavit výpočetní region podle aktuálního okna" msgid "Set computational region extent interactively" msgstr "Nastavit výpočetní region interaktivně" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "Nastavit výpočetní region podle pojmenovaného regionu" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Uložit výpočetní region jako pojmenovaný region" @@ -18369,17 +18365,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "Nelze vypočítat směrodatnou odchylku." #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_de.po b/locale/po/grasswxpy_de.po index 2a52e3dd394..f0047ccae3d 100644 --- a/locale/po/grasswxpy_de.po +++ b/locale/po/grasswxpy_de.po @@ -6948,8 +6948,8 @@ msgstr "SIMWE Oberflächenabflussmodellierung" #: ../gui/wxpython/menustrings.py:428 ../gui/wxpython/menustrings.py:1391 msgid "Overland flow hydrologic simulation using path sampling method (SIMWE)." msgstr "" -"Hydrologische Simulation des Oberflächenabfluss mittels \"path " -"sampling\" (SIMWE)." +"Hydrologische Simulation des Oberflächenabfluss mittels \"path sampling\" " +"(SIMWE)." #: ../gui/wxpython/menustrings.py:429 ../gui/wxpython/menustrings.py:1392 msgid "SIMWE Sediment flux modeling" @@ -13102,7 +13102,7 @@ msgid "Zoom to saved region extents" msgstr "Auf die Ausdehnung der gespeicherten Region vergrößern" #: ../gui/wxpython/mapwin/buffered.py:2102 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2113 @@ -14486,7 +14486,7 @@ msgstr "Fehler: " #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Kann den Befehl '%s' nicht ausführen." #: ../gui/wxpython/core/utils.py:50 @@ -14565,7 +14565,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15227,10 +15227,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1563 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1566 msgid "Save computational region to named region" msgstr "" @@ -18297,17 +18293,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4047 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4056 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4083 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4091 diff --git a/locale/po/grasswxpy_el.po b/locale/po/grasswxpy_el.po index 21230ae0488..582972aba2b 100644 --- a/locale/po/grasswxpy_el.po +++ b/locale/po/grasswxpy_el.po @@ -7647,7 +7647,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -13012,7 +13012,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14352,7 +14352,7 @@ msgstr "Σφάλμα:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Αδυναμία εκτέλεσης εντολής: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14422,7 +14422,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15045,10 +15045,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18053,17 +18049,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_es.po b/locale/po/grasswxpy_es.po index 7e0d2865020..dd64f3e2ca1 100644 --- a/locale/po/grasswxpy_es.po +++ b/locale/po/grasswxpy_es.po @@ -8127,7 +8127,7 @@ msgstr "Disolver contornos" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Disuelve contornos entre áreas adyacentes que comparten un número de " @@ -13890,7 +13890,7 @@ msgid "Zoom to saved region extents" msgstr "Acercamiento a la extensión de la región guardada (zoom to saved...)" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Definir región computacional desde la región nombrada" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -15348,7 +15348,7 @@ msgstr "Error:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "No se puede ejecutar el comando: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -15428,7 +15428,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "Etiqueta desconocida %s" #: ../gui/wxpython/core/debug.py:46 @@ -16108,10 +16108,6 @@ msgstr "Definir región computacional a partir de la visualización" msgid "Set computational region extent interactively" msgstr "Definir extensión de la región computacional de manera interactiva" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "Establecer región computacional desde región nombrada" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Guardar región computacional con nombre" @@ -19292,19 +19288,19 @@ msgid "Statistics is not support for DBF tables." msgstr "Las estadísticas no están soportadas para tablas DBF." #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "No es posible calcular estadísticas." #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" "No se pueden calcular las estadísticas. Número de líneas %d inválido (debe " "ser %d)." #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "No es posible calcular desviación estándar." #: ../gui/wxpython/dbmgr/base.py:4106 @@ -22328,12 +22324,6 @@ msgstr "etiquetas:" #~ msgid "Deactive overwrite" #~ msgstr "Desactivar sobreescribir" -#~ msgid "Systematic contiguos" -#~ msgstr "Sistemático continuo" - -#~ msgid "Systematic non contiguos" -#~ msgstr "Sistemático no continuo" - #, python-format #~ msgid "Unable to load icon theme. Reason: %s. Quiting wxGUI..." #~ msgstr "" diff --git a/locale/po/grasswxpy_fi.po b/locale/po/grasswxpy_fi.po index 2e7a8a52e1c..72ce83830d8 100644 --- a/locale/po/grasswxpy_fi.po +++ b/locale/po/grasswxpy_fi.po @@ -7592,7 +7592,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12942,7 +12942,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14285,7 +14285,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14355,7 +14355,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14975,10 +14975,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17969,17 +17965,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_fr.po b/locale/po/grasswxpy_fr.po index acafa54fde4..8879c526ca7 100644 --- a/locale/po/grasswxpy_fr.po +++ b/locale/po/grasswxpy_fr.po @@ -8108,7 +8108,7 @@ msgstr "Fusionner des contours" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Fusionne des contours entre surfaces adjacentes partageant un attribut ou " @@ -11908,8 +11908,8 @@ msgstr "Niveau de verbosité :" #: ../gui/wxpython/gui_core/preferences.py:1294 msgid "Number of threads for parallel computing (supported tools only):" msgstr "" -"Nombre de threads pour le calcul parallèle (outils pris en charge uniquement)" -" :" +"Nombre de threads pour le calcul parallèle (outils pris en charge " +"uniquement) :" #: ../gui/wxpython/gui_core/preferences.py:1319 msgid "Maximum memory in MB to be used (supported tools only):" @@ -13849,7 +13849,7 @@ msgid "Zoom to saved region extents" msgstr "Zoomer sur les limites de la région enregistrée" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Définir la région de calcul à partir d'une région enregistrée" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -15300,7 +15300,7 @@ msgstr "Erreur :" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Impossible d'exécuter la commande : '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -15379,7 +15379,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "Étiquette inconnue %s" #: ../gui/wxpython/core/debug.py:46 @@ -16054,10 +16054,6 @@ msgstr "Définir la région calculée à partir de celle de l'écran" msgid "Set computational region extent interactively" msgstr "Définir l'emprise de la région de calcul de manière interactive" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "Définir la région calculée depuis un nom de région" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Enregistrer la région calculée vers un nom de région" @@ -19232,19 +19228,19 @@ msgid "Statistics is not support for DBF tables." msgstr "Les statistiques ne sont pas suportées pour les tables DBF." #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "Impossible de calculer les statistiques" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" "Impossible de calculer les statistiques. Nombre de lignes %d invalides " "(devrait être %d)." #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "Impossible de calculer l'écart-type." #: ../gui/wxpython/dbmgr/base.py:4106 @@ -21053,6 +21049,9 @@ msgstr "Cliquez-déposez pour redimensionner l'objet" msgid "labels: " msgstr "étiquettes :" +msgid "supported tools only" +msgstr "outils pris en charge uniquement" + #~ msgid "Location Name:" #~ msgstr "Nom du secteur : " @@ -22505,12 +22504,6 @@ msgstr "étiquettes :" #~ msgid "Deactive overwrite" #~ msgstr "Désactiver l'écrasement" -#~ msgid "Systematic contiguos" -#~ msgstr "systématiquement contigüs" - -#~ msgid "Systematic non contiguos" -#~ msgstr "Systématiquement non contigüs" - #, python-format #~ msgid "Unable to load icon theme. Reason: %s. Quiting wxGUI..." #~ msgstr "" @@ -22522,6 +22515,3 @@ msgstr "étiquettes :" #~ msgstr "" #~ "Impossible d'obtenir l’extension géographique courante. Sortie forcée de " #~ "wxGUI. Merci d'exécuter manuellement g.region pour résoudre ce problème." - -msgid "supported tools only" -msgstr "outils pris en charge uniquement" diff --git a/locale/po/grasswxpy_hu.po b/locale/po/grasswxpy_hu.po index a512c692f8b..c461a875154 100644 --- a/locale/po/grasswxpy_hu.po +++ b/locale/po/grasswxpy_hu.po @@ -7715,7 +7715,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -13132,7 +13132,7 @@ msgid "Zoom to saved region extents" msgstr "Nagyítás a mentett régió terjedelmére" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Számítási régió beállítása névvel bíró régióval" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14522,7 +14522,7 @@ msgstr "Hiba:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Nem tudom végrehajtani a parancsot: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14592,7 +14592,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15220,10 +15220,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "Számítási régió interaktív beállítása" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "Számítási régió beállítása névvel bíró régióval" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Számítási régió mentése névvel bíró régióba" @@ -18238,17 +18234,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "Nem tudok statisztikát számítani." #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "Nem tudok szórást számítani." #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_id_ID.po b/locale/po/grasswxpy_id_ID.po index b3876296a0e..e1983612035 100644 --- a/locale/po/grasswxpy_id_ID.po +++ b/locale/po/grasswxpy_id_ID.po @@ -7571,7 +7571,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12912,7 +12912,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14247,7 +14247,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14317,7 +14317,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14937,10 +14937,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17922,17 +17918,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_it.po b/locale/po/grasswxpy_it.po index dafa7437a82..ddeb21e75d2 100644 --- a/locale/po/grasswxpy_it.po +++ b/locale/po/grasswxpy_it.po @@ -7922,7 +7922,7 @@ msgstr "Dissolvi confini" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Dissolve i confini tra aree adiacenti che condividono categorie o attributi " @@ -13535,7 +13535,7 @@ msgid "Zoom to saved region extents" msgstr "Zoom all'estensione della regione salvata" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Imposta la regione computazionale dalla regione salvata" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14967,7 +14967,7 @@ msgstr "Errore:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Impossibile eseguire il comando '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -15044,7 +15044,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "Etichetta sconosciuta %s" #: ../gui/wxpython/core/debug.py:46 @@ -15709,10 +15709,6 @@ msgstr "Imposta la regione computazionale dall'estensione del display" msgid "Set computational region extent interactively" msgstr "Imposta la region computazionale interattivamente" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "Imposta regione computazionale da una regione precedentemente salvata" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Salva la regione computazionale a una regione con nome" @@ -18846,19 +18842,19 @@ msgid "Statistics is not support for DBF tables." msgstr "Statistiche non è supportato per le tabelle DBF." #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "Impossibile calcolare le statistiche." #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" "Impossibile calcolare le statistiche. Numero non valido di linee %d " "(dovrebbe essere %d)." #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "Impossibile calcolare la deviazione standard." #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_ja.po b/locale/po/grasswxpy_ja.po index 2feb9436763..dce28745650 100644 --- a/locale/po/grasswxpy_ja.po +++ b/locale/po/grasswxpy_ja.po @@ -7723,7 +7723,7 @@ msgstr "境界の融合" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "共通のカテゴリー番号や属性を共有するエリアを融合させる" @@ -13140,7 +13140,7 @@ msgid "Zoom to saved region extents" msgstr "保存領域をズーム" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14518,7 +14518,7 @@ msgstr "エラー:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "コマンドが実行できません: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14596,7 +14596,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "不明なタグ %s" #: ../gui/wxpython/core/debug.py:46 @@ -15242,10 +15242,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18294,17 +18290,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_ko.po b/locale/po/grasswxpy_ko.po index bbb4a9a638b..2562d99de06 100644 --- a/locale/po/grasswxpy_ko.po +++ b/locale/po/grasswxpy_ko.po @@ -7640,7 +7640,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -13016,7 +13016,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14381,7 +14381,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14451,7 +14451,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15073,10 +15073,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18094,17 +18090,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_lv.po b/locale/po/grasswxpy_lv.po index 83f6f002239..e733c4449a3 100644 --- a/locale/po/grasswxpy_lv.po +++ b/locale/po/grasswxpy_lv.po @@ -7710,7 +7710,7 @@ msgstr "Izšķīdināt robežas" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -13106,7 +13106,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14461,7 +14461,7 @@ msgstr "Kļūda: " #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Nebija iespējams izpildīt komandu: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14531,7 +14531,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "Nezināma birka %s" #: ../gui/wxpython/core/debug.py:46 @@ -15155,10 +15155,6 @@ msgstr "Iestatīt aprēķinu reģiona apjomu no kartes skata" msgid "Set computational region extent interactively" msgstr "Interaktīvi iestatīt aprēķinu reģiona apjomu" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18167,17 +18163,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_ml.po b/locale/po/grasswxpy_ml.po index 73eaedf0eb5..f0cd245758a 100644 --- a/locale/po/grasswxpy_ml.po +++ b/locale/po/grasswxpy_ml.po @@ -7611,7 +7611,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12968,7 +12968,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14331,7 +14331,7 @@ msgstr "തെറ്റ്:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "ആജ്ഞ നടപ്പാക്കുന്നതിൽ പാളിച: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14401,7 +14401,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15022,10 +15022,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18020,17 +18016,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_pl.po b/locale/po/grasswxpy_pl.po index c4826ee408a..f399314c413 100644 --- a/locale/po/grasswxpy_pl.po +++ b/locale/po/grasswxpy_pl.po @@ -7768,7 +7768,7 @@ msgstr "Granice regionu" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Usuwa granice pomiędzy sąsiadującymi obszarami o tej samej kategorii lub " @@ -13183,7 +13183,7 @@ msgid "Zoom to saved region extents" msgstr "Przybliż do zapisanego regionu" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Ustaw region obliczeniowy z nazwanego regionu" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14577,7 +14577,7 @@ msgstr "Błąd:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Nie można wykonać polecenia: %s" #: ../gui/wxpython/core/utils.py:50 @@ -14652,7 +14652,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15292,10 +15292,6 @@ msgstr "Ustaw zasięg wyświetlonej mapy jako region obliczeniowy" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Zapisz region obliczeniowy do nazwanego regionu" @@ -18348,17 +18344,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_pt.po b/locale/po/grasswxpy_pt.po index bae0e777dbe..9ac71057c8c 100644 --- a/locale/po/grasswxpy_pt.po +++ b/locale/po/grasswxpy_pt.po @@ -7628,7 +7628,7 @@ msgstr "Dissolver fronteiras/contornos" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12993,7 +12993,7 @@ msgid "Zoom to saved region extents" msgstr "Zoom para a extensão da região guardada" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14338,7 +14338,7 @@ msgstr "Erro:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14408,7 +14408,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15041,10 +15041,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18050,17 +18046,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_pt_BR.po b/locale/po/grasswxpy_pt_BR.po index 8888a1631a8..bd7f33c244d 100644 --- a/locale/po/grasswxpy_pt_BR.po +++ b/locale/po/grasswxpy_pt_BR.po @@ -7995,7 +7995,7 @@ msgstr "Dissolver fronteiras" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Dissolve fronteiras entre áreas adjacentes que compartilham um número de " @@ -13682,7 +13682,7 @@ msgid "Zoom to saved region extents" msgstr "Zoom para extensões de região salvas" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Definir região compulacional da região nomeada" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -15110,7 +15110,7 @@ msgstr "Erro:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Não foi possível executar o comando: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -15188,7 +15188,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "Rótulo %s desconhecido" #: ../gui/wxpython/core/debug.py:46 @@ -15863,10 +15863,6 @@ msgstr "Definir a extensão da região computacional a partir da exibição" msgid "Set computational region extent interactively" msgstr "Definir a extensão da região computacional interativamente" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "Definir a região computacional da região nomeada" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Salvar região computacional para região nomeada" @@ -18990,17 +18986,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 @@ -21946,12 +21942,6 @@ msgstr "rótulos:" #~ msgid "Deactive overwrite" #~ msgstr "Desativar susbstituição" -#~ msgid "Systematic contiguos" -#~ msgstr "Contiguo sistemático" - -#~ msgid "Systematic non contiguos" -#~ msgstr "Não contiguo sistemático" - #, python-format #~ msgid "Unable to load icon theme. Reason: %s. Quiting wxGUI..." #~ msgstr "" diff --git a/locale/po/grasswxpy_ro.po b/locale/po/grasswxpy_ro.po index 4eb12668f10..973569f6110 100644 --- a/locale/po/grasswxpy_ro.po +++ b/locale/po/grasswxpy_ro.po @@ -7799,7 +7799,7 @@ msgstr "Dizolvă limitele" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Se dizolvă limitele dintre arealele adiacente un număr comun de categorii " @@ -13292,7 +13292,7 @@ msgid "Zoom to saved region extents" msgstr "Zoom pentru a salva extinderea regiunii" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14673,7 +14673,7 @@ msgstr "Eroare:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Nu s-a putut executa comanda: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14749,7 +14749,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15407,10 +15407,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18497,17 +18493,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_ru.po b/locale/po/grasswxpy_ru.po index 4d6f7d54fc6..67c026b0770 100644 --- a/locale/po/grasswxpy_ru.po +++ b/locale/po/grasswxpy_ru.po @@ -8225,7 +8225,7 @@ msgstr "Удаление границ" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Удаляет границы между смежными полигонами с одинаковым номером категории или " @@ -13975,7 +13975,7 @@ msgid "Zoom to saved region extents" msgstr "Задать масштаб до размера сохранённого фрагмента" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "Задать расчётный фрагмент от именованного фрагмента" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -15414,7 +15414,7 @@ msgstr "Ошибка: " #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "Не удалось выполнить команду: «%s»" #: ../gui/wxpython/core/utils.py:50 @@ -15492,7 +15492,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "Неизвестный тег %s" #: ../gui/wxpython/core/debug.py:46 @@ -16173,10 +16173,6 @@ msgstr "Задайте охват расчётного фрагмента из msgid "Set computational region extent interactively" msgstr "Задайте охват расчётного фрагмента в интерактивном режиме" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "Задайте охват расчётного фрагмента из именованного фрагмента" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "Сохраните охват расчётного фрагмента из именованного фрагмента" @@ -19344,19 +19340,19 @@ msgid "Statistics is not support for DBF tables." msgstr "Статистика для таблиц DBF не поддерживается." #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "Не удалось вычислить статистику." #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" "Не удалось вычислить статистику. Недопустимое количество линий %d (должно " "быть %d)." #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "Не удалось рассчитать стандартное отклонение." #: ../gui/wxpython/dbmgr/base.py:4106 @@ -22052,12 +22048,6 @@ msgstr "подписи:" #~ msgid "Georectifier manual" #~ msgstr "Руководство для инструмента геопривязки" -#~ msgid "Systematic contiguos" -#~ msgstr "Систематическая непрерывная выборка" - -#~ msgid "Systematic non contiguos" -#~ msgstr "Систематическая несвязная выборка" - #, python-brace-format #~ msgid "" #~ "The following error occured when deleting mapset <{path}>:\n" diff --git a/locale/po/grasswxpy_si.po b/locale/po/grasswxpy_si.po index af376434553..f3d27cc8385 100644 --- a/locale/po/grasswxpy_si.po +++ b/locale/po/grasswxpy_si.po @@ -7570,7 +7570,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12911,7 +12911,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14246,7 +14246,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14316,7 +14316,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14936,10 +14936,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17921,17 +17917,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_sl.po b/locale/po/grasswxpy_sl.po index ecd79bf6108..d38b3ea58a5 100644 --- a/locale/po/grasswxpy_sl.po +++ b/locale/po/grasswxpy_sl.po @@ -7568,7 +7568,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12909,7 +12909,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14244,7 +14244,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14314,7 +14314,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14934,10 +14934,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17919,17 +17915,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_ta.po b/locale/po/grasswxpy_ta.po index d9a3d921f5a..7d752f435f6 100644 --- a/locale/po/grasswxpy_ta.po +++ b/locale/po/grasswxpy_ta.po @@ -7580,7 +7580,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12925,7 +12925,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14260,7 +14260,7 @@ msgstr "பிழை:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "கட்டளையை செயல்படுத்த முடியவில்லை: '%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14330,7 +14330,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14950,10 +14950,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17936,17 +17932,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_th.po b/locale/po/grasswxpy_th.po index 359511f80b9..b65840cfe09 100644 --- a/locale/po/grasswxpy_th.po +++ b/locale/po/grasswxpy_th.po @@ -7598,7 +7598,7 @@ msgstr "ละลาย ขอบเขต" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "Dissolves เขต ระหว่าง พื้นที่ที่อยู่ติดกันและมี ข้อมูลเหมือนกัน" @@ -12962,7 +12962,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14298,7 +14298,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14368,7 +14368,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14990,10 +14990,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17984,17 +17980,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_tr.po b/locale/po/grasswxpy_tr.po index cef0605d3d9..760a131dcc6 100644 --- a/locale/po/grasswxpy_tr.po +++ b/locale/po/grasswxpy_tr.po @@ -7662,7 +7662,7 @@ msgstr "Sınırları çöz" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 #, fuzzy msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" "Ortak kategori numarası veya özniteliği paylaşan komşu alanlar arasındaki " @@ -13045,7 +13045,7 @@ msgid "Zoom to saved region extents" msgstr "Kaydedilmiş bölge boyutlarına göre yakınlaştır" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14399,7 +14399,7 @@ msgstr "Hata:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "'%s' komutu çalıştırılamıyor" #: ../gui/wxpython/core/utils.py:50 @@ -14469,7 +14469,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15095,10 +15095,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18104,17 +18100,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_uk.po b/locale/po/grasswxpy_uk.po index a225fe82eb0..4bf446da553 100644 --- a/locale/po/grasswxpy_uk.po +++ b/locale/po/grasswxpy_uk.po @@ -7571,7 +7571,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12912,7 +12912,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14247,7 +14247,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14317,7 +14317,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14937,10 +14937,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17922,17 +17918,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_vi.po b/locale/po/grasswxpy_vi.po index c5621a9bf4e..364aed72ba1 100644 --- a/locale/po/grasswxpy_vi.po +++ b/locale/po/grasswxpy_vi.po @@ -7581,7 +7581,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12923,7 +12923,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14258,7 +14258,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14328,7 +14328,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14948,10 +14948,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17934,17 +17930,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/po/grasswxpy_zh.po b/locale/po/grasswxpy_zh.po index 25fba6850cc..4d2ab8dfd85 100644 --- a/locale/po/grasswxpy_zh.po +++ b/locale/po/grasswxpy_zh.po @@ -7684,7 +7684,7 @@ msgstr "边界融合" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -13066,7 +13066,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14420,7 +14420,7 @@ msgstr "错误:" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "无法执行命令:'%s'" #: ../gui/wxpython/core/utils.py:50 @@ -14492,7 +14492,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -15117,10 +15117,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -18147,17 +18143,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 @@ -20720,12 +20716,6 @@ msgstr "标签:" #~ msgid "Automatically hightlight selected features in map display" #~ msgstr "地图显示窗口中自动高亮所选择要素" -#~ msgid "Systematic contiguos" -#~ msgstr "系统连续" - -#~ msgid "Systematic non contiguos" -#~ msgstr "系统不连续" - #~ msgid "" #~ "Unable to get current geographic extent. Force quiting wxGUI. Please " #~ "manually run g.region to fix the problem." diff --git a/locale/po/grasswxpy_zh_CN.po b/locale/po/grasswxpy_zh_CN.po index 64212537ad1..cbb050149b9 100644 --- a/locale/po/grasswxpy_zh_CN.po +++ b/locale/po/grasswxpy_zh_CN.po @@ -7571,7 +7571,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12912,7 +12912,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14247,7 +14247,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14317,7 +14317,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -14937,10 +14937,6 @@ msgstr "" msgid "Set computational region extent interactively" msgstr "" -#: ../gui/wxpython/mapdisp/frame.py:1531 -msgid "Set computational region from named region" -msgstr "" - #: ../gui/wxpython/mapdisp/frame.py:1534 msgid "Save computational region to named region" msgstr "" @@ -17922,17 +17918,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/locale/templates/grassmods.pot b/locale/templates/grassmods.pot index c339eb81069..30b09b22a2b 100644 --- a/locale/templates/grassmods.pot +++ b/locale/templates/grassmods.pot @@ -32646,7 +32646,7 @@ msgstr "" #: ../locale/scriptstrings/v.what.spoly_to_translate.c:1 msgid "" -"Queries vector map with overlaping \"spaghetti\" polygons (e.g. Landsat " +"Queries vector map with overlapping \"spaghetti\" polygons (e.g. Landsat " "footprints) at given location. Polygons must have not intersected boundaries." msgstr "" @@ -37639,7 +37639,7 @@ msgstr "" #: ../locale/scriptstrings/v.dissolve_to_translate.c:1 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -47629,7 +47629,7 @@ msgstr "" #: ../locale/scriptstrings/v.scatterplot_to_translate.c:85 msgid "" -"Colum with categories. If selected, a separate ellipse will be drawn for " +"Column with categories. If selected, a separate ellipse will be drawn for " "each group/category" msgstr "" @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/templates/grasswxpy.pot b/locale/templates/grasswxpy.pot index ed4066f6747..57126b7f1a1 100644 --- a/locale/templates/grasswxpy.pot +++ b/locale/templates/grasswxpy.pot @@ -7569,7 +7569,7 @@ msgstr "" #: ../gui/wxpython/menustrings.py:572 ../gui/wxpython/menustrings.py:1537 msgid "" -"Dissolves adjacent or overlaping features sharing a common category number " +"Dissolves adjacent or overlapping features sharing a common category number " "or attribute." msgstr "" @@ -12910,7 +12910,7 @@ msgid "Zoom to saved region extents" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2103 -msgid "Set compulational region from named region" +msgid "Set computational region from named region" msgstr "" #: ../gui/wxpython/mapwin/buffered.py:2114 @@ -14245,7 +14245,7 @@ msgstr "" #: ../gui/wxpython/core/gcmd.py:504 #, python-format -msgid "Unable to exectute command: '%s'" +msgid "Unable to execute command: '%s'" msgstr "" #: ../gui/wxpython/core/utils.py:50 @@ -14315,7 +14315,7 @@ msgstr "" #: ../gui/wxpython/core/menutree.py:155 #, python-format -msgid "Unknow tag %s" +msgid "Unknown tag %s" msgstr "" #: ../gui/wxpython/core/debug.py:46 @@ -17920,17 +17920,17 @@ msgid "Statistics is not support for DBF tables." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4062 -msgid "Unable to calculte statistics." +msgid "Unable to calculate statistics." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4071 #, python-format msgid "" -"Unable to calculte statistics. Invalid number of lines %d (should be %d)." +"Unable to calculate statistics. Invalid number of lines %d (should be %d)." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4098 -msgid "Unable to calculte standard deviation." +msgid "Unable to calculate standard deviation." msgstr "" #: ../gui/wxpython/dbmgr/base.py:4106 diff --git a/macosx/ReadMe.md b/macosx/ReadMe.md index ac19f4c57de..fa9c13b1aff 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 @@ -228,9 +228,9 @@ build)*: `--x-includes=/usr/X11R6/include --x-libraries=/usr/X11R6/lib` -To install the new Python GUI (see [REQUIREMENTS.html](../REQUIREMENTS.html) +To install the new Python GUI (see [REQUIREMENTS.md](../REQUIREMENTS.md) and [gui/wxpython/README](../gui/wxpython/README), wxpython installer -available at [wxpython.org](http://wxpython.org/)), add this to configure (fill +available at [wxpython.org](https://wxpython.org/)), add this to configure (fill in the correct version at x.x.x.x for the wxpython you have installed): ```bash @@ -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/man/Makefile b/man/Makefile index 1a189c8d7c8..4ad90b29a74 100644 --- a/man/Makefile +++ b/man/Makefile @@ -12,7 +12,11 @@ DSTFILES := \ $(HTMLDIR)/grass_icon.png \ $(HTMLDIR)/jquery.fixedheadertable.min.js \ $(HTMLDIR)/parser_standard_options.css \ - $(HTMLDIR)/parser_standard_options.js + $(HTMLDIR)/parser_standard_options.js \ + $(MDDIR)/mkdocs.yml \ + $(MDDIR)/source/grass_logo.png \ + $(MDDIR)/source/grassdocs.css \ + $(MDDIR)/overrides/partials/footer.html categories = \ d:display \ @@ -34,7 +38,11 @@ IDXSRC = full_index index topics keywords graphical_index manual_gallery class_g INDICES := $(patsubst %,$(HTMLDIR)/%.html,$(IDXSRC)) +IDXSRC_MD = full_index index topics keywords graphical_index manual_gallery parser_standard_options $(IDXCATS) +INDICES_MD := $(patsubst %,$(MDDIR)/source/%.md,$(IDXSRC_MD)) + ALL_HTML := $(wildcard $(HTMLDIR)/*.*.html) +ALL_MD := $(wildcard $(MDDIR)/source/*.*.html) ifneq (@(type sphinx-build2 > /dev/null),) SPHINXBUILD = sphinx-build2 @@ -44,10 +52,12 @@ SPHINXBUILD = sphinx-build endif default: $(DSTFILES) - @echo "Generating HTML manual pages index (help system)..." + @echo "Generating manual pages index (help system)..." $(MAKE) $(INDICES) $(call build,check) $(MAKE) manpages + $(MAKE) $(INDICES_MD) +# $(MAKE) build-mkdocs # This must be a separate target so that evaluation of $(MANPAGES) # is delayed until the indices have been generated @@ -60,32 +70,37 @@ manpages: define build GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ + MDDIR="${MDDIR}" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ $(PYTHON) ./build_$(1).py $(2) endef define build_topics GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ + MDDIR="${MDDIR}" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ - $(PYTHON) ./build_topics.py $(HTMLDIR) + $(PYTHON) ./build_topics.py endef define build_keywords GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ + MDDIR="${MDDIR}" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ - $(PYTHON) ./build_keywords.py $(HTMLDIR) + $(PYTHON) ./build_keywords.py endef define build_graphical_index GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ + MDDIR="${MDDIR}" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ - $(PYTHON) ./build_graphical_index.py $(HTMLDIR) + $(PYTHON) ./build_graphical_index.py endef define build_manual_gallery GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ + MDDIR="${MDDIR}" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ - $(PYTHON) ./build_manual_gallery.py $(HTMLDIR) + $(PYTHON) ./build_manual_gallery.py endef define build_pso @@ -95,8 +110,18 @@ GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ -f "grass" -o "$(HTMLDIR)/parser_standard_options.html" -p 'id="opts_table" class="scroolTable"' endef +define build_pso_md +GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ + MDDIR="${MDDIR}" \ + VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ + $(PYTHON) ./parser_standard_options.py -t "$(GRASS_HOME)/lib/gis/parser_standard_options.c" \ + -f "grass" -o "$(MDDIR)/source/parser_standard_options.md" +endef + $(HTMLDIR)/topics.html: $(ALL_HTML) +$(MDDIR)/source/topics.md: $(ALL_MD) + define build_class_graphical GISBASE="$(RUN_GISBASE)" ARCH="$(ARCH)" ARCH_DISTDIR="$(ARCH_DISTDIR)" \ VERSION_NUMBER=$(GRASS_VERSION_NUMBER) VERSION_DATE=$(GRASS_VERSION_DATE) \ @@ -107,30 +132,56 @@ $(HTMLDIR)/topics.html: $(ALL_HTML) build_topics.py $(call build_topics) touch $@ +$(MDDIR)/source/topics.md: $(ALL_MD) build_topics.py + $(call build_topics) + touch $@ + $(HTMLDIR)/full_index.html: $(ALL_HTML) build_full_index.py build_html.py $(call build,full_index) touch $@ +$(MDDIR)/source/full_index.md: $(ALL_MD) build_full_index.py build_html.py + $(call build,full_index) + touch $@ + $(HTMLDIR)/index.html: build_index.py build_html.py $(call build,index) touch $@ +$(MDDIR)/source/index.md: build_index.py build_md.py + $(call build,index) + touch $@ + $(HTMLDIR)/keywords.html: $(ALL_HTML) $(call build_keywords) touch $@ +$(MDDIR)/source/keywords.md: $(ALL_MD) + $(call build_keywords) + touch $@ $(HTMLDIR)/graphical_index.html: $(ALL_HTML) $(call build_graphical_index) touch $@ +$(MDDIR)/source/graphical_index.md: $(ALL_MD) + $(call build_graphical_index) + touch $@ + $(HTMLDIR)/manual_gallery.html: $(ALL_HTML) $(call build_manual_gallery) +$(MDDIR)/source/manual_gallery.md: $(ALL_MD) + $(call build_manual_gallery) + $(HTMLDIR)/parser_standard_options.html: $(ALL_HTML) $(call build_pso) touch $@ +$(MDDIR)/source/parser_standard_options.md: $(ALL_MD) + $(call build_pso_md) + touch $@ + # TODO: this should be done in the same way as category_rule $(HTMLDIR)/class_graphical.html: $(ALL_HTML) $(call build_class_graphical) @@ -144,12 +195,24 @@ endef $(foreach cat,$(categories),$(eval $(call category_rule,$(firstword $(subst :, ,$(cat))),$(lastword $(subst :, ,$(cat)))))) +define category_rule_md +$$(MDDIR)/source/$(2).md: $$(wildcard $$(MDDIR)/source/$(1).*.md) build_class.py build_md.py + $$(call build,class,$(1) $(2)) + touch $$@ +endef + +$(foreach cat,$(categories),$(eval $(call category_rule_md,$(firstword $(subst :, ,$(cat))),$(lastword $(subst :, ,$(cat)))))) + + $(HTMLDIR)/grassdocs.css: grassdocs.css $(INSTALL_DATA) $< $@ $(HTMLDIR)/grass_logo.png: grass_logo.png $(INSTALL_DATA) $< $@ +$(MDDIR)/source/grass_logo.png: grass_logo.png + $(INSTALL_DATA) $< $@ + $(HTMLDIR)/hamburger_menu.svg: hamburger_menu.svg $(INSTALL_DATA) $< $@ @@ -167,3 +230,20 @@ $(HTMLDIR)/parser_standard_options.js: parser_standard_options.js $(HTMLDIR)/parser_standard_options.css: parser_standard_options.css $(INSTALL_DATA) $< $@ + +$(MDDIR)/mkdocs.yml: mkdocs/mkdocs.yml + $(INSTALL_DATA) $< $@ + +$(MDDIR)/source/grassdocs.css: mkdocs/grassdocs.css + $(INSTALL_DATA) $< $@ + +$(MDDIR)/overrides/partials/footer.html: mkdocs/overrides/partials/footer.html | $(MDDIR)/overrides/partials + $(INSTALL_DATA) $< $@ + +$(MDDIR)/overrides/partials: + $(MKDIR) $@ + +build-mkdocs: + @cd $(MDDIR) ; SITE_NAME="GRASS GIS $(GRASS_VERSION_NUMBER) Reference Manual" \ + COPYRIGHT="© 2003-$(GRASS_VERSION_DATE) GRASS Development Team, GRASS GIS $(GRASS_VERSION_NUMBER) Reference Manual" \ + mkdocs build diff --git a/man/build.py b/man/build.py new file mode 100644 index 00000000000..9c394a8749d --- /dev/null +++ b/man/build.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 + +# utilities for generating HTML indices +# (C) 2003-2024 Markus Neteler and the GRASS Development Team +# Authors: +# Markus Neteler +# Glynn Clements +# Luca Delucchi + +import os +import string +from datetime import datetime +from pathlib import Path + +# TODO: better fix this in include/Make/Html.make, see bug RT #5361 + +# exclude following list of modules from help index: + +exclude_mods = [ + "i.find", + "r.watershed.ram", + "r.watershed.seg", + "v.topo.check", + "helptext.html", +] + +# these modules don't use G_parser() + +desc_override = { + "g.parser": "Provides automated parser, GUI, and help support for GRASS scipts.", + "r.li.daemon": "Support module for r.li landscape index calculations.", +} + +# File template pieces follow + +message_tmpl = string.Template( + r"""Generated HTML docs in ${man_dir}/index.html +---------------------------------------------------------------------- +Following modules are missing the 'modulename.html' file in src code: +""" +) + +############################################################################ + + +def check_for_desc_override(basename): + return desc_override.get(basename) + + +def read_file(name): + return Path(name).read_text() + + +def write_file(name, contents): + Path(name).write_text(contents) + + +def try_mkdir(path): + try: + os.mkdir(path) + except OSError: + pass + + +def replace_file(name): + temp = name + ".tmp" + if ( + os.path.exists(name) + and os.path.exists(temp) + and read_file(name) == read_file(temp) + ): + os.remove(temp) + else: + try: + os.remove(name) + except OSError: + pass + os.rename(temp, name) + + +def copy_file(src, dst): + write_file(dst, read_file(src)) + + +def get_files(man_dir, cls=None, ignore_gui=True, extension="html"): + for cmd in sorted(os.listdir(man_dir)): + if ( + cmd.endswith(f".{extension}") + and (cls in (None, "*") or cmd.startswith(cls + ".")) + and (cls != "*" or len(cmd.split(".")) >= 3) + and cmd not in [f"full_index.{extension}", f"index.{extension}"] + and cmd not in exclude_mods + and ((ignore_gui and not cmd.startswith("wxGUI.")) or not ignore_gui) + ): + yield cmd + + +def write_header(f, title, ismain=False, body_width="99%", template="html"): + if template == "html": + from build_html import header1_tmpl, macosx_tmpl, header2_tmpl + else: + from build_md import header1_tmpl, macosx_tmpl, header2_tmpl + f.write(header1_tmpl.substitute(title=title)) + if ismain and macosx: + f.write( + macosx_tmpl.substitute(grass_version=grass_version, grass_mmver=grass_mmver) + ) + f.write(header2_tmpl.substitute(grass_version=grass_version, body_width=body_width)) + + +def write_cmd_overview(f, template="html"): + if template == "html": + from build_html import overview_tmpl + else: + from build_md import overview_tmpl + f.write( + overview_tmpl.substitute( + grass_version_major=grass_version_major, + grass_version_minor=grass_version_minor, + ) + ) + + +def write_footer(f, index_url, year=None, template="html"): + if template == "html": + from build_html import footer_tmpl + else: + from build_md import footer_tmpl + cur_year = default_year if year is None else year + f.write( + footer_tmpl.substitute( + grass_version=grass_version, index_url=index_url, year=cur_year + ) + ) + + +def to_title(name): + """Convert name of command class/family to form suitable for title""" + if name == "PostScript": + return name + return name.capitalize() + + +############################################################################ + +arch_dist_dir = os.environ["ARCH_DISTDIR"] +gisbase = os.environ["GISBASE"] +grass_version = os.getenv("VERSION_NUMBER", "unknown") +grass_version_major = grass_version.split(".")[0] +grass_version_minor = grass_version.split(".")[1] +grass_mmver = ".".join(grass_version.split(".")[0:2]) +macosx = "darwin" in os.environ["ARCH"].lower() +default_year = os.getenv("VERSION_DATE") +if not default_year: + default_year = str(datetime.now().year) + +############################################################################ diff --git a/man/build_check.py b/man/build_check.py index 9d9675fb7ac..1dc578c56af 100644 --- a/man/build_check.py +++ b/man/build_check.py @@ -9,13 +9,14 @@ import sys import os -from build_html import html_dir, message_tmpl, html_files, read_file +from build import message_tmpl, get_files, read_file +from build_html import man_dir -os.chdir(html_dir) +os.chdir(man_dir) -sys.stdout.write(message_tmpl.substitute(html_dir=html_dir)) +sys.stdout.write(message_tmpl.substitute(man_dir=man_dir)) -for cmd in html_files("*"): +for cmd in get_files(man_dir, "*"): if "DESCRIPTION" not in read_file(cmd): sys.stdout.write("%s\n" % cmd[:-5]) diff --git a/man/build_class.py b/man/build_class.py index 564fb5c20e6..7dc53c121bf 100644 --- a/man/build_class.py +++ b/man/build_class.py @@ -9,67 +9,84 @@ import sys import os -from build_html import ( - html_dir, - write_html_header, - grass_version, - modclass_intro_tmpl, - modclass_tmpl, - to_title, - html_files, - check_for_desc_override, - get_desc, - desc2_tmpl, - write_html_footer, - replace_file, -) +no_intro_page_classes = ["display", "general", "miscellaneous", "postscript"] -no_intro_page_classes = ["display", "general", "miscellaneous", "postscript"] +def build_class(ext): + if ext == "html": + from build_html import ( + modclass_tmpl, + get_desc, + desc2_tmpl, + modclass_intro_tmpl, + man_dir, + ) + else: + from build_md import ( + modclass_tmpl, + get_desc, + desc2_tmpl, + modclass_intro_tmpl, + man_dir, + ) -os.chdir(html_dir) + os.chdir(man_dir) -# write separate module pages: + filename = modclass + f".{ext}" + with open(filename + ".tmp", "w") as f: + write_header( + f, + "{} modules - GRASS GIS {} Reference Manual".format( + modclass.capitalize(), grass_version + ), + template=ext, + ) + modclass_lower = modclass.lower() + modclass_visible = modclass + if modclass_lower not in no_intro_page_classes: + if modclass_visible == "raster3d": + # convert keyword to nice form + modclass_visible = "3D raster" + f.write( + modclass_intro_tmpl.substitute( + modclass=modclass_visible, modclass_lower=modclass_lower + ) + ) + f.write(modclass_tmpl.substitute(modclass=to_title(modclass_visible))) -# for all module groups: -cls = sys.argv[1] -modclass = sys.argv[2] -year = None -if len(sys.argv) > 3: - year = sys.argv[3] + # for all modules: + for cmd in get_files(man_dir, cls, extension=ext): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc2_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) + if ext == "html": + f.write("
  • \n") -filename = modclass + ".html" + write_footer(f, f"index.{ext}", year, template=ext) -f = open(filename + ".tmp", "w") + replace_file(filename) -write_html_header( - f, - "%s modules - GRASS GIS %s Reference Manual" - % (modclass.capitalize(), grass_version), -) -modclass_lower = modclass.lower() -modclass_visible = modclass -if modclass_lower not in no_intro_page_classes: - if modclass_visible == "raster3d": - # covert keyword to nice form - modclass_visible = "3D raster" - f.write( - modclass_intro_tmpl.substitute( - modclass=modclass_visible, modclass_lower=modclass_lower - ) - ) -f.write(modclass_tmpl.substitute(modclass=to_title(modclass_visible))) -# for all modules: -for cmd in html_files(cls): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc2_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) -f.write("\n") +if __name__ == "__main__": + # for all module groups: + cls = sys.argv[1] + modclass = sys.argv[2] + year = None + if len(sys.argv) > 3: + year = sys.argv[3] + + from build import ( + grass_version, + to_title, + check_for_desc_override, + replace_file, + get_files, + write_header, + write_footer, + ) -write_html_footer(f, "index.html", year) + build_class("html") -f.close() -replace_file(filename) + build_class("md") diff --git a/man/build_class_graphical.py b/man/build_class_graphical.py index 554c950d3a8..0eed97beb46 100644 --- a/man/build_class_graphical.py +++ b/man/build_class_graphical.py @@ -17,20 +17,23 @@ import os import fnmatch -# from build_html import * -from build_html import ( +from build import ( default_year, - header1_tmpl, grass_version, - modclass_intro_tmpl, to_title, - html_files, + get_files, check_for_desc_override, - get_desc, - write_html_footer, + write_footer, replace_file, ) +from build_html import ( + header1_tmpl, + modclass_intro_tmpl, + get_desc, + man_dir, +) + header_graphical_index_tmpl = """\ @@ -128,65 +131,62 @@ def generate_page_for_category( short_family, module_family, imgs, year, skip_no_image=False ): filename = module_family + "_graphical.html" - - output = open(filename + ".tmp", "w") - - output.write( - header1_tmpl.substitute( - title="GRASS GIS %s Reference Manual: Graphical index" % grass_version - ) - ) - output.write(header_graphical_index_tmpl) - - if module_family.lower() not in {"general", "postscript"}: - if module_family == "raster3d": - # covert keyword to nice form - module_family = "3D raster" + with open(filename + ".tmp", "w") as output: output.write( - modclass_intro_tmpl.substitute( - modclass=module_family, modclass_lower=module_family.lower() + header1_tmpl.substitute( + title="GRASS GIS %s Reference Manual: Graphical index" % grass_version ) ) - if module_family == "wxGUI": - output.write("

    wxGUI components:

    ") - elif module_family == "guimodules": - output.write("

    g.gui.* modules:

    ") - else: - output.write("

    {0} modules:

    ".format(to_title(module_family))) - output.write('
      ') - - # for all modules: - for cmd in html_files(short_family, ignore_gui=False): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - img = get_module_image(basename, imgs) - img_class = "linkimg" - if skip_no_image and not img: - continue - elif not img: - img = "grass_logo.png" - img_class = "default-img" - if basename.startswith("wxGUI"): - basename = basename.replace(".", " ") - output.write( - "
    • " - '' - '' - '{name} ' - '{desc}' - "" - "
    • ".format( - html=cmd, img=img, name=basename, desc=desc, img_class=img_class + output.write(header_graphical_index_tmpl) + + if module_family.lower() not in {"general", "postscript"}: + if module_family == "raster3d": + # covert keyword to nice form + module_family = "3D raster" + output.write( + modclass_intro_tmpl.substitute( + modclass=module_family, modclass_lower=module_family.lower() + ) + ) + if module_family == "wxGUI": + output.write("

      wxGUI components:

      ") + elif module_family == "guimodules": + output.write("

      g.gui.* modules:

      ") + else: + output.write("

      {0} modules:

      ".format(to_title(module_family))) + output.write('
        ') + + # for all modules: + for cmd in get_files(man_dir, short_family, ignore_gui=False): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + img = get_module_image(basename, imgs) + img_class = "linkimg" + if skip_no_image and not img: + continue + if not img: + img = "grass_logo.png" + img_class = "default-img" + if basename.startswith("wxGUI"): + basename = basename.replace(".", " ") + output.write( + "
      • " + '' + '' + '{name} ' + '{desc}' + "" + "
      • ".format( + html=cmd, img=img, name=basename, desc=desc, img_class=img_class + ) ) - ) - output.write("
      ") + output.write("
    ") - write_html_footer(output, "index.html", year) + write_footer(output, "index.html", year, template="html") - output.close() replace_file(filename) diff --git a/man/build_class_rest.py b/man/build_class_rest.py index 05aec125d04..97d49a5cdb8 100644 --- a/man/build_class_rest.py +++ b/man/build_class_rest.py @@ -32,27 +32,26 @@ modclass = sys.argv[2] filename = modclass + ".txt" - -f = open(filename + ".tmp", "wb") - -write_rest_header(f, "GRASS GIS %s Reference Manual: %s" % (grass_version, modclass)) -if modclass.lower() not in {"general", "miscellaneous", "postscript"}: - f.write( - modclass_intro_tmpl.substitute( - modclass=modclass, modclass_lower=modclass.lower() - ) +with open(filename + ".tmp", "wb") as f: + write_rest_header( + f, "GRASS GIS %s Reference Manual: %s" % (grass_version, modclass) ) -f.write(modclass_tmpl.substitute(modclass=modclass)) + if modclass.lower() not in {"general", "miscellaneous", "postscript"}: + f.write( + modclass_intro_tmpl.substitute( + modclass=modclass, modclass_lower=modclass.lower() + ) + ) + f.write(modclass_tmpl.substitute(modclass=modclass)) -# for all modules: -for cmd in rest_files(cls): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc2_tmpl.substitute(basename=basename, desc=desc)) + # for all modules: + for cmd in rest_files(cls): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc2_tmpl.substitute(basename=basename, desc=desc)) -write_rest_footer(f, "index.txt") + write_rest_footer(f, "index.txt") -f.close() replace_file(filename) diff --git a/man/build_full_index.py b/man/build_full_index.py index 7d2ce03e342..a47630e3e31 100644 --- a/man/build_full_index.py +++ b/man/build_full_index.py @@ -11,77 +11,98 @@ from operator import itemgetter -from build_html import ( - html_dir, - grass_version, - html_files, - write_html_header, - write_html_footer, - check_for_desc_override, - get_desc, - replace_file, - to_title, - full_index_header, - toc, - cmd2_tmpl, - desc1_tmpl, -) - -year = None -if len(sys.argv) > 1: - year = sys.argv[1] - -os.chdir(html_dir) - -# TODO: create some master function/dict somewhere -class_labels = { - "d": "display", - "db": "database", - "g": "general", - "i": "imagery", - "m": "miscellaneous", - "ps": "PostScript", - "r": "raster", - "r3": "3D raster", - "t": "temporal", - "v": "vector", -} - -classes = [] -for cmd in html_files("*"): - prefix = cmd.split(".")[0] - if prefix not in [item[0] for item in classes]: - classes.append((prefix, class_labels.get(prefix, prefix))) -classes.sort(key=itemgetter(0)) - -# begin full index: -filename = "full_index.html" -f = open(filename + ".tmp", "w") - -write_html_header( - f, "GRASS GIS %s Reference Manual: Full index" % grass_version, body_width="80%" -) - -# generate main index of all modules: -f.write(full_index_header) - -f.write(toc) - -# for all module groups: -for cls, cls_label in classes: - f.write(cmd2_tmpl.substitute(cmd_label=to_title(cls_label), cmd=cls)) - # for all modules: - for cmd in html_files(cls): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc1_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) - f.write("\n") - -write_html_footer(f, "index.html", year) - -f.close() -replace_file(filename) - -# done full index + +def build_full_index(ext): + if ext == "html": + from build_html import ( + man_dir, + full_index_header, + cmd2_tmpl, + desc1_tmpl, + get_desc, + toc, + ) + else: + from build_md import ( + man_dir, + full_index_header, + cmd2_tmpl, + desc1_tmpl, + get_desc, + ) + + os.chdir(man_dir) + + # TODO: create some master function/dict somewhere + class_labels = { + "d": "display", + "db": "database", + "g": "general", + "i": "imagery", + "m": "miscellaneous", + "ps": "PostScript", + "r": "raster", + "r3": "3D raster", + "t": "temporal", + "v": "vector", + } + + classes = [] + for cmd in get_files(man_dir, "*", extension=ext): + prefix = cmd.split(".")[0] + if prefix not in [item[0] for item in classes]: + classes.append((prefix, class_labels.get(prefix, prefix))) + classes.sort(key=itemgetter(0)) + + # begin full index: + filename = f"full_index.{ext}" + with open(filename + ".tmp", "w") as f: + write_header( + f, + "GRASS GIS {} Reference Manual - Full index".format(grass_version), + body_width="80%", + template=ext, + ) + + # generate main index of all modules: + f.write(full_index_header) + + if ext == "html": + f.write(toc) + + # for all module groups: + for cls, cls_label in classes: + f.write(cmd2_tmpl.substitute(cmd_label=to_title(cls_label), cmd=cls)) + # for all modules: + for cmd in get_files(man_dir, cls, extension=ext): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc1_tmpl.substitute(cmd=cmd, basename=basename, desc=desc)) + if ext == "html": + f.write("\n") + + write_footer(f, f"index.{ext}", year, template=ext) + + replace_file(filename) + + +if __name__ == "__main__": + year = None + if len(sys.argv) > 1: + year = sys.argv[1] + + from build import ( + get_files, + write_footer, + write_header, + to_title, + grass_version, + check_for_desc_override, + replace_file, + ) + + build_full_index("html") + + build_full_index("md") diff --git a/man/build_full_index_rest.py b/man/build_full_index_rest.py index 26183505393..c877d914cc0 100644 --- a/man/build_full_index_rest.py +++ b/man/build_full_index_rest.py @@ -34,34 +34,32 @@ # begin full index: filename = "full_index.txt" -f = open(filename + ".tmp", "wb") +with open(filename + ".tmp", "wb") as f: + write_rest_header(f, "GRASS GIS %s Reference Manual: Full index" % grass_version) -write_rest_header(f, "GRASS GIS %s Reference Manual: Full index" % grass_version) + # generate main index of all modules: + f.write(full_index_header) + # " -# generate main index of all modules: -f.write(full_index_header) -# " + # for cls in classes: + # f.write(cmd1_tmpl.substitute(cmd = cls)) + # if cls != classes[-1]: + # f.write(" | ") -# for cls in classes: -# f.write(cmd1_tmpl.substitute(cmd = cls)) -# if cls != classes[-1]: -# f.write(" | ") + f.write(sections) -f.write(sections) + # for all module groups: + for cls in classes: + f.write(cmd2_tmpl.substitute(cmd=cls)) + # for all modules: + for cmd in rest_files(cls): + basename = os.path.splitext(cmd)[0] + desc = check_for_desc_override(basename) + if desc is None: + desc = get_desc(cmd) + f.write(desc1_tmpl.substitute(basename=basename, desc=desc)) + f.write("\n") -# for all module groups: -for cls in classes: - f.write(cmd2_tmpl.substitute(cmd=cls)) - # for all modules: - for cmd in rest_files(cls): - basename = os.path.splitext(cmd)[0] - desc = check_for_desc_override(basename) - if desc is None: - desc = get_desc(cmd) - f.write(desc1_tmpl.substitute(basename=basename, desc=desc)) - f.write("\n") + write_rest_footer(f, "index.txt") -write_rest_footer(f, "index.txt") - -f.close() replace_file(filename) diff --git a/man/build_graphical_index.py b/man/build_graphical_index.py index 04e981c021e..d46574af0a8 100755 --- a/man/build_graphical_index.py +++ b/man/build_graphical_index.py @@ -14,73 +14,11 @@ ############################################################################# import os -import sys -from build_html import write_html_footer, grass_version, header1_tmpl - - -output_name = "graphical_index.html" +output_name = "graphical_index" year = os.getenv("VERSION_DATE") -# other similar strings are in a different file -# TODO: all HTML manual building needs refactoring (perhaps grass.tools?) -header_graphical_index_tmpl = """\ - - - - -
    - -GRASS logo -
    -

    Graphical index of GRASS GIS modules

    -""" - def std_img_name(name): return "gi_{0}.jpg".format(name) @@ -114,30 +52,57 @@ def std_img_name(name): ] -def main(): - html_dir = sys.argv[1] +def main(ext): + if ext == "html": + from build_html import ( + header1_tmpl, + header_graphical_index_tmpl, + man_dir, + ) + else: + from build_md import ( + header1_tmpl, + header_graphical_index_tmpl, + man_dir, + ) - with open(os.path.join(html_dir, output_name), "w") as output: + with open(os.path.join(man_dir, output_name + f".{ext}"), "w") as output: output.write( header1_tmpl.substitute( - title="GRASS GIS %s Reference " - "Manual: Graphical index" % grass_version + title=f"GRASS GIS {grass_version} Reference Manual - Graphical index" ) ) output.write(header_graphical_index_tmpl) - output.write('
      \n') + if ext == "html": + output.write('
        \n') for html_file, image, label in index_items: - output.write( - "
      • " - '' - '' - '{name}' - "" - "
      • \n".format(html=html_file, img=image, name=label) - ) - output.write("
      ") - write_html_footer(output, "index.html", year) + if ext == "html": + output.write( + "
    • " + '' + '' + '{name}' + "" + "
    • \n".format(html=html_file, img=image, name=label) + ) + else: + output.write( + "- [![{name}]({img})]({link})".format( + link=html_file, img=image, name=label + ) + ) + + if ext == "html": + output.write("
    ") + write_footer(output, f"index.{ext}", year, template=ext) if __name__ == "__main__": - main() + from build import ( + write_footer, + grass_version, + ) + + main("html") + + main("md") diff --git a/man/build_html.py b/man/build_html.py index 0ef860d42f3..8116c8fccc5 100644 --- a/man/build_html.py +++ b/man/build_html.py @@ -1,34 +1,6 @@ -#!/usr/bin/env python3 - -# utilities for generating HTML indices -# (C) 2003-2024 Markus Neteler and the GRASS Development Team -# Authors: -# Markus Neteler -# Glynn Clements -# Luca Delucchi - import os import string -from datetime import datetime - -# TODO: better fix this in include/Make/Html.make, see bug RT #5361 - -# exclude following list of modules from help index: - -exclude_mods = [ - "i.find", - "r.watershed.ram", - "r.watershed.seg", - "v.topo.check", - "helptext.html", -] - -# these modules don't use G_parser() - -desc_override = { - "g.parser": "Provides automated parser, GUI, and help support for GRASS scipts.", - "r.li.daemon": "Support module for r.li landscape index calculations.", -} +from pathlib import Path # File template pieces follow @@ -108,7 +80,8 @@

     Graphical User Interface

    @@ -310,15 +283,6 @@ """ # " - -message_tmpl = string.Template( - r"""Generated HTML docs in ${html_dir}/index.html ----------------------------------------------------------------------- -Following modules are missing the 'modulename.html' file in src code: -""" -) -# " - moduletopics_tmpl = string.Template( r"""
  • ${name}
  • @@ -385,139 +349,90 @@ """ # " -############################################################################ - - -def check_for_desc_override(basename): - return desc_override.get(basename) - - -def read_file(name): - f = open(name) - s = f.read() - f.close() - return s - - -def write_file(name, contents): - f = open(name, "w") - f.write(contents) - f.close() - - -def try_mkdir(path): - try: - os.mkdir(path) - except OSError: - pass - - -def replace_file(name): - temp = name + ".tmp" - if ( - os.path.exists(name) - and os.path.exists(temp) - and read_file(name) == read_file(temp) - ): - os.remove(temp) - else: - try: - os.remove(name) - except OSError: - pass - os.rename(temp, name) - - -def copy_file(src, dst): - write_file(dst, read_file(src)) - +# TODO: all HTML manual building needs refactoring (perhaps grass.tools?) +header_graphical_index_tmpl = """\ + + + + +
    -def write_html_footer(f, index_url, year=None): - if year is None: - cur_year = default_year - else: - cur_year = year - f.write( - footer_tmpl.substitute( - grass_version=grass_version, index_url=index_url, year=cur_year - ) - ) +GRASS logo +
    +

    Graphical index of GRASS GIS modules

    +""" def get_desc(cmd): - f = open(cmd) - while True: - line = f.readline() - if not line: - return "" - if "NAME" in line: - break - - while True: - line = f.readline() - if not line: - return "" - if "SYNOPSIS" in line: - break - if "" in line: - sp = line.split("-", 1) - if len(sp) > 1: - return sp[1].strip() - return None + with Path(cmd).open() as f: + while True: + line = f.readline() + if not line: + return "" + if "NAME" in line: + break + + while True: + line = f.readline() + if not line: + return "" + if "SYNOPSIS" in line: + break + if "" in line: + sp = line.split("-", 1) + if len(sp) > 1: + return sp[1].strip() + return None return "" -def to_title(name): - """Convert name of command class/family to form suitable for title""" - if name == "PostScript": - return name - return name.capitalize() - - ############################################################################ -arch_dist_dir = os.environ["ARCH_DISTDIR"] -html_dir = os.path.join(arch_dist_dir, "docs", "html") -gisbase = os.environ["GISBASE"] -grass_version = os.getenv("VERSION_NUMBER", "unknown") -grass_version_major = grass_version.split(".")[0] -grass_version_minor = grass_version.split(".")[1] -grass_mmver = ".".join(grass_version.split(".")[0:2]) -macosx = "darwin" in os.environ["ARCH"].lower() -default_year = os.getenv("VERSION_DATE") -if not default_year: - default_year = str(datetime.now().year) +man_dir = os.path.join(os.environ["ARCH_DISTDIR"], "docs", "html") ############################################################################ diff --git a/man/build_index.py b/man/build_index.py index 12de7f01162..ef4dbc0dcc1 100644 --- a/man/build_index.py +++ b/man/build_index.py @@ -9,26 +9,42 @@ import sys import os -from build_html import ( - html_dir, - grass_version, - write_html_header, - write_html_cmd_overview, - write_html_footer, +from build import ( + write_header, + write_cmd_overview, + write_footer, replace_file, + grass_version, ) -os.chdir(html_dir) - -filename = "index.html" -f = open(filename + ".tmp", "w") - year = None if len(sys.argv) > 1: year = sys.argv[1] -write_html_header(f, "GRASS GIS %s Reference Manual" % grass_version, True) -write_html_cmd_overview(f) -write_html_footer(f, "index.html", year) -f.close() -replace_file(filename) + +def build_index(ext): + if ext == "html": + from build_html import ( + man_dir, + ) + else: + from build_md import ( + man_dir, + ) + + filename = f"index.{ext}" + os.chdir(man_dir) + with open(filename + ".tmp", "w") as f: + write_header( + f, f"GRASS GIS {grass_version} Reference Manual", True, template=ext + ) + write_cmd_overview(f) + write_footer(f, f"index.{ext}", year, template=ext) + replace_file(filename) + + +if __name__ == "__main__": + + build_index("html") + + build_index("md") diff --git a/man/build_index_rest.py b/man/build_index_rest.py index b919042e4af..0986838b19f 100644 --- a/man/build_index_rest.py +++ b/man/build_index_rest.py @@ -21,11 +21,9 @@ os.chdir(rest_dir) filename = "index.txt" -f = open(filename + ".tmp", "w") +with open(filename + ".tmp", "w") as f: + write_rest_header(f, "GRASS GIS %s Reference Manual" % grass_version, True) + write_rest_cmd_overview(f) + write_rest_footer(f, "index.txt") -write_rest_header(f, "GRASS GIS %s Reference Manual" % grass_version, True) -write_rest_cmd_overview(f) -write_rest_footer(f, "index.txt") - -f.close() replace_file(filename) diff --git a/man/build_keywords.py b/man/build_keywords.py index 7b239511796..c0f8bba8af9 100644 --- a/man/build_keywords.py +++ b/man/build_keywords.py @@ -21,13 +21,6 @@ import os import sys import glob -from build_html import ( - grass_version, - header1_tmpl, - headerkeywords_tmpl, - write_html_footer, -) - blacklist = [ "Display", @@ -42,34 +35,25 @@ "Vector", ] -path = sys.argv[1] addons_path = None -if len(sys.argv) >= 3: - addons_path = sys.argv[2] +if len(sys.argv) >= 2: + addons_path = sys.argv[1] year = os.getenv("VERSION_DATE") -keywords = {} - -htmlfiles = glob.glob(os.path.join(path, "*.html")) -if addons_path: - addons_man_files = glob.glob(os.path.join(addons_path, "*.html")) - htmlfiles.extend(addons_man_files) - -char_list = {} - -def get_module_man_html_file_path(module): +def get_module_man_file_path(man_dir, module, addons_man_files): """Get module manual HTML file path :param str module: module manual HTML file name e.g. v.surf.rst.html + :param addons_man_files: list of HTML manual files :return str module_path: core/addon module manual HTML file path """ if addons_path and module in ",".join(addons_man_files): module_path = os.path.join(addons_path, module) module_path = module_path.replace( - os.path.commonpath([path, module_path]), + os.path.commonpath([man_dir, module_path]), ".", ) else: @@ -77,97 +61,139 @@ def get_module_man_html_file_path(module): return module_path -for html_file in htmlfiles: - fname = os.path.basename(html_file) - with open(html_file) as f: - lines = f.readlines() - # TODO maybe move to Python re (regex) - # remove empty lines - lines = [x for x in lines if x != "\n"] - try: - index_keys = lines.index("

    KEYWORDS

    \n") + 1 - index_desc = lines.index("

    NAME

    \n") + 1 - except ValueError: - continue - try: - keys = lines[index_keys].split(",") - except (IndexError, TypeError): - continue - for key in keys: - key = key.strip() - try: - key = key.split(">")[1].split("<")[0] - except IndexError: - pass - if not key: - sys.exit("Empty keyword from file %s line: %s" % (fname, lines[index_keys])) - if key not in keywords.keys(): - keywords[key] = [] - keywords[key].append(fname) - elif fname not in keywords[key]: - keywords[key].append(fname) - -for black in blacklist: - try: - del keywords[black] - except KeyError: - try: - del keywords[black.lower()] - except (KeyError, TypeError): - continue - -for key in sorted(keywords.keys()): - # this list it is useful to create the TOC using only the first - # character for keyword - firstchar = key[0].lower() - if firstchar not in char_list.keys(): - char_list[str(firstchar)] = key - elif firstchar in char_list.keys(): - if key.lower() < char_list[str(firstchar)].lower(): - char_list[str(firstchar.lower())] = key - -keywordsfile = open(os.path.join(path, "keywords.html"), "w") -keywordsfile.write( - header1_tmpl.substitute( - title="GRASS GIS %s Reference Manual: Keywords index" % grass_version - ) -) -keywordsfile.write(headerkeywords_tmpl) -keywordsfile.write("
    ") +def build_keywords(ext): + if ext == "html": + from build_html import header1_tmpl, headerkeywords_tmpl, man_dir + else: + from build_md import ( + header1_tmpl, + headerkeywords_tmpl, + man_dir, + ) -sortedKeys = sorted(keywords.keys(), key=lambda s: s.lower()) + keywords = {} -for key in sortedKeys: - keyword_line = '
    %s
    ' % ( - key, - key, - ) - for value in sorted(keywords[key]): - keyword_line += ( - f' ' - f'{value.replace(".html", "")},' - ) - keyword_line = keyword_line.rstrip(",") - keyword_line += "
    \n" - keywordsfile.write(keyword_line) -keywordsfile.write("
    \n") -# create toc -toc = '
    \n

    Table of contents

    ' -test_length = 0 -all_keys = len(char_list.keys()) -for k in sorted(char_list.keys()): - test_length += 1 - # toc += '

  • %s
  • ' % (char_list[k], k) - if test_length % 4 == 0 and test_length != all_keys: - toc += '\n%s, ' % (char_list[k], k) - elif test_length % 4 == 0 and test_length == all_keys: - toc += '\n%s' % (char_list[k], k) - elif test_length == all_keys: - toc += '%s' % (char_list[k], k) + files = glob.glob(os.path.join(man_dir, f"*.{ext}")) + # TODO: add markdown support + if addons_path: + addons_man_files = glob.glob(os.path.join(addons_path, f"*.{ext}")) + files.extend(addons_man_files) else: - toc += '%s, ' % (char_list[k], k) -toc += "

    \n" -keywordsfile.write(toc) + addons_man_files = [] + + char_list = {} + + for in_file in files: + fname = os.path.basename(in_file) + with open(in_file) as f: + lines = f.readlines() + + if ext == "html": + # TODO maybe move to Python re (regex) + try: + index_keys = lines.index("

    KEYWORDS

    \n") + 1 + except ValueError: + continue + try: + keys = [] + for k in lines[index_keys].split(","): + keys.append(k.strip().split(">")[1].split("<")[0]) + except (IndexError, TypeError): + continue + else: + keys = [] + for line in lines: + if "keywords:" in line: + keys = [x.strip() for x in line.split(":", 1)[1].strip().split(",")] + break + + for key in keys: + if key not in keywords.keys(): + keywords[key] = [] + keywords[key].append(fname) + elif fname not in keywords[key]: + keywords[key].append(fname) + + for black in blacklist: + try: + del keywords[black] + except KeyError: + try: + del keywords[black.lower()] + except (KeyError, TypeError): + continue + + for key in sorted(keywords.keys()): + # this list it is useful to create the TOC using only the first + # character for keyword + firstchar = key[0].lower() + if firstchar not in char_list.keys(): + char_list[str(firstchar)] = key + elif firstchar in char_list.keys(): + if key.lower() < char_list[str(firstchar)].lower(): + char_list[str(firstchar.lower())] = key + + with open(os.path.join(man_dir, f"keywords.{ext}"), "w") as keywordsfile: + keywordsfile.write( + header1_tmpl.substitute( + title=f"GRASS GIS {grass_version} Reference Manual - Keywords index" + ) + ) + keywordsfile.write(headerkeywords_tmpl) + if ext == "html": + keywordsfile.write("
    ") + sortedKeys = sorted(keywords.keys(), key=lambda s: s.lower()) + + for key in sortedKeys: + if ext == "html": + keyword_line = '
    {key}
    '.format( # noqa: E501 + key=key + ) + else: + keyword_line = f"### **{key}**\n" + for value in sorted(keywords[key]): + man_file_path = get_module_man_file_path( + man_dir, value, addons_man_files + ) + if ext == "html": + keyword_line += f' {value.replace(f".{ext}", "")},' # noqa: E501 + else: + keyword_line += f' [{value.rsplit(".", 1)[0]}]({man_file_path}),' + keyword_line = keyword_line.rstrip(",") + if ext == "html": + keyword_line += "
    " + keyword_line += "\n" + keywordsfile.write(keyword_line) + if ext == "html": + keywordsfile.write("
    \n") + if ext == "html": + # create toc + toc = '
    \n

    Table of contents

    ' # noqa: E501 + test_length = 0 + all_keys = len(char_list.keys()) + for k in sorted(char_list.keys()): + test_length += 1 + # toc += '

  • %s
  • ' % (char_list[k], k) + if test_length % 4 == 0 and test_length != all_keys: + toc += '\n%s, ' % (char_list[k], k) + elif test_length % 4 == 0 and test_length == all_keys: + toc += '\n%s' % (char_list[k], k) + elif test_length == all_keys: + toc += '%s' % (char_list[k], k) + else: + toc += '%s, ' % (char_list[k], k) + toc += "

    \n" + keywordsfile.write(toc) + + write_footer(keywordsfile, f"index.{ext}", year, template=ext) + + +if __name__ == "__main__": + from build import ( + grass_version, + write_footer, + ) + + build_keywords("html") -write_html_footer(keywordsfile, "index.html", year) -keywordsfile.close() + build_keywords("md") diff --git a/man/build_manual_gallery.py b/man/build_manual_gallery.py index a8b077be8f9..a0f8176a246 100755 --- a/man/build_manual_gallery.py +++ b/man/build_manual_gallery.py @@ -12,17 +12,16 @@ # for details. # ############################################################################# +from __future__ import annotations import os from pathlib import Path -import sys import fnmatch import re +from typing import TYPE_CHECKING -from build_html import write_html_footer, grass_version, header1_tmpl - - -output_name = "manual_gallery.html" +if TYPE_CHECKING: + from collections.abc import Iterable img_extensions = ["png", "jpg", "gif"] img_patterns = ["*." + extension for extension in img_extensions] @@ -94,14 +93,18 @@ """ -def img_in_html(filename, imagename) -> bool: +def img_in_file(filename: str | os.PathLike[str], imagename: str, ext: str) -> bool: # for some reason, calling search just once is much faster # than calling it on every line (time is spent in _compile) - pattern = re.compile("".format(imagename)) + if ext == "html": + pattern = re.compile("".format(imagename)) + else: + # expecting markdown + pattern = re.compile(r"!\[(.*?)\]\({0}\)".format(imagename)) return bool(re.search(pattern, Path(filename).read_text())) -def file_matches(filename, patterns): +def file_matches(filename: str, patterns: Iterable[str]): return any(fnmatch.fnmatch(filename, pattern) for pattern in patterns) @@ -135,51 +138,82 @@ def title_from_names(module_name, img_name): return "{name}".format(name=module_name) -def get_module_name(filename): - return filename.replace(".html", "") +def get_module_name(filename, ext): + return filename.replace(f".{ext}", "") + +def main(ext): + if ext == "html": + from build_html import ( + header1_tmpl, + man_dir, + ) + else: + from build_md import ( + header1_tmpl, + man_dir, + ) -def main(): - html_dir = sys.argv[1] + output_name = f"manual_gallery.{ext}" - html_files = get_files( - html_dir, - ["*.html"], - exclude_patterns=[output_name, "*_graphical.html", "graphical_index.html"], + man_files = get_files( + man_dir, + [f"*.{ext}"], + exclude_patterns=[output_name, f"*_graphical.{ext}", f"graphical_index.{ext}"], ) - img_html_files = {} + img_files = {} - for filename in os.listdir(html_dir): + for filename in os.listdir(man_dir): if filename in img_blacklist: continue if file_matches(filename, img_patterns): - for html_file in html_files: - if img_in_html(os.path.join(html_dir, html_file), filename): - img_html_files[filename] = html_file - # for now suppose one image per html + for man_filename in man_files: + if img_in_file(Path(man_dir, man_filename), filename, ext): + img_files[filename] = man_filename + # for now suppose one image per manual filename - with open(os.path.join(html_dir, output_name), "w") as output: + with open(Path(man_dir, output_name), "w") as output: output.write( header1_tmpl.substitute( title="GRASS GIS %s Reference Manual: Manual gallery" % grass_version ) ) - output.write(header_graphical_index_tmpl) - output.write('
      \n') - for image, html_file in sorted(img_html_files.items()): - name = get_module_name(html_file) + if ext == "html": + output.write(header_graphical_index_tmpl) + output.write('
        \n') + for image, filename in sorted(img_files.items()): + name = get_module_name(filename, ext) title = title_from_names(name, image) - output.write( - "
      • " - '' - '' - '{name}' - "" - "
      • \n".format(html=html_file, img=image, title=title, name=name) - ) - output.write("
      ") - write_html_footer(output, "index.html", year) + if ext == "html": + output.write( + "
    • " + '' + '' + '{name}' + "" + "
    • \n".format(fn=filename, img=image, title=title, name=name) + ) + else: + output.write(f'[![{name}]({image} "{title}")]({filename})\n') + if ext == "html": + output.write("
    ") + write_footer(output, f"index.{ext}", year) + + return img_files if __name__ == "__main__": - main() + from build import ( + write_footer, + grass_version, + ) + + img_files_html = main("html") + + img_files_md = main("md") + + # TODO: img_files_html and img_files_md should be the same + # remove lines when fixed + for k in img_files_html: + if k not in img_files_md: + print(k) diff --git a/man/build_md.py b/man/build_md.py new file mode 100644 index 00000000000..ff3da882ab8 --- /dev/null +++ b/man/build_md.py @@ -0,0 +1,267 @@ +import os +import string + +# File template pieces follow + +header1_tmpl = string.Template( + r"""--- +title: ${title} +author: GRASS Development Team +--- + +""" +) + +macosx_tmpl = string.Template( + r""" +AppleTitle: GRASS GIS ${grass_version} +AppleIcon: GRASS-${grass_mmver}/grass_icon.png +""" +) + +header2_tmpl = string.Template( + r"""# GRASS GIS ${grass_version} Reference Manual + +**Geographic Resources Analysis Support System**, commonly +referred to as [GRASS GIS](https://grass.osgeo.org), is a +[Geographic Information System](https://en.wikipedia.org/wiki/Geographic_information_system) +(GIS) used for geospatial data management and +analysis, image processing, graphics/maps production, spatial +modeling, and visualization. GRASS is currently used in academic and +commercial settings around the world, as well as by many governmental +agencies and environmental consulting companies. + +This reference manual details the use of modules distributed with +Geographic Resources Analysis Support System (GRASS), an open source +([GNU GPLed](https://www.gnu.org/licenses/gpl.html), image +processing and geographic information system (GIS). + +""" +) + +# TODO: avoid HTML tags +overview_tmpl = string.Template( + r""" + + + + + + + + + + + + + + + + + + + + + + + + +

     Quick Introduction

    + +

    +

    +

    +

    +

    +

    +

     Graphical User Interface

    + + + +

     Display

    + +

     General

    + +

     Addons

    + +

     Programmer's Manual

    + +

     Raster processing

    + +

     3D raster processing

    +

     Image processing

    +

     Vector processing

    +

     Database

    + +

     Temporal processing

    + +

     Cartography

    + +

     Miscellaneous & Variables

    + +

     Python

    + +
    +""" +) + +# footer_tmpl = string.Template( +# r""" +# ____ +# [Main index](${index_url}) | +# [Topics index](topics.md) | +# [Keywords index](keywords.md) | +# [Graphical index](graphical_index.md) | +# [Full index](full_index.md) + +# © 2003-${year} +# [GRASS Development Team](https://grass.osgeo.org), +# GRASS GIS ${grass_version} Reference Manual +# """ +# ) +# replaced by footer +footer_tmpl = string.Template("") + +cmd2_tmpl = string.Template( + r""" +### ${cmd_label} commands (${cmd}.*) + +| Module | Description | +|--------|-------------| +""" +) + +desc1_tmpl = string.Template( + r"""| [${basename}](${cmd}) | ${desc} | +""" +) + +modclass_intro_tmpl = string.Template( + r"""Go to [${modclass} introduction](${modclass_lower}intro.md) | [topics](topics.md) +""" +) +# " + + +modclass_tmpl = string.Template( + r"""Go [back to help overview](index.md) +### ${modclass} commands +| Module | Description | +|--------|-------------| +""" +) + +desc2_tmpl = string.Template( + r"""| [${basename}](${cmd}) | ${desc} | +""" +) + +full_index_header = r"""Go [back to help overview](index.md) +""" + +moduletopics_tmpl = string.Template( + r""" +- [${name}](topic_${key}.md) +""" +) + +headertopics_tmpl = r"""# Topics +""" + +headerkeywords_tmpl = r"""# Keywords - Index of GRASS GIS modules +""" + +headerkey_tmpl = string.Template( + r"""# Topic: ${keyword} + +| Module | Description | +|--------|-------------| +""" +) + + +headerpso_tmpl = r""" +## Parser standard options +""" + +header_graphical_index_tmpl = """# Graphical index of GRASS GIS modules +""" + +############################################################################ + + +def get_desc(cmd): + desc = "" + with open(cmd) as f: + while True: + line = f.readline() + if not line: + return desc + if "description:" in line: + desc = line.split(":", 1)[1].strip() + break + + return desc + + +############################################################################ + +man_dir = os.path.join(os.environ["ARCH_DISTDIR"], "docs", "mkdocs", "source") + +############################################################################ diff --git a/man/build_rest.py b/man/build_rest.py index a98a099a076..168a5ba6127 100644 --- a/man/build_rest.py +++ b/man/build_rest.py @@ -13,6 +13,7 @@ import os import string +from pathlib import Path # TODO: better fix this in include/Make/Rest.make, see bug RT #5361 @@ -78,6 +79,7 @@ Intro vector map processing and network analysis Intro database management Intro temporal data processing + Intro Graphical User Interface Display/Graphical User Interfaces ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -271,16 +273,11 @@ def check_for_desc_override(basename): def read_file(name): - f = open(name) - s = f.read() - f.close() - return s + return Path(name).read_text() def write_file(name, contents): - f = open(name, "w") - f.write(contents) - f.close() + Path(name).write_text(contents) def try_mkdir(path): @@ -337,25 +334,25 @@ def write_rest_footer(f, index_url): def get_desc(cmd): - f = open(cmd) - while True: - line = f.readline() - if not line: - return "" - if "NAME" in line: - break - - while True: - line = f.readline() - if not line: - return "" - if "SYNOPSIS" in line: - break - if "*" in line: - sp = line.split("-", 1) - if len(sp) > 1: - return sp[1].strip() - return None + with Path(cmd).open() as f: + while True: + line = f.readline() + if not line: + return "" + if "NAME" in line: + break + + while True: + line = f.readline() + if not line: + return "" + if "SYNOPSIS" in line: + break + if "*" in line: + sp = line.split("-", 1) + if len(sp) > 1: + return sp[1].strip() + return None return "" diff --git a/man/build_topics.py b/man/build_topics.py index 81a7b31fd6f..5074d30cbd7 100644 --- a/man/build_topics.py +++ b/man/build_topics.py @@ -1,91 +1,149 @@ #!/usr/bin/env python3 # generates topics.html and topic_*.html -# (c) 2012 by the GRASS Development Team, Markus Neteler, Luca Delucchi +# (c) 2012-2024 by the GRASS Development Team import os -import sys import glob -from build_html import ( - grass_version, - header1_tmpl, - headertopics_tmpl, - headerkey_tmpl, - desc1_tmpl, - moduletopics_tmpl, - write_html_footer, -) - -path = sys.argv[1] +from pathlib import Path + year = os.getenv("VERSION_DATE") min_num_modules_for_topic = 3 -keywords = {} - -htmlfiles = glob.glob1(path, "*.html") - -for fname in htmlfiles: - fil = open(os.path.join(path, fname)) - # TODO maybe move to Python re (regex) - lines = fil.readlines() - try: - index_keys = lines.index("

    KEYWORDS

    \n") + 1 - index_desc = lines.index("

    NAME

    \n") + 1 - except ValueError: - continue - try: - key = lines[index_keys].split(",")[1].strip().replace(" ", "_") - key = key.split(">")[1].split("<")[0] - except IndexError: - continue - try: - desc = lines[index_desc].split("-", 1)[1].strip() - except IndexError: - desc.strip() - if key not in keywords.keys(): - keywords[key] = {} - keywords[key][fname] = desc - elif fname not in keywords[key]: - keywords[key][fname] = desc - -topicsfile = open(os.path.join(path, "topics.html"), "w") -topicsfile.write( - header1_tmpl.substitute( - title="GRASS GIS %s Reference Manual: Topics index" % grass_version - ) -) -topicsfile.write(headertopics_tmpl) - -for key, values in sorted(keywords.items(), key=lambda s: s[0].lower()): - keyfile = open(os.path.join(path, "topic_%s.html" % key), "w") - keyfile.write( - header1_tmpl.substitute( - title="GRASS GIS " - "%s Reference Manual: Topic %s" % (grass_version, key.replace("_", " ")) + +def build_topics(ext): + if ext == "html": + from build_html import ( + header1_tmpl, + headertopics_tmpl, + headerkey_tmpl, + desc1_tmpl, + moduletopics_tmpl, + man_dir, ) - ) - keyfile.write(headerkey_tmpl.substitute(keyword=key.replace("_", " "))) - num_modules = 0 - for mod, desc in sorted(values.items()): - num_modules += 1 - keyfile.write( - desc1_tmpl.substitute(cmd=mod, desc=desc, basename=mod.replace(".html", "")) + else: + from build_md import ( + header1_tmpl, + headertopics_tmpl, + headerkey_tmpl, + desc1_tmpl, + moduletopics_tmpl, + man_dir, ) - if num_modules >= min_num_modules_for_topic: - topicsfile.writelines( - [moduletopics_tmpl.substitute(key=key, name=key.replace("_", " "))] + + keywords = {} + + files = glob.glob1(man_dir, f"*.{ext}") + for fname in files: + with Path(man_dir, fname).open() as fil: + # TODO maybe move to Python re (regex) + lines = fil.readlines() + try: + if ext == "html": + index_keys = lines.index("

    KEYWORDS

    \n") + 1 + index_desc = lines.index("

    NAME

    \n") + 1 + else: + # expecting markdown + index_keys = lines.index("### KEYWORDS\n") + 3 + index_desc = lines.index("## NAME\n") + 2 + except ValueError: + continue + try: + if ext == "html": + key = lines[index_keys].split(",")[1].strip().replace(" ", "_") + key = key.split(">")[1].split("<")[0] + else: + # expecting markdown + key = lines[index_keys].split("]")[0].lstrip("[") + except IndexError: + continue + try: + desc = lines[index_desc].split("-", 1)[1].strip() + except IndexError: + desc.strip() + + if key not in keywords.keys(): + keywords[key] = {} + keywords[key][fname] = desc + elif fname not in keywords[key]: + keywords[key][fname] = desc + + with Path(man_dir, f"topics.{ext}").open("w") as topicsfile: + topicsfile.write( + header1_tmpl.substitute( + title="GRASS GIS %s Reference Manual - Topics index" % grass_version + ) ) - keyfile.write("\n") - # link to the keywords index - # TODO: the labels in keywords index are with spaces and capitals - # this should be probably changed to lowercase with underscores - keyfile.write( - "

    See also the corresponding keyword" - ' {key}' - " for additional references.".format(key=key.replace("_", " ")) + topicsfile.write(headertopics_tmpl) + + for key, values in sorted(keywords.items(), key=lambda s: s[0].lower()): + with Path(man_dir, f"topic_%s.{ext}" % key.replace(" ", "_")).open( + "w" + ) as keyfile: + if ext == "html": + keyfile.write( + header1_tmpl.substitute( + title="GRASS GIS " + "%s Reference Manual: Topic %s" + % (grass_version, key.replace("_", " ")) + ) + ) + keyfile.write(headerkey_tmpl.substitute(keyword=key.replace("_", " "))) + num_modules = 0 + for mod, desc in sorted(values.items()): + num_modules += 1 + keyfile.write( + desc1_tmpl.substitute( + cmd=mod, desc=desc, basename=mod.replace(f".{ext}", "") + ) + ) + if num_modules >= min_num_modules_for_topic: + topicsfile.writelines( + [ + moduletopics_tmpl.substitute( + key=key, name=key.replace("_", " ") + ) + ] + ) + if ext == "html": + keyfile.write("\n") + else: + keyfile.write("\n") + # link to the keywords index + # TODO: the labels in keywords index are with spaces and capitals + # this should be probably changed to lowercase with underscores + if ext == "html": + keyfile.write( + "

    See also the corresponding keyword" + ' {key}' + " for additional references.".format( + key=key.replace("_", " ") + ) + ) + else: + # expecting markdown + keyfile.write( + "*See also the corresponding keyword" + " [{key}](keywords.md#{key})" + " for additional references.*\n".format( + key=key.replace(" ", "-").replace("_", "-").lower() + ) + ) + + write_footer(keyfile, f"index.{ext}", year, template=ext) + + if ext == "html": + topicsfile.write("\n") + write_footer(topicsfile, f"index.{ext}", year, template=ext) + + +if __name__ == "__main__": + from build import ( + grass_version, + write_footer, ) - write_html_footer(keyfile, "index.html", year) -topicsfile.write("\n") -write_html_footer(topicsfile, "index.html", year) -topicsfile.close() + + build_topics("html") + + build_topics("md") diff --git a/man/mkdocs/grassdocs.css b/man/mkdocs/grassdocs.css new file mode 100644 index 00000000000..e42cc692fd4 --- /dev/null +++ b/man/mkdocs/grassdocs.css @@ -0,0 +1,21 @@ +:root > * { + --md-primary-fg-color: #088B36; + --md-primary-fg-color--light: #088B36; + --md-primary-fg-color--dark: #088B36; + --md-footer-bg-color: #088B36; + --md-footer-bg-color--light: #088B36; + --md-footer-bg-color--dark: #088B36; +} + +.md-header__button.md-logo { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} + +.md-header__button.md-logo img, +.md-header__button.md-logo svg { + height: 70%; + width: 70%; +} diff --git a/man/mkdocs/mkdocs.yml b/man/mkdocs/mkdocs.yml new file mode 100644 index 00000000000..dcd4deec542 --- /dev/null +++ b/man/mkdocs/mkdocs.yml @@ -0,0 +1,46 @@ +--- +site_name: !ENV SITE_NAME +site_url: https://grass.osgeo.org/grass-stable/manuals/ +docs_dir: source +extra: + homepage: ./index.html +theme: + name: material + custom_dir: overrides + language: en + logo: grass_logo.png + features: + - content.code.copy + - navigation.footer + palette: + primary: custom +copyright: !ENV COPYRIGHT +extra_css: + - grassdocs.css +plugins: + - search + - glightbox +use_directory_urls: false +nav: + - GUI: wxGUI.md + - Startup: grass.md + - Databases: database.md + - Display: display.md + - General: general.md + - Imagery: imagery.md + - Misc: miscellaneous.md + - Postscript: postscript.md + - Raster: raster.md + - Raster 3D: raster3d.md + - SQL: sql.md + - Temporal: temporal.md + - Variables: variables.md + - Vector: vector.md + - Keywords: keywords.md + - Topics: topics.md +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences + - attr_list + - md_in_html diff --git a/man/mkdocs/overrides/partials/footer.html b/man/mkdocs/overrides/partials/footer.html new file mode 100644 index 00000000000..a713e2e6db8 --- /dev/null +++ b/man/mkdocs/overrides/partials/footer.html @@ -0,0 +1,100 @@ + + + +

    diff --git a/man/mkdocs/requirements.txt b/man/mkdocs/requirements.txt new file mode 100644 index 00000000000..36f78605155 --- /dev/null +++ b/man/mkdocs/requirements.txt @@ -0,0 +1,5 @@ +mkdocs +mkdocs-glightbox +mkdocs-material +pymdown-extensions +pyyaml-env-tag diff --git a/man/parser_standard_options.py b/man/parser_standard_options.py index ad027a1b6b4..5ff79455eef 100644 --- a/man/parser_standard_options.py +++ b/man/parser_standard_options.py @@ -10,13 +10,6 @@ from urllib.request import urlopen -from build_html import ( - header1_tmpl, - grass_version, - headerpso_tmpl, - write_html_footer, -) - def parse_options(lines, startswith="Opt"): def split_in_groups(lines): @@ -132,6 +125,21 @@ def csv(self, delimiter=";", endline="\n"): ) return endline.join(csv) + def markdown(self, endline="\n"): + """Return a Markdown table with the options""" + # write header + md = ["| " + " | ".join(self.columns) + " |"] + md.append("| " + " | ".join(len(x) * "-" for x in self.columns) + " |") + + # write body + for optname, options in self.options: + row = "| {0} ".format(optname) + for col in self.columns: + row += "| {0} ".format(options.get(col, "")) + md.append(row + "|") + + return endline.join(md) + def html(self, endline="\n", indent=" ", toptions="border=1"): """Return a HTML table with the options""" html = ["".format(" " + toptions if toptions else "")] @@ -161,9 +169,10 @@ def _repr_html_(self): if __name__ == "__main__": URL = ( - "https://trac.osgeo.org/grass/browser/grass/" - "trunk/lib/gis/parser_standard_options.c?format=txt" + "https://raw.githubusercontent.com/OSGeo/grass/main/" + "lib/gis/parser_standard_options.c" ) + parser = argparse.ArgumentParser( description="Extract GRASS default options from link." ) @@ -172,7 +181,7 @@ def _repr_html_(self): "--format", default="html", dest="format", - choices=["html", "csv", "grass"], + choices=["html", "csv", "grass", "markdown"], help="Define the output format", ) parser.add_argument( @@ -220,21 +229,45 @@ def _repr_html_(self): options = OptTable(parse_options(cfile.readlines(), startswith=args.startswith)) outform = args.format - if outform in {"csv", "html"}: + if outform in ("csv", "html", "markdown"): print(getattr(options, outform)(), file=args.output) args.output.close() else: year = os.getenv("VERSION_DATE") name = args.output.name args.output.close() - topicsfile = open(name, "w") - topicsfile.write( - header1_tmpl.substitute( - title="GRASS GIS " - "%s Reference Manual: Parser standard options index" % grass_version - ) + + def write_output(ext): + with open(name, "w") as outfile: + outfile.write( + header1_tmpl.substitute( + title=f"GRASS GIS {grass_version} Reference Manual: " + "Parser standard options index" + ) + ) + outfile.write(headerpso_tmpl) + if ext == "html": + outfile.write(options.html(toptions=args.htmlparmas)) + else: + outfile.write(options.markdown()) + write_footer(outfile, f"index.{ext}", year, template=ext) + + from build import ( + grass_version, + write_footer, ) - topicsfile.write(headerpso_tmpl) - topicsfile.write(options.html(toptions=args.htmlparmas)) - write_html_footer(topicsfile, "index.html", year) - topicsfile.close() + + ext = os.path.splitext(name)[1][1:] + + if ext == "html": + from build_html import ( + header1_tmpl, + headerpso_tmpl, + ) + else: + from build_md import ( + header1_tmpl, + headerpso_tmpl, + ) + + write_output(ext) # html or md diff --git a/misc/m.measure/m.measure.html b/misc/m.measure/m.measure.html index 97c7b44ff63..388c3d81b23 100644 --- a/misc/m.measure/m.measure.html +++ b/misc/m.measure/m.measure.html @@ -19,7 +19,7 @@

    EXAMPLES

    -Visualization (with d.geodesic) of m.measure distance example
    +Visualization (with d.geodesic) of m.measure distance example
    Visualization (with d.geodesic) of m.measure distance example
    diff --git a/misc/m.nviz.script/m.nviz.script.html b/misc/m.nviz.script/m.nviz.script.html index d5c4997ed86..f7cddaf1d82 100644 --- a/misc/m.nviz.script/m.nviz.script.html +++ b/misc/m.nviz.script/m.nviz.script.html @@ -11,7 +11,7 @@

    DESCRIPTION

    The script generated by m.nviz.script can be run from the NVIZ command line (nviz script=script_name) or after NVIZ is started by -selecting Scripting->Play Script. +selecting Scripting->Play Script.

    OPTIONS

    @@ -23,14 +23,14 @@

    Flags:

    -c
    Flay at constant elevation
    With this flag the camera will be set to an elevation given by the - ht= parameter. The default is to fly at ht= - above the topography (i.e. camera height = elevation + ht) + ht= parameter. The default is to fly at ht= + above the topography (i.e. camera height = elevation + ht)
    -k
    Output KeyFrame file
    Generate a KeyFrame file that can be loaded from the NVIZ - Keyframe Animation panel. The KeyFrame file is - automatically assigned the script name with a - .kanimator extension. + Keyframe Animation panel. The KeyFrame file is + automatically assigned the script name with a + .kanimator extension.
    -o
    Render the animation in an off-screen context
    -e diff --git a/mswindows/GRASS-Installer.nsi.tmpl b/mswindows/GRASS-Installer.nsi.tmpl index 2b2722a5083..ab01e133a51 100644 --- a/mswindows/GRASS-Installer.nsi.tmpl +++ b/mswindows/GRASS-Installer.nsi.tmpl @@ -4,7 +4,7 @@ ;Written by Marco Pasetti ;Updated for OSGeo4W by Colin Nielsen, Helmut Kudrnovsky, and Martin Landa ;Last Update: $Id$ -;Mail to: grass-dev@lists.osgeo.org +;Mail to: grass-dev@lists.osgeo.org ;---------------------------------------------------------------------------------------------------------------------------- @@ -102,7 +102,7 @@ ShowUnInstDetails hide ;StrReplace Function ;Replaces all occurrences of a given needle within a haystack with another string ;Written by dandaman32 - + Var STR_REPLACE_VAR_0 Var STR_REPLACE_VAR_1 Var STR_REPLACE_VAR_2 @@ -112,7 +112,7 @@ Var STR_REPLACE_VAR_5 Var STR_REPLACE_VAR_6 Var STR_REPLACE_VAR_7 Var STR_REPLACE_VAR_8 - + Function StrReplace Exch $STR_REPLACE_VAR_2 Exch 1 @@ -140,7 +140,7 @@ Function StrReplace Pop $STR_REPLACE_VAR_1 ; stack as it was before the function was called Exch $STR_REPLACE_VAR_0 FunctionEnd - + !macro _strReplaceConstructor OUT NEEDLE NEEDLE2 HAYSTACK Push "${HAYSTACK}" Push "${NEEDLE}" @@ -148,7 +148,7 @@ FunctionEnd Call StrReplace Pop "${OUT}" !macroend - + !define StrReplace '!insertmacro "_strReplaceConstructor"' ;---------------------------------------------------------------------------------------------------------------------------- @@ -184,35 +184,35 @@ Function .onInit Var /GLOBAL UNINSTALL_STRING Var /GLOBAL INSTALL_PATH - + Var /GLOBAL INSTALLED_VERSION_NUMBER Var /GLOBAL INSTALLED_GIT_REVISION Var /GLOBAL INSTALLED_BINARY_REVISION - + Var /GLOBAL INSTALLED_VERSION - + Var /GLOBAL DISPLAYED_INSTALLED_VERSION - + Var /GLOBAL MESSAGE_0_ Var /GLOBAL MESSAGE_1_ Var /GLOBAL MESSAGE_2_ Var /GLOBAL MESSAGE_3_ - + ReadRegStr $UNINSTALL_STRING HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "UninstallString" ReadRegStr $INSTALL_PATH HKLM "Software\${GRASS_BASE}" "InstallPath" ReadRegStr $INSTALLED_VERSION_NUMBER HKLM "Software\${GRASS_BASE}" "VersionNumber" ReadRegStr $INSTALLED_GIT_REVISION HKLM "Software\${GRASS_BASE}" "GitRevision" - + ${If} $INSTALLED_GIT_REVISION == "" ReadRegStr $INSTALLED_GIT_REVISION HKLM "Software\${GRASS_BASE}" "Revision" - ${EndIf} - + ${EndIf} + ReadRegStr $INSTALLED_BINARY_REVISION HKLM "Software\${GRASS_BASE}" "BinaryRevision" - + StrCpy $MESSAGE_0_ "${CHECK_INSTALL_NAME} is already installed on your system.$\r$\n" StrCpy $MESSAGE_0_ "$MESSAGE_0_$\r$\n" - - !if ${INSTALLER_TYPE} == "Release" + + !if ${INSTALLER_TYPE} == "Release" ${If} $INSTALLED_BINARY_REVISION == "" StrCpy $DISPLAYED_INSTALLED_VERSION "$INSTALLED_VERSION_NUMBER" ${Else} @@ -221,32 +221,32 @@ Function .onInit !else StrCpy $DISPLAYED_INSTALLED_VERSION "$INSTALLED_VERSION_NUMBER-$INSTALLED_GIT_REVISION-$INSTALLED_BINARY_REVISION" !endif - + StrCpy $MESSAGE_0_ "$MESSAGE_0_The installed release is $DISPLAYED_INSTALLED_VERSION$\r$\n" - + StrCpy $MESSAGE_1_ "$MESSAGE_0_$\r$\n" StrCpy $MESSAGE_1_ "$MESSAGE_1_You are going to install a newer release of ${CHECK_INSTALL_NAME}$\r$\n" StrCpy $MESSAGE_1_ "$MESSAGE_1_$\r$\n" StrCpy $MESSAGE_1_ "$MESSAGE_1_Press OK to uninstall GRASS $DISPLAYED_INSTALLED_VERSION" StrCpy $MESSAGE_1_ "$MESSAGE_1_ and install ${DISPLAYED_NAME} or Cancel to quit." - + StrCpy $MESSAGE_2_ "$MESSAGE_0_$\r$\n" StrCpy $MESSAGE_2_ "$MESSAGE_2_You are going to install an older release of ${CHECK_INSTALL_NAME}$\r$\n" StrCpy $MESSAGE_2_ "$MESSAGE_2_$\r$\n" StrCpy $MESSAGE_2_ "$MESSAGE_2_Press OK to uninstall GRASS $DISPLAYED_INSTALLED_VERSION" StrCpy $MESSAGE_2_ "$MESSAGE_2_ and install ${DISPLAYED_NAME} or Cancel to quit." - + StrCpy $MESSAGE_3_ "$MESSAGE_0_$\r$\n" StrCpy $MESSAGE_3_ "$MESSAGE_3_This is the latest release available.$\r$\n" StrCpy $MESSAGE_3_ "$MESSAGE_3_$\r$\n" StrCpy $MESSAGE_3_ "$MESSAGE_3_Press OK to reinstall ${DISPLAYED_NAME} or Cancel to quit." - + IntOp $INSTALLED_GIT_REVISION $INSTALLED_GIT_REVISION * 1 IntOp $INSTALLED_BINARY_REVISION $INSTALLED_BINARY_REVISION * 1 IntOp $INSTALLED_VERSION $INSTALLED_GIT_REVISION + $INSTALLED_BINARY_REVISION - + !define /math VERSION ${GIT_REVISION} + ${BINARY_REVISION} - + ${If} $INSTALLED_VERSION_NUMBER == "" ${Else} ${If} $INSTALLED_VERSION < ${VERSION} @@ -275,9 +275,9 @@ Function .onInit quit_reinstall: Abort continue_reinstall: - ${EndIf} + ${EndIf} ${EndIf} - + ${If} $INSTALLED_VERSION_NUMBER == "" ${Else} ${If} $0 = 0 @@ -295,10 +295,10 @@ FunctionEnd Function CheckUpdate - ${If} $ASK_FOR_PATH == "NO" + ${If} $ASK_FOR_PATH == "NO" Abort ${EndIf} - + FunctionEnd ;---------------------------------------------------------------------------------------------------------------------------- @@ -310,26 +310,26 @@ FunctionEnd ;Function CheckInstDir ; Var /GLOBAL INSTDIR_TEST -; Var /GLOBAL INSTDIR_LENGTH +; Var /GLOBAL INSTDIR_LENGTH ; Var /GLOBAL INSTDIR_TEST_LENGTH ; Var /GLOBAL MESSAGE_CHKINST_ -; +; ; StrCpy $MESSAGE_CHKINST_ "WARNING: you are about to install GRASS into a directory that has spaces$\r$\n" ; StrCpy $MESSAGE_CHKINST_ "$MESSAGE_CHKINST_in either its name or the path of directories leading up to it.$\r$\n" ; StrCpy $MESSAGE_CHKINST_ "$MESSAGE_CHKINST_Some functionalities of GRASS might be hampered by this. We would highly$\r$\n" ; StrCpy $MESSAGE_CHKINST_ "$MESSAGE_CHKINST_appreciate if you tried and reported any problems, so that we can fix them.$\r$\n" ; StrCpy $MESSAGE_CHKINST_ "$MESSAGE_CHKINST_However, if you want to avoid any such issues, we recommend that you$\r$\n" ; StrCpy $MESSAGE_CHKINST_ "$MESSAGE_CHKINST_choose a simple installation path without spaces, such as: C:\${GRASS_BASE}.$\r$\n" -; +; ; ${StrReplace} "$INSTDIR_TEST" " " "" "$INSTDIR" -; +; ; StrLen $INSTDIR_LENGTH "$INSTDIR" ; StrLen $INSTDIR_TEST_LENGTH "$INSTDIR_TEST" -; -; ${If} $INSTDIR_TEST_LENGTH < $INSTDIR_LENGTH +; +; ${If} $INSTDIR_TEST_LENGTH < $INSTDIR_LENGTH ; MessageBox MB_OK|MB_ICONEXCLAMATION "$MESSAGE_CHKINST_" ; ${EndIf} -; +; ;FunctionEnd ;---------------------------------------------------------------------------------------------------------------------------- @@ -351,39 +351,39 @@ Function ReplaceLineStr Push $R7 ; input string length Push $R8 ; line string length Push $R9 ; global - + StrLen $R7 $R1 - + GetTempFileName $R4 - + FileOpen $R5 $R4 w FileOpen $R3 $R2 r - + ReadLoop: ClearErrors FileRead $R3 $R6 IfErrors Done - + StrLen $R8 $R6 StrCpy $R9 $R6 $R7 -$R8 StrCmp $R9 $R1 0 +3 - + FileWrite $R5 "$R0$\r$\n" Goto ReadLoop - + FileWrite $R5 $R6 Goto ReadLoop - + Done: - + FileClose $R3 FileClose $R5 - + SetDetailsPrint none Delete $R2 Rename $R4 $R2 SetDetailsPrint both - + Pop $R9 Pop $R8 Pop $R7 @@ -491,24 +491,24 @@ Var /GLOBAL DOWNLOAD_MESSAGE_ Section "GRASS" SecGRASS SectionIn RO - + ;Set the INSTALL_DIR variable Var /GLOBAL INSTALL_DIR - - ${If} $ASK_FOR_PATH == "NO" + + ${If} $ASK_FOR_PATH == "NO" StrCpy $INSTALL_DIR "$INSTALL_PATH" ${Else} StrCpy $INSTALL_DIR "$INSTDIR" ${EndIf} - + ;Set to try to overwrite existing files - SetOverwrite try - + SetOverwrite try + ;Set the GIS_DATABASE directory SetShellVarContext current - Var /GLOBAL GIS_DATABASE + Var /GLOBAL GIS_DATABASE StrCpy $GIS_DATABASE "$DOCUMENTS\grassdata" - + ;Create the GIS_DATABASE directory CreateDirectory "$GIS_DATABASE" @@ -516,7 +516,7 @@ Section "GRASS" SecGRASS SetOutPath "$INSTALL_DIR" File .\Installer-Files\GRASS-WebSite.url File .\Installer-Files\WinGRASS-README.url - + ;add GRASS files SetOutPath "$INSTALL_DIR" File /r ${PACKAGE_FOLDER}\*.* @@ -524,12 +524,12 @@ Section "GRASS" SecGRASS ;grant $INSTDIR\etc read write accessible and show if succeeded: error if it failed AccessControl::GrantOnFile "$INSTDIR\etc" "(S-1-5-32-545)" "FullAccess" Pop $R0 - DetailPrint $R0 - ;grant modifying/overwriting fontcap file and show if succeeded: error if it failed + DetailPrint $R0 + ;grant modifying/overwriting fontcap file and show if succeeded: error if it failed AccessControl::GrantOnFile "$INSTDIR\etc\fontcap" "(S-1-5-32-545)" "FullAccess" Pop $R0 - DetailPrint $R0 - + DetailPrint $R0 + ;create run_gmkfontcap.bat ClearErrors FileOpen $0 $INSTALL_DIR\etc\run_gmkfontcap.bat w @@ -567,12 +567,12 @@ Section "GRASS" SecGRASS FileOpen $0 $INSTALL_DIR\etc\run_gmkfontcap.bat.manifest w IfErrors done_create_run_gmkfontcap.bat.manifest FileWrite $0 ' $\r$\n' - FileWrite $0 '$\r$\n' + FileWrite $0 '$\r$\n' FileWrite $0 ' $\r$\n' - FileWrite $0 ' GRASS help script:run_gmkfontcap$\r$\n' + FileWrite $0 ' type="win32"/>$\r$\n' + FileWrite $0 ' GRASS help script:run_gmkfontcap$\r$\n' FileWrite $0 ' $\r$\n' FileWrite $0 ' $\r$\n' FileWrite $0 ' $\r$\n' @@ -586,13 +586,13 @@ Section "GRASS" SecGRASS FileWrite $0 '$\r$\n' FileClose $0 done_create_run_gmkfontcap.bat.manifest: - + ;Run g.mkfontcap outside a grass session during installation to catch all fonts ExecWait '"$INSTALL_DIR\etc\run_gmkfontcap.bat"' ;set $INSTDIR\etc back to read accessible - AccessControl::SetOnFile "$INSTDIR\etc" "(S-1-5-32-545)" "GenericRead + GenericExecute" - + AccessControl::SetOnFile "$INSTDIR\etc" "(S-1-5-32-545)" "GenericRead + GenericExecute" + ;Install demolocation into the GIS_DATABASE directory SetOutPath "$GIS_DATABASE\demolocation" File /r ${DEMOLOCATION_PATH}\*.* @@ -605,9 +605,9 @@ Section "GRASS" SecGRASS ;Create the Uninstaller WriteUninstaller "$INSTALL_DIR\Uninstall-GRASS.exe" - + ;Registry Key Entries - + ;HKEY_LOCAL_MACHINE Install entries ;Set the Name, Version and Revision of GRASS + PublisherInfo + InstallPath WriteRegStr HKLM "Software\${GRASS_BASE}" "Name" "${GRASS_BASE}" @@ -617,11 +617,11 @@ Section "GRASS" SecGRASS WriteRegStr HKLM "Software\${GRASS_BASE}" "Publisher" "${PUBLISHER}" WriteRegStr HKLM "Software\${GRASS_BASE}" "WebSite" "${WEB_SITE}" WriteRegStr HKLM "Software\${GRASS_BASE}" "InstallPath" "$INSTALL_DIR" - + ;HKEY_LOCAL_MACHINE Uninstall entries WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "DisplayName" "GRASS GIS @GRASS_VERSION_MAJOR@.@GRASS_VERSION_MINOR@" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "UninstallString" "$INSTALL_DIR\Uninstall-GRASS.exe" - + !if ${INSTALLER_TYPE} == "Release" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}"\ "DisplayVersion" "${VERSION_NUMBER}-${BINARY_REVISION}" @@ -629,31 +629,31 @@ Section "GRASS" SecGRASS WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}"\ "DisplayVersion" "${VERSION_NUMBER}-${GIT_REVISION}-${BINARY_REVISION}" !endif - + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "DisplayIcon" "$INSTALL_DIR\gui\icons\grass.ico" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "EstimatedSize" 1 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "HelpLink" "${WIKI_PAGE}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "URLInfoAbout" "${WEB_SITE}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" "Publisher" "${PUBLISHER}" - + ;Create the Desktop Shortcut SetShellVarContext current - + CreateShortCut "$DESKTOP\${GRASS_BASE}.lnk" "$INSTALL_DIR\${GRASS_COMMAND}.bat" "--gui"\ "$INSTALL_DIR\gui\icons\grass.ico" "" SW_SHOWNORMAL "" "Launch GRASS GIS ${VERSION_NUMBER}" - + ;Create the Windows Start Menu Shortcuts SetShellVarContext all - + CreateDirectory "$SMPROGRAMS\${GRASS_BASE}" - + CreateShortCut "$SMPROGRAMS\${GRASS_BASE}\${GRASS_BASE}.lnk" "$INSTALL_DIR\${GRASS_COMMAND}.bat" "--gui"\ "$INSTALL_DIR\gui\icons\grass.ico" "" SW_SHOWNORMAL "" "Launch GRASS GIS ${VERSION_NUMBER}" - + CreateShortCut "$SMPROGRAMS\${GRASS_BASE}\Uninstall ${GRASS_BASE}.lnk" "$INSTALL_DIR\Uninstall-GRASS.exe" ""\ "$INSTALL_DIR\Uninstall-GRASS.exe" "" SW_SHOWNORMAL "" "Uninstall GRASS GIS ${VERSION_NUMBER}" - + ;Create the grass_command.bat ClearErrors FileOpen $0 $INSTALL_DIR\${GRASS_COMMAND}.bat w @@ -680,20 +680,20 @@ Section "GRASS" SecGRASS FileWrite $0 'if %ERRORLEVEL% GEQ 1 pause' FileClose $0 done_create_grass_command.bat: - + ;Set the UNIX_LIKE GRASS Path Var /GLOBAL UNIX_LIKE_DRIVE Var /GLOBAL UNIX_LIKE_GRASS_PATH - + StrCpy $UNIX_LIKE_DRIVE "$INSTALL_DIR" 3 StrCpy $UNIX_LIKE_GRASS_PATH "$INSTALL_DIR" "" 3 - + ;replace "\" with "/" in $UNIX_LIKE_DRIVE ${StrReplace} "$UNIX_LIKE_DRIVE" "\" "/" "$UNIX_LIKE_DRIVE" - + ;replace ":" with "" in $UNIX_LIKE_DRIVE ${StrReplace} "$UNIX_LIKE_DRIVE" ":" "" "$UNIX_LIKE_DRIVE" - + ;replace "\" with "/" in $UNIX_LIKE_GRASS_PATH ${StrReplace} "$UNIX_LIKE_GRASS_PATH" "\" "/" "$UNIX_LIKE_GRASS_PATH" @@ -709,28 +709,28 @@ Section "GRASS" SecGRASS ;It first read the $PROFILE variable, to scan the OS version: ;If equal to "drive:\Users\UserName", the OS is Vista, and the $USERNAME variable set to $PROFILE - "drive:\Users\" ;If not, the OS is XP or previous, and the $USERNAME variable set to $PROFILE - "drive:\Documents and Settings\" - + ${If} $USERNAME == "" StrCpy $PROFILE_DRIVE "$PROFILE" 2 StrCpy $PROFILE_ROOT "$PROFILE" 5 -3 - ${If} $USERNAME = "Users" + ${If} $USERNAME = "Users" ${StrReplace} "$USERNAME" "$PROFILE_DRIVE\Users\" "" "$PROFILE" ${Else} ${StrReplace} "$USERNAME" "$PROFILE_DRIVE\Documents and Settings\" "" "$PROFILE" ${EndIf} ${EndIf} - + ;Get the short form of the install path (to allow for paths with spaces) VAR /GLOBAL INST_DIR_SHORT GetFullPathName /SHORT $INST_DIR_SHORT $INSTALL_DIR ;Set the Unix-Like GIS_DATABASE Path ;Var /GLOBAL UNIX_LIKE_GIS_DATABASE_PATH - + ;replace \ with / in $GIS_DATABASE ;${StrReplace} "$UNIX_LIKE_GIS_DATABASE_PATH" "\" "/" "$GIS_DATABASE" - SetShellVarContext current + SetShellVarContext current ${If} ${FileExists} "$APPDATA\GRASS@GRASS_VERSION_MAJOR@\rc" DetailPrint "File $APPDATA\GRASS@GRASS_VERSION_MAJOR@\rc already exists. Skipping." ${Else} @@ -742,7 +742,7 @@ Section "GRASS" SecGRASS FileWrite $0 'GISDBASE: $GIS_DATABASE$\r$\n' FileWrite $0 'LOCATION_NAME: demolocation$\r$\n' FileWrite $0 'MAPSET: PERMANENT$\r$\n' - FileClose $0 + FileClose $0 done_create_grass_rc: ${EndIf} @@ -751,7 +751,7 @@ Section "GRASS" SecGRASS Push 'gisbase = "/c/OSGeo4W/apps/grass/grass-@GRASS_VERSION_MAJOR@.@GRASS_VERSION_MINOR@.@GRASS_VERSION_RELEASE@"' ; string that a line must begin with *WS Sensitive* Push 'gisbase = "$INSTDIR"' ; string to replace whole line with Call ReplaceLineStr - + ;replace config_projshare Push "$INSTDIR\etc\grass@GRASS_VERSION_MAJOR@@GRASS_VERSION_MINOR@.py" ; file to modify Push 'config_projshare = "/c/OSGeo4W/share/proj"' ; string that a line must begin with *WS Sensitive* @@ -759,7 +759,7 @@ Section "GRASS" SecGRASS Call ReplaceLineStr ;replace BU with numeric group name for local users. Users S-1-5-32-545 does not work for Windows Enterprise. Try Authenticated Users S-1-5-11 - AccessControl::SetOnFile "$INSTDIR\etc\grass@GRASS_VERSION_MAJOR@@GRASS_VERSION_MINOR@.py" "(S-1-5-11)" "GenericRead + GenericExecute" + AccessControl::SetOnFile "$INSTDIR\etc\grass@GRASS_VERSION_MAJOR@@GRASS_VERSION_MINOR@.py" "(S-1-5-11)" "GenericRead + GenericExecute" SectionEnd ;-------------------------------------------------------------------------- @@ -789,30 +789,30 @@ Function DownloadInstallMSRuntime StrCpy $DOWNLOAD_MESSAGE_ "$DOWNLOAD_MESSAGE_ installation without the $EXTENDED_ARCHIVE_NAME.$\r$\n" MessageBox MB_OKCANCEL "$DOWNLOAD_MESSAGE_" IDOK download IDCANCEL cancel_download - - download: - SetShellVarContext current + + download: + SetShellVarContext current InitPluginsDir NSISdl::download "$HTTP_PATH/$ARCHIVE_NAME" "$TEMP\$ARCHIVE_NAME" Pop $0 StrCmp $0 "success" download_ok download_failed - - download_ok: + + download_ok: InitPluginsDir untgz::extract -d "$TEMP\$ORIGINAL_UNTAR_FOLDER" -zbz2 "$TEMP\$ARCHIVE_NAME" Pop $0 StrCmp $0 "success" untar_ok untar_failed - + download_failed: DetailPrint "$0" ;print error message to log MessageBox MB_OK "Download Failed.$\r$\nGRASS will be installed without the $EXTENDED_ARCHIVE_NAME." Goto end - + cancel_download: MessageBox MB_OK "Download Cancelled.$\r$\nGRASS will be installed without the $EXTENDED_ARCHIVE_NAME." Goto end - + untar_failed: DetailPrint "$0" ;print error message to log @@ -822,7 +822,7 @@ Function DownloadInstallMSRuntime CopyFiles "$TEMP\$ORIGINAL_UNTAR_FOLDER\bin\*.dll" "$INSTALL_DIR\extrabin" DetailPrint "MS runtime files installed." Goto end - + end: FunctionEnd @@ -831,15 +831,15 @@ Section "Important Microsoft Runtime DLLs" SecMSRuntime ;Set the size (in KB) of the archive file StrCpy $ARCHIVE_SIZE_KB 833 - + ;Set the size (in KB) of the unpacked archive file AddSize 13500 - + StrCpy $HTTP_PATH "http://download.osgeo.org/osgeo4w/v2/${PLATFORM}/release/msvcrt2019/" StrCpy $ARCHIVE_NAME "msvcrt2019-14.2-1.tar.bz2" StrCpy $EXTENDED_ARCHIVE_NAME "Microsoft Visual C++ Redistributable Packages" StrCpy $ORIGINAL_UNTAR_FOLDER "install_msruntime" - + Call DownloadInstallMSRuntime SectionEnd @@ -847,7 +847,7 @@ SectionEnd Function DownloadDataSet ; IntOp $ARCHIVE_SIZE_MB $ARCHIVE_SIZE_KB / 1024 - + StrCpy $DOWNLOAD_MESSAGE_ "The installer will download the $EXTENDED_ARCHIVE_NAME sample data set.$\r$\n" StrCpy $DOWNLOAD_MESSAGE_ "$DOWNLOAD_MESSAGE_$\r$\n" ; StrCpy $DOWNLOAD_MESSAGE_ "$DOWNLOAD_MESSAGE_The archive is about $ARCHIVE_SIZE_MB MB and may take" @@ -859,40 +859,40 @@ Function DownloadDataSet StrCpy $DOWNLOAD_MESSAGE_ "$DOWNLOAD_MESSAGE_$\r$\n" StrCpy $DOWNLOAD_MESSAGE_ "$DOWNLOAD_MESSAGE_Press OK to continue or Cancel to skip the download and complete the GRASS" StrCpy $DOWNLOAD_MESSAGE_ "$DOWNLOAD_MESSAGE_ installation without the $EXTENDED_ARCHIVE_NAME data set.$\r$\n" - + MessageBox MB_OKCANCEL "$DOWNLOAD_MESSAGE_" IDOK download IDCANCEL cancel_download - - download: - SetShellVarContext current + + download: + SetShellVarContext current InitPluginsDir NSISdl::download "$HTTP_PATH/$ARCHIVE_NAME" "$TEMP\$ARCHIVE_NAME" Pop $0 StrCmp $0 "success" download_ok download_failed - - download_ok: + + download_ok: InitPluginsDir untgz::extract -d "$GIS_DATABASE" "$TEMP\$ARCHIVE_NAME" Pop $0 StrCmp $0 "success" untar_ok untar_failed - - untar_ok: + + untar_ok: Rename "$GIS_DATABASE\$ORIGINAL_UNTAR_FOLDER" "$GIS_DATABASE\$CUSTOM_UNTAR_FOLDER" Delete "$TEMP\$ARCHIVE_NAME" Goto end - + download_failed: DetailPrint "$0" ;print error message to log MessageBox MB_OK "Download Failed.$\r$\nGRASS will be installed without the $EXTENDED_ARCHIVE_NAME sample data set." Goto end - + cancel_download: MessageBox MB_OK "Download Cancelled.$\r$\nGRASS will be installed without the $EXTENDED_ARCHIVE_NAME sample data set." Goto end - + untar_failed: DetailPrint "$0" ;print error message to log - + end: FunctionEnd @@ -901,34 +901,34 @@ Section /O "North Carolina (Wake County) Data Set" SecNorthCarolinaSDB ;Set the size (in KB) of the archive file StrCpy $ARCHIVE_SIZE_KB 144213 - + ;Set the size (in KB) of the unpacked archive file AddSize 254521 - + StrCpy $HTTP_PATH "https://grass.osgeo.org/sampledata/north_carolina/" StrCpy $ARCHIVE_NAME "nc_spm_08_grass7.tar.gz" StrCpy $EXTENDED_ARCHIVE_NAME "North Carolina (Wake County)" StrCpy $ORIGINAL_UNTAR_FOLDER "nc_spm_08_grass7" StrCpy $CUSTOM_UNTAR_FOLDER "North_Carolina" - - Call DownloadDataSet - + + Call DownloadDataSet + SectionEnd Section /O "South Dakota (Spearfish County) Data Set" SecSpearfishSDB ;Set the size (in KB) of the archive file StrCpy $ARCHIVE_SIZE_KB 20803 - + ;Set the size (in KB) of the unpacked archive file AddSize 42171 - + StrCpy $HTTP_PATH "https://grass.osgeo.org/sampledata" StrCpy $ARCHIVE_NAME "spearfish_grass70data-0.3.tar.gz" StrCpy $EXTENDED_ARCHIVE_NAME "South Dakota (Spearfish County)" StrCpy $ORIGINAL_UNTAR_FOLDER "spearfish60_grass7" StrCpy $CUSTOM_UNTAR_FOLDER "Spearfish60_grass7" - + Call DownloadDataSet SectionEnd @@ -940,7 +940,7 @@ Function .onInstSuccess ${If} ${SectionIsSelected} ${SecMSRuntime} Delete "$TEMP\$ARCHIVE_NAME" RMDir /r "$TEMP\$ORIGINAL_UNTAR_FOLDER" - RMDir "$TEMP\$ORIGINAL_UNTAR_FOLDER" + RMDir "$TEMP\$ORIGINAL_UNTAR_FOLDER" ${EndIf} FunctionEnd @@ -951,23 +951,23 @@ FunctionEnd Section "Uninstall" ;remove files & folders RMDir /r "$INSTDIR" - + ;remove the Desktop ShortCut SetShellVarContext current Delete "$DESKTOP\${GRASS_BASE}.lnk" - + ;remove the Programs Start ShortCuts SetShellVarContext all RMDir /r "$SMPROGRAMS\${GRASS_BASE}" - + ;remove the $APPDATA\GRASS@GRASS_VERSION_MAJOR@ folder ;disabled, don't remove user settings ; SetShellVarContext current - ;RMDir /r "$APPDATA\GRASS@GRASS_VERSION_MAJOR@" + ;RMDir /r "$APPDATA\GRASS@GRASS_VERSION_MAJOR@" ;${If} ${FileExists} "$APPDATA\GRASS@GRASS_VERSION_MAJOR@\addons\*.*" ; RMDir /r "$APPDATA\GRASS@GRASS_VERSION_MAJOR@\addons" ;${EndIf} - + ;remove the Registry Entries DeleteRegKey HKLM "Software\${GRASS_BASE}" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GRASS_BASE}" diff --git a/mswindows/Makefile b/mswindows/Makefile index 3a33ac70b74..de2a4c6463c 100644 --- a/mswindows/Makefile +++ b/mswindows/Makefile @@ -11,7 +11,7 @@ ifneq ($(MINGW),) default: GRASS-Packager.bat GRASS-Installer.nsi parsubdirs else default: -endif +endif GRASS-Packager.bat: GRASS-Packager.bat.tmpl sed \ diff --git a/mswindows/README.html b/mswindows/README.html index 2b6f87db703..91be0f9afbb 100644 --- a/mswindows/README.html +++ b/mswindows/README.html @@ -7,7 +7,7 @@ Instructions how to prepare a WinGRASS package installer has been moved to -the wiki +the wiki page. 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/external/README.license b/mswindows/external/README.license index 2423c610f5f..f9345809a9d 100644 --- a/mswindows/external/README.license +++ b/mswindows/external/README.license @@ -1,21 +1,21 @@ - - -In the following directories you will find code which was not -written by The GRASS Development Team. - -Parts of GRASS are not copyright by The GRASS Development Team. -The original authors hold the copyrights and you have to abide -to their licensing terms where noted. -(Keep in mind that code linking into GRASS can only be distributed -if compatible with the GPL.) - -Specifically the source code below this directory is not necessarily -licensed under the GPL. Check the READMEs and source code header -comments carefully. - - - - * Windows batchfiles for use with R / (GNU GPL v2) - http://code.google.com/p/batchfiles/ - https://github.com/ggrothendieck/batchfiles (new code repository) - + + +In the following directories you will find code which was not +written by The GRASS Development Team. + +Parts of GRASS are not copyright by The GRASS Development Team. +The original authors hold the copyrights and you have to abide +to their licensing terms where noted. +(Keep in mind that code linking into GRASS can only be distributed +if compatible with the GPL.) + +Specifically the source code below this directory is not necessarily +licensed under the GPL. Check the READMEs and source code header +comments carefully. + + + + * Windows batchfiles for use with R / (GNU GPL v2) + http://code.google.com/p/batchfiles/ + https://github.com/ggrothendieck/batchfiles (new code repository) + diff --git a/mswindows/external/rbatch/ANNOUNCE b/mswindows/external/rbatch/ANNOUNCE index 98618afec5f..a033c16b2d1 100644 --- a/mswindows/external/rbatch/ANNOUNCE +++ b/mswindows/external/rbatch/ANNOUNCE @@ -1,21 +1,21 @@ -A new version of the Windows batchfiles is available. +A new version of the Windows batchfiles is available. CHANGES -The key change is the new R.bat utility. R.bat has a new interface and +The key change is the new R.bat utility. R.bat has a new interface and extended functionality covering many of the other prior utilities. (These older utilities are no longer needed and have been removed.) Unlike R.bat which requires no configuration the new Rpathset.bat utility is configured by manually changing the Windows batch SET statements in it. The -main advantage is just that it is very simple internally which may be +main advantage is just that it is very simple internally which may be advantageous in some situations involving customization. A new pdf document accompanies the utilities providing more detail. OVERVIEW -These are self contained independent no-install Windows batch, javascript and +These are self contained independent no-install Windows batch, javascript and .hta files. Just place any that you wish to use on your Windows PATH. R.bat @@ -28,7 +28,7 @@ line do this: R gui R.bat locates R, MiKTeX and Rtools using the registry or heuristics and then -runs the subcommand indicated by the first argument. +runs the subcommand indicated by the first argument. In addition to the gui subcommand, the following subcommands are available: cd, cmd, dir, gui, help, ls, path, R, script, show, SetReg, tools, touch. @@ -48,7 +48,7 @@ R show -- show R_ variable values used (R_ROOT, R_HOME, R_VER, R_ARCH, etc.) R path -- temporarily add R, MiKTeX and Rtools to the Windows path R tools -- similar but only add MiKTeX and Rtools to the Windows path -Except for R touch (which updates the date on your R_HOME directory) and +Except for R touch (which updates the date on your R_HOME directory) and R SetReg (which calls RSetReg.exe to update the registry with your R version), R.bat makes no permanent changes to your system. @@ -56,16 +56,16 @@ Rpathset.bat Rpathset.bat temporarily sets the Windows path to R, Rtools and MiKTeX based on SET statements that the user can configure manually. It is an -alternative to R.bat that lacks R.bat's "no configuration" nature but may be +alternative to R.bat that lacks R.bat's "no configuration" nature but may be preferred in some situations due to its internal simplicity. -Also Rpathset.bat is more likely to work on systems that have not been -tested given its simplicity. (The utilities were tested on 32 bit Windows +Also Rpathset.bat is more likely to work on systems that have not been +tested given its simplicity. (The utilities were tested on 32 bit Windows Vista and 64 bit Windows 8 systems.) Other -Other commands which continue to be available are copydir.bat, movedir.bat, +Other commands which continue to be available are copydir.bat, movedir.bat, el.js, clip2r.js and find-miktex.hta . These copy and move R libraries, run a command in elevated mode (i.e. as Administrator), copy the clipboard to a running R instance and find MiKTeX. diff --git a/mswindows/external/rbatch/NEWS b/mswindows/external/rbatch/NEWS index ed028a3d445..2b53b78602a 100644 --- a/mswindows/external/rbatch/NEWS +++ b/mswindows/external/rbatch/NEWS @@ -10,7 +10,7 @@ Changes in version 0.7-1 Changes in version 0.7-0 - o R.bat reworked. It now has a with different interface and many prior + o R.bat reworked. It now has a with different interface and many prior batch files have been incorporated into it and removed o new Rpathset.bat @@ -33,7 +33,7 @@ Changes in version 0.6-5 %ProgramFiles%\MySQL\* - This allows one to install and run RMySQL without setting any environment + This allows one to install and run RMySQL without setting any environment variables. (Note that MySQL should be installed from the mysql site. xampp and wamp do not include the header files needed by RMySQL.) @@ -71,7 +71,7 @@ Changes in version 0.5-0 or higher. o new command find-miktex.hta can be run without arguments from the - Windows command line or double clicked from Windows Explorer + Windows command line or double clicked from Windows Explorer to show path to the MiKTeX bin directory. o Rversions.hta now also changes the .RData association and has @@ -90,14 +90,14 @@ Changes in version 0.5-0 Changes in version 0.4-3 - o Sweave.bat and Stangle.bat were not automatically finding MiKTeX. + o Sweave.bat and Stangle.bat were not automatically finding MiKTeX. Fixed. Changes in version 0.4-2 o can optionally work off initialization files in place of registry. - Place rbatchfilesrc.bat in current directory or %userprofile% (so - different directories can work off different versions of R, say) + Place rbatchfilesrc.bat in current directory or %userprofile% (so + different directories can work off different versions of R, say) or same directory as the other batchfiles and it will run it first. Typically rbatchfiles.bat would constain these two lines or similar: set R_HOME=C:\Program Files\R\R-2.7.0 @@ -110,13 +110,13 @@ Changes in version 0.4-1 o it is no longer necessary to set any paths to build R packages provided Rtools 2.7 or later is used. Rcmd.bat and the other scripts automatically find Rtools from the registry (including perl) - and if MikTeX is at %ProgramFiles%\MiKTeX* or %SystemDrive%:\MiKTex - then it will find MiKTeX too. New optional environment variables + and if MikTeX is at %ProgramFiles%\MiKTeX* or %SystemDrive%:\MiKTex + then it will find MiKTeX too. New optional environment variables R_TOOLS and R_MIKTEX are available to force specified paths to be used. o new Rtools.bat command that sets the path for the current cmd instance to the one that R*.bat files use internally. That is, rtools/bin, - rtools/perl/bin, rtools/MinGW/bin and MiKTeX .../miktex/bin are added + rtools/perl/bin, rtools/MinGW/bin and MiKTeX .../miktex/bin are added to the path. This is not needed to run or install R programs but only if you want to access the rtools for other purposes. @@ -162,7 +162,7 @@ Changes in version 0.4-0 by Dieter Menne. Changes in version 0.3-2 - + o sweave.bat now uses Rterm.bat rather than Rcmd.bat which makes it usable with a basic R installation (i.e. sh.exe not needed). Previously it required Rcmd.bat but now it requires Rterm.bat instead. @@ -173,7 +173,7 @@ Changes in Version 0.3-1 o new find-miktex.bat which lists the mixktex folders from the registry - o new Rscript.bat which allows one to use the Rscript facility in + o new Rscript.bat which allows one to use the Rscript facility in R 2.5.0 and later without changing pathnames. Just place Rscript.bat in any existing path and it will automatically find the current version of R from the registry and run the Rscript.exe that @@ -182,24 +182,24 @@ Changes in Version 0.3-1 o runR.bat. If you have an R script such as myfile.R then you can create a batch script for it by copying runR.bat to myfile.bat. Then when you issue the command myfile or myfile.bat it will run the R script in - myfile.R . Just place myfile.bat and myfile.R anywhere in your path. + myfile.R . Just place myfile.bat and myfile.R anywhere in your path. This uses Rscript.bat . o #Rscript. If you have an Rscript called myfile.R, say, then if you - copy the script to myfile.bat and place - #Rscript %0 %* + copy the script to myfile.bat and place + #Rscript %0 %* as the first line with the remainder being the R commands then issuing the command myfile or myfile.bat will run the R script. The advantage over the runR.bat method is that there is only one file, myfile.bat. - You don't need myfile.R anymore. The disadvantage is that it will - echo the #Rscript line to stdout. This will be fixed if and when - Rscript ever gets the perl/python/ruby -x flag. (The runR approach will - not echo additional lines but does require two files.) + You don't need myfile.R anymore. The disadvantage is that it will + echo the #Rscript line to stdout. This will be fixed if and when + Rscript ever gets the perl/python/ruby -x flag. (The runR approach will + not echo additional lines but does require two files.) o new Rtidy.bat is a sample Rscript that uses the #Rscript facility based on George Georgalis' UNIX code - o withgs.bat now checks for latest ghostscript version. (Previously + o withgs.bat now checks for latest ghostscript version. (Previously version was hard coded and it only worked for that version.) Changes in Version 0.3-0 @@ -211,13 +211,13 @@ Changes in Version 0.3-0 o new --tex, --pdf, --nobck.pdf switches are available on sweave. Also expanded help when entering sweave without args. - + Changes in Version 0.2-9 o updated README and other documentation files and inline documentation o added sweave.bat - + o new google code home page and svn repository http://code.google.com/p/batchfiles/ @@ -244,7 +244,7 @@ Changes in Version 0.2-6 o Rrefresh.bat has been removed (after having been deprecated in in previous versions of batchfiles). - o tested movedir.bat by using it to upgrade R-2.2.0pat to R-2.2.1. + o tested movedir.bat by using it to upgrade R-2.2.0pat to R-2.2.1. See instructions in README. Changes in Version 0.2-5 @@ -261,27 +261,27 @@ Changes in Version 0.2-3 R to another. (This is a temporary solution until R provides facilities for upgrading the libraries, expected in R 2.3.0 .) See README for usage. - + o eliminated all code associated with reading and manipulation of R_ENVIRON, R_PROFILE and R_LIBS simplifying the batch files. Use copydir.bat instead. - o Rversions.hta is a javascript GUI version of Rversions.bat + o Rversions.hta is a javascript GUI version of Rversions.bat Changes in Version 0.2-2 o added jgr.bat which starts up the JGR GUI. - o added Rversions.bat which can list the directories of all R versions + o added Rversions.bat which can list the directories of all R versions available and can set one to become the current R version. - o all batch scripts which used the environment variable name Rrw now + o all batch scripts which used the environment variable name Rrw now use the environment variable name R_HOME instead. - o Rcmd.bat, Rgui.bat, R.bat, jgr.bat files will now read R_ENVIRON, + o Rcmd.bat, Rgui.bat, R.bat, jgr.bat files will now read R_ENVIRON, if present, and set the R_LIBS definition in it, if present (unless R_LIBS is already defined as an environment variable). All R_ENVIRON - file syntax accepted by R is supported including comments (#), + file syntax accepted by R is supported including comments (#), var=value, var=${foo-bar} and recursions, var=${A-${B-C}}. o makepkg.bat internals were simplified due to previous point. @@ -290,7 +290,7 @@ Changes in Version 0.2-2 o updated THANKS. - o updated README. More introductory information. Also instructions + o updated README. More introductory information. Also instructions for Rgui shortcut will disable screen flash on startup. Corrections. Changes in Version 0.2-1 @@ -300,18 +300,18 @@ Changes in Version 0.2-1 Changes in Version 0.2-0 o can now support configurations without *.site files (as well as - configurations with *.site files) thereby reducing the minimum - configuration even further. + configurations with *.site files) thereby reducing the minimum + configuration even further. o Rcmd.bat, Rgui.bat and R.bat now temporarily set R_ENVIRON, - R_PROFILE and R_LIBS as needed so that it is no longer necessary to + R_PROFILE and R_LIBS as needed so that it is no longer necessary to copy the *.site files into the etc directory eliminating all reconfiguration when upgrading to a new version of R (except for refreshing MiKTeX). o new command miktex-refresh.bat is used to refresh MiKTeX after a new version of R is installed. Previously this was done in - Rrefresh.bat which is now deprecated. Rrefresh.bat is no longer + Rrefresh.bat which is now deprecated. Rrefresh.bat is no longer needed (unless you want each R version to have its own *.site files). o new NEWS, WISHLIST and RESOURCES files. diff --git a/mswindows/external/rbatch/R.bat b/mswindows/external/rbatch/R.bat index d55a6b395a8..8cbb2f65e88 100644 --- a/mswindows/external/rbatch/R.bat +++ b/mswindows/external/rbatch/R.bat @@ -1,7 +1,7 @@ -@Echo OFF +@Echo OFF -:: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: Software and documentation is (c) 2013 GKX Associates Inc. and +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). :: Help is at bottom of script or just run script with single argument: help @@ -19,7 +19,7 @@ if not defined R_REGISTRY set R_REGISTRY=1 set CYGWIN=nodosfilewarning -SetLocal EnableExtensions EnableDelayedExpansion +SetLocal EnableExtensions EnableDelayedExpansion :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: R_CMD @@ -62,11 +62,11 @@ rem echo R_CMD:%R_CMD% args=[%args%] ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 1. If .\Rgui.exe exist use implied R_PATH and skip remaining points. :: 2. If .\{x64,i386}\Rgui.exe or .\bin\{x64,i386}\Rgui.exe exists use implied R_HOME. -:: 3. if R_HOME defined then derive any of R_ROOT and R_VER that +:: 3. if R_HOME defined then derive any of R_ROOT and R_VER that :: are not already defined. :: 4. if R_PATH defined then derive any of R_ROOT, R_HOME, R_VER and R_ARCH that :: are not already defined. -:: 4a. If R_REGISTRY=1 and R found in registry derive any of R_HOME, R_ROOT and +:: 4a. If R_REGISTRY=1 and R found in registry derive any of R_HOME, R_ROOT and :: R_VER that are not already defined. :: 5. If R_ROOT not defined try %ProgramFiles%\R\*, %ProgramFiles(x86)%\R\* :: and then %SystemRoot%\R else error @@ -149,7 +149,7 @@ if defined R_HOME ( ) ) - + :: 5 if defined R_ROOT goto:R_ROOT_end @@ -385,10 +385,10 @@ goto:eof ver | findstr XP >NUL if not errorlevel 1 goto:Rtouch_next if not exist "%ProgramFiles%\R" goto:Rtouch_next -reg query "HKU\S-1-5-19" >NUL 2>&1 && ( goto Rtouch_next ) || ( +reg query "HKU\S-1-5-19" >NUL 2>&1 && ( goto Rtouch_next ) || ( echo Please run this as Administator. goto :eof -) +) :Rtouch_next if not defined R_HOME set R_HOME=%R_ROOT%\%R_VER% @@ -401,7 +401,7 @@ goto:eof ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:: set path +:: set path ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :Rpath endlocal & PATH %PATH%;%R_PATH% @@ -450,15 +450,15 @@ goto:eof :: Extract text from file: :: %1 = input string that starts text :: %2 = input file -:: final = output variable holding text from and including %1 until +:: final = output variable holding text from and including %1 until :: binary data encountered :: -:: Needs: SetLocal EnableExtensions EnableDelayedExpansion +:: Needs: SetLocal EnableExtensions EnableDelayedExpansion :: -:: Example: +:: Example: :: call :extract_string {app} C:\Rtools\unins000.dat :: echo %final% -:: where {app} is the string that starts extraction and +:: where {app} is the string that starts extraction and :: C:\Rtoolsiunins000.dat is the file :: :: Based on code by Frank Westlake, https://github.com/FrankWestlake @@ -467,61 +467,61 @@ goto:eof :extract_string - SetLocal EnableExtensions EnableDelayedExpansion + SetLocal EnableExtensions EnableDelayedExpansion - Set "string=%1" + Set "string=%1" Set "file=%2" - For /F "delims=" %%a in ( - 'findstr /C:"%string%" "%file%"^|MORE' - ) Do ( - Set "$=%%~a" - If /I "!$:~0,5!" EQU "%string%" ( - Set $=!$:;=" "! - For %%b in ("!$!") Do ( - Set "#=%%~b" - If "!#:~0,5!" EQU "%string%" ( + For /F "delims=" %%a in ( + 'findstr /C:"%string%" "%file%"^|MORE' + ) Do ( + Set "$=%%~a" + If /I "!$:~0,5!" EQU "%string%" ( + Set $=!$:;=" "! + For %%b in ("!$!") Do ( + Set "#=%%~b" + If "!#:~0,5!" EQU "%string%" ( CALL :work "!#!" - ) - ) - ) - ) + ) + ) + ) + ) endlocal & set final=%final% - Goto :EOF - :work + Goto :EOF + :work set final=%final%!#!; - Goto :EOF - - :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - :trimPath: [segment to add] - :: Eliminates redundant path segments from the variable and - :: optionally adds new segmants. - :: Example: CALL :trimPath:PATH - :: Example: CALL :trimPath:PATH "C:\A & B" C:\a\b\c - :: - :: Note that only a colon separates the subroutine name and - :: the name of the variable to be edited. + Goto :EOF + + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + :trimPath: [segment to add] + :: Eliminates redundant path segments from the variable and + :: optionally adds new segmants. + :: Example: CALL :trimPath:PATH + :: Example: CALL :trimPath:PATH "C:\A & B" C:\a\b\c + :: + :: Note that only a colon separates the subroutine name and + :: the name of the variable to be edited. :: - Frank Westlake, https://github.com/FrankWestlake - SetLocal EnableExtensions EnableDelayedExpansion - For /F "tokens=2 delims=:" %%a in ("%0") Do ( - For %%a in (%* !%%a!) Do ( - Set "#=%%~a" - For %%b in (!new!) Do If /I "!#!" EQU "%%~b" Set "#=" - If DEFINED # ( - If DEFINED new (Set "new=!new!;!#!") Else ( Set "new=!#!") - ) - ) - ) - EndLocal & For /F "tokens=2 delims=:" %%a in ("%0") Do Set "%%a=%new%" - Goto :EOF - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + SetLocal EnableExtensions EnableDelayedExpansion + For /F "tokens=2 delims=:" %%a in ("%0") Do ( + For %%a in (%* !%%a!) Do ( + Set "#=%%~a" + For %%b in (!new!) Do If /I "!#!" EQU "%%~b" Set "#=" + If DEFINED # ( + If DEFINED new (Set "new=!new!;!#!") Else ( Set "new=!#!") + ) + ) + ) + EndLocal & For /F "tokens=2 delims=:" %%a in ("%0") Do Set "%%a=%new%" + Goto :EOF + +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :Rhelp -echo (c) 2013 G. Grothendieck -echo License: GPL 2.0 ( http://www.gnu.org/licenses/gpl-2.0.html ) -echo Launch script for R and associated functions. +echo (c) 2013 G. Grothendieck +echo License: GPL 2.0 ( https://www.gnu.org/licenses/gpl-2.0.html ) +echo Launch script for R and associated functions. echo Usage: R.bat [subcommand] [arguments] echo Subcommands where (0) means takes no arguments; (A) means may need Admin priv echo cd - cd to R_ROOT, typically to C:\Program Files\R (0) @@ -555,35 +555,35 @@ echo start set R_HOME=%ProgramFiles%\R\R-2.14.0 ^& R gui echo echo ==Customization by renaming== echo. -echo If the optional first argument is missing then it uses the value of -echo the environment variable R_CMD or if that is not set it uses the name of -echo the script file as the default first argument. The idea is one could have +echo If the optional first argument is missing then it uses the value of +echo the environment variable R_CMD or if that is not set it uses the name of +echo the script file as the default first argument. The idea is one could have echo multiple versions of the script called R.bat, Rgui.bat, etc. which invoke echo the corresponding functionality without having to specify first argument. echo. echo ==Customization by setting environment variables at top of script== echo. -echo It can be customized by setting any of R_CMD, R_HOME, R_ARCH, -echo R_MIKTEX_PATH, R_TOOLS after the @echo off command at the top of the -echo script. R_CMD will be used as the default first argument (instead of the -echo script name). +echo It can be customized by setting any of R_CMD, R_HOME, R_ARCH, +echo R_MIKTEX_PATH, R_TOOLS after the @echo off command at the top of the +echo script. R_CMD will be used as the default first argument (instead of the +echo script name). echo. echo e.g. use the following after @echo off to force 32-bit echo set R_ARCH=32 echo. -echo e.g. use the following after @echo off to force a particular version of +echo e.g. use the following after @echo off to force a particular version of echo R to be used echo set R_HOME=%ProgramFiles%\R\R-2.14.0 echo. -echo e.g. use the following after @echo off to change the default command to +echo e.g. use the following after @echo off to change the default command to echo Rgui even if the script is called myRgui.bat, say: echo set R_CMD=Rgui echo. echo ==Installation== -echo. +echo. echo The script is self contained so just place it anywhere on your Windows echo PATH. (From the Windows cmd line the command PATH shows your current -echo Windows path.) You may optionally make copies of this script with names +echo Windows path.) You may optionally make copies of this script with names echo like R.bat, Rscript.bat, Rcmd.bat so that each has a different default. echo. diff --git a/mswindows/external/rbatch/README.grass b/mswindows/external/rbatch/README.grass index 85f32b7a9be..5566aba14d6 100644 --- a/mswindows/external/rbatch/README.grass +++ b/mswindows/external/rbatch/README.grass @@ -1,11 +1,11 @@ README.grass - written by Helmut Kudrnovsky - alectoria gmx.at -This directory contains windows batch files for installing and maintaining R, for +This directory contains windows batch files for installing and maintaining R, for an improved coupling of GRASS GIS and R (www.r-project.org) in a windows environment. -- -Files integrated from +Files integrated from svn checkout http://batchfiles.googlecode.com/svn/trunk/ @@ -13,7 +13,7 @@ at svn-revision 104 (2012-08-31). -- -See http://trac.osgeo.org/grass/ticket/1149#comment:9 +See https://trac.osgeo.org/grass/ticket/1149#comment:9 -- diff --git a/mswindows/external/rbatch/README.html b/mswindows/external/rbatch/README.html index 104405115b2..71335b5915a 100644 --- a/mswindows/external/rbatch/README.html +++ b/mswindows/external/rbatch/README.html @@ -2,7 +2,7 @@

    Batchfiles

    -Home Page: batchfiles home page. +Home Page: batchfiles home page.

    Discuss: sqldf dicussion group is being used for discussion of this software too.

    diff --git a/mswindows/external/rbatch/RESOURCES b/mswindows/external/rbatch/RESOURCES index 39471b824e4..d5ac89da8af 100644 --- a/mswindows/external/rbatch/RESOURCES +++ b/mswindows/external/rbatch/RESOURCES @@ -1,7 +1,7 @@ GENERAL RESOURCES ON WINDOWS BATCH FILE PROGRAMMMING ---------------------------------------------------- -The Windows command line commands will bring up help information +The Windows command line commands will bring up help information that is particularly useful: help set @@ -18,7 +18,7 @@ Here are some links on Windows batch file programmming. http://groups-beta.google.com/group/alt.msdos.batch.nt/msg/5a9587e871c27a75 - cmd bugs - http://groups-beta.google.com/group/alt.msdos.batch/msg/7b1d22945c89af75 - cmd help resources + http://groups-beta.google.com/group/alt.msdos.batch/msg/7b1d22945c89af75 - cmd help resources http://msdn.microsoft.com/downloads/list/webdev.asp - Windows script downloads @@ -28,9 +28,9 @@ Here are some links on Windows batch file programmming. http://www.commandline.co.uk - Ritchie Lawrence cmd line utilities - http://www.cybermesa.com/~bstewart/ - Bill Stewarts scripting tools + http://www.cybermesa.com/~bstewart/ - Bill Stewart�s scripting tools - http://www.fpschultze.de - FP Shcultzes batch tricks + http://www.fpschultze.de - FP Shcultze�s batch tricks http://www.microsoft.com/technet/community/columns/scripts - MS TechNet scripting diff --git a/mswindows/external/rbatch/Rpathset.bat b/mswindows/external/rbatch/Rpathset.bat index 7873fc01907..d3762ce66f2 100644 --- a/mswindows/external/rbatch/Rpathset.bat +++ b/mswindows/external/rbatch/Rpathset.bat @@ -1,10 +1,10 @@ -:: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: Software and documentation is (c) 2013 GKX Associates Inc. and +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). :: Purpose: setup path to use R, Rtools and other utilities from cmd line. :: :: Makes no permanent system changes. Does not read or write registry. -:: Temporarily prepends to PATH and sets environment variables for current +:: Temporarily prepends to PATH and sets environment variables for current :: Windows cmd line session only. :: :: Use: Run this each time you launch cmd.exe and want to use R or Rtools. @@ -14,13 +14,13 @@ :: Install: Modify set statements appropriately for your installation. :: and then place this batch script anywhre on your existing path. :: (The Windows commandline command PATH shows the current PATH.) -:: +:: :: In many cases no changes are needed at all in this file. :: R_HOME and R_ARCH are the most likely that may need to be changed. :: :: Report bugs to: :: ggrothendieck at gmail.com -:: +:: :: License: GPL 2.0 :: Go into R and issue this command: normalizePath(R.home()) @@ -29,7 +29,7 @@ :: R is available from: http://www.r-project.org set R_HOME=C:\Program Files\R\R-3.1.0 -:: 32 or 64 bit version of R. +:: 32 or 64 bit version of R. :: (If you wish to use both versions of R make two versions of this file.) :: set R_ARCH=i386 set R_ARCH=x64 @@ -38,21 +38,21 @@ set R_ARCH=x64 set R_PATH=%R_HOME%\bin\%R_ARCH% :: directory path where Rtools was installed. Usually best to use default -:: which is the one shown below. Note that different versions of R may +:: which is the one shown below. Note that different versions of R may :: require different versions of Rtools. :: Rtools is available from: http://cran.r-project.org/bin/windows/Rtools/ set R_TOOLS=C:\Rtools -:: If in future Rtools changes the required paths then modify accordingly. -:: To check, run the following findstr command which lists the R_TOOLS_PATH +:: If in future Rtools changes the required paths then modify accordingly. +:: To check, run the following findstr command which lists the R_TOOLS_PATH :: (plus some garbage): :: findstr {app} %R_TOOLS%\unins000.dat set R_TOOLS_PATH=%R_TOOLS%\bin;%R_TOOLS%\gcc-4.6.3\bin :: From within R, the R_USER directory path can be viewed like this: :: cat(normalizePath('~')) -:: It contains your personal .Rprofile, if any, and unless set otherwise -:: %R_USER%\R\win-library contains your personal R library of packages +:: It contains your personal .Rprofile, if any, and unless set otherwise +:: %R_USER%\R\win-library contains your personal R library of packages :: (from CRAN and elsewhere). set R_USER=%userprofile%\Documents @@ -74,11 +74,11 @@ set R_MIKTEX_PATH=C:\Program Files (x86)\MiKTeX 2.9\miktex\bin :: This is only needed to run JGR and Deducer. :: R_LIBS is the system library. -:: If you have installed at least one package (at which point R will ask to +:: If you have installed at least one package (at which point R will ask to :: set up a personal library -- which you should allow) then R_LIBS_USER :: is similar to output of .libPaths() with first comnponent being your -:: personal library and second component being library holding packages that -:: come with R. +:: personal library and second component being library holding packages that +:: come with R. :: Be sure NOT to store the packages that you downloaded from CRAN :: in the %R_HOME%\library directory. :: set R_LIBS=%R_USER%\R\win-library\2.15 diff --git a/mswindows/external/rbatch/batchfiles.md b/mswindows/external/rbatch/batchfiles.md index 2c10e2bcf75..de26ff2748f 100644 --- a/mswindows/external/rbatch/batchfiles.md +++ b/mswindows/external/rbatch/batchfiles.md @@ -3,7 +3,7 @@ G. Grothendieck Software and documentation is (c) 2013 GKX Associates Inc. and licensed -under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). ## Introduction ## diff --git a/mswindows/external/rbatch/batchfiles.tex b/mswindows/external/rbatch/batchfiles.tex index da8d64664b7..87653c10b0d 100644 --- a/mswindows/external/rbatch/batchfiles.tex +++ b/mswindows/external/rbatch/batchfiles.tex @@ -3,7 +3,7 @@ \section{Windows Batch Files for R} G. Grothendieck Software and documentation is (c) 2013 GKX Associates Inc. and licensed -under \href{http://www.gnu.org/licenses/gpl-2.0.html}{GPL 2.0}. +under \href{https://www.gnu.org/licenses/gpl-2.0.html}{GPL 2.0}. \subsection{Introduction} @@ -275,7 +275,7 @@ \subsection{Rpathset.bat} An alternative to \begin{verbatim} -R.bat path +R.bat path \end{verbatim} is the \texttt{Rpathset.bat}. Unlike \texttt{R.bat}, @@ -300,7 +300,7 @@ \subsection{movedir.bat and copydir.bat} \begin{verbatim} cd %userprofile%\\Documents\\win-library copydir 2.15\\library 3.0\\library -R.bat gui +R.bat gui ... now enter update.packages() into R... \end{verbatim} diff --git a/mswindows/external/rbatch/copydir.bat b/mswindows/external/rbatch/copydir.bat index f346560b3f0..3e80f2054d3 100644 --- a/mswindows/external/rbatch/copydir.bat +++ b/mswindows/external/rbatch/copydir.bat @@ -1,12 +1,12 @@ @echo off -:: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: Software and documentation is (c) 2013 GKX Associates Inc. and +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). setlocal if not "%2"=="" goto:run echo Usage: copydir fromdir todir -echo All files/directories in fromdir that do not also exist in todir are +echo All files/directories in fromdir that do not also exist in todir are echo recursively copied. -echo e.g. +echo e.g. echo cd "%userprofile%\Documents\R\win-library" echo copydir 2.14 2.15 echo Now start up R 2.15.x and issue update.packages() diff --git a/mswindows/external/rbatch/find-miktex.hta b/mswindows/external/rbatch/find-miktex.hta index 43a994fa5d9..8b7603723a2 100644 --- a/mswindows/external/rbatch/find-miktex.hta +++ b/mswindows/external/rbatch/find-miktex.hta @@ -5,7 +5,7 @@ .highlight {background:#ff00ff} .text {color:#ff00ff} .both {color:white;background:black} - + find-miktex @@ -25,7 +25,7 @@ while (true) { i++; } catch(e) {break}; } - + diff --git a/mswindows/external/rbatch/make-batchfiles-pdf.bat b/mswindows/external/rbatch/make-batchfiles-pdf.bat index 5e133489ff0..f366db29176 100644 --- a/mswindows/external/rbatch/make-batchfiles-pdf.bat +++ b/mswindows/external/rbatch/make-batchfiles-pdf.bat @@ -1,4 +1,3 @@ - :: make pdf documentation. To run: :: 1. install pandoc from http://code.google.com/p/pandoc/downloads/list :: 2. run this file diff --git a/mswindows/external/rbatch/movedir.bat b/mswindows/external/rbatch/movedir.bat index 104d6a0d5f0..53c35ae7487 100644 --- a/mswindows/external/rbatch/movedir.bat +++ b/mswindows/external/rbatch/movedir.bat @@ -1,12 +1,12 @@ @echo off -:: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: Software and documentation is (c) 2013 GKX Associates Inc. and +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). setlocal if not "%2"=="" goto:run echo Usage: copydir fromdir todir -echo All files/directories in fromdir that do not also exist in todir are +echo All files/directories in fromdir that do not also exist in todir are echo recursively copied. -echo e.g. +echo e.g. echo cd "%userprofile%\Documents\R\win-library" echo movedir 2.14 2.15 echo Now start up R 2.15.x and issue update.packages() diff --git a/mswindows/generic.manifest b/mswindows/generic.manifest index 0855fe9cba5..bd0ea40eea3 100644 --- a/mswindows/generic.manifest +++ b/mswindows/generic.manifest @@ -1,10 +1,10 @@ - + - GRASS modules + type="win32"/> + GRASS modules 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/gdal-config b/mswindows/osgeo4w/gdal-config index 1917531b73e..9ad585f47b5 100755 --- a/mswindows/osgeo4w/gdal-config +++ b/mswindows/osgeo4w/gdal-config @@ -25,7 +25,7 @@ if test $# -eq 0; then usage 1 1>&2 fi -case $1 in +case $1 in --libs) echo $CONFIG_LIBS ;; diff --git a/mswindows/osgeo4w/geos-config b/mswindows/osgeo4w/geos-config index 6b52971ee80..523059726ee 100755 --- a/mswindows/osgeo4w/geos-config +++ b/mswindows/osgeo4w/geos-config @@ -32,7 +32,7 @@ case $1 in echo $OSGEO4W_ROOT_MSYS/lib/geos_c.lib ;; --ldflags) - echo + echo ;; --includes) echo $OSGEO4W_ROOT_MSYS/include diff --git a/mswindows/osgeo4w/liblas-config b/mswindows/osgeo4w/liblas-config index 0fbef69b696..05212ae94fc 100755 --- a/mswindows/osgeo4w/liblas-config +++ b/mswindows/osgeo4w/liblas-config @@ -7,57 +7,57 @@ INCLUDES="-I${prefix}/include " LIBS="-L$libdir -llas -llas_c" GDAL_INCLUDE="" -if test -n "$GDAL_INCLUDE" ; then +if test -n "$GDAL_INCLUDE" ; then INCLUDES="$INCLUDES -I$GDAL_INCLUDE" fi GDAL_LIBRARY="" -if test -n "$GDAL_LIBRARY" ; then +if test -n "$GDAL_LIBRARY" ; then LIBS="$LIBS $GDAL_LIBRARY" fi GEOTIFF_INCLUDE="" -if test -n "$GEOTIFF_INCLUDE" ; then +if test -n "$GEOTIFF_INCLUDE" ; then INCLUDES="$INCLUDES -I$GEOTIFF_INCLUDE" fi GEOTIFF_LIBRARY="" -if test -n "$GEOTIFF_LIBRARY" ; then +if test -n "$GEOTIFF_LIBRARY" ; then LIBS="$LIBS $GEOTIFF_LIBRARY" fi ORACLE_INCLUDE="" -if test -n "$ORACLE_INCLUDE" ; then +if test -n "$ORACLE_INCLUDE" ; then INCLUDES="$INCLUDES -I$ORACLE_INCLUDE" fi ORACLE_OCI_LIBRARY="" -if test -n "$ORACLE_OCI_LIBRARY" ; then +if test -n "$ORACLE_OCI_LIBRARY" ; then LIBS="$LIBS $ORACLE_OCI_LIBRARY " fi TIFF_INCLUDE="" -if test -n "$TIFF_INCLUDE" ; then +if test -n "$TIFF_INCLUDE" ; then INCLUDES="$INCLUDES -I$TIFF_INCLUDE" fi TIFF_LIBRARY="" -if test -n "$TIFF_LIBRARY" ; then +if test -n "$TIFF_LIBRARY" ; then LIBS="$LIBS $TIFF_LIBRARY" fi LIBXML2_INCLUDE_DIR="" -if test -n "$LIBXML2_INCLUDE_DIR" ; then +if test -n "$LIBXML2_INCLUDE_DIR" ; then INCLUDES="$INCLUDES -I$LIBXML2_INCLUDE_DIR" fi LIBXML2_LIBRARIES="" -if test -n "$LIBXML2_LIBRARIES" ; then +if test -n "$LIBXML2_LIBRARIES" ; then LIBS="$LIBS $LIBXML2_LIBRARIES" fi LASZIP_INCLUDE_DIR="" -if test -n "$LASZIP_INCLUDE_DIR" ; then +if test -n "$LASZIP_INCLUDE_DIR" ; then INCLUDES="$INCLUDES -I$LASZIP_INCLUDE_DIR" fi LASZIP_LIBRARY="" -if test -n "$LASZIP_LIBRARY" ; then +if test -n "$LASZIP_LIBRARY" ; then LIBS="$LIBS $LASZIP_LIBRARY" fi @@ -80,8 +80,8 @@ if test $# -eq 0; then usage 1 1>&2 fi -case $1 in - --libs) +case $1 in + --libs) echo $OSGEO4W_ROOT_MSYS/lib/liblas_c.lib ;; @@ -94,7 +94,7 @@ case $1 in ;; --defines) - echo + echo ;; --includes) @@ -102,13 +102,13 @@ case $1 in ;; --cflags) - echo + echo ;; --cxxflags) echo -pedantic -ansi -Wall -Wpointer-arith -Wcast-align -Wcast-qual -Wfloat-equal -Wredundant-decls -Wno-long-long -std=c++98 ;; - + *) usage 1 1>&2 ;; diff --git a/mswindows/osgeo4w/mysql_config b/mswindows/osgeo4w/mysql_config index 11204eb9c72..d6b96ed2f13 100755 --- a/mswindows/osgeo4w/mysql_config +++ b/mswindows/osgeo4w/mysql_config @@ -1,15 +1,15 @@ #!/bin/sh # Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. -# +# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA @@ -109,7 +109,7 @@ else port=3306 fi -# Create options +# Create options # We intentionally add a space to the beginning and end of lib strings, simplifies replace later libs=" $ldflags -L$pkglibdir -lmysqlclient -lpthread -lz -lm -ldl " libs="$libs " @@ -131,19 +131,19 @@ for remove in DDBUG_OFF DSAFE_MUTEX DFORCE_INIT_OF_VARS \ do # The first option we might strip will always have a space before it because # we set -I$pkgincludedir as the first option - cflags=`echo "$cflags"|sed -e "s/ -$remove */ /g"` - cxxflags=`echo "$cxxflags"|sed -e "s/ -$remove */ /g"` + cflags=`echo "$cflags"|sed -e "s/ -$remove */ /g"` + cxxflags=`echo "$cxxflags"|sed -e "s/ -$remove */ /g"` done -cflags=`echo "$cflags"|sed -e 's/ *\$//'` -cxxflags=`echo "$cxxflags"|sed -e 's/ *\$//'` +cflags=`echo "$cflags"|sed -e 's/ *\$//'` +cxxflags=`echo "$cxxflags"|sed -e 's/ *\$//'` # Same for --libs(_r) for remove in lmtmalloc static-libcxa i-static static-intel do # We know the strings starts with a space - libs=`echo "$libs"|sed -e "s/ -$remove */ /g"` - libs_r=`echo "$libs_r"|sed -e "s/ -$remove */ /g"` - embedded_libs=`echo "$embedded_libs"|sed -e "s/ -$remove */ /g"` + libs=`echo "$libs"|sed -e "s/ -$remove */ /g"` + libs_r=`echo "$libs_r"|sed -e "s/ -$remove */ /g"` + embedded_libs=`echo "$embedded_libs"|sed -e "s/ -$remove */ /g"` done # Strip trailing and ending space if any, and '+' (FIXME why?) diff --git a/mswindows/osgeo4w/package.sh b/mswindows/osgeo4w/package.sh index b3113292c99..643d6735362 100755 --- a/mswindows/osgeo4w/package.sh +++ b/mswindows/osgeo4w/package.sh @@ -107,32 +107,31 @@ 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/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/libharfbuzz-0.dll + /mingw64/bin/libiconv-2.dll + /mingw64/bin/libintl-8.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/liblapack.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 + /mingw64/bin/libopenblas.dll " if ! [ -f mswindows/osgeo4w/configure-stamp ]; then @@ -153,47 +152,46 @@ 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-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/mswindows/osgeo4w/postinstall.bat b/mswindows/osgeo4w/postinstall.bat index 61d2d98b7d4..10e8f727673 100644 --- a/mswindows/osgeo4w/postinstall.bat +++ b/mswindows/osgeo4w/postinstall.bat @@ -5,8 +5,8 @@ textreplace -std -t "%OSGEO4W_ROOT%\apps\grass\grass@POSTFIX@\etc\fontcap" for /F "tokens=* USEBACKQ" %%F IN (`getspecialfolder Documents`) do set DOCUMENTS=%%F -if not %OSGEO4W_MENU_LINKS%==0 xxmklink "%OSGEO4W_STARTMENU%\GRASS GIS @VERSION@.lnk" "%BATCH%" "--gui" "%DOCUMENTS%" "Launch GRASS GIS @VERSION@" 1 "%ICON%" -if not %OSGEO4W_DESKTOP_LINKS%==0 xxmklink "%OSGEO4W_DESKTOP%\GRASS GIS @VERSION@.lnk" "%BATCH%" "--gui" "%DOCUMENTS%" "Launch GRASS GIS @VERSION@" 1 "%ICON%" +if not %OSGEO4W_MENU_LINKS%==0 xxmklink "%OSGEO4W_STARTMENU%\GRASS GIS @VERSION@.lnk" "%BATCH%" "--gui" "%DOCUMENTS%" "Launch GRASS GIS @VERSION@" 1 "%ICON%" +if not %OSGEO4W_DESKTOP_LINKS%==0 xxmklink "%OSGEO4W_DESKTOP%\GRASS GIS @VERSION@.lnk" "%BATCH%" "--gui" "%DOCUMENTS%" "Launch GRASS GIS @VERSION@" 1 "%ICON%" rem run g.mkfontcap outside a GRASS session during rem an OSGeo4W installation for updating paths to fonts 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/ps/ps.map/ps.map.html b/ps/ps.map/ps.map.html index 23fd71a8116..8245e909c21 100644 --- a/ps/ps.map/ps.map.html +++ b/ps/ps.map/ps.map.html @@ -48,7 +48,7 @@

    NOTES

    encoding, for example by using the iconv utility:
    -iconv -f UTF-8 -t ISO_8859-1 utf_file > iso_file
    +iconv -f UTF-8 -t ISO_8859-1 utf_file > iso_file
     
    @@ -188,9 +188,9 @@

    border

    Controls the border which is drawn around the map area.
     USAGE:  border [y|n]
    -	color color
    -	width #
    -	end
    +    color color
    +    width #
    +    end
     
    The color may be either a standard GRASS color, a R:G:B triplet, or "none". The width is specified in points, unless followed by an "i" @@ -204,10 +204,10 @@

    border

    This example would create a grey border 0.1" wide.
     EXAMPLE:
    -	border
    -	color grey
    -	width 0.1i
    -	end
    +    border
    +    color grey
    +    width 0.1i
    +    end
     

    @@ -216,20 +216,20 @@

    colortable

    Prints the color table legend for the raster map layer anywhere on the page.
    -USAGE:	colortable [y|n]
    -	where x y
    -	raster raster map
    -	range minimum maximum
    -	width table width
    -	height table height (FP legend only)
    -	cols table columns
    -	font font name
    -	fontsize font size
    -	color text color
    -	nodata [Y|n]
    -	tickbar [y|N]
    -	discrete [y|n]
    -	end
    +USAGE:    colortable [y|n]
    +    where x y
    +    raster raster map
    +    range minimum maximum
    +    width table width
    +    height table height (FP legend only)
    +    cols table columns
    +    font font name
    +    fontsize font size
    +    color text color
    +    nodata [Y|n]
    +    tickbar [y|N]
    +    discrete [y|n]
    +    end
     
    For a categorical (CELL) map the color table will create a legend displaying @@ -298,7 +298,7 @@

    Floating point (FCELL and DCELL) Maps

    information, starting at the left margin, with 4 columns:
     EXAMPLE:
    -	colortable y
    +    colortable y
             cols 4
             width 4
             end
    @@ -310,12 +310,12 @@ 

    comments

    Prints comments anywhere on the page.
    -USAGE:	comments commentfile
    -	where x y
    -	font font name
    -	fontsize font size
    -	color text color
    -	end
    +USAGE:    comments commentfile
    +    where x y
    +    font font name
    +    fontsize font size
    +    color text color
    +    end
     
    The default location is immediately below the last item item printed, starting at the left margin. The default text color is black. @@ -330,13 +330,13 @@

    comments

    the page, using a 15/72 inch Helvetica Bold font.
     EXAMPLE:
    -	raster vegetation
    -	comments veg.comments
    -	where 1.5 7.25
    -	font Helvetica Bold
    -	fontsize 15
    -	color blue
    -	end
    +    raster vegetation
    +    comments veg.comments
    +    where 1.5 7.25
    +    font Helvetica Bold
    +    fontsize 15
    +    color blue
    +    end
     
    Presumably, the file veg.comments @@ -350,7 +350,7 @@

    copies

    Specifies the number of copies to be printed.
    -USAGE:	copies n
    +USAGE:    copies n
     
    Each page will be printed n times.

    This instruction is identical to the copies command line parameter. @@ -361,13 +361,13 @@

    eps

    Places EPS (Encapsulated PostScript) pictures on the output map.
    -USAGE:	eps east north
    -	eps x% y%
    -	epsfile EPS file
    -	scale #
    -	rotate #
    -	masked [y|n]
    -	end
    +USAGE:    eps east north
    +    eps x% y%
    +    epsfile EPS file
    +    scale #
    +    rotate #
    +    masked [y|n]
    +    end
     
    The EPS picture location is entered in the main instruction line by giving either the map @@ -388,12 +388,12 @@

    eps

    in original file and would not be masked by the current mask.
     EXAMPLE:
    -	eps 456000 7890000
    -	epsfile ./epsf/logo.eps
    -	scale 3
    -	rotate 20
    -	masked n
    -	end
    +    eps 456000 7890000
    +    epsfile ./epsf/logo.eps
    +    scale 3
    +    rotate 20
    +    masked n
    +    end
     
    Of course, multiple EPS pictures may be drawn with multiple eps @@ -405,13 +405,13 @@

    geogrid

    Overlays a geographic grid onto the output map.
    -USAGE:	geogrid spacing unit
    -	color color
    -	numbers # [color]
    -	font font name
    -	fontsize font size
    -	width #
    -	end
    +USAGE:    geogrid spacing unit
    +    color color
    +    numbers # [color]
    +    font font name
    +    fontsize font size
    +    width #
    +    end
     
    The spacing and spacing unit of the geographic grid is given on the main instruction line. The spacing unit is given as one of d for @@ -435,10 +435,10 @@

    geogrid

    lines would be numbered with yellow numbers.
     EXAMPLE:
    -	geogrid 30 m
    -	color blue
    -	numbers 2 yellow
    -	end
    +    geogrid 30 m
    +    color blue
    +    numbers 2 yellow
    +    end
     

    @@ -447,7 +447,7 @@

    greyrast

    Selects a raster map layer for output in shades of grey.
    -USAGE:	greyrast mapname
    +USAGE:    greyrast mapname
     
    For each ps.map @@ -460,14 +460,14 @@

    grid

    Overlays a coordinate grid onto the output map.
    -USAGE:	grid spacing
    -	color color
    -	numbers # [color]
    -	cross cross size
    -	font font name
    -	fontsize font size
    -	width #
    -	end
    +USAGE:    grid spacing
    +    color color
    +    numbers # [color]
    +    cross cross size
    +    font font name
    +    fontsize font size
    +    width #
    +    end
     
    The spacing of the grid is given (in the geographic coordinate system units) on the main instruction line. The subsection instructions @@ -487,10 +487,10 @@

    grid

    lines would be numbered with red numbers.
     EXAMPLE:
    -	grid 10000
    -	color green
    -	numbers 2 red
    -	end
    +    grid 10000
    +    color green
    +    numbers 2 red
    +    end
     

    @@ -499,7 +499,7 @@

    group

    Selects an RGB imagery group for output.
    -USAGE:	group groupname
    +USAGE:    group groupname
     
    This is similar to raster, except that it uses an imagery group instead of a raster map layer. The group must contain three raster map @@ -511,12 +511,12 @@

    header

    Prints the map header above the map.
    -USAGE:	header
    -	file header file
    -	font font name
    -	fontsize font size
    -	color text color
    -	end
    +USAGE:    header
    +    file header file
    +    font font name
    +    fontsize font size
    +    color text color
    +    end
     
    If the file sub-instruction is absent the header will consist of the map's title @@ -527,18 +527,17 @@

    header

    of the text in the text file specified, with some special formatting keys:
      -
    • %% - a literal % -
    • %n - ? newline ? -
    • %_ - horizontal bar -
    • %c - "<raster name> in mapset <mapset name>" -
    • %d - today's date -
    • %l - project name -
    • %L - project's text description -
    • %m - mapset name -
    • %u - user name -
    • %x - mask info -
    • %- - advance to this character column number (see example below) - +
    • %% - a literal %
    • +
    • %n - ? newline ?
    • +
    • %_ - horizontal bar
    • +
    • %c - "<raster name> in mapset <mapset name>"
    • +
    • %d - today's date
    • +
    • %l - project name
    • +
    • %L - project's text description
    • +
    • %m - mapset name
    • +
    • %u - user name
    • +
    • %x - mask info
    • +
    • %- - advance to this character column number (see example below)
    Example header file: @@ -560,12 +559,12 @@

    header

    the map, using a 20/72 inch Courier font.
     EXAMPLE:
    -	header
    -	file soils.hdr
    -	font Courier
    -	fontsize 20
    -	color red
    -	end
    +    header
    +    file soils.hdr
    +    font Courier
    +    fontsize 20
    +    color red
    +    end
     

    @@ -577,9 +576,9 @@

    labels

    v.label ).
    -USAGE:	labels  labelfile
    -	font font name
    -	end
    +USAGE:    labels  labelfile
    +    font font name
    +    end
     

    NOTE: ps.map can read new option 'ROTATE:' from labels file, which specifies counter clockwise rotation in degrees. @@ -588,8 +587,8 @@

    labels

    towns on the map.
     EXAMPLE:
    -	labels town.names
    -	end
    +    labels town.names
    +    end
     

    @@ -598,12 +597,12 @@

    line

    Draws lines on the output map.
    -USAGE:	line east north east north
    -	line x% y% x% y%
    -	color color
    -	width #
    -	masked [y|n]
    -	end
    +USAGE:    line east north east north
    +    line x% y% x% y%
    +    color color
    +    width #
    +    masked [y|n]
    +    end
     
    The beginning and ending points of the line are entered on the main instruction. These points can be defined either by map coordinates or @@ -623,11 +622,11 @@

    line

    there is a mask.
     EXAMPLE:
    -	line 10% 80% 30% 70%
    -	color yellow
    -	width 2
    -	masked n
    -	end
    +    line 10% 80% 30% 70%
    +    color yellow
    +    width 2
    +    masked n
    +    end
     
    Of course, multiple lines may be drawn with multiple line @@ -640,14 +639,14 @@

    mapinfo

    Prints the portion of the map legend containing the scale, grid and region information, on or below the map.
    -USAGE:	mapinfo
    -	where x y
    -	font font name
    -	fontsize font size
    -	color text color
    -	background box color|none
    -	border color|none
    -	end
    +USAGE:    mapinfo
    +    where x y
    +    font font name
    +    fontsize font size
    +    color text color
    +    background box color|none
    +    border color|none
    +    end
     
    The default location is immediately below the map, starting at the left edge of the map. @@ -662,12 +661,12 @@

    mapinfo

     EXAMPLE:
    -	mapinfo
    -	where 1.5 0
    -	font Courier
    -	fontsize 12
    -	color brown
    -	end
    +    mapinfo
    +    where 1.5 0
    +    font Courier
    +    fontsize 12
    +    color brown
    +    end
     

    @@ -676,7 +675,7 @@

    maploc

    Positions the map on the page.
    -USAGE:	maploc  x y [width height]
    +USAGE:    maploc  x y [width height]
     
    The upper left corner of the map will be positioned x inches from the left edge of the page and y inches from the top of the page. @@ -688,7 +687,7 @@

    maploc

    the left edge and 3.5 inches from the top edge of the map.
     EXAMPLE:
    -	maploc 2.0 3.5
    +    maploc 2.0 3.5
     

    @@ -697,7 +696,7 @@

    maskcolor

    Color to be used for mask.
    -USAGE:	maskcolor  color
    +USAGE:    maskcolor  color
     
    @@ -706,10 +705,10 @@

    outline

    Outlines the areas of a raster map layer with a specified color.
    -USAGE:	outline
    -	color  color
    -	width  width of line in points
    -	end
    +USAGE:    outline
    +    color  color
    +    width  width of line in points
    +    end
     
    Distinct areas of the raster map will be separated from each other visually by drawing a border (or outline) in the specified @@ -730,11 +729,11 @@

    outline

    in grey.
     EXAMPLE:
    -	raster soils
    -	outline
    -	color grey
    -	width 2
    -	end
    +    raster soils
    +    outline
    +    color grey
    +    width 2
    +    end
     

    @@ -743,14 +742,14 @@

    paper

    Specifies paper size and margins.
    -USAGE:	paper paper name
    -	height #
    -	width #
    -	left #
    -	right #
    -	bottom #
    -	top #
    -	end
    +USAGE:    paper paper name
    +    height #
    +    width #
    +    left #
    +    right #
    +    bottom #
    +    top #
    +    end
     
    paper may select predefined paper name (a4,a3,a2,a1,a0,us-legal,us-letter,us-tabloid). @@ -761,20 +760,20 @@

    paper

     EXAMPLE:
    -	paper a3
    -	end
    +    paper a3
    +    end
     

     EXAMPLE:
    -	paper
    -	width 10
    -	height 10
    -	left 2
    -	right 2
    -	bottom 2
    -	top 2
    -	end
    +    paper
    +    width 10
    +    height 10
    +    left 2
    +    right 2
    +    bottom 2
    +    top 2
    +    end
     

    @@ -783,16 +782,16 @@

    point

    Places additional points or icons on the output map.
    -USAGE:	point east north
    -	point x% y%
    -	color color
    -	fcolor color
    -	symbol symbol group/name
    -	size #
    -	width #
    -	rotate #
    -	masked [y|n]
    -	end
    +USAGE:    point east north
    +    point x% y%
    +    color color
    +    fcolor color
    +    symbol symbol group/name
    +    size #
    +    width #
    +    rotate #
    +    masked [y|n]
    +    end
     
    The point location is entered in the main instruction line by giving either the map coordinates or by using percentages of the geographic region. @@ -811,13 +810,13 @@

    point

    the size of a 15 points and would not be masked by the current mask.
     EXAMPLE:
    -	point 456000 7890000
    -	fcolor purple
    -	color black
    -	symbol basic/diamond
    -	size 15
    -	masked n
    -	end
    +    point 456000 7890000
    +    fcolor purple
    +    color black
    +    symbol basic/diamond
    +    size 15
    +    masked n
    +    end
     
    Of course, multiple points may be drawn with multiple point @@ -836,12 +835,12 @@

    psfile

    correct directory or specify the full path on the psfile instruction. (Note to /bin/csh users: ~ won't work with this instruction).
    -USAGE:	psfile filename
    +USAGE:    psfile filename
     
    This example copies the file "logo.ps" into the output file.
     EXAMPLE:
    -	psfile logo.ps
    +    psfile logo.ps
     

    @@ -850,7 +849,7 @@

    raster

    Selects a raster map layer for output.
    -USAGE:	raster mapname
    +USAGE:    raster mapname
     
    For each ps.map run, only one raster map layer (or set of layers or imagery group; see below) can be requested. If no @@ -867,7 +866,7 @@

    raster

     EXAMPLE:
    -	raster soils
    +    raster soils
     

    @@ -876,7 +875,7 @@

    read

    Provides ps.map with a previously prepared input stream.
    -USAGE:	read previously prepared UNIX file
    +USAGE:    read previously prepared UNIX file
     
    Mapping instructions can be placed into a file and read into ps.map. @@ -894,7 +893,7 @@

    read

    the vector map layer roads onto the output map.
     EXAMPLE:
    -	read pmap.roads
    +    read pmap.roads
     
    The user may have created this file because this vector map layer is particularly useful for many ps.map @@ -908,13 +907,13 @@

    rectangle

    Draws rectangle on the output map.
    -USAGE:	rectangle east north east north
    -	rectangle x% y% x% y%
    -	color color
    -	fcolor fill color
    -	width #
    -	masked [y|n]
    -	end
    +USAGE:    rectangle east north east north
    +    rectangle x% y% x% y%
    +    color color
    +    fcolor fill color
    +    width #
    +    masked [y|n]
    +    end
     
    The two corners of the rectangle are entered on the main instruction. These points can be defined either by map coordinates or @@ -936,12 +935,12 @@

    rectangle

    The border line would be 1/16" wide and would appear even if there is a mask.
     EXAMPLE:
    -	rectangle 10% 80% 30% 70%
    -	color yellow
    -	fcolor green
    -	width 0.0625i
    -	masked n
    -	end
    +    rectangle 10% 80% 30% 70%
    +    color yellow
    +    fcolor green
    +    width 0.0625i
    +    masked n
    +    end
     

    @@ -951,10 +950,10 @@

    region

    Places the outline of a smaller geographic region on the output.
    -USAGE:	region regionfile
    -	color color
    -	width #
    -	end
    +USAGE:    region regionfile
    +    color color
    +    width #
    +    end
     
    Geographic region settings are created and saved using the g.region module. @@ -971,10 +970,10 @@

    region

    g.region.
     EXAMPLE:
    -	region fire.zones
    -	color white
    -	width 2
    -	end
    +    region fire.zones
    +    color white
    +    width 2
    +    end
     

    @@ -983,7 +982,7 @@

    rgb

    Selects three raster map layers for output as an RGB color image.
    -USAGE:	rgb red green blue
    +USAGE:    rgb red green blue
     
    This is similar to raster, except that it uses three raster map layers instead of a single layer. The three layers @@ -1001,7 +1000,7 @@

    scale

    Selects a scale for the output map.
    -USAGE:	scale scale
    +USAGE:    scale scale
     
    The scale can be selected either as:
    @@ -1022,7 +1021,7 @@

    scale

    units.
     EXAMPLE:
    -	scale 1:25000
    +    scale 1:25000
     

    @@ -1031,16 +1030,16 @@

    scalebar

    Draws a scalebar on the map.
    -USAGE:	scalebar [f|s]
    -	where x y
    -	length overall distance in map units
    -	units [auto|meters|kilometers|feet|miles|nautmiles]
    -	height scale height in inches
    -	segment number of segments
    -	numbers #
    -	fontsize font size
    -	background [Y|n]
    -	end
    +USAGE:    scalebar [f|s]
    +    where x y
    +    length overall distance in map units
    +    units [auto|meters|kilometers|feet|miles|nautmiles]
    +    height scale height in inches
    +    segment number of segments
    +    numbers #
    +    fontsize font size
    +    background [Y|n]
    +    end
     
    Draw one of two types of scale bar. Fancy (f) draws alternating black and white scale boxes. @@ -1067,13 +1066,13 @@

    scalebar

    and is 0.25 inches high.
     EXAMPLE:
    -	scalebar s
    -	where 4 5
    -	length 1000
    -	height 0.25
    -	segment 5
    -	numbers 2
    -	end
    +    scalebar s
    +    where 4 5
    +    length 1000
    +    height 0.25
    +    segment 5
    +    numbers 2
    +    end
     
    @@ -1083,16 +1082,16 @@

    setcolor

    Overrides the color assigned to one or more categories of the raster map layer.
    -USAGE:	setcolor cat(s) color
    +USAGE:    setcolor cat(s) color
     
    This example would set the color for categories 2,5 and 8 of the raster map layer watersheds to white and category 10 to green. (NOTE: no spaces are inserted between the category values.)
     EXAMPLE:
    -	raster watersheds
    -	setcolor 2,5,8 white
    -	setcolor 10 green
    +    raster watersheds
    +    setcolor 2,5,8 white
    +    setcolor 10 green
     
    Of course, setcolor can be requested more than once to override the default color for additional @@ -1107,23 +1106,23 @@

    text

    Places text on the map.
    -USAGE:	text  east north text
    -	text  x% y% text
    -	font fontname
    -	color color|none
    -	width #
    -	hcolor color|none
    -	hwidth #
    -	background color|none
    -	border color|none
    -	fontsize font size
    -	size #
    -	ref reference point
    -	rotate degrees CCW
    -	xoffset #
    -	yoffset #
    -	opaque [y|n]
    -	end
    +USAGE:    text  east north text
    +    text  x% y% text
    +    font fontname
    +    color color|none
    +    width #
    +    hcolor color|none
    +    hwidth #
    +    background color|none
    +    border color|none
    +    fontsize font size
    +    size #
    +    ref reference point
    +    rotate degrees CCW
    +    xoffset #
    +    yoffset #
    +    opaque [y|n]
    +    end
     
    The user specifies where the text will be placed by providing map coordinates or percentages of the geographic region. @@ -1180,18 +1179,18 @@

    text

    vectors on the map would stop at the border of this text.
     EXAMPLE:
    -	text 650000 7365000 SPEARFISH LAND COVER
    -	font romand
    -	color red
    -	width 2
    -	hcolor black
    -	hwidth 1
    -	background white
    -	border red
    -	size 500
    -	ref lower left
    -	opaque y
    -	end
    +    text 650000 7365000 SPEARFISH LAND COVER
    +    font romand
    +    color red
    +    width 2
    +    hcolor black
    +    hwidth 1
    +    background white
    +    border red
    +    size 500
    +    ref lower left
    +    opaque y
    +    end
     

    @@ -1200,21 +1199,21 @@

    vareas

    Selects a vector map layer for output and plots areas.
    -USAGE:	vareas vectormap
    -	layer # (layer number used with cats/where option)
    -	cats list of categories (e.g. 1,3,5-7)
    -	where SQL where statement
    -	masked [y|n]
    -	color color
    -	fcolor color
    -	rgbcolumn column
    -	width #
    -	label label to use in legend
    -	lpos position in legend
    -	pat pattern file
    -	pwidth #
    -	scale #
    -	end
    +USAGE:    vareas vectormap
    +    layer # (layer number used with cats/where option)
    +    cats list of categories (e.g. 1,3,5-7)
    +    where SQL where statement
    +    masked [y|n]
    +    color color
    +    fcolor color
    +    rgbcolumn column
    +    width #
    +    label label to use in legend
    +    lpos position in legend
    +    pat pattern file
    +    pwidth #
    +    scale #
    +    end
     
    The user can specify:

    color - color of the vector lines or area boundaries; @@ -1266,12 +1265,12 @@

    vareas

     EXAMPLE:
    -	vareas forest
    -	color blue
    -	width 1
    -	masked y
    -	cats 2,5-7
    -	end
    +    vareas forest
    +    color blue
    +    width 1
    +    masked y
    +    cats 2,5-7
    +    end
     

    @@ -1280,26 +1279,26 @@

    vlines

    Selects a vector map layer for output and plots lines.
    -USAGE:	vlines vectormap
    -	type line and/or boundary
    -	layer # (layer number used with cats/where option)
    -	cats list of categories (e.g. 1,3,5-7)
    -	where SQL where statement like: vlastnik = 'Cimrman'
    -	masked [y|n]
    -	color color
    -	rgbcolumn column
    -	width #
    -	cwidth #
    -	hcolor color
    -	hwidth #
    -	offset #
    -	coffset #
    -	ref left|right
    -	style 00001111
    -	linecap style
    -	label label
    -	lpos #
    -	end
    +USAGE:    vlines vectormap
    +    type line and/or boundary
    +    layer # (layer number used with cats/where option)
    +    cats list of categories (e.g. 1,3,5-7)
    +    where SQL where statement like: vlastnik = 'Cimrman'
    +    masked [y|n]
    +    color color
    +    rgbcolumn column
    +    width #
    +    cwidth #
    +    hcolor color
    +    hwidth #
    +    offset #
    +    coffset #
    +    ref left|right
    +    style 00001111
    +    linecap style
    +    label label
    +    lpos #
    +    end
     
    The user can specify:

    type - the default is lines only; @@ -1348,15 +1347,15 @@

    vlines

     EXAMPLE:
    -	vlines streams
    -	color blue
    -	width 2
    -	hcolor white
    -	hwidth 1
    -	masked y
    -	cats 2
    -	label Streams - category 2
    -	end
    +    vlines streams
    +    color blue
    +    width 2
    +    hcolor white
    +    hwidth 1
    +    masked y
    +    cats 2
    +    label Streams - category 2
    +    end
     

    @@ -1365,26 +1364,26 @@

    vpoints

    Selects vector point data to be placed on the output map
    -USAGE:	vpoints vectormap
    -	type point and/or centroid
    -	layer # (layer number used with cats/where/sizecol options)
    -	cats list of categories (e.g. 1,3,5-7)
    -	where SQL where statement like: vlastnik = 'Cimrman'
    -	masked [y|n]
    -	color color
    -	fcolor color
    -	rgbcolumn column
    -	width #
    -	eps epsfile
    -	symbol symbol group/name
    -	size #
    -	sizecolumn attribute column used for symbol sizing
    -	scale scaling factor for sizecolumn values
    -	rotate #
    -	rotatecolumn column
    -	label legend label
    -	lpos position in legend
    -	end
    +USAGE:    vpoints vectormap
    +    type point and/or centroid
    +    layer # (layer number used with cats/where/sizecol options)
    +    cats list of categories (e.g. 1,3,5-7)
    +    where SQL where statement like: vlastnik = 'Cimrman'
    +    masked [y|n]
    +    color color
    +    fcolor color
    +    rgbcolumn column
    +    width #
    +    eps epsfile
    +    symbol symbol group/name
    +    size #
    +    sizecolumn attribute column used for symbol sizing
    +    scale scaling factor for sizecolumn values
    +    rotate #
    +    rotatecolumn column
    +    label legend label
    +    lpos position in legend
    +    end
     
    The user may specify the the color of the sites (see section on NAMED COLORS); @@ -1403,11 +1402,11 @@

    vpoints

     EXAMPLE:
    -	vpoints windmills
    -	color blue
    -	symbol mills/windmill
    -	size 10
    -	end
    +    vpoints windmills
    +    color blue
    +    symbol mills/windmill
    +    size 10
    +    end
     

    @@ -1417,15 +1416,15 @@

    vlegend

    vector information, on or below the map.
    -USAGE:	vlegend
    -	where x y
    -	font font name
    -	fontsize font size
    -	width width of color symbol
    -	cols number of columns to print
    -	span column separation
    -	border color|none
    -	end
    +USAGE:    vlegend
    +    where x y
    +    font font name
    +    fontsize font size
    +    width width of color symbol
    +    cols number of columns to print
    +    span column separation
    +    border color|none
    +    end
     
    The default location is immediately below the legend containing the scale, grid and region information, starting at the left edge of the map. @@ -1454,11 +1453,11 @@

    vlegend

     EXAMPLE:
    -	vlegend
    -	where 4.5 0
    -	font Courier
    -	fontsize 12
    -	end
    +    vlegend
    +    where 4.5 0
    +    font Courier
    +    fontsize 12
    +    end
     

    @@ -1468,7 +1467,7 @@

    end

    Terminates input and begin painting the map.
    -USAGE:	end
    +USAGE:    end
     

    @@ -1499,7 +1498,7 @@

    EXAMPLES

    - +

    Figure: Result of for the a simple Wake county terrain and roads example

    @@ -1585,7 +1584,7 @@

    More complicated example

    - +

    Figure: Result of for the more complicated Wake county, NC example

    diff --git a/ps/ps.map/ps_vlegend.c b/ps/ps.map/ps_vlegend.c index dd99720a5fc..839f76cf3c5 100644 --- a/ps/ps.map/ps_vlegend.c +++ b/ps/ps.map/ps_vlegend.c @@ -281,5 +281,9 @@ int PS_vlegend(void) if (PS.min_y > y) PS.min_y = y; + G_free(nvec); + for (i = 0; i < vector.count; i++) + G_free(vec[i]); + G_free(vec); return 0; } diff --git a/ps/ps.map/ps_vlines.c b/ps/ps.map/ps_vlines.c index c5aced7c51b..fb3bc2fa760 100644 --- a/ps/ps.map/ps_vlines.c +++ b/ps/ps.map/ps_vlines.c @@ -206,5 +206,8 @@ int PS_vlines_plot(struct Map_info *P_map, int vec, int type) } fprintf(PS.fp, "\n"); fprintf(PS.fp, "0 setlinejoin\n"); /* reset line join to miter */ + Vect_destroy_line_struct(Points); + Vect_destroy_line_struct(nPoints); + Vect_destroy_cats_struct(Cats); return 0; } diff --git a/pyproject.toml b/pyproject.toml index 2a2287aaaad..f14ec703ce2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ extend-exclude = ''' ''' [tool.ruff] -required-version = ">=0.6.0" +required-version = ">=0.8.0" builtins = ["_"] @@ -34,9 +34,7 @@ select = [ "COM", # flake8-commas (COM) "D", # pydocstyle (D) "DTZ", # flake8-datetimez (DTZ) - "E4", # pycodestyle (E, W) - "E7", # pycodestyle (E, W) - "E9", # pycodestyle (E, W) + "E", # pycodestyle (E, W) "F", # Pyflakes (F) "FA", # flake8-future-annotations (FA) "FBT", # flake8-boolean-trap (FBT) @@ -48,6 +46,7 @@ select = [ "INT", # flake8-gettext (INT) "ISC", # flake8-implicit-str-concat (ISC) "LOG", # flake8-logging (LOG) + "N", # pep8-naming (N) "NPY", # NumPy-specific rules (NPY) "PERF", # Perflint (PERF) "PGH", # pygrep-hooks (PGH) @@ -126,16 +125,14 @@ ignore = [ "DTZ006", # call-datetime-fromtimestamp "DTZ007", # call-datetime-strptime-without-zone "DTZ011", # call-date-today - "E401", # multiple-imports-on-one-line "E402", # module-import-not-at-top-of-file + "E501", # line-too-long "E721", # type-comparison "E722", # bare-except "E731", # lambda-assignment "E741", # ambiguous-variable-name - "F401", # unused-import "F403", # undefined-local-with-import-star "F405", # undefined-local-with-import-star-usage - "F601", # multi-value-repeated-key-literal "F811", # redefined-while-unused "F821", # undefined-name "F822", # undefined-export @@ -145,6 +142,16 @@ ignore = [ "FBT003", # boolean-positional-value-in-call "I001", # unsorted-imports "ISC003", # explicit-string-concatenation + "N801", # invalid-class-name + "N802", # invalid-function-name + "N803", # invalid-argument-name + "N806", # non-lowercase-variable-in-function + "N812", # lowercase-imported-as-non-lowercase + "N814", # camelcase-imported-as-constant + "N815", # mixed-case-variable-in-class-scope + "N816", # mixed-case-variable-in-global-scope + "N818", # error-suffix-on-exception-name + "N999", # invalid-module-name "PERF203", # try-except-in-loop "PERF401", # manual-list-comprehension "PERF402", # manual-list-copy @@ -176,7 +183,6 @@ ignore = [ "PLW1641", # eq-without-hash "PLW2901", # redefined-loop-name "PLW3201", # bad-dunder-method-name - "PT004", # pytest-missing-fixture-name-underscore # deprecated, so doesn't appear with --preview "PTH100", # os-path-abspath "PTH101", # os-chmod "PTH102", # os-mkdir @@ -201,9 +207,6 @@ ignore = [ "RET501", # unnecessary-return-none "RET502", # implicit-return-value "RET503", # implicit-return - "RET506", # superfluous-else-raise - "RET507", # superfluous-else-continue - "RET508", # superfluous-else-break "RUF003", # ambiguous-unicode-character-comment "RUF005", # collection-literal-concatenation "RUF012", # mutable-class-default @@ -234,12 +237,10 @@ ignore = [ "S608", # hardcoded-sql-expression "SIM102", # collapsible-if "SIM105", # suppressible-exception - "SIM108", # if-else-block-instead-of-if-exp "SIM113", # enumerate-for-loop "SIM116", # if-else-block-instead-of-dict-lookup "SIM118", # in-dict-keys "SIM223", # expr-and-false - "SIM401", # if-else-block-instead-of-dict-get "SLF001", # private-member-access "TRY002", # raise-vanilla-class "TRY003", # raise-vanilla-args @@ -258,21 +259,29 @@ ignore = [ # See https://docs.astral.sh/ruff/settings/#lint_per-file-ignores # "A005", # builtin-module-shadowing # "PLW0108", # unnecessary-lambda +# "SIM115", # open-file-with-context-handler # 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"] "gui/**" = ["PLW0108"] # See https://github.com/OSGeo/grass/issues/4124 "gui/wxpython/animation/temporal_manager.py" = ["SIM115"] "gui/wxpython/core/*.py" = ["SIM115"] +"gui/wxpython/core/globalvar.py" = ["PTH208"] +"gui/wxpython/core/settings.py" = ["PTH208"] +"gui/wxpython/datacatalog/catalog.py" = ["PTH208"] "gui/wxpython/dbmgr/base.py" = ["SIM115"] -"gui/wxpython/gcp/manager.py" = ["SIM115"] +"gui/wxpython/gcp/manager.py" = ["PTH208", "SIM115"] "gui/wxpython/gmodeler/*.py" = ["SIM115"] "gui/wxpython/gui_core/*.py" = ["SIM115"] +"gui/wxpython/gui_core/dialogs.py" = ["PTH208"] "gui/wxpython/iclass/frame*.py" = ["SIM115"] "gui/wxpython/iclass/frame.py" = ["FLY002"] "gui/wxpython/iclass/statistics.py" = ["A005"] +"gui/wxpython/icons/grass_icons.py" = ["PTH208"] "gui/wxpython/image2target/*.py" = ["SIM115"] +"gui/wxpython/image2target/ii2t_manager.py" = ["PTH208"] "gui/wxpython/iscatt/plots.py" = ["PLW0108"] "gui/wxpython/lmgr/workspace.py" = ["SIM115"] "gui/wxpython/location_wizard/wizard.py" = ["SIM115"] @@ -281,9 +290,11 @@ ignore = [ "gui/wxpython/modules/mcalc_builder.py" = ["SIM115"] "gui/wxpython/photo2image/*.py" = ["SIM115"] "gui/wxpython/psmap/*.py" = ["SIM115"] +"gui/wxpython/psmap/dialogs.py" = ["PTH208"] "gui/wxpython/psmap/utils.py" = ["PGH004"] "gui/wxpython/rdigit/controller.py" = ["SIM115"] "gui/wxpython/rlisetup/*.py" = ["SIM115"] +"gui/wxpython/rlisetup/frame.py" = ["PTH208"] "gui/wxpython/timeline/frame.py" = ["FLY002"] "gui/wxpython/tools/update_menudata.py" = ["SIM115"] "gui/wxpython/tplot/frame.py" = ["FLY002"] @@ -296,39 +307,48 @@ ignore = [ "lib/imagery/testsuite/test_imagery_signature_management.py" = ["SIM115"] "lib/imagery/testsuite/test_imagery_sigsetfile.py" = ["FURB152"] "lib/init/grass.py" = ["SIM115"] +"lib/init/testsuite/test_grass_tmp_mapset.py" = ["PTH208"] "locale/grass_po_stats.py" = ["SIM115"] -"man/build_*.py" = ["SIM115"] -"man/parser_standard_options.py" = ["SIM115"] +"man/build.py" = ["PTH208"] +"man/build_class_graphical.py" = ["PTH208"] +"man/build_manual_gallery.py" = ["PTH208"] +"man/build_rest.py" = ["PTH208"] "python/grass/__init__.py" = ["PYI056"] "python/grass/exp*/tests/grass_script_mapset_session_test.py" = ["SIM117"] "python/grass/exp*/tests/grass_script_tmp_mapset_session_test.py" = ["SIM117"] "python/grass/gunittest/case.py" = ["PT009"] -"python/grass/gunittest/loader.py" = ["PYI024"] +"python/grass/gunittest/loader.py" = ["PTH208", "PYI024"] "python/grass/gunittest/multireport.py" = ["PYI024"] "python/grass/gunittest/testsu*/d*/s*/s*/subsub*/t*/test_segfaut.py" = ["B018"] "python/grass/gunittest/testsuite/test_assertions_rast3d.py" = ["FLY002"] "python/grass/imaging/images2*.py" = ["SIM115"] +"python/grass/imaging/images2ims.py" = ["PTH208"] "python/grass/jupyter/testsuite/interactivemap_test.py" = ["PGH004"] "python/grass/jupyter/testsuite/map_test.py" = ["PGH004"] "python/grass/pydispatch/signal.py" = ["A005"] -"python/grass/pygrass/modules/grid/grid.py" = ["SIM115"] +"python/grass/pygrass/gis/__init__.py" = ["PTH208"] +"python/grass/pygrass/modules/grid/grid.py" = ["PTH208", "SIM115"] +"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/utils.py" = ["PTH208"] "python/grass/pygrass/vector/geometry.py" = ["PYI024"] "python/grass/pygrass/vector/sql.py" = ["FLY002"] "python/grass/pygrass/vector/testsuite/test_table.py" = ["PLW0108"] "python/grass/script/array.py" = ["A005"] -"python/grass/script/core.py" = ["SIM115"] +"python/grass/script/core.py" = ["PTH208", "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"] "python/grass/temporal/stds_import.py" = ["SIM115"] "python/grass/temporal/univar_statistics.py" = ["SIM115"] -"python/grass/utils/download.py" = ["SIM115"] +"python/grass/utils/download.py" = ["PTH208", "SIM115"] "raster/r.*/testsuite/*.py" = ["SIM115"] "raster/r.topidx/*.py" = ["SIM115"] "raster3d/r3.flow/testsuite/r3flow_test.py" = ["FLY002"] @@ -339,8 +359,10 @@ ignore = [ "scripts/db.in.ogr/db.in.ogr.py" = ["SIM115"] "scripts/db.test/db.test.py" = ["SIM115"] "scripts/db.univar/db.univar.py" = ["SIM115"] +"scripts/g.download.project/g.download.project.py" = ["PTH208"] "scripts/g.extension.all/g.extension.all.py" = ["SIM115"] -"scripts/g.extension/g.extension.py" = ["SIM115"] +"scripts/g.extension/g.extension.py" = ["PTH208", "SIM115"] +"scripts/g.extension/testsuite/test_addons_modules.py" = ["PTH208"] "scripts/g.search.modules/g.search.modules.py" = ["SIM115"] "scripts/i.in.spotvgt/i.in.spotvgt.py" = ["SIM115"] "scripts/i.oif/i.oif*.py" = ["SIM115"] @@ -366,6 +388,7 @@ ignore = [ "temporal/t.unregister/t.unregister.py" = ["SIM115"] "utils/**.py" = ["SIM115"] "utils/generate_release_notes.py" = ["PGH004"] +"utils/thumbnails.py" = ["PTH208"] "vector/v.fill.holes/examples.ipynb" = ["PTH201"] [tool.ruff.lint.flake8-import-conventions.extend-aliases] diff --git a/python/grass/app/__init__.py b/python/grass/app/__init__.py index df22d8bbb44..b7ff0ce08c0 100644 --- a/python/grass/app/__init__.py +++ b/python/grass/app/__init__.py @@ -1 +1,17 @@ -from .data import * +from .data import ( + get_possible_database_path, + create_database_directory, + create_startup_location_in_grassdb, + ensure_default_data_hierarchy, + MapsetLockingException, + lock_mapset, +) + +__all__ = [ + "MapsetLockingException", + "create_database_directory", + "create_startup_location_in_grassdb", + "ensure_default_data_hierarchy", + "get_possible_database_path", + "lock_mapset", +] diff --git a/python/grass/app/runtime.py b/python/grass/app/runtime.py index 3f3805c9dfd..27f35760b8f 100644 --- a/python/grass/app/runtime.py +++ b/python/grass/app/runtime.py @@ -79,10 +79,7 @@ def append_left_addon_paths(paths, config_dir, env): # addons (base) addon_base = env.get("GRASS_ADDON_BASE") if not addon_base: - if MACOS: - name = "Addons" - else: - name = "addons" + name = "addons" if not MACOS else "Addons" addon_base = os.path.join(config_dir, name) env["GRASS_ADDON_BASE"] = addon_base @@ -174,10 +171,7 @@ def set_python_path_variable(install_path, env): """Set PYTHONPATH to find GRASS Python package in subprocesses""" path = env.get("PYTHONPATH") etcpy = os.path.join(install_path, "etc", "python") - if path: - path = etcpy + os.pathsep + path - else: - path = etcpy + path = etcpy + os.pathsep + path if path else etcpy env["PYTHONPATH"] = path diff --git a/python/grass/benchmark/__init__.py b/python/grass/benchmark/__init__.py index a4a7bf4e991..62a6a85c3e1 100644 --- a/python/grass/benchmark/__init__.py +++ b/python/grass/benchmark/__init__.py @@ -34,3 +34,17 @@ save_results_to_file, ) from .runners import benchmark_nprocs, benchmark_resolutions, benchmark_single + +__all__ = [ + "benchmark_nprocs", + "benchmark_resolutions", + "benchmark_single", + "join_results", + "join_results_from_files", + "load_results", + "load_results_from_file", + "nprocs_plot", + "num_cells_plot", + "save_results", + "save_results_to_file", +] diff --git a/python/grass/benchmark/app.py b/python/grass/benchmark/app.py index 09cdf3f9481..835fc0d544b 100644 --- a/python/grass/benchmark/app.py +++ b/python/grass/benchmark/app.py @@ -47,11 +47,7 @@ def join_results_cli(args): def select_only(result): return result.label == args.only - if args.only: - select_function = select_only - else: - select_function = None - + select_function = select_only if args.only else None results = join_results_from_files( source_filenames=args.results, prefixes=args.prefixes, diff --git a/python/grass/benchmark/plots.py b/python/grass/benchmark/plots.py index 9483fda9116..24afcbcfbae 100644 --- a/python/grass/benchmark/plots.py +++ b/python/grass/benchmark/plots.py @@ -25,10 +25,7 @@ def get_pyplot(to_file): """ import matplotlib as mpl # pylint: disable=import-outside-toplevel - if to_file: - backend = "agg" - else: - backend = None + backend = "agg" if to_file else None if backend: mpl.use(backend) @@ -124,10 +121,7 @@ def num_cells_plot(results, filename=None, title=None, show_resolution=False): x_ticks = set() for result in results: - if show_resolution: - x = result.resolutions - else: - x = result.cells + x = result.resolutions if show_resolution else result.cells x_ticks.update(x) plt.plot(x, result.times, label=result.label) if hasattr(result, "all_times"): diff --git a/python/grass/docs/_templates/oholosidebar.html b/python/grass/docs/_templates/oholosidebar.html index 06dd9dc7540..bebce37732f 100644 --- a/python/grass/docs/_templates/oholosidebar.html +++ b/python/grass/docs/_templates/oholosidebar.html @@ -1,9 +1,9 @@

    - +

    - +

    - +

    diff --git a/python/grass/docs/src/pygrass_index.rst b/python/grass/docs/src/pygrass_index.rst index 9e782e4c452..844e5578ae8 100644 --- a/python/grass/docs/src/pygrass_index.rst +++ b/python/grass/docs/src/pygrass_index.rst @@ -46,7 +46,7 @@ References Resources Analysis Support System (GRASS) Geographic Information System (GIS)*. ISPRS International Journal of Geo-Information. 2(1):201-219. `doi:10.3390/ijgi2010201 - `_ + `_ * `Python related articles in the GRASS GIS Wiki `_ * `GRASS GIS 8 Programmer's Manual @@ -54,7 +54,7 @@ References This project has been funded with support from the `Google Summer of Code 2012 -`_ +`_ .. Indices and tables diff --git a/python/grass/docs/src/pygrass_modules.rst b/python/grass/docs/src/pygrass_modules.rst index a668739a34f..854119057d6 100644 --- a/python/grass/docs/src/pygrass_modules.rst +++ b/python/grass/docs/src/pygrass_modules.rst @@ -200,4 +200,4 @@ Multiple GRASS modules can be joined into one object by :class:`~pygrass.modules.interface.module.MultiModule`. -.. _Popen: http://docs.python.org/library/subprocess.html#Popen +.. _Popen: https://docs.python.org/library/subprocess.html#Popen diff --git a/python/grass/docs/src/temporal_framework.rst b/python/grass/docs/src/temporal_framework.rst index 7e68de132a9..2443098b26a 100644 --- a/python/grass/docs/src/temporal_framework.rst +++ b/python/grass/docs/src/temporal_framework.rst @@ -414,7 +414,7 @@ Temporal shifting References ---------- -* Gebbert, S., Pebesma, E., 2014. *TGRASS: A temporal GIS for field based environmental modeling*. Environmental Modelling & Software. 2(1):201-219. `doi:10.1016/j.envsoft.2013.11.001 `_ +* Gebbert, S., Pebesma, E., 2014. *TGRASS: A temporal GIS for field based environmental modeling*. Environmental Modelling & Software. 2(1):201-219. `doi:10.1016/j.envsoft.2013.11.001 `_ * `TGRASS related articles in the GRASS GIS Wiki `_ * Supplementary material of the publication *The GRASS GIS Temporal Framework* to be published in diff --git a/python/grass/exceptions/__init__.py b/python/grass/exceptions/__init__.py index b22d0a45c1d..deec48ffd96 100644 --- a/python/grass/exceptions/__init__.py +++ b/python/grass/exceptions/__init__.py @@ -71,13 +71,9 @@ def __init__(self, module, code, returncode, errors=None): """ # CalledProcessError has undocumented constructor super().__init__(returncode, module) - if not module or module in code: - # No need to include module name if it is directly in code - # of if it is not set. - executed = code - else: - # Make sure module name is there if provided and not in code. - executed = f"{module} {code}" + # No need to include module name if it is directly in code of if it is not set. + # Otherwise, make sure module name is there if provided and not in code. + executed = code if not module or module in code else f"{module} {code}" if errors: # We assume actual errors, e.g., captured stderr. err = _("See the following errors:\n{errors}").format(errors=errors) diff --git a/python/grass/experimental/__init__.py b/python/grass/experimental/__init__.py index 1253d09df0a..8ccb44413bb 100644 --- a/python/grass/experimental/__init__.py +++ b/python/grass/experimental/__init__.py @@ -1,4 +1,11 @@ """Experimental code, all can change""" -from .create import * -from .mapset import * +from .create import require_create_ensure_mapset, create_temporary_mapset +from .mapset import MapsetSession, TemporaryMapsetSession + +__all__ = [ + "MapsetSession", + "TemporaryMapsetSession", + "create_temporary_mapset", + "require_create_ensure_mapset", +] diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 369cdf60e62..9024ac33517 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -9,6 +9,8 @@ .. sectionauthor:: Vaclav Petras """ +from __future__ import annotations + import datetime import glob import os @@ -20,7 +22,7 @@ from grass.script import gisenv -def mapset_exists(path, location=None, mapset=None): +def mapset_exists(path: str | os.PathLike[str], location=None, mapset=None) -> bool: """Returns True whether mapset path exists. Either only *path* is provided or all three parameters need to be provided. @@ -30,27 +32,27 @@ def mapset_exists(path, location=None, mapset=None): :param mapset: name of a Mapset if not part of *path* """ if location and mapset: - path = os.path.join(path, location, mapset) + path = Path(path, location, mapset) elif location or mapset: raise ValueError(_("Provide only path or all three parameters, not two")) - return os.path.exists(path) + return Path(path).exists() -def location_exists(path, location=None): +def location_exists(path: str | os.PathLike[str], location=None) -> bool: """Returns True whether location path exists. :param path: Path to a Location or to a GRASS GIS database directory :param location: name of a Location if not part of *path* """ if location: - path = os.path.join(path, location) - return os.path.exists(path) + path = Path(path, location) + return Path(path).exists() # TODO: distinguish between valid for getting maps and usable as current # https://lists.osgeo.org/pipermail/grass-dev/2016-September/082317.html # interface created according to the current usage -def is_mapset_valid(path, location=None, mapset=None): +def is_mapset_valid(path: str | os.PathLike[str], location=None, mapset=None) -> bool: """Return True if GRASS Mapset is valid Either only *path* is provided or all three parameters need to be provided. @@ -64,13 +66,13 @@ def is_mapset_valid(path, location=None, mapset=None): # WIND doesn't exist (assuming that neither GRASS_REGION nor # WIND_OVERRIDE environmental variables are set). if location and mapset: - path = os.path.join(path, location, mapset) + path = Path(path, location, mapset) elif location or mapset: raise ValueError(_("Provide only path or all three parameters, not two")) - return os.access(os.path.join(path, "WIND"), os.R_OK) + return os.access(Path(path, "WIND"), os.R_OK) -def is_location_valid(path, location=None): +def is_location_valid(path: str | os.PathLike[str], location=None) -> bool: """Return True if GRASS Location is valid :param path: Path to a Location or to a GRASS GIS database directory @@ -81,8 +83,8 @@ def is_location_valid(path, location=None): # containing a PERMANENT/DEFAULT_WIND file is probably a GRASS # location, while a directory lacking it probably isn't. if location: - path = os.path.join(path, location) - return os.access(os.path.join(path, "PERMANENT", "DEFAULT_WIND"), os.F_OK) + path = Path(path, location) + return os.access(Path(path, "PERMANENT", "DEFAULT_WIND"), os.F_OK) def is_mapset_current(database, location, mapset) -> bool: @@ -101,7 +103,7 @@ def is_location_current(database, location) -> bool: return bool(database == genv["GISDBASE"] and location == genv["LOCATION_NAME"]) -def is_current_user_mapset_owner(mapset_path): +def is_current_user_mapset_owner(mapset_path: str | os.PathLike[str]) -> bool: """Returns True if mapset owner is the current user. On Windows it always returns True.""" # Note that this does account for libgis built with SKIP_MAPSET_OWN_CHK @@ -118,12 +120,12 @@ def is_current_user_mapset_owner(mapset_path): return mapset_uid == os.getuid() -def is_different_mapset_owner(mapset_path): +def is_different_mapset_owner(mapset_path: str | os.PathLike[str]) -> bool: """Returns True if mapset owner is different from the current user""" return not is_current_user_mapset_owner(mapset_path) -def get_mapset_owner(mapset_path): +def get_mapset_owner(mapset_path: str | os.PathLike[str]) -> str | None: """Returns mapset owner name or None if owner name unknown. On Windows it always returns None.""" if sys.platform == "win32": @@ -164,27 +166,27 @@ def is_first_time_user(): return False -def is_mapset_locked(mapset_path): +def is_mapset_locked(mapset_path: str | os.PathLike[str]) -> bool: """Check if the mapset is locked""" lock_name = ".gislock" - lockfile = os.path.join(mapset_path, lock_name) - return os.path.exists(lockfile) + lockfile = Path(mapset_path, lock_name) + return lockfile.exists() -def get_lockfile_if_present(database, location, mapset): +def get_lockfile_if_present(database, location, mapset) -> str | None: """Return path to lock if present, None otherwise Returns the path as a string or None if nothing was found, so the return value can be used to test if the lock is present. """ lock_name = ".gislock" - lockfile = os.path.join(database, location, mapset, lock_name) - if os.path.isfile(lockfile): - return lockfile + lockfile = Path(database, location, mapset, lock_name) + if lockfile.is_file(): + return str(lockfile) return None -def get_mapset_lock_info(mapset_path): +def get_mapset_lock_info(mapset_path: str | os.PathLike[str]): """Get information about .gislock file. Assumes lock file exists, use is_mapset_locked to find out. Returns information as a dictionary with keys @@ -233,13 +235,14 @@ def get_reason_id_mapset_not_usable(mapset_path): return None -def dir_contains_location(path): +def dir_contains_location(path: str | os.PathLike[str]) -> bool: """Return True if directory *path* contains a valid location""" - if not os.path.isdir(path): + p = Path(path) + if not p.is_dir(): return False - for name in os.listdir(path): - if os.path.isdir(os.path.join(path, name)): - if is_location_valid(path, name): + for name in p.iterdir(): + if name.is_dir(): + if is_location_valid(name): return True return False @@ -260,8 +263,8 @@ def get_mapset_invalid_reason(database, location, mapset, none_for_no_reason=Fal # Since we are trying to get the one most likely message, we need all # those return statements here. # pylint: disable=too-many-return-statements - location_path = os.path.join(database, location) - mapset_path = os.path.join(location_path, mapset) + location_path = Path(database, location) + mapset_path = location_path / mapset # first checking the location validity # perhaps a special set of checks with different messages mentioning mapset # will be needed instead of the same set of messages used for location @@ -271,14 +274,14 @@ def get_mapset_invalid_reason(database, location, mapset, none_for_no_reason=Fal if location_msg: return location_msg # if location is valid, check mapset - if mapset not in os.listdir(location_path): + if not mapset_path.exists(): # TODO: remove the grass.py specific wording return _( "Mapset <{mapset}> doesn't exist in GRASS Location <{location}>" ).format(mapset=mapset, location=location) - if not os.path.isdir(mapset_path): + if not mapset_path.is_dir(): return _("<%s> is not a GRASS Mapset because it is not a directory") % mapset - if not os.path.isfile(os.path.join(mapset_path, "WIND")): + if not (mapset_path / "WIND").is_file(): return ( _( "<%s> is not a valid GRASS Mapset" @@ -287,7 +290,7 @@ def get_mapset_invalid_reason(database, location, mapset, none_for_no_reason=Fal % mapset ) # based on the is_mapset_valid() function - if not os.access(os.path.join(mapset_path, "WIND"), os.R_OK): + if not os.access(mapset_path / "WIND", os.R_OK): return ( _( "<%s> is not a valid GRASS Mapset" @@ -303,7 +306,9 @@ def get_mapset_invalid_reason(database, location, mapset, none_for_no_reason=Fal ).format(mapset=mapset, location=location) -def get_location_invalid_reason(database, location, none_for_no_reason=False): +def get_location_invalid_reason( + database, location, none_for_no_reason=False +) -> str | None: """Returns a message describing what is wrong with the Location The goal is to provide the most suitable error message @@ -321,14 +326,14 @@ def get_location_invalid_reason(database, location, none_for_no_reason=False): :param none_for_no_reason: When True, return None when reason is unknown :returns: translated message or None """ - location_path = os.path.join(database, location) - permanent_path = os.path.join(location_path, "PERMANENT") + location_path = Path(database, location) + permanent_path = location_path / "PERMANENT" # directory - if not os.path.exists(location_path): + if not location_path.exists(): return _("Location <%s> doesn't exist") % location_path # permanent mapset - if "PERMANENT" not in os.listdir(location_path): + if not permanent_path.exists(): return ( _( "<%s> is not a valid GRASS Location" @@ -336,7 +341,7 @@ def get_location_invalid_reason(database, location, none_for_no_reason=False): ) % location_path ) - if not os.path.isdir(permanent_path): + if not permanent_path.is_dir(): return ( _( "<%s> is not a valid GRASS Location" @@ -345,7 +350,7 @@ def get_location_invalid_reason(database, location, none_for_no_reason=False): % location_path ) # partially based on the is_location_valid() function - if not os.path.isfile(os.path.join(permanent_path, "DEFAULT_WIND")): + if not (permanent_path / "DEFAULT_WIND").is_file(): return ( _( "<%s> is not a valid GRASS Location" @@ -362,14 +367,14 @@ def get_location_invalid_reason(database, location, none_for_no_reason=False): ) -def get_location_invalid_suggestion(database, location): +def get_location_invalid_suggestion(database, location) -> str | None: """Return suggestion what to do when specified location is not valid It gives suggestion when: * A mapset was specified instead of a location. * A GRASS database was specified instead of a location. """ - location_path = os.path.join(database, location) + location_path = Path(database, location) # a common error is to use mapset instead of location, # if that's the case, include that info into the message if is_mapset_valid(location_path): diff --git a/python/grass/gunittest/case.py b/python/grass/gunittest/case.py index 1277ee542b5..49a378d6133 100644 --- a/python/grass/gunittest/case.py +++ b/python/grass/gunittest/case.py @@ -691,10 +691,7 @@ def assertFileMd5(self, filename, md5, text=False, msg=None): at the end of file (as for example, Git or PEP8 requires). """ self.assertFileExists(filename, msg=msg) - if text: - actual = text_file_md5(filename) - else: - actual = file_md5(filename) + actual = text_file_md5(filename) if text else file_md5(filename) if actual != md5: standardMsg = ( "File <{name}> does not have the right MD5 sum.\n" @@ -1323,10 +1320,10 @@ def runModule(cls, module, expecting_stdout=False, **kwargs): # TODO: standardized error code would be handy here import re - if re.search("Raster map.*not found", errors, flags=re.DOTALL): + if re.search(r"Raster map.*not found", errors, flags=re.DOTALL): errors += "\nSee available raster maps:\n" errors += call_module("g.list", type="raster") - if re.search("Vector map.*not found", errors, flags=re.DOTALL): + if re.search(r"Vector map.*not found", errors, flags=re.DOTALL): errors += "\nSee available vector maps:\n" errors += call_module("g.list", type="vector") # TODO: message format, parameters @@ -1339,12 +1336,9 @@ def runModule(cls, module, expecting_stdout=False, **kwargs): errors = " The errors are:\n" + module.outputs.stderr else: errors = " There were no error messages." - if module.outputs.stdout: - # this is not appropriate for translation but we don't want - # and don't need testing to be translated - got = "only whitespace." - else: - got = "nothing." + # This is not appropriate for translation but we don't want + # and don't need testing to be translated + got = "only whitespace." if module.outputs.stdout else "nothing." raise RuntimeError( "Module call " + module.get_python() diff --git a/python/grass/gunittest/invoker.py b/python/grass/gunittest/invoker.py index f07e8dd5a84..29b62830e25 100644 --- a/python/grass/gunittest/invoker.py +++ b/python/grass/gunittest/invoker.py @@ -54,10 +54,7 @@ def update_keyval_file(filename, module, returncode): keyval["name"] = module.name keyval["tested_dir"] = module.tested_dir if "status" not in keyval.keys(): - if returncode is None or returncode: - status = "failed" - else: - status = "passed" + status = "failed" if returncode is None or returncode else "passed" keyval["status"] = status keyval["returncode"] = returncode keyval["test_file_authors"] = test_file_authors @@ -244,7 +241,7 @@ def try_decode(data, encodings): Path(stdout_path).write_text(stdout) with open(stderr_path, "w") as stderr_file: - if type(stderr) == "bytes": + if isinstance(stderr, bytes): stderr_file.write(decode(stderr)) elif isinstance(stderr, str): stderr_file.write(stderr) diff --git a/python/grass/gunittest/multireport.py b/python/grass/gunittest/multireport.py index c5f36a6e0db..5a0350f1786 100644 --- a/python/grass/gunittest/multireport.py +++ b/python/grass/gunittest/multireport.py @@ -119,10 +119,7 @@ def median(values): smedian = median(successes) smax = max(successes) - if successes[-1] < smedian: - color = "r" - else: - color = "g" + color = "r" if successes[-1] < smedian else "g" # another possibility is to color according to the gradient, ideally # on the whole curve but that's much more complicated diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 09f371dfffc..7c93872a656 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -107,7 +107,7 @@ def get_source_url(path, revision, line=None): :param revision: SVN revision (should be a number) :param line: line in the file (should be None for directories) """ - tracurl = "http://trac.osgeo.org/grass/browser/" + tracurl = "https://trac.osgeo.org/grass/browser/" if line: return "{tracurl}{path}?rev={revision}#L{line}".format(**locals()) return "{tracurl}{path}?rev={revision}".format(**locals()) @@ -234,11 +234,8 @@ def get_svn_path_authors(path, from_date=None): :returns: a set of authors """ - if from_date is None: - # this is the SVN default for local copies - revision_range = "BASE:1" - else: - revision_range = "BASE:{%s}" % from_date + # "BASE:1" is the SVN default for local copies + revision_range = "BASE:1" if from_date is None else "BASE:{%s}" % from_date try: # TODO: allow also usage of --limit p = subprocess.Popen( @@ -487,10 +484,7 @@ def tail(filename, n): def returncode_to_html_text(returncode, timed_out=None): if returncode: - if timed_out is not None: - extra = f" (timeout >{timed_out}s)" - else: - extra = "" + extra = f" (timeout >{timed_out}s)" if timed_out is not None else "" return f'FAILED{extra}' # alternatives: SUCCEEDED, passed, OK return 'succeeded' @@ -857,10 +851,7 @@ def finish(self): # this shoul be moved to some additional meta passed in constructor svn_info = get_svn_info() - if not svn_info: - svn_revision = "" - else: - svn_revision = svn_info["revision"] + svn_revision = "" if not svn_info else svn_info["revision"] summary = {} summary["files_total"] = self.test_files @@ -1025,10 +1016,7 @@ def end_file_test( num_failed = test_summary.get("failures", 0) num_failed += test_summary.get("errors", 0) if num_failed: - if num_failed > 1: - text = " ({f} tests failed)" - else: - text = " ({f} test failed)" + text = " ({f} tests failed)" if num_failed > 1 else " ({f} test failed)" self._stream.write(text.format(f=num_failed)) self._stream.write("\n") # TODO: here we lost the possibility to include also file name diff --git a/python/grass/imaging/__init__.py b/python/grass/imaging/__init__.py index 41626697f8e..7434942abe0 100644 --- a/python/grass/imaging/__init__.py +++ b/python/grass/imaging/__init__.py @@ -1,4 +1,15 @@ -from grass.imaging.images2gif import readGif, writeGif -from grass.imaging.images2swf import readSwf, writeSwf from grass.imaging.images2avi import readAvi, writeAvi +from grass.imaging.images2gif import readGif, writeGif from grass.imaging.images2ims import readIms, writeIms +from grass.imaging.images2swf import readSwf, writeSwf + +__all__ = [ + "readAvi", + "readGif", + "readIms", + "readSwf", + "writeAvi", + "writeGif", + "writeIms", + "writeSwf", +] diff --git a/python/grass/imaging/images2avi.py b/python/grass/imaging/images2avi.py index 1b0d9d8cd20..9776b9c0db2 100644 --- a/python/grass/imaging/images2avi.py +++ b/python/grass/imaging/images2avi.py @@ -141,19 +141,18 @@ def writeAvi( print(gs.decode(outPut)) print(gs.decode(S.stderr.read())) raise RuntimeError(_("Could not write avi.")) - else: - try: - # Copy avi - shutil.copy(os.path.join(tempDir, "output.avi"), filename) - except Exception as err: - # Clean up - _cleanDir(tempDir) - if bg_task: - return str(err) - raise - + try: + # Copy avi + shutil.copy(os.path.join(tempDir, "output.avi"), filename) + except Exception as err: # Clean up _cleanDir(tempDir) + if bg_task: + return str(err) + raise + + # Clean up + _cleanDir(tempDir) def readAvi(filename, asNumpy=True): @@ -195,11 +194,11 @@ def readAvi(filename, asNumpy=True): # Clean up _cleanDir(tempDir) raise RuntimeError("Could not read avi.") - else: - # Read images - images = images2ims.readIms(os.path.join(tempDir, "im*.jpg"), asNumpy) - # Clean up - _cleanDir(tempDir) + + # Read images + images = images2ims.readIms(os.path.join(tempDir, "im*.jpg"), asNumpy) + # Clean up + _cleanDir(tempDir) # Done return images diff --git a/python/grass/imaging/images2gif.py b/python/grass/imaging/images2gif.py index 4084dade509..d37ec0c4e32 100644 --- a/python/grass/imaging/images2gif.py +++ b/python/grass/imaging/images2gif.py @@ -58,7 +58,7 @@ Useful links: * http://tronche.com/computer-graphics/gif/ - * http://en.wikipedia.org/wiki/Graphics_Interchange_Format + * https://en.wikipedia.org/wiki/Graphics_Interchange_Format * http://www.w3.org/Graphics/GIF/spec-gif89a.txt """ diff --git a/python/grass/imaging/images2ims.py b/python/grass/imaging/images2ims.py index a5cee9b49de..d86a2247952 100644 --- a/python/grass/imaging/images2ims.py +++ b/python/grass/imaging/images2ims.py @@ -32,6 +32,7 @@ import os from operator import itemgetter +from string import digits try: import numpy as np @@ -117,7 +118,7 @@ def _getSequenceNumber(filename, part1, part2): # Get all numeric chars seq2 = "" for c in seq: - if c in "0123456789": + if c in digits: seq2 += c else: break diff --git a/python/grass/jupyter/__init__.py b/python/grass/jupyter/__init__.py index 91457f07ac3..21223c2cd47 100644 --- a/python/grass/jupyter/__init__.py +++ b/python/grass/jupyter/__init__.py @@ -109,6 +109,17 @@ from .interactivemap import InteractiveMap, Raster, Vector from .map import Map from .map3d import Map3D +from .seriesmap import SeriesMap from .setup import init from .timeseriesmap import TimeSeriesMap -from .seriesmap import SeriesMap + +__all__ = [ + "InteractiveMap", + "Map", + "Map3D", + "Raster", + "SeriesMap", + "TimeSeriesMap", + "Vector", + "init", +] diff --git a/python/grass/jupyter/map3d.py b/python/grass/jupyter/map3d.py index dd373f315a7..99253251406 100644 --- a/python/grass/jupyter/map3d.py +++ b/python/grass/jupyter/map3d.py @@ -210,10 +210,7 @@ def render(self, **kwargs): with Display( size=(self._width, self._height), **additional_kwargs ) as display: - if has_env_copy: - env = display.env() - else: - env = os.environ.copy() + env = display.env() if has_env_copy else os.environ.copy() self._region_manager.set_region_from_command(env=env, **kwargs) self.overlay.region_manager.set_region_from_env(env) gs.run_command(module, env=env, **kwargs) diff --git a/python/grass/pydispatch/signal.py b/python/grass/pydispatch/signal.py index 1e968e99dca..51808e01ee3 100644 --- a/python/grass/pydispatch/signal.py +++ b/python/grass/pydispatch/signal.py @@ -7,7 +7,7 @@ from grass.pydispatch import dispatcher -def _islambda(function): +def _islambda(function) -> bool: """ Tests if object is a lambda function. @@ -146,10 +146,7 @@ class connects to the signal:: will print """ if weak is None: - if _islambda(handler): - weak = False - else: - weak = True + weak = not _islambda(handler) dispatcher.connect(receiver=handler, signal=self, weak=weak) def disconnect(self, handler, weak=True): diff --git a/python/grass/pygrass/gis/__init__.py b/python/grass/pygrass/gis/__init__.py index 597c4bf75fa..29fecd3d699 100644 --- a/python/grass/pygrass/gis/__init__.py +++ b/python/grass/pygrass/gis/__init__.py @@ -114,7 +114,7 @@ def make_mapset(mapset, location=None, gisdbase=None): res = libgis.G_make_mapset(gisdbase, location, mapset) if res == -1: raise GrassError("Cannot create new mapset") - elif res == -2: + if res == -2: raise GrassError("Illegal name") diff --git a/python/grass/pygrass/messages/__init__.py b/python/grass/pygrass/messages/__init__.py index 36356433381..cf83a7722c4 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 @@ -262,33 +270,31 @@ def fatal(self, message): if self.raise_on_error is True: raise FatalError(message) - else: - sys.exit(1) + 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( @@ -301,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 @@ -316,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 @@ -324,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 @@ -334,12 +339,12 @@ def test_fatal_error(self, message): def get_msgr( - _instance=[ + instance=[ None, ], *args, **kwargs, -): +) -> Messenger: """Return a Messenger instance. :returns: the Messenger instance. @@ -352,9 +357,9 @@ def get_msgr( >>> msgr0 is msgr2 False """ - if not _instance[0]: - _instance[0] = Messenger(*args, **kwargs) - return _instance[0] + if not instance[0]: + instance[0] = Messenger(*args, **kwargs) + return instance[0] if __name__ == "__main__": 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/modules/__init__.py b/python/grass/pygrass/modules/__init__.py index 61073791599..ce4d169fedd 100644 --- a/python/grass/pygrass/modules/__init__.py +++ b/python/grass/pygrass/modules/__init__.py @@ -1,2 +1,9 @@ -from grass.pygrass.modules.interface import Module, MultiModule, ParallelModuleQueue from grass.pygrass.modules import shortcuts +from grass.pygrass.modules.interface import Module, MultiModule, ParallelModuleQueue + +__all__ = [ + "Module", + "MultiModule", + "ParallelModuleQueue", + "shortcuts", +] diff --git a/python/grass/pygrass/modules/grid/__init__.py b/python/grass/pygrass/modules/grid/__init__.py index 1c971174998..0d770ed3ad2 100644 --- a/python/grass/pygrass/modules/grid/__init__.py +++ b/python/grass/pygrass/modules/grid/__init__.py @@ -1 +1,3 @@ from grass.pygrass.modules.grid.grid import GridModule + +__all__ = ["GridModule"] diff --git a/python/grass/pygrass/modules/grid/grid.py b/python/grass/pygrass/modules/grid/grid.py index ffae173ca79..cc3f406d72d 100644 --- a/python/grass/pygrass/modules/grid/grid.py +++ b/python/grass/pygrass/modules/grid/grid.py @@ -582,7 +582,7 @@ def estimate_tile_size(self): self.height = ceil(region.rows / self.processes) def get_works(self): - """Return a list of tuble with the parameters for cmd_exe function""" + """Return a list of tuples with the parameters for cmd_exe function""" works = [] reg = Region() if self.move: diff --git a/python/grass/pygrass/modules/interface/__init__.py b/python/grass/pygrass/modules/interface/__init__.py index a05211e21c3..bde59049c6e 100644 --- a/python/grass/pygrass/modules/interface/__init__.py +++ b/python/grass/pygrass/modules/interface/__init__.py @@ -4,14 +4,20 @@ @author: pietro """ -from grass.pygrass.modules.interface import flag -from grass.pygrass.modules.interface import parameter -from grass.pygrass.modules.interface import module -from grass.pygrass.modules.interface import typedict -from grass.pygrass.modules.interface import read - +from grass.pygrass.modules.interface import flag, module, parameter, read, typedict from grass.pygrass.modules.interface.module import ( Module, MultiModule, ParallelModuleQueue, ) + +__all__ = [ + "Module", + "MultiModule", + "ParallelModuleQueue", + "flag", + "module", + "parameter", + "read", + "typedict", +] diff --git a/python/grass/pygrass/modules/interface/module.py b/python/grass/pygrass/modules/interface/module.py index 392d7571015..7f70d82bac1 100644 --- a/python/grass/pygrass/modules/interface/module.py +++ b/python/grass/pygrass/modules/interface/module.py @@ -559,7 +559,7 @@ def __init__(self, cmd, *args, **kargs): # get the xml of the module self.xml = get_cmd_xml.communicate()[0] # transform and parse the xml into an Element class: - # http://docs.python.org/library/xml.etree.elementtree.html + # https://docs.python.org/library/xml.etree.elementtree.html tree = fromstring(self.xml) for e in tree: diff --git a/python/grass/pygrass/modules/interface/parameter.py b/python/grass/pygrass/modules/interface/parameter.py index 3b58ea2b372..d950cd40008 100644 --- a/python/grass/pygrass/modules/interface/parameter.py +++ b/python/grass/pygrass/modules/interface/parameter.py @@ -18,15 +18,15 @@ def _check_value(param, value): string = (bytes, str) def raiseexcpet(exc, param, ptype, value): - """Function to modifa the error message""" + """Function to modify the error message""" msg = req % (param.name, param.typedesc, ptype, value, str(exc)) if isinstance(exc, ValueError): raise ValueError(msg) - elif isinstance(exc, TypeError): + if isinstance(exc, TypeError): raise TypeError(msg) - else: - exc.message = msg - raise exc + + exc.message = msg + raise exc def check_string(value): """Function to check that a string parameter is already a string""" @@ -337,10 +337,7 @@ def __doc__(self): .. """ if hasattr(self, "values"): - if self.isrange: - vals = self.isrange - else: - vals = ", ".join([repr(val) for val in self.values]) + vals = self.isrange or ", ".join([repr(val) for val in self.values]) else: vals = False if self.keydescvalues: diff --git a/python/grass/pygrass/modules/interface/testsuite/test_modules.py b/python/grass/pygrass/modules/interface/testsuite/test_modules.py index 3318154f87d..ee005498692 100644 --- a/python/grass/pygrass/modules/interface/testsuite/test_modules.py +++ b/python/grass/pygrass/modules/interface/testsuite/test_modules.py @@ -21,7 +21,7 @@ class ModulesMeta(type): - def __new__(mcs, name, bases, dict): + def __new__(cls, name, bases, dict): def gen_test(cmd): def test(self): Module(cmd) @@ -36,7 +36,7 @@ def test(self): for cmd in cmds: test_name = "test__%s" % cmd.replace(".", "_") dict[test_name] = gen_test(cmd) - return type.__new__(mcs, name, bases, dict) + return type.__new__(cls, name, bases, dict) class TestModules(TestCase, metaclass=ModulesMeta): diff --git a/python/grass/pygrass/modules/testsuite/test_import_isolation.py b/python/grass/pygrass/modules/testsuite/test_import_isolation.py index d1321a554d0..af643ec2fee 100644 --- a/python/grass/pygrass/modules/testsuite/test_import_isolation.py +++ b/python/grass/pygrass/modules/testsuite/test_import_isolation.py @@ -36,14 +36,17 @@ def test_import_isolation(self): isolate, check(*self.patterns), msg="Test isolation before any import." ) # same import done in __init__ file - from grass.pygrass.modules.interface import Module, ParallelModuleQueue - from grass.pygrass.modules import shortcuts + from grass.pygrass.modules.interface import ( + Module, # noqa: F401 + ParallelModuleQueue, # noqa: F401 + ) + from grass.pygrass.modules import shortcuts # noqa: F401 self.assertEqual( isolate, check(*self.patterns), msg="Test isolation after import Module." ) # test the other way round - from grass.pygrass.vector import VectorTopo + from grass.pygrass.vector import VectorTopo # noqa: F401 self.assertNotEqual( isolate, diff --git a/python/grass/pygrass/raster/__init__.py b/python/grass/pygrass/raster/__init__.py index 61ec85841cb..9967d62d98e 100644 --- a/python/grass/pygrass/raster/__init__.py +++ b/python/grass/pygrass/raster/__init__.py @@ -13,6 +13,7 @@ libgis.G_gisinit("") +# flake8: noqa: E402 # import pygrass modules from grass.pygrass.errors import must_be_open from grass.pygrass.gis.region import Region @@ -25,6 +26,8 @@ from grass.pygrass.raster.segment import Segment from grass.pygrass.raster.rowio import RowIO +# flake8: qa + WARN_OVERWRITE = "Raster map <{0}> already exists and will be overwritten" test_raster_name = "Raster_test_map" diff --git a/python/grass/pygrass/raster/category.py b/python/grass/pygrass/raster/category.py index fa4e8d37b12..9ace632d136 100644 --- a/python/grass/pygrass/raster/category.py +++ b/python/grass/pygrass/raster/category.py @@ -107,7 +107,7 @@ def __repr__(self): return "[{0}]".format(",\n ".join(cats)) def _chk_index(self, index): - if type(index) == str: + if isinstance(index, str): try: index = self.labels().index(index) except ValueError: @@ -115,7 +115,7 @@ def _chk_index(self, index): return index def _chk_value(self, value): - if type(value) == tuple: + if isinstance(value, tuple): length = len(value) if length == 2: label, min_cat = value @@ -189,7 +189,7 @@ def _set_c_cat(self, label, min_cat, max_cat=None): return None if err == 0: raise GrassError(_("Null value detected")) - elif err == -1: + if err == -1: raise GrassError(_("Error executing: Rast_set_cat")) def __del__(self): diff --git a/python/grass/pygrass/rpc/__init__.py b/python/grass/pygrass/rpc/__init__.py index 07cbfe6503a..e95c3453250 100644 --- a/python/grass/pygrass/rpc/__init__.py +++ b/python/grass/pygrass/rpc/__init__.py @@ -10,21 +10,19 @@ :authors: Soeren Gebbert """ -import time -import threading 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 -import logging ############################################################################### ############################################################################### @@ -44,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 @@ -90,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] """ @@ -131,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] @@ -199,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): @@ -232,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" @@ -464,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..e12bea9f985 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,46 @@ :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 + + +logger: logging.Logger = logging.getLogger(__name__) + ############################################################################### -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 +93,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 +107,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,25 +122,23 @@ 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""" - logging.debug("Start the libgis server") + logger.debug("Start the libgis server") self.client_conn, self.server_conn = Pipe(True) self.lock = Lock() @@ -140,30 +149,32 @@ 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() + logger.debug("Check libgis server restart") - 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: + logger.warning( + "Needed to restart the libgis server, caller: %(caller)s", + {"caller": caller}, + ) - self.threadLock.release() self.stopped = False def safe_receive(self, message): """Receive the data and throw a FatalError exception in case the server process was killed and the pipe was closed by the checker thread""" - logging.debug("Receive message: {message}") + if logger.isEnabledFor(logging.DEBUG): + logger.debug("Receive message: %s", message) try: ret = self.client_conn.recv() @@ -180,15 +191,16 @@ def stop(self): This method should be called at exit using the package atexit """ - logging.debug("Stop libgis server") + logger.debug("Stop libgis server") 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/pygrass/tests/benchmark.py b/python/grass/pygrass/tests/benchmark.py index fa7f0c01a65..b6c5e98c26d 100644 --- a/python/grass/pygrass/tests/benchmark.py +++ b/python/grass/pygrass/tests/benchmark.py @@ -15,14 +15,19 @@ from jinja2 import Template from pathlib import Path + sys.path.append(str(Path.cwd())) sys.path.append("%s/.." % (str(Path.cwd()))) + +# flake8: noqa: E402 import grass.lib.gis as libgis import grass.lib.raster as libraster import grass.script as gs import ctypes +# flake8: qa + def test__RasterSegment_value_access__if(): test_a = pygrass.RasterSegment(name="test_a") diff --git a/python/grass/pygrass/utils.py b/python/grass/pygrass/utils.py index d8804665b1e..2d6a2498848 100644 --- a/python/grass/pygrass/utils.py +++ b/python/grass/pygrass/utils.py @@ -1,19 +1,21 @@ -import itertools import fnmatch +import itertools import os from sqlite3 import OperationalError import grass.lib.gis as libgis +from grass.script import core as grasscore +from grass.script import utils as grassutils +# flake8: noqa: E402 libgis.G_gisinit("") import grass.lib.raster as libraster from grass.lib.ctypes_preamble import String -from grass.script import core as grasscore -from grass.script import utils as grassutils - from grass.pygrass.errors import GrassError +# flake8: qa + test_vector_name = "Utils_test_vector" test_raster_name = "Utils_test_raster" @@ -461,7 +463,7 @@ def create_test_vector_map(map_name="test_vector"): """ from grass.pygrass.vector import VectorTopo - from grass.pygrass.vector.geometry import Point, Line, Centroid, Boundary + from grass.pygrass.vector.geometry import Boundary, Centroid, Line, Point cols = [ ("cat", "INTEGER PRIMARY KEY"), @@ -589,6 +591,7 @@ def create_test_stream_network_map(map_name="streams"): if __name__ == "__main__": import doctest + from grass.script.core import run_command create_test_vector_map(test_vector_name) diff --git a/python/grass/pygrass/vector/__init__.py b/python/grass/pygrass/vector/__init__.py index 461050807b0..6723b2e44b3 100644 --- a/python/grass/pygrass/vector/__init__.py +++ b/python/grass/pygrass/vector/__init__.py @@ -859,10 +859,7 @@ def features_to_wkb_list(self, bbox=None, feature_type="point", field=1): ok = libvect.Vect_cat_get( ctypes.byref(line_c), field, ctypes.byref(cat) ) - if ok < 1: - pcat = None - else: - pcat = cat.value + pcat = None if ok < 1 else cat.value wkb_list.append((f_id, pcat, ctypes.string_at(barray, size.value))) libgis.G_free(barray) diff --git a/python/grass/pygrass/vector/geometry.py b/python/grass/pygrass/vector/geometry.py index 10ecb1d2d13..b734161d1ea 100644 --- a/python/grass/pygrass/vector/geometry.py +++ b/python/grass/pygrass/vector/geometry.py @@ -810,10 +810,7 @@ def extend(self, line, forward=True): """ # set direction - if forward: - direction = libvect.GV_FORWARD - else: - direction = libvect.GV_BACKWARD + direction = libvect.GV_FORWARD if forward else libvect.GV_BACKWARD # check if is a Line object if isinstance(line, Line): c_points = line.c_points diff --git a/python/grass/pygrass/vector/table.py b/python/grass/pygrass/vector/table.py index 9c8d0c3f9a2..b83f751a0dd 100644 --- a/python/grass/pygrass/vector/table.py +++ b/python/grass/pygrass/vector/table.py @@ -134,8 +134,7 @@ def limit(self, number): """ if not isinstance(number, int): raise ValueError("Must be an integer.") - else: - self._limit = "LIMIT {number}".format(number=number) + self._limit = "LIMIT {number}".format(number=number) return self def group_by(self, *groupby): @@ -1261,10 +1260,7 @@ def create(self, cols, name=None, overwrite=False, cursor=None): """ cur = cursor or self.conn.cursor() coldef = ",\n".join(["%s %s" % col for col in cols]) - if name: - newname = name - else: - newname = self.name + newname = name or self.name try: cur.execute(sql.CREATE_TAB.format(tname=newname, coldef=coldef)) self.conn.commit() diff --git a/python/grass/pygrass/vector/testsuite/test_filters.py b/python/grass/pygrass/vector/testsuite/test_filters.py index 9252b134c02..9adba4cdefc 100644 --- a/python/grass/pygrass/vector/testsuite/test_filters.py +++ b/python/grass/pygrass/vector/testsuite/test_filters.py @@ -6,7 +6,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test - from grass.pygrass.vector.table import Filters diff --git a/python/grass/pygrass/vector/testsuite/test_geometry.py b/python/grass/pygrass/vector/testsuite/test_geometry.py index b2a7a1e37df..6957a473165 100644 --- a/python/grass/pygrass/vector/testsuite/test_geometry.py +++ b/python/grass/pygrass/vector/testsuite/test_geometry.py @@ -6,18 +6,15 @@ import sys import unittest + import numpy as np +import grass.lib.vector as libvect from grass.gunittest.case import TestCase from grass.gunittest.main import test - -import grass.lib.vector as libvect -from grass.script.core import run_command - -from grass.pygrass.vector import Vector, VectorTopo -from grass.pygrass.vector.geometry import Point, Line, Node -from grass.pygrass.vector.geometry import Area, Boundary, Centroid +from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.basic import Bbox +from grass.pygrass.vector.geometry import Area, Line, Node, Point class PointTestCase(TestCase): diff --git a/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py b/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py index 356a55ec4d7..cba638b1901 100644 --- a/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py +++ b/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py @@ -4,16 +4,8 @@ @author: pietro """ -import sys -import unittest -import numpy as np - from grass.gunittest.case import TestCase from grass.gunittest.main import test - -import grass.lib.vector as libvect -from grass.script.core import run_command - from grass.pygrass.vector import VectorTopo diff --git a/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py b/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py index b3d26220ec1..2cf0d0ba0c5 100644 --- a/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py +++ b/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py @@ -7,10 +7,7 @@ import grass.gunittest.case import grass.gunittest.main import grass.gunittest.utils - import grass.pygrass.vector as gvector -import grass.pygrass.utils as gutils - # doctest does not allow changing the base classes of test case, skip test case # and test suite, so we need to create a new type which inherits from our class diff --git a/python/grass/pygrass/vector/testsuite/test_table.py b/python/grass/pygrass/vector/testsuite/test_table.py index d87786fb3bd..c77233400b1 100644 --- a/python/grass/pygrass/vector/testsuite/test_table.py +++ b/python/grass/pygrass/vector/testsuite/test_table.py @@ -7,16 +7,15 @@ import os import sqlite3 import tempfile as tmp -from string import ascii_letters, digits from random import choice +from string import ascii_letters, digits + import numpy as np from grass.gunittest.case import TestCase from grass.gunittest.main import test - from grass.pygrass.vector.table import Table, get_path - # dictionary that generate random data RNG = np.random.default_rng() COL2VALS = { diff --git a/python/grass/pygrass/vector/testsuite/test_vector.py b/python/grass/pygrass/vector/testsuite/test_vector.py index 5d16333c31f..b4eebb2ab1e 100644 --- a/python/grass/pygrass/vector/testsuite/test_vector.py +++ b/python/grass/pygrass/vector/testsuite/test_vector.py @@ -6,8 +6,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test - -from grass.script.core import run_command from grass.pygrass.vector import VectorTopo diff --git a/python/grass/pygrass/vector/testsuite/test_vector3d.py b/python/grass/pygrass/vector/testsuite/test_vector3d.py index 796f85ca529..84e688d22e8 100644 --- a/python/grass/pygrass/vector/testsuite/test_vector3d.py +++ b/python/grass/pygrass/vector/testsuite/test_vector3d.py @@ -8,13 +8,9 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test - -from grass.script.core import run_command - +from grass.pygrass.gis.region import Region from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.geometry import Point -from grass.pygrass.gis.region import Region -from grass.pygrass.utils import get_mapset_vector def generate_coordinates(number, bbox=None, with_z=False): diff --git a/python/grass/script/Makefile b/python/grass/script/Makefile index 2ca98db5041..888417f8ca6 100644 --- a/python/grass/script/Makefile +++ b/python/grass/script/Makefile @@ -5,7 +5,7 @@ include $(MODULE_TOPDIR)/include/Make/Python.make DSTDIR = $(ETC)/python/grass/script -MODULES = core db raster raster3d vector array setup task utils +MODULES = core db imagery raster raster3d vector array setup task utils PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__) PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__) diff --git a/python/grass/script/__init__.py b/python/grass/script/__init__.py index 8589e8a1521..032a0eb67f3 100644 --- a/python/grass/script/__init__.py +++ b/python/grass/script/__init__.py @@ -1,10 +1,211 @@ """Python interface to launch GRASS GIS modules in scripts """ -from .core import * -from .db import * -from .raster import * -from .raster3d import * -from .vector import * -from .utils import * from . import setup +from .core import ( + PIPE, + Popen, + call, + compare_key_value_text_files, + create_environment, + create_location, + create_project, + debug, + debug_level, + del_temp_region, + error, + exec_command, + fatal, + feed_command, + find_file, + find_program, + get_capture_stderr, + get_commands, + get_raise_on_error, + get_real_command, + gisenv, + handle_errors, + info, + legal_name, + list_grouped, + list_pairs, + list_strings, + locn_is_latlong, + make_command, + mapsets, + message, + named_colors, + overwrite, + parse_color, + parse_command, + parser, + percent, + pipe_command, + read_command, + region, + region_env, + run_command, + sanitize_mapset_environment, + set_capture_stderr, + set_raise_on_error, + start_command, + tempdir, + tempfile, + tempname, + use_temp_region, + verbose, + verbosity, + version, + warning, + write_command, +) +from .db import ( + db_begin_transaction, + db_commit_transaction, + db_connection, + db_describe, + db_select, + db_table_exist, + db_table_in_vector, +) +from .imagery import group_to_dict +from .raster import mapcalc, mapcalc_start, raster_history, raster_info, raster_what +from .raster3d import mapcalc3d, raster3d_info +from .utils import ( + KeyValue, + append_node_pid, + append_random, + append_uuid, + basename, + clock, + decode, + diff_files, + encode, + float_or_dms, + get_lib_path, + get_num_suffix, + legalize_vector_name, + natural_sort, + naturally_sorted, + parse_key_val, + separator, + set_path, + split, + text_to_string, + try_remove, + try_rmdir, +) +from .vector import ( + vector_columns, + vector_db, + vector_db_select, + vector_history, + vector_info, + vector_info_topo, + vector_layer_db, + vector_what, +) + +__all__ = [ + "PIPE", + "KeyValue", + "Popen", + "append_node_pid", + "append_random", + "append_uuid", + "basename", + "call", + "clock", + "compare_key_value_text_files", + "create_environment", + "create_location", + "create_project", + "db_begin_transaction", + "db_commit_transaction", + "db_connection", + "db_describe", + "db_select", + "db_table_exist", + "db_table_in_vector", + "debug", + "debug_level", + "decode", + "del_temp_region", + "diff_files", + "encode", + "error", + "exec_command", + "fatal", + "feed_command", + "find_file", + "find_program", + "float_or_dms", + "get_capture_stderr", + "get_commands", + "get_lib_path", + "get_num_suffix", + "get_raise_on_error", + "get_real_command", + "gisenv", + "group_to_dict", + "handle_errors", + "info", + "legal_name", + "legalize_vector_name", + "list_grouped", + "list_pairs", + "list_strings", + "locn_is_latlong", + "make_command", + "mapcalc", + "mapcalc3d", + "mapcalc_start", + "mapsets", + "message", + "named_colors", + "natural_sort", + "naturally_sorted", + "overwrite", + "parse_color", + "parse_command", + "parse_key_val", + "parser", + "percent", + "pipe_command", + "raster3d_info", + "raster_history", + "raster_info", + "raster_what", + "read_command", + "region", + "region_env", + "run_command", + "sanitize_mapset_environment", + "separator", + "set_capture_stderr", + "set_path", + "set_raise_on_error", + "setup", + "split", + "start_command", + "tempdir", + "tempfile", + "tempname", + "text_to_string", + "try_remove", + "try_rmdir", + "use_temp_region", + "vector_columns", + "vector_db", + "vector_db_select", + "vector_history", + "vector_info", + "vector_info_topo", + "vector_layer_db", + "vector_what", + "verbose", + "verbosity", + "version", + "warning", + "write_command", +] diff --git a/python/grass/script/core.py b/python/grass/script/core.py index 4f70f525133..e6de4331b43 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -18,6 +18,8 @@ .. sectionauthor:: Michael Barton """ +from __future__ import annotations + import os import sys import atexit @@ -334,10 +336,7 @@ def get_module_and_code(args, kwargs): args = make_command(*args, **kwargs) # Since we are in error handler, let's be extra cautious # about an empty command. - if args: - module = args[0] - else: - module = None + module = args[0] if args else None code = " ".join(args) return module, code @@ -858,9 +857,9 @@ def get_capture_stderr(): # interface to g.parser -def _parse_opts(lines): - options = {} - flags = {} +def _parse_opts(lines: list) -> tuple[dict[str, str], dict[str, bool]]: + options: dict[str, str] = {} + flags: dict[str, bool] = {} for line in lines: if not line: break @@ -890,7 +889,7 @@ def _parse_opts(lines): return (options, flags) -def parser(): +def parser() -> tuple[dict[str, str], dict[str, bool]]: """Interface to g.parser, intended to be run from the top-level, e.g.: :: @@ -1448,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( @@ -1521,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: @@ -1544,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: @@ -1699,13 +1700,10 @@ def mapsets(search_path=False, env=None): :return: list of mapsets """ - if search_path: - flags = "p" - else: - flags = "l" + 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() @@ -2033,10 +2031,7 @@ def create_environment(gisdbase, location, mapset, env=None): f.write("GISDBASE: {g}\n".format(g=gisdbase)) f.write("LOCATION_NAME: {l}\n".format(l=location)) f.write("GUI: text\n") - if env: - env = env.copy() - else: - env = os.environ.copy() + env = env.copy() if env else os.environ.copy() env["GISRC"] = f.name # remove mapset-specific env vars env = sanitize_mapset_environment(env) 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/imagery.py b/python/grass/script/imagery.py new file mode 100644 index 00000000000..2c2c3868423 --- /dev/null +++ b/python/grass/script/imagery.py @@ -0,0 +1,150 @@ +""" +Imagery related functions to be used in Python scripts. + +Usage: + +:: + + import grass.script as gs + + gs.imagery.group_to_dict(imagery_group) + ... + +(C) 2024 by Stefan Blumentrath and 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. + +.. sectionauthor:: Stefan Blumentrath +""" + +from .core import read_command, warning, fatal +from .raster import raster_info + + +def group_to_dict( + imagery_group_name, + subgroup=None, + dict_keys="semantic_labels", + dict_values="map_names", + fill_semantic_label=True, + env=None, +): + """Create a dictionary to represent an imagery group with metadata. + + Depending on the dict_keys option, the returned dictionary uses either + the names of the raster maps ("map_names"), their row indices in the group + ("indices") or their associated semantic_labels ("semantic_labels") as keys. + The default is to use semantic_labels. Note that map metadata + of the maps in the group have to be read to get the semantic label, + in addition to the group file. The same metadata is read when the + "metadata" is requested as dict_values. Other supported dict_values + are "map_names" (default), "semantic_labels", or "indices". + + The function can also operate on the level of subgroups. In case a + non-existing (or empty sub-group) is requested a warning is printed + and an empty dictionary is returned (following the behavior of i.group). + + Example:: + + >>> run_command("g.copy", raster="lsat7_2000_10,lsat7_2000_10") + >>> run_command("r.support", raster="lsat7_2000_10", semantic_label="L8_1") + >>> run_command("g.copy", raster="lsat7_2000_20,lsat7_2000_20") + >>> run_command("r.support", raster="lsat7_2000_20", semantic_label="L8_2") + >>> run_command("g.copy", raster="lsat7_2000_30,lsat7_2000_30") + >>> run_command("r.support", raster="lsat7_2000_30", semantic_label="L8_3") + >>> run_command("i.group", group="L8_group", + >>> input="lsat7_2000_10,lsat7_2000_20,lsat7_2000_30") + >>> group_to_dict("L8_group") # doctest: +ELLIPSIS + {"L8_1": "lsat7_2000_10", ... "L8_3": "lsat7_2000_30"} + >>> run_command("g.remove", flags="f", type="group", name="L8_group") + >>> run_command("g.remove", flags="f", type="raster", + >>> name="lsat7_2000_10,lsat7_2000_20,lsat7_2000_30") + + :param str imagery_group_name: Name of the imagery group to process (or None) + :param str subgroup: Name of the imagery sub-group to process (or None) + :param str dict_keys: What to use as key for dictionary. It can be either + "semantic_labels" (default), "map_names" or "indices" + :param str dict_values: What to use as values for dictionary. It can be either + "map_names" (default), "semanic_labels", "indices" or + "metadata" (to return dictionaries with full map metadata) + :param bool fill_semantic_label: If maps in a group do not have a semantic + label, their index in the group is used + instead (default). Otherwise None / "none" + is used. + :param dict env: Environment to use when parsing the imagery group + + :return: dictionary representing an imagery group with it's maps and their + semantic labels, row indices in the group, or metadata + :rtype: dict + """ + group_dict = {} + maps_in_group = ( + read_command( + "i.group", + group=imagery_group_name, + subgroup=subgroup, + flags="g", + quiet=True, + env=env, + ) + .strip() + .split() + ) + + if dict_keys not in {"indices", "map_names", "semantic_labels"}: + raise ValueError(f"Invalid dictionary keys <{dict_keys}> requested") + + if dict_values not in {"indices", "map_names", "semantic_labels", "metadata"}: + raise ValueError(f"Invalid dictionary values <{dict_values}> requested") + + if subgroup and not maps_in_group: + warning( + _("Empty result returned for subgroup <{sg}> in group <{g}>").format( + sg=subgroup, g=imagery_group_name + ) + ) + + for idx, raster_map in enumerate(maps_in_group): + raster_map_info = None + # Get raster metadata if needed + if ( + dict_values in {"semantic_labels", "metadata"} + or dict_keys == "semantic_labels" + ): + raster_map_info = raster_info(raster_map, env=env) + + # Get key for dictionary + if dict_keys == "indices": + key = str(idx + 1) + elif dict_keys == "map_names": + key = raster_map + elif dict_keys == "semantic_labels": + key = raster_map_info["semantic_label"] + if not key or key == '"none"': + if fill_semantic_label: + key = str(idx + 1) + else: + fatal( + _( + "Semantic label missing for raster map {m} in group <{g}>." + ).format(m=raster_map, g=imagery_group_name) + ) + + if dict_values == "indices": + val = str(idx + 1) + elif dict_values == "map_names": + val = raster_map + elif dict_values == "semantic_labels": + val = raster_map_info["semantic_label"] + elif dict_values == "metadata": + val = raster_map_info + if key in group_dict: + warning( + _( + "Key {k} from raster map {m} already present in group dictionary." + "Overwriting existing entry..." + ).format(k=key, r=raster_map) + ) + group_dict[key] = val + return group_dict diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index bcaab7ef596..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} + % {"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( @@ -218,10 +222,7 @@ def raster_what(map, coord, env=None, localized=False): query :param env: """ - if isinstance(map, (bytes, str)): - map_list = [map] - else: - map_list = map + map_list = [map] if isinstance(map, (bytes, str)) else map coord_list = [] if isinstance(coord, tuple): 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/task.py b/python/grass/script/task.py index cf398c59214..758372938e3 100644 --- a/python/grass/script/task.py +++ b/python/grass/script/task.py @@ -153,8 +153,7 @@ def get_param(self, value, element="name", raiseError=True): _("Parameter element '%(element)s' not found: '%(value)s'") % {"element": element, "value": value} ) - else: - return None + return None def get_flag(self, aFlag): """Find and return a flag by name @@ -345,14 +344,8 @@ def _process_params(self): for ki in node_key_desc.findall("item"): key_desc.append(ki.text) - if p.get("multiple", "no") == "yes": - multiple = True - else: - multiple = False - if p.get("required", "no") == "yes": - required = True - else: - required = False + multiple = p.get("multiple", "no") == "yes" + required = p.get("required", "no") == "yes" if ( self.task.blackList["enabled"] diff --git a/python/grass/script/tests/test_script_task.py b/python/grass/script/tests/test_script_task.py index 6799885761e..cae8735827e 100644 --- a/python/grass/script/tests/test_script_task.py +++ b/python/grass/script/tests/test_script_task.py @@ -1,11 +1,11 @@ -from grass.script.task import grassTask as gtask +from grass.script.task import grassTask def test_mapcalc_simple_e_name(): - gt = gtask("r.mapcalc.simple") + gt = grassTask("r.mapcalc.simple") assert gt.get_param("e")["name"] == "e" def test_mapcalc_simple_expession_name(): - gt = gtask("r.mapcalc.simple") + gt = grassTask("r.mapcalc.simple") assert gt.get_param("expression")["name"] == "expression" diff --git a/python/grass/script/testsuite/data/script_using_temporary_region.py b/python/grass/script/testsuite/data/script_using_temporary_region.py index 5bb5a4cda26..839bf3d0a72 100755 --- a/python/grass/script/testsuite/data/script_using_temporary_region.py +++ b/python/grass/script/testsuite/data/script_using_temporary_region.py @@ -65,15 +65,9 @@ def main(): argument = sys.argv[1] sizes = argument.split(",", 1) size = sizes[0] - if len(sizes) > 1: - remaining = sizes[1] - else: - remaining = None + remaining = sizes[1] if len(sizes) > 1 else None nesting = int(sys.argv[2]) - if len(sys.argv) == 4: - map_name = sys.argv[3] - else: - map_name = None + map_name = sys.argv[3] if len(sys.argv) == 4 else None call_use_temp_region( script=this_file, size=size, diff --git a/python/grass/script/testsuite/test_imagery.py b/python/grass/script/testsuite/test_imagery.py new file mode 100644 index 00000000000..543bda774b6 --- /dev/null +++ b/python/grass/script/testsuite/test_imagery.py @@ -0,0 +1,163 @@ +from grass.exceptions import CalledModuleError +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + +import grass.script as gs + + +class TestImageryGroupToDict(TestCase): + """Tests function `group_to_dict` that returns raster maps + from an imagery group and their metadata.""" + + @classmethod + def setUpClass(cls): + cls.bands = [1, 2, 3] + cls.raster_maps = [f"lsat7_2002_{band}0" for band in cls.bands] + cls.group = "L8_group" + cls.subgroup = "L8_group_subgroup" + # Create input maps with label and group + for band in cls.bands: + cls.runModule( + "g.copy", raster=[f"lsat7_2002_{band}0", f"lsat7_2002_{band}0"] + ) + cls.runModule( + "r.support", map=f"lsat7_2002_{band}0", semantic_label=f"L8_{band}" + ) + cls.runModule("i.group", group=cls.group, input=cls.raster_maps) + + @classmethod + def tearDownClass(cls): + cls.runModule("g.remove", type="raster", name=cls.raster_maps, flags="f") + cls.runModule("g.remove", type="group", name=cls.group, flags="f") + + def test_basic_group_dict_defaults(self): + """Test with semantic labels as keys and map names as values (defaults)""" + ref_dict = {f"L8_{band}": f"lsat7_2002_{band}0" for band in self.bands} + group_info = gs.imagery.group_to_dict(self.group) + # Check that a dict is returned + self.assertIsInstance(group_info, dict) + self.assertListEqual(list(ref_dict.keys()), list(group_info.keys())) + self.assertListEqual( + list(ref_dict.values()), [val.split("@")[0] for val in group_info.values()] + ) + + def test_non_existing_group(self): + """Test that function fails if group does not exist""" + # Non existing group + self.assertRaises( + CalledModuleError, gs.imagery.group_to_dict, "non_existing_group" + ) + + def test_invalid_dict_key(self): + """Test that function fails if invalid keys are requested""" + self.assertRaises( + ValueError, + gs.imagery.group_to_dict, + self.group, + dict_keys="invalid_dict_key", + ) + + def test_invalid_dict_value(self): + """Test that function fails if invalid values are requested""" + self.assertRaises( + ValueError, + gs.imagery.group_to_dict, + self.group, + dict_values="invalid_dict_value", + ) + + def test_missing_subgroup(self): + """Test that empty dict is returned if subgroup does not exist""" + group_info = gs.imagery.group_to_dict( + self.group, subgroup="non_existing_subgroup" + ) + + # Check that an empty dict is returned + self.assertDictEqual(group_info, {}) + + def test_basic_group_map_keys(self): + """Test with map_names as keys and semantic_labels as values""" + ref_dict = {f"lsat7_2002_{band}0": f"L8_{band}" for band in self.bands} + group_info = gs.imagery.group_to_dict( + self.group, dict_keys="map_names", dict_values="semantic_labels" + ) + # Check that a dict is returned + self.assertIsInstance(group_info, dict) + self.assertListEqual( + list(ref_dict.keys()), [key.split("@")[0] for key in group_info.keys()] + ) + self.assertListEqual(list(ref_dict.values()), list(group_info.values())) + + def test_basic_group_index_keys(self): + """Test with indices as keys and mapnames as values""" + ref_dict = {str(band): f"lsat7_2002_{band}0" for band in self.bands} + group_info = gs.imagery.group_to_dict(self.group, dict_keys="indices") + # Check that a dict is returned + self.assertIsInstance(group_info, dict) + self.assertListEqual(list(ref_dict.keys()), list(group_info.keys())) + self.assertListEqual( + list(ref_dict.values()), + [val.split("@")[0] for val in group_info.values()], + ) + + def test_full_info_group_label_keys(self): + """Test with semantic labels as keys and full map metadata as values""" + group_info = gs.imagery.group_to_dict(self.group, dict_values="metadata") + # Check that a dict is returned + self.assertIsInstance(group_info, dict) + self.assertListEqual( + [f"L8_{band}" for band in self.bands], + [key.split("@")[0] for key in group_info.keys()], + ) + for band in self.bands: + # Take some metadata keys from raster_info + for metadata_key in [ + "north", + "nsres", + "cols", + "datatype", + "map", + "date", + "semantic_label", + "comments", + ]: + self.assertIn(metadata_key, group_info[f"L8_{band}"]) + + def test_full_info_group_label_keys_subgroup(self): + """Test with map names as keys and full map metadata as values""" + metadata_keys = { + "north", + "nsres", + "cols", + "datatype", + "map", + "date", + "semantic_label", + "comments", + } + self.runModule( + "i.group", group=self.group, subgroup=self.subgroup, input=self.raster_maps + ) + group_info = gs.imagery.group_to_dict( + self.group, + subgroup=self.subgroup, + dict_keys="map_names", + dict_values="metadata", + ) + # Check that a dict is returned + self.assertIsInstance(group_info, dict) + self.assertListEqual( + [f"lsat7_2002_{band}0" for band in self.bands], + [key.split("@")[0] for key in group_info.keys()], + ) + for key, val in group_info.items(): + # Check keys + self.assertTrue(key.startswith("lsat7_2002_")) + # Check values + self.assertIsInstance(val, dict) + # Take some metadata keys from raster_info + self.assertTrue(metadata_keys.issubset(set(val.keys()))) + + +if __name__ == "__main__": + test() diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 448289b57aa..7cbcc28ae4a 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -190,10 +190,7 @@ def decode(bytes_, encoding=None): if isinstance(bytes_, str): return bytes_ if isinstance(bytes_, bytes): - if encoding is None: - enc = _get_encoding() - else: - enc = encoding + enc = _get_encoding() if encoding is None else encoding return bytes_.decode(enc) # only text should be used raise TypeError("can only accept types str and bytes") @@ -221,10 +218,7 @@ def encode(string, encoding=None): if isinstance(string, bytes): return string if isinstance(string, str): - if encoding is None: - enc = _get_encoding() - else: - enc = encoding + enc = _get_encoding() if encoding is None else encoding return string.encode(enc) # if something else than text raise TypeError("can only accept types str and bytes") @@ -276,10 +270,7 @@ def parse_key_val(s, sep="=", dflt=None, val_type=None, vsep=None): for line in lines: kv = line.split(sep, 1) k = decode(kv[0].strip()) - if len(kv) > 1: - v = decode(kv[1].strip()) - else: - v = dflt + v = decode(kv[1].strip()) if len(kv) > 1 else dflt if val_type: result[k] = val_type(v) @@ -330,7 +321,7 @@ def split(s): # source: -# http://stackoverflow.com/questions/4836710/ +# https://stackoverflow.com/questions/4836710/ # does-python-have-a-built-in-function-for-string-natural-sort/4836734#4836734 def natural_sort(items): """Returns sorted list using natural sort @@ -353,11 +344,8 @@ def convert(text): return int(text) if text.isdigit() else text.lower() def alphanum_key(actual_key): - if key: - sort_key = key(actual_key) - else: - sort_key = actual_key - return [convert(c) for c in re.split("([0-9]+)", sort_key)] + sort_key = key(actual_key) if key else actual_key + return [convert(c) for c in re.split(r"([0-9]+)", sort_key)] items.sort(key=alphanum_key) @@ -464,10 +452,10 @@ def set_path(modulename, dirname=None, path="."): import sys # TODO: why dirname is checked first - the logic should be revised - _pathlib = None + pathlib_ = None if dirname: - _pathlib = os.path.join(path, dirname) - if _pathlib and os.path.exists(_pathlib): + pathlib_ = os.path.join(path, dirname) + if pathlib_ and os.path.exists(pathlib_): # we are running the script from the script directory, therefore # we add the path to sys.path to reach the directory (dirname) sys.path.append(os.path.abspath(path)) @@ -513,15 +501,15 @@ def legalize_vector_name(name, fallback_prefix="x"): # The implementation is based on Vect_legal_filename(). if not name: raise ValueError("name cannot be empty") - if fallback_prefix and re.match("[^A-Za-z]", fallback_prefix[0]): + if fallback_prefix and re.match(r"[^A-Za-z]", fallback_prefix[0]): raise ValueError("fallback_prefix must start with an ASCII letter") - if fallback_prefix and re.match("[^A-Za-z]", name[0], flags=re.ASCII): + if fallback_prefix and re.match(r"[^A-Za-z]", name[0], flags=re.ASCII): # We prefix here rather than just replace, because in cases of unique # identifiers, e.g., columns or node names, replacing the first # character by the same replacement character increases chances of # conflict (e.g. column names 10, 20, 30). name = "{fallback_prefix}{name}".format(**locals()) - name = re.sub("[^A-Za-z0-9_]", "_", name, flags=re.ASCII) + name = re.sub(r"[^A-Za-z0-9_]", "_", name, flags=re.ASCII) keywords = ["and", "or", "not"] if name in keywords: name = "{name}_".format(**locals()) diff --git a/python/grass/script/vector.py b/python/grass/script/vector.py index ca3caf18471..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 @@ -129,10 +129,7 @@ def vector_columns(map, layer=None, getDict=True, env=None, **kwargs): s = read_command( "v.info", flags="c", map=map, layer=layer, quiet=True, env=env, **kwargs ) - if getDict: - result = {} - else: - result = [] + result = {} if getDict else [] i = 0 for line in s.splitlines(): ctype, cname = line.split("|") @@ -253,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": {}} @@ -262,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 = [] @@ -377,10 +375,7 @@ def vector_what( if "LC_ALL" in env: env["LC_ALL"] = "C" - if isinstance(map, (bytes, str)): - map_list = [map] - else: - map_list = map + map_list = [map] if isinstance(map, (bytes, str)) else map if layer: if isinstance(layer, (tuple, list)): diff --git a/python/grass/semantic_label/__init__.py b/python/grass/semantic_label/__init__.py index 9f0b9b6caed..58bfe11a418 100644 --- a/python/grass/semantic_label/__init__.py +++ b/python/grass/semantic_label/__init__.py @@ -1 +1,3 @@ from .reader import SemanticLabelReader, SemanticLabelReaderError + +__all__ = ["SemanticLabelReader", "SemanticLabelReaderError"] diff --git a/python/grass/temporal/abstract_dataset.py b/python/grass/temporal/abstract_dataset.py index bf30afa21dd..fefef525216 100644 --- a/python/grass/temporal/abstract_dataset.py +++ b/python/grass/temporal/abstract_dataset.py @@ -10,6 +10,8 @@ :authors: Soeren Gebbert """ +from __future__ import annotations + from abc import ABCMeta, abstractmethod from .core import get_current_mapset, get_tgis_message_interface, init_dbif @@ -27,12 +29,12 @@ class AbstractDataset( __metaclass__ = ABCMeta - def __init__(self): + def __init__(self) -> None: SpatialTopologyDatasetConnector.__init__(self) TemporalTopologyDatasetConnector.__init__(self) self.msgr = get_tgis_message_interface() - def reset_topology(self): + def reset_topology(self) -> None: """Reset any information about temporal topology""" self.reset_spatial_topology() @@ -86,12 +88,12 @@ def get_number_of_relations(self): return None - def set_topology_build_true(self): + def set_topology_build_true(self) -> None: """Use this method when the spatio-temporal topology was build""" self.set_spatial_topology_build_true() self.set_temporal_topology_build_true() - def set_topology_build_false(self): + def set_topology_build_false(self) -> None: """Use this method when the spatio-temporal topology was not build""" self.set_spatial_topology_build_false() self.set_temporal_topology_build_false() @@ -108,13 +110,13 @@ def is_topology_build(self): return d - def print_topology_info(self): + def print_topology_info(self) -> None: if self.is_temporal_topology_build(): self.print_temporal_topology_info() if self.is_spatial_topology_build(): self.print_spatial_topology_info() - def print_topology_shell_info(self): + def print_topology_shell_info(self) -> None: if self.is_temporal_topology_build(): self.print_temporal_topology_shell_info() if self.is_spatial_topology_build(): @@ -221,7 +223,7 @@ def print_shell_info(self): def print_self(self): """Print the content of the internal structure to stdout""" - def set_id(self, ident): + def set_id(self, ident) -> None: """Set the identifier of the dataset""" self.base.set_id(ident) self.temporal_extent.set_id(ident) @@ -349,7 +351,7 @@ def get_spatial_extent(self): """Return the spatial extent""" return self.spatial_extent - def select(self, dbif=None, mapset=None): + def select(self, dbif=None, mapset=None) -> None: """Select temporal dataset entry from database and fill the internal structure @@ -390,7 +392,7 @@ def is_in_db(self, dbif=None, mapset=None): def delete(self): """Delete dataset from database if it exists""" - def insert(self, dbif=None, execute=True): + def insert(self, dbif=None, execute: bool = True): """Insert dataset into database :param dbif: The database interface to be used @@ -432,7 +434,7 @@ def insert(self, dbif=None, execute=True): dbif.close() return statement - def update(self, dbif=None, execute=True, ident=None): + def update(self, dbif=None, execute: bool = True, ident=None): """Update the dataset entry in the database from the internal structure excluding None variables @@ -466,7 +468,7 @@ def update(self, dbif=None, execute=True, ident=None): dbif.close() return statement - def update_all(self, dbif=None, execute=True, ident=None): + def update_all(self, dbif=None, execute: bool = True, ident=None): """Update the dataset entry in the database from the internal structure and include None variables. @@ -504,7 +506,7 @@ def update_all(self, dbif=None, execute=True, ident=None): dbif.close() return statement - def is_time_absolute(self): + def is_time_absolute(self) -> bool | None: """Return True in case the temporal type is absolute :return: True if temporal type is absolute, False otherwise @@ -513,7 +515,7 @@ def is_time_absolute(self): return self.base.get_ttype() == "absolute" return None - def is_time_relative(self): + def is_time_relative(self) -> bool | None: """Return True in case the temporal type is relative :return: True if temporal type is relative, False otherwise @@ -587,7 +589,7 @@ class AbstractDatasetComparisonKeyStartTime: sorted_map_list = sorted(map_list, key=AbstractDatasetComparisonKeyStartTime) """ - def __init__(self, obj, *args): + def __init__(self, obj, *args) -> None: self.obj = obj def __lt__(self, other): @@ -639,7 +641,7 @@ class AbstractDatasetComparisonKeyEndTime: sorted_map_list = sorted(map_list, key=AbstractDatasetComparisonKeyEndTime) """ - def __init__(self, obj, *args): + def __init__(self, obj, *args) -> None: self.obj = obj def __lt__(self, other): diff --git a/python/grass/temporal/abstract_map_dataset.py b/python/grass/temporal/abstract_map_dataset.py index ecbf761d139..c91020d4941 100644 --- a/python/grass/temporal/abstract_map_dataset.py +++ b/python/grass/temporal/abstract_map_dataset.py @@ -57,7 +57,7 @@ class AbstractMapDataset(AbstractDataset): __metaclass__ = ABCMeta - def __init__(self): + def __init__(self) -> None: AbstractDataset.__init__(self) self.ciface = get_tgis_c_library_interface() @@ -167,7 +167,7 @@ def get_map_id(self): return self.base.get_map_id() @staticmethod - def split_name(name, layer=None, mapset=None): + def split_name(name: str, layer=None, mapset=None): """Convenient method to split a map name into three potentially contained parts: map name, map layer and mapset. For the layer and mapset, default keyword arguments can be given if not present in @@ -194,9 +194,9 @@ def split_name(name, layer=None, mapset=None): return name, layer, mapset @staticmethod - def build_id_from_search_path(name, element): + def build_id_from_search_path(name: str, element) -> str: """Convenient method to build the unique identifier while - checking the current seach path for the correct mapset. + checking the current search path for the correct mapset. Existing mapset definitions in the name string will be reused. @@ -225,7 +225,7 @@ def build_id_from_search_path(name, element): else: gs.fatal( _( - "Map <{map_name}> of element tpye '{element}' not found on \ + "Map <{map_name}> of element type '{element}' not found on \ search path" ).format(element=element, map_name=name) ) @@ -235,7 +235,7 @@ def build_id_from_search_path(name, element): return f"{name}@{mapset}" @staticmethod - def build_id(name, mapset, layer=None): + def build_id(name: str, mapset, layer=None) -> str: """Convenient method to build the unique identifier Existing layer and mapset definitions in the name @@ -266,7 +266,7 @@ def get_layer(self): """ return self.base.get_layer() - def print_self(self): + def print_self(self) -> None: """Print the content of the internal structure to stdout""" self.base.print_self() self.temporal_extent.print_self() @@ -274,7 +274,7 @@ def print_self(self): self.metadata.print_self() self.stds_register.print_self() - def print_info(self): + def print_info(self) -> None: """Print information about this object in human readable style""" if self.get_type() == "raster": @@ -322,7 +322,7 @@ def print_info(self): " +----------------------------------------------------------------------------+" # noqa: E501 ) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this object in shell style""" self.base.print_shell_info() self.temporal_extent.print_shell_info() @@ -343,7 +343,7 @@ def print_shell_info(self): if self.is_topology_build(): self.print_topology_shell_info() - def insert(self, dbif=None, execute=True): + def insert(self, dbif=None, execute: bool = True): """Insert the map content into the database from the internal structure @@ -364,7 +364,7 @@ def insert(self, dbif=None, execute=True): self.write_timestamp_to_grass() return AbstractDataset.insert(self, dbif=dbif, execute=execute) - def update(self, dbif=None, execute=True): + def update(self, dbif=None, execute: bool = True): """Update the map content in the database from the internal structure excluding None variables @@ -383,7 +383,7 @@ def update(self, dbif=None, execute=True): self.write_timestamp_to_grass() return AbstractDataset.update(self, dbif, execute) - def update_all(self, dbif=None, execute=True): + def update_all(self, dbif=None, execute: bool = True): """Update the map content in the database from the internal structure including None variables @@ -403,15 +403,15 @@ def update_all(self, dbif=None, execute=True): self.write_timestamp_to_grass() return AbstractDataset.update_all(self, dbif, execute) - def set_time_to_absolute(self): + def set_time_to_absolute(self) -> None: """Set the temporal type to absolute""" self.base.set_ttype("absolute") - def set_time_to_relative(self): + def set_time_to_relative(self) -> None: """Set the temporal type to relative""" self.base.set_ttype("relative") - def set_absolute_time(self, start_time, end_time=None): + def set_absolute_time(self, start_time, end_time=None) -> bool: """Set the absolute time with start time and end time The end time is optional and must be set to None in case of time @@ -501,7 +501,7 @@ def set_absolute_time(self, start_time, end_time=None): return True - def update_absolute_time(self, start_time, end_time=None, dbif=None): + def update_absolute_time(self, start_time, end_time=None, dbif=None) -> None: """Update the absolute time The end time is optional and must be set to None in case of time @@ -543,7 +543,7 @@ def update_absolute_time(self, start_time, end_time=None, dbif=None): if get_enable_timestamp_write(): self.write_timestamp_to_grass() - def set_relative_time(self, start_time, end_time, unit): + def set_relative_time(self, start_time, end_time, unit) -> bool: """Set the relative time interval The end time is optional and must be set to None in case of time @@ -624,7 +624,7 @@ def set_relative_time(self, start_time, end_time, unit): return True - def update_relative_time(self, start_time, end_time, unit, dbif=None): + def update_relative_time(self, start_time, end_time, unit, dbif=None) -> None: """Update the relative time interval The end time is optional and must be set to None in case of time @@ -664,7 +664,7 @@ def update_relative_time(self, start_time, end_time, unit, dbif=None): if get_enable_timestamp_write(): self.write_timestamp_to_grass() - def set_temporal_extent(self, extent): + def set_temporal_extent(self, extent) -> None: """Convenient method to set the temporal extent from a temporal extent object @@ -721,7 +721,7 @@ def set_temporal_extent(self, extent): self.set_absolute_time(start, end) - def temporal_buffer(self, increment, update=False, dbif=None): + def temporal_buffer(self, increment, update: bool = False, dbif=None) -> None: """Create a temporal buffer based on an increment For absolute time the increment must be a string of type "integer @@ -820,17 +820,16 @@ def temporal_buffer(self, increment, update=False, dbif=None): else: start, end, unit = self.get_relative_time() new_start = start - increment - if end is None: - new_end = start + increment - else: - new_end = end + increment + new_end = start + increment if end is None else end + increment if update: self.update_relative_time(new_start, new_end, unit, dbif=dbif) else: self.set_relative_time(new_start, new_end, unit) - def set_spatial_extent_from_values(self, north, south, east, west, top=0, bottom=0): + def set_spatial_extent_from_values( + self, north, south, east, west, top=0, bottom=0 + ) -> None: """Set the spatial extent of the map from values This method only modifies this object and does not commit @@ -847,7 +846,7 @@ def set_spatial_extent_from_values(self, north, south, east, west, top=0, bottom north, south, east, west, top, bottom ) - def set_spatial_extent(self, spatial_extent): + def set_spatial_extent(self, spatial_extent) -> None: """Set the spatial extent of the map This method only modifies this object and does not commit @@ -871,7 +870,7 @@ def set_spatial_extent(self, spatial_extent): """ self.spatial_extent.set_spatial_extent(spatial_extent) - def spatial_buffer(self, size, update=False, dbif=None): + def spatial_buffer(self, size, update: bool = False, dbif=None) -> None: """Buffer the spatial extent by a given size in all spatial directions. @@ -903,7 +902,7 @@ def spatial_buffer(self, size, update=False, dbif=None): if update: self.spatial_extent.update(dbif) - def spatial_buffer_2d(self, size, update=False, dbif=None): + def spatial_buffer_2d(self, size, update: bool = False, dbif=None) -> None: """Buffer the spatial extent by a given size in 2d spatial directions. @@ -933,7 +932,7 @@ def spatial_buffer_2d(self, size, update=False, dbif=None): if update: self.spatial_extent.update(dbif) - def check_for_correct_time(self): + def check_for_correct_time(self) -> bool: """Check for correct time :return: True in case of success, False otherwise @@ -973,7 +972,7 @@ def check_for_correct_time(self): return True - def delete(self, dbif=None, update=True, execute=True): + def delete(self, dbif=None, update: bool = True, execute: bool = True): """Delete a map entry from database if it exists Remove dependent entries: @@ -1035,7 +1034,7 @@ def delete(self, dbif=None, update=True, execute=True): return statement - def unregister(self, dbif=None, update=True, execute=True): + def unregister(self, dbif=None, update: bool = True, execute: bool = True): """Remove the map entry in each space time dataset in which this map is registered @@ -1126,7 +1125,7 @@ def get_registered_stds(self, dbif=None, mapset=None): # this fn should not be in a class for maps, # but instead in a class for stds: AbstractSpaceTimeDataset ? - def add_stds_to_register(self, stds_id, dbif=None, execute=True): + def add_stds_to_register(self, stds_id, dbif=None, execute: bool = True): """Add a new space time dataset to the register :param stds_id: The id of the space time dataset to be registered @@ -1175,7 +1174,7 @@ def add_stds_to_register(self, stds_id, dbif=None, execute=True): return statement - def remove_stds_from_register(self, stds_id, dbif=None, execute=True): + def remove_stds_from_register(self, stds_id, dbif=None, execute: bool = True): """Remove a space time dataset from the register :param stds_id: The id of the space time dataset to removed from @@ -1223,7 +1222,7 @@ def remove_stds_from_register(self, stds_id, dbif=None, execute=True): return statement - def read_semantic_label_from_grass(self): + def read_semantic_label_from_grass(self) -> None: """Read the band identifier of this map from the map metadata in the GRASS file system based spatial database and set the internal band identifier that should be insert/updated @@ -1233,7 +1232,7 @@ def read_semantic_label_from_grass(self): silently pass. """ - def set_semantic_label(self, semantic_label): + def set_semantic_label(self, semantic_label) -> None: """Set semantic label identifier Currently only implemented in RasterDataset. Otherwise diff --git a/python/grass/temporal/abstract_space_time_dataset.py b/python/grass/temporal/abstract_space_time_dataset.py index 32b760cc1b9..47828943bf9 100644 --- a/python/grass/temporal/abstract_space_time_dataset.py +++ b/python/grass/temporal/abstract_space_time_dataset.py @@ -10,6 +10,8 @@ class that is the base class for all space time datasets. :authors: Soeren Gebbert """ +from __future__ import annotations + import copy import os import sys @@ -59,7 +61,7 @@ class AbstractSpaceTimeDataset(AbstractDataset): __metaclass__ = ABCMeta - def __init__(self, ident): + def __init__(self, ident) -> None: AbstractDataset.__init__(self) self.reset(ident) self.map_counter = 0 @@ -67,7 +69,7 @@ def __init__(self, ident): # SpaceTimeRasterDataset related only self.semantic_label = None - def get_name(self, semantic_label=True): + def get_name(self, semantic_label: bool = True): """Get dataset name including semantic label filter if enabled. :param bool semantic_label: True to return dataset name @@ -128,14 +130,14 @@ def set_map_register(self, name): :param name: The name of the register table """ - def print_self(self): + def print_self(self) -> None: """Print the content of the internal structure to stdout""" self.base.print_self() self.temporal_extent.print_self() self.spatial_extent.print_self() self.metadata.print_self() - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" if self.get_type() == "strds": @@ -167,22 +169,26 @@ def print_info(self): " +----------------------------------------------------------------------------+" # noqa: E501 ) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self.base.print_shell_info() self.temporal_extent.print_shell_info() self.spatial_extent.print_shell_info() self.metadata.print_shell_info() - def print_history(self): + def print_history(self) -> None: """Print history information about this class in human readable shell style """ self.metadata.print_history() def set_initial_values( - self, temporal_type, semantic_type=None, title=None, description=None - ): + self, + temporal_type, + semantic_type=None, + title=None, + description: str | None = None, + ) -> None: """Set the initial values of the space time dataset In addition the command creation string is generated @@ -213,7 +219,7 @@ def set_initial_values( self.metadata.set_description(description) self.metadata.set_command(self.create_command_string()) - def set_aggregation_type(self, aggregation_type): + def set_aggregation_type(self, aggregation_type) -> None: """Set the aggregation type of the space time dataset :param aggregation_type: The aggregation type of the space time @@ -221,7 +227,7 @@ def set_aggregation_type(self, aggregation_type): """ self.metadata.set_aggregation_type(aggregation_type) - def update_command_string(self, dbif=None): + def update_command_string(self, dbif=None) -> None: """Append the current command string to any existing command string in the metadata class and calls metadata update @@ -311,7 +317,7 @@ def get_granularity(self): return self.temporal_extent.get_granularity() - def set_granularity(self, granularity): + def set_granularity(self, granularity) -> None: """Set the granularity The granularity is usually computed by the space time dataset at @@ -343,7 +349,7 @@ def set_granularity(self, granularity): self.temporal_extent.set_granularity(granularity) - def set_relative_time_unit(self, unit): + def set_relative_time_unit(self, unit) -> None: """Set the relative time unit which may be of type: years, months, days, hours, minutes or seconds @@ -363,7 +369,7 @@ def set_relative_time_unit(self, unit): self.msgr.fatal(_("Unsupported temporal unit: %s") % (unit)) self.relative_time.set_unit(unit) - def insert(self, dbif=None, execute=True): + def insert(self, dbif=None, execute: bool = True): """Insert the space time dataset content into the database from the internal structure @@ -500,7 +506,9 @@ def count_gaps(self, maps=None, dbif=None): return gaps - def print_spatio_temporal_relationships(self, maps=None, spatial=None, dbif=None): + def print_spatio_temporal_relationships( + self, maps=None, spatial=None, dbif=None + ) -> None: """Print the spatio-temporal relationships for each map of the space time dataset or for each map of the optional list of maps @@ -541,7 +549,7 @@ def count_temporal_relations(self, maps=None, dbif=None): return count_temporal_topology_relationships(maps1=maps, dbif=dbif) - def check_temporal_topology(self, maps=None, dbif=None): + def check_temporal_topology(self, maps=None, dbif=None) -> bool: """Check the temporal topology of all maps of the current space time dataset or of an optional list of maps @@ -613,7 +621,7 @@ def check_temporal_topology(self, maps=None, dbif=None): return True - def sample_by_dataset(self, stds, method=None, spatial=False, dbif=None): + def sample_by_dataset(self, stds, method=None, spatial: bool = False, dbif=None): """Sample this space time dataset with the temporal topology of a second space time dataset @@ -779,10 +787,7 @@ def sample_by_dataset(self, stds, method=None, spatial=False, dbif=None): # print(relations) tb = SpatioTemporalTopologyBuilder() - if spatial: - spatial = "2D" - else: - spatial = None + spatial = "2D" if spatial else None mapsA = self.get_registered_maps_as_objects(dbif=dbif) mapsB = stds.get_registered_maps_as_objects_with_gaps(dbif=dbif) @@ -823,7 +828,9 @@ def sample_by_dataset(self, stds, method=None, spatial=False, dbif=None): return obj_list - def sample_by_dataset_sql(self, stds, method=None, spatial=False, dbif=None): + def sample_by_dataset_sql( + self, stds, method=None, spatial: bool = False, dbif=None + ): """Sample this space time dataset with the temporal topology of a second space time dataset using SQL queries. @@ -1429,10 +1436,7 @@ def get_registered_maps_as_objects_with_gaps( start1, end1 = maps[i].get_temporal_extent_as_tuple() start2, end2 = maps[i + 1].get_temporal_extent_as_tuple() end = start2 - if end1 is not None: - start = end1 - else: - start = start1 + start = end1 if end1 is not None else start1 map = self.get_new_map_instance(None) @@ -2002,7 +2006,7 @@ def shift_map_list(maps, gran): return maps - def shift(self, gran, dbif=None): + def shift(self, gran, dbif=None) -> bool: """Temporally shift each registered map with the provided granularity :param gran: The granularity to be used for shifting @@ -2179,7 +2183,7 @@ def snap_map_list(maps): return maps - def snap(self, dbif=None): + def snap(self, dbif=None) -> None: """For each registered map snap the end time to the start time of its temporal nearest neighbor in the future @@ -2237,7 +2241,7 @@ def snap(self, dbif=None): if connection_state_changed: dbif.close() - def _update_map_timestamps(self, maps, date_list, dbif): + def _update_map_timestamps(self, maps, date_list, dbif) -> None: """Update the timestamps of maps with the start and end time stored in the date_list. @@ -2284,7 +2288,7 @@ def _update_map_timestamps(self, maps, date_list, dbif): ds.select(dbif) ds.update_from_registered_maps(dbif) - def rename(self, ident, dbif=None): + def rename(self, ident, dbif=None) -> None: """Rename the space time dataset This method renames the space time dataset, the map register table @@ -2362,7 +2366,7 @@ def rename(self, ident, dbif=None): if connection_state_changed: dbif.close() - def delete(self, dbif=None, execute=True): + def delete(self, dbif=None, execute: bool = True): """Delete a space time dataset from the temporal database This method removes the space time dataset from the temporal @@ -2471,7 +2475,7 @@ def is_map_registered(self, map_id, dbif=None): return is_registered - def register_map(self, map, dbif=None): + def register_map(self, map, dbif=None) -> bool: """Register a map in the space time dataset. This method takes care of the registration of a map @@ -2554,7 +2558,7 @@ def register_map(self, map, dbif=None): stds_register_table = self.get_map_register() stds_ttype = self.get_temporal_type() - # The gathered SQL statemets are stroed here + # The gathered SQL statements are stored here statement = "" # Check temporal types @@ -2670,7 +2674,7 @@ def register_map(self, map, dbif=None): return True - def unregister_map(self, map, dbif=None, execute=True): + def unregister_map(self, map, dbif=None, execute: bool = True): """Unregister a map from the space time dataset. This method takes care of the un-registration of a map @@ -2755,7 +2759,7 @@ def unregister_map(self, map, dbif=None, execute=True): return statement - def update_from_registered_maps(self, dbif=None): + def update_from_registered_maps(self, dbif=None) -> None: """This methods updates the modification time, the spatial and temporal extent as well as type specific metadata. It should always been called after maps are registered or unregistered/deleted from diff --git a/python/grass/temporal/aggregation.py b/python/grass/temporal/aggregation.py index 354600855e0..69537ab0e49 100644 --- a/python/grass/temporal/aggregation.py +++ b/python/grass/temporal/aggregation.py @@ -115,7 +115,7 @@ def collect_map_names(sp, dbif, start, end, sampling): def aggregate_raster_maps( - inputs, base, start, end, count, method, register_null, dbif, offset=0 + inputs, base, start, end, count: int, method, register_null, dbif, offset: int = 0 ): """Aggregate a list of raster input maps with r.series @@ -219,13 +219,13 @@ def aggregate_by_topology( topo_list, basename, time_suffix, - offset=0, + offset: int = 0, method="average", - nprocs=1, + nprocs: int = 1, spatial=None, dbif=None, - overwrite=False, - file_limit=1000, + overwrite: bool = False, + file_limit: int = 1000, ): """Aggregate a list of raster input maps with r.series diff --git a/python/grass/temporal/base.py b/python/grass/temporal/base.py index ebb4b715e29..4c4378921a6 100644 --- a/python/grass/temporal/base.py +++ b/python/grass/temporal/base.py @@ -25,6 +25,8 @@ :author: Soeren Gebbert """ +from __future__ import annotations + from datetime import datetime from .core import ( @@ -38,7 +40,7 @@ class DictSQLSerializer: - def __init__(self): + def __init__(self) -> None: self.D = {} self.dbmi_paramstyle = get_tgis_dbmi_paramstyle() @@ -174,7 +176,7 @@ def serialize(self, type, table, where=None): return sql, tuple(args) - def deserialize(self, row): + def deserialize(self, row) -> None: """Convert the content of the dbmi dictionary like row into the internal dictionary @@ -184,11 +186,11 @@ def deserialize(self, row): for key in row.keys(): self.D[key] = row[key] - def clear(self): + def clear(self) -> None: """Initialize the internal storage""" self.D = {} - def print_self(self): + def print_self(self) -> None: """Print the content of the internal dictionary to stdout""" print(self.D) @@ -243,7 +245,7 @@ class SQLDatabaseInterface(DictSQLSerializer): """ # noqa: E501 - def __init__(self, table=None, ident=None): + def __init__(self, table=None, ident=None) -> None: """Constructor of this class :param table: The name of the table @@ -280,7 +282,7 @@ def get_delete_statement(self): + "';\n" ) - def delete(self, dbif=None): + def delete(self, dbif=None) -> None: """Delete the entry of this object from the temporal database :param dbif: The database interface to be used, @@ -367,7 +369,7 @@ def get_select_statement_mogrified(self, dbif=None): self.get_select_statement(), mapset=self.mapset ) - def select(self, dbif=None, mapset=None): + def select(self, dbif=None, mapset=None) -> bool: """Select the content from the temporal database and store it in the internal dictionary structure @@ -432,7 +434,7 @@ def get_insert_statement_mogrified(self, dbif=None): mapset = get_current_mapset() return dbif.mogrify_sql_statement(self.get_insert_statement(), mapset=mapset) - def insert(self, dbif=None): + def insert(self, dbif=None) -> None: """Serialize the content of this object and store it in the temporal database using the internal identifier @@ -489,7 +491,7 @@ def get_update_statement_mogrified(self, dbif=None, ident=None): self.get_update_statement(ident), mapset=mapset ) - def update(self, dbif=None, ident=None): + def update(self, dbif=None, ident=None) -> None: """Serialize the content of this object and update it in the temporal database using the internal identifier @@ -547,7 +549,7 @@ def get_update_all_statement_mogrified(self, dbif=None, ident=None): return dbif.mogrify_sql_statement(self.get_update_all_statement(ident)) - def update_all(self, dbif=None, ident=None): + def update_all(self, dbif=None, ident=None) -> None: """Serialize the content of this object, including None objects, and update it in the temporal database using the internal identifier @@ -627,12 +629,12 @@ def __init__( self, table=None, ident=None, - name=None, + name: str | None = None, mapset=None, creator=None, ctime=None, ttype=None, - ): + ) -> None: """Constructor :param table: The name of the temporal database table @@ -665,7 +667,7 @@ def __init__( self.set_ctime(ctime) self.set_ttype(ttype) - def set_id(self, ident): + def set_id(self, ident) -> None: """Convenient method to set the unique identifier (primary key) :param ident: The unique identifier must be a combination @@ -688,21 +690,21 @@ def set_id(self, ident): self.set_layer(layer) self.set_name(name) - def set_name(self, name): + def set_name(self, name) -> None: """Set the name of the dataset :param name: The name of the dataset """ self.D["name"] = name - def set_mapset(self, mapset): + def set_mapset(self, mapset) -> None: """Set the mapset of the dataset :param mapset: The name of the mapset in which this dataset is stored """ self.D["mapset"] = mapset - def set_layer(self, layer): + def set_layer(self, layer) -> None: """Convenient method to set the layer of the map (part of primary key) Layer are supported for vector maps @@ -711,14 +713,14 @@ def set_layer(self, layer): """ self.D["layer"] = layer - def set_creator(self, creator): + def set_creator(self, creator) -> None: """Set the creator of the dataset :param creator: The name of the creator """ self.D["creator"] = creator - def set_ctime(self, ctime=None): + def set_ctime(self, ctime=None) -> None: """Set the creation time of the dataset, if nothing set the current time is used @@ -729,7 +731,7 @@ def set_ctime(self, ctime=None): else: self.D["creation_time"] = ctime - def set_ttype(self, ttype): + def set_ttype(self, ttype) -> None: """Set the temporal type of the dataset: absolute or relative, if nothing set absolute time will assumed @@ -818,7 +820,7 @@ def get_ttype(self): ttype = property(fget=get_ttype, fset=set_ttype) creator = property(fget=get_creator, fset=set_creator) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( @@ -833,7 +835,7 @@ def print_info(self): print(" | Temporal type: ............. " + str(self.get_ttype())) print(" | Creation time: ............. " + str(self.get_ctime())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" print("id=" + str(self.get_id())) print("name=" + str(self.get_name())) @@ -854,12 +856,12 @@ class RasterBase(DatasetBase): def __init__( self, ident=None, - name=None, + name: str | None = None, mapset=None, creator=None, creation_time=None, temporal_type=None, - ): + ) -> None: DatasetBase.__init__( self, "raster_base", @@ -878,12 +880,12 @@ class Raster3DBase(DatasetBase): def __init__( self, ident=None, - name=None, + name: str | None = None, mapset=None, creator=None, creation_time=None, temporal_type=None, - ): + ) -> None: DatasetBase.__init__( self, "raster3d_base", @@ -902,13 +904,13 @@ class VectorBase(DatasetBase): def __init__( self, ident=None, - name=None, + name: str | None = None, mapset=None, layer=None, creator=None, creation_time=None, temporal_type=None, - ): + ) -> None: DatasetBase.__init__( self, "vector_base", @@ -984,24 +986,24 @@ def __init__( self, table=None, ident=None, - name=None, + name: str | None = None, mapset=None, semantic_type=None, creator=None, ctime=None, ttype=None, mtime=None, - ): + ) -> None: DatasetBase.__init__(self, table, ident, name, mapset, creator, ctime, ttype) self.set_semantic_type(semantic_type) self.set_mtime(mtime) - def set_semantic_type(self, semantic_type): + def set_semantic_type(self, semantic_type) -> None: """Set the semantic type of the space time dataset""" self.D["semantic_type"] = semantic_type - def set_mtime(self, mtime=None): + def set_mtime(self, mtime=None) -> None: """Set the modification time of the space time dataset, if nothing set the current time is used """ @@ -1030,14 +1032,14 @@ def get_mtime(self): semantic_type = property(fget=get_semantic_type, fset=set_semantic_type) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" DatasetBase.print_info(self) # 0123456789012345678901234567890 print(" | Modification time:.......... " + str(self.get_mtime())) print(" | Semantic type:.............. " + str(self.get_semantic_type())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" DatasetBase.print_shell_info(self) print("modification_time='{}'".format(str(self.get_mtime()))) @@ -1053,13 +1055,13 @@ class STRDSBase(STDSBase): def __init__( self, ident=None, - name=None, + name: str | None = None, mapset=None, semantic_type=None, creator=None, ctime=None, ttype=None, - ): + ) -> None: STDSBase.__init__( self, "strds_base", @@ -1079,13 +1081,13 @@ class STR3DSBase(STDSBase): def __init__( self, ident=None, - name=None, + name: str | None = None, mapset=None, semantic_type=None, creator=None, ctime=None, ttype=None, - ): + ) -> None: STDSBase.__init__( self, "str3ds_base", @@ -1105,13 +1107,13 @@ class STVDSBase(STDSBase): def __init__( self, ident=None, - name=None, + name: str | None = None, mapset=None, semantic_type=None, creator=None, ctime=None, ttype=None, - ): + ) -> None: STDSBase.__init__( self, "stvds_base", @@ -1145,7 +1147,7 @@ class AbstractSTDSRegister(SQLDatabaseInterface): """ - def __init__(self, table=None, ident=None, registered_stds=None): + def __init__(self, table=None, ident=None, registered_stds=None) -> None: """Constructor :param table: The name of the temporal database table @@ -1162,7 +1164,7 @@ def __init__(self, table=None, ident=None, registered_stds=None): self.set_id(ident) self.set_registered_stds(registered_stds) - def set_id(self, ident): + def set_id(self, ident) -> None: """Convenient method to set the unique identifier (primary key) :param ident: The unique identifier must be a combination @@ -1172,7 +1174,7 @@ def set_id(self, ident): self.ident = ident self.D["id"] = ident - def set_registered_stds(self, registered_stds): + def set_registered_stds(self, registered_stds) -> None: """Get the comma separated list of space time datasets ids in which this map is registered @@ -1211,7 +1213,7 @@ def get_registered_stds(self): class RasterSTDSRegister(AbstractSTDSRegister): """Time stamped raster map base information class""" - def __init__(self, ident=None, registered_stds=None): + def __init__(self, ident=None, registered_stds=None) -> None: AbstractSTDSRegister.__init__( self, "raster_stds_register", ident, registered_stds ) @@ -1220,7 +1222,7 @@ def __init__(self, ident=None, registered_stds=None): class Raster3DSTDSRegister(AbstractSTDSRegister): """Time stamped 3D raster map base information class""" - def __init__(self, ident=None, registered_stds=None): + def __init__(self, ident=None, registered_stds=None) -> None: AbstractSTDSRegister.__init__( self, "raster3d_stds_register", ident, registered_stds ) @@ -1229,7 +1231,7 @@ def __init__(self, ident=None, registered_stds=None): class VectorSTDSRegister(AbstractSTDSRegister): """Time stamped vector map base information class""" - def __init__(self, ident=None, registered_stds=None): + def __init__(self, ident=None, registered_stds=None) -> None: AbstractSTDSRegister.__init__( self, "vector_stds_register", ident, registered_stds ) diff --git a/python/grass/temporal/c_libraries_interface.py b/python/grass/temporal/c_libraries_interface.py index 85a19a3ec6e..5ac75f6b139 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,13 @@ 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 + + +logger = logging.getLogger(__name__) + ############################################################################### @@ -63,12 +73,13 @@ class RPCDefs: ############################################################################### -def _read_map_full_info(lock, conn, data): +def _read_map_full_info(lock: _LockLike, conn: Connection, data) -> None: """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 +201,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) -> None: """Calls G_fatal_error()""" libgis.G_fatal_error("Fatal Error in C library server") @@ -198,11 +209,12 @@ def _fatal_error(lock, conn, data): ############################################################################### -def _get_mapset(lock, conn, data): +def _get_mapset(lock: _LockLike, conn: Connection, data) -> None: """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 +226,12 @@ def _get_mapset(lock, conn, data): ############################################################################### -def _get_location(lock, conn, data): +def _get_location(lock: _LockLike, conn: Connection, data) -> None: """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 +243,12 @@ def _get_location(lock, conn, data): ############################################################################### -def _get_gisdbase(lock, conn, data): +def _get_gisdbase(lock: _LockLike, conn: Connection, data) -> None: """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,21 +260,18 @@ def _get_gisdbase(lock, conn, data): ############################################################################### -def _get_driver_name(lock, conn, data): +def _get_driver_name(lock: _LockLike, conn: Connection, data) -> None: """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 """ mapset = data[1] - if not mapset: - mapset = libgis.G_mapset() - else: - mapset = encode(mapset) - + mapset = libgis.G_mapset() if not mapset else encode(mapset) drstring = libtgis.tgis_get_mapset_driver_name(mapset) conn.send(decode(drstring.data)) @@ -268,11 +279,12 @@ def _get_driver_name(lock, conn, data): ############################################################################### -def _get_database_name(lock, conn, data): +def _get_database_name(lock: _LockLike, conn: Connection, data) -> None: """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 @@ -280,10 +292,7 @@ def _get_database_name(lock, conn, data): dbstring = None try: mapset = data[1] - if not mapset: - mapset = libgis.G_mapset() - else: - mapset = encode(mapset) + mapset = libgis.G_mapset() if not mapset else encode(mapset) dbstring = libtgis.tgis_get_mapset_database_name(mapset) dbstring = dbstring.data @@ -300,11 +309,12 @@ def _get_database_name(lock, conn, data): ############################################################################### -def _available_mapsets(lock, conn, data): +def _available_mapsets(lock: _LockLike, conn: Connection, data) -> None: """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 @@ -356,12 +366,13 @@ def _available_mapsets(lock, conn, data): ############################################################################### -def _has_timestamp(lock, conn, data): +def _has_timestamp(lock: _LockLike, conn: Connection, data) -> None: """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] @@ -388,7 +399,7 @@ def _has_timestamp(lock, conn, data): ############################################################################### -def _read_timestamp(lock, conn, data): +def _read_timestamp(lock: _LockLike, conn: Connection, data) -> None: """Read the file based GRASS timestamp and send the result using the provided pipe. @@ -408,7 +419,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] @@ -436,7 +448,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. @@ -447,7 +459,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] """ @@ -462,8 +475,9 @@ def _write_timestamp(lock, conn, data): check = libgis.G_scan_timestamp(byref(ts), timestring) if check != 1: - logging.error( - "Unable to convert the timestamp: {timestring}", timestring=timestring + logger.error( + "Unable to convert the timestamp: %(timestring)s", + {"timestring": timestring}, ) return -2 @@ -480,7 +494,7 @@ def _write_timestamp(lock, conn, data): ############################################################################### -def _remove_timestamp(lock, conn, data): +def _remove_timestamp(lock: _LockLike, conn: Connection, data) -> None: """Remove the file based GRASS timestamp the return values of the called C-functions using the provided pipe. @@ -491,7 +505,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] @@ -515,7 +530,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. @@ -523,7 +538,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] @@ -542,9 +558,9 @@ def _read_semantic_label(lock, conn, data): if ret: semantic_label = decode(ret) else: - logging.error( - "Unable to read semantic label. Unsupported map type {maptype}", - maptype=maptype, + logger.error( + "Unable to read semantic label. Unsupported map type %(maptype)s", + {"maptype": maptype}, ) return -1 finally: @@ -554,14 +570,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] @@ -578,9 +595,9 @@ def _write_semantic_label(lock, conn, data): raise ValueError(_("Invalid semantic label")) libraster.Rast_write_semantic_label(name, semantic_label) else: - logging.error( - "Unable to write semantic label. Unsupported map type {maptype}", - maptype=maptype, + logger.error( + "Unable to write semantic label. Unsupported map type %(maptype)s", + {"maptype": maptype}, ) return -2 finally: @@ -590,13 +607,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] @@ -611,9 +629,9 @@ def _remove_semantic_label(lock, conn, data): if maptype == RPCDefs.TYPE_RASTER: check = libgis.G_remove_misc("cell_misc", "semantic_label", name) else: - logging.error( - "Unable to remove semantic label. Unsupported map type {maptype}", - maptype=maptype, + logger.error( + "Unable to remove semantic label. Unsupported map type %(maptype)s", + {"maptype": maptype}, ) return -2 finally: @@ -623,14 +641,15 @@ def _remove_semantic_label(lock, conn, data): ############################################################################### -def _map_exists(lock, conn, data): +def _map_exists(lock: _LockLike, conn: Connection, data) -> None: """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] """ @@ -655,12 +674,13 @@ def _map_exists(lock, conn, data): ############################################################################### -def _read_map_info(lock, conn, data): +def _read_map_info(lock: _LockLike, conn: Connection, data) -> None: """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 @@ -727,11 +747,11 @@ def _read_raster_info(name, mapset): libraster.Rast_init_fp_range(byref(range)) ret = libraster.Rast_read_fp_range(name, mapset, byref(range)) if ret < 0: - logging.warning(_("Unable to read range file")) + logger.warning(_("Unable to read range file")) kvp["min"] = None kvp["max"] = None elif ret == 2: - logging.info(_("Raster range file is empty")) + logger.info(_("Raster range file is empty")) kvp["min"] = None kvp["max"] = None else: @@ -745,11 +765,11 @@ def _read_raster_info(name, mapset): libraster.Rast_init_range(byref(range)) ret = libraster.Rast_read_range(name, mapset, byref(range)) if ret < 0: - logging.warning(_("Unable to read range file")) + logger.warning(_("Unable to read range file")) kvp["min"] = None kvp["max"] = None elif ret == 2: - logging.info(_("Raster range file is empty")) + logger.info(_("Raster range file is empty")) kvp["min"] = None kvp["max"] = None else: @@ -815,7 +835,7 @@ def _read_raster3d_info(name, mapset): ) if not g3map: - logging.error(_("Unable to open 3D raster map <%s>"), (name)) + logger.error(_("Unable to open 3D raster map <%s>"), name) return None maptype = libraster3d.Rast3d_file_type_map(g3map) @@ -830,7 +850,7 @@ def _read_raster3d_info(name, mapset): max = libgis.DCELL() ret = libraster3d.Rast3d_range_load(g3map) if not ret: - logging.error(_("Unable to load range of 3D raster map <%s>"), (name)) + logger.error(_("Unable to load range of 3D raster map <%s>"), name) return None libraster3d.Rast3d_range_min_max(g3map, byref(min), byref(max)) @@ -844,7 +864,7 @@ def _read_raster3d_info(name, mapset): kvp["max"] = float(max.value) if not libraster3d.Rast3d_close(g3map): - logging.error(_("Unable to close 3D raster map <%s>"), (name)) + logger.error(_("Unable to close 3D raster map <%s>"), name) return None return kvp @@ -886,9 +906,9 @@ def _read_vector_info(name, mapset): libvector.Vect_set_open_level(1) # no topology with_topo = False if libvector.Vect_open_old2(byref(Map), name, mapset, "1") < 1: - logging.error( + logger.error( _("Unable to open vector map <%s>"), - (libvector.Vect_get_full_name(byref(Map))), + libvector.Vect_get_full_name(byref(Map)), ) return None @@ -962,11 +982,12 @@ def _read_vector_info(name, mapset): ############################################################################### -def _read_map_history(lock, conn, data): +def _read_map_history(lock: _LockLike, conn: Connection, data) -> None: """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 @@ -1009,7 +1030,7 @@ def _read_raster_history(name, mapset): hist = libraster.History() ret = libraster.Rast_read_history(name, mapset, byref(hist)) if ret < 0: - logging.warning(_("Unable to read history file")) + logger.warning(_("Unable to read history file")) return None kvp["creation_time"] = decode( libraster.Rast_get_history(byref(hist), libraster.HIST_MAPID) @@ -1046,7 +1067,7 @@ def _read_raster3d_history(name, mapset): hist = libraster.History() ret = libraster3d.Rast3d_read_history(name, mapset, byref(hist)) if ret < 0: - logging.warning(_("Unable to read history file")) + logger.warning(_("Unable to read history file")) return None kvp["creation_time"] = decode( libraster.Rast_get_history(byref(hist), libraster3d.HIST_MAPID) @@ -1181,7 +1202,7 @@ def _convert_timestamp_from_grass(ts): ############################################################################### -def _stop(lock, conn, data): +def _stop(lock: _LockLike, conn: Connection, data) -> None: libgis.G_debug(1, "Stop C-interface server") conn.close() lock.release() @@ -1191,15 +1212,16 @@ def _stop(lock, conn, data): ############################################################################### -def c_library_server(lock, conn): +def c_library_server(lock: _LockLike, conn: Connection) -> None: """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): + def error_handler(data) -> None: """This function will be called in case of a fatal error in libgis""" # sys.stderr.write("Error handler was called\n") # We send an exception that will be handled in @@ -1246,9 +1268,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): @@ -1473,10 +1494,10 @@ class CLibrariesInterface(RPCServerBase): """ # noqa: E501 - def __init__(self): + def __init__(self) -> None: RPCServerBase.__init__(self) - def start_server(self): + def start_server(self) -> None: self.client_conn, self.server_conn = Pipe(True) self.lock = Lock() self.server = Process( diff --git a/python/grass/temporal/core.py b/python/grass/temporal/core.py index bd2c91564d5..316142238ed 100644 --- a/python/grass/temporal/core.py +++ b/python/grass/temporal/core.py @@ -30,6 +30,8 @@ :author: Soeren Gebbert """ +from __future__ import annotations + # import traceback import os from pathlib import Path @@ -59,7 +61,7 @@ ############################################################################### -def profile_function(func): +def profile_function(func) -> None: """Profiling function provided by the temporal framework""" do_profiling = os.getenv("GRASS_TGIS_PROFILE") @@ -246,7 +248,7 @@ def get_enable_timestamp_write(): message_interface = None -def _init_tgis_message_interface(raise_on_error=False): +def _init_tgis_message_interface(raise_on_error: bool = False) -> None: """Initiate the global message interface :param raise_on_error: If True raise a FatalError exception in case of @@ -276,7 +278,7 @@ def get_tgis_message_interface(): c_library_interface = None -def _init_tgis_c_library_interface(): +def _init_tgis_c_library_interface() -> None: """Set the global C-library interface variable that provides a fast and exit safe interface to the C-library libgis, libraster, libraster3d and libvector functions @@ -302,7 +304,7 @@ def get_tgis_c_library_interface(): raise_on_error = False -def set_raise_on_error(raise_exp=True): +def set_raise_on_error(raise_exp: bool = True): """Define behavior on fatal error, invoked using the tgis messenger interface (msgr.fatal()) @@ -451,7 +453,7 @@ def get_sql_template_path(): ############################################################################### -def stop_subprocesses(): +def stop_subprocesses() -> None: """Stop the messenger and C-interface subprocesses that are started by tgis.init() """ @@ -512,7 +514,7 @@ def get_available_temporal_mapsets(): ############################################################################### -def init(raise_fatal_error=False, skip_db_version_check=False): +def init(raise_fatal_error: bool = False, skip_db_version_check: bool = False): """This function set the correct database backend from GRASS environmental variables and creates the grass temporal database structure for raster, vector and raster3d maps as well as for the space-time datasets strds, @@ -807,7 +809,7 @@ def get_database_info_string(): ############################################################################### -def _create_temporal_database_views(dbif): +def _create_temporal_database_views(dbif) -> None: """Create all views in the temporal database (internal use only) Used by create_temporal_database() and upgrade_temporal_database(). @@ -828,7 +830,7 @@ def _create_temporal_database_views(dbif): dbif.execute_transaction(sql_filepath) -def create_temporal_database(dbif): +def create_temporal_database(dbif) -> None: """This function will create the temporal database It will create all tables and triggers that are needed to run @@ -935,7 +937,7 @@ def create_temporal_database(dbif): ############################################################################### -def upgrade_temporal_database(dbif): +def upgrade_temporal_database(dbif) -> None: """This function will upgrade the temporal database if needed. It will update all tables and triggers that are requested by @@ -998,7 +1000,7 @@ def upgrade_temporal_database(dbif): ############################################################################### -def _create_tgis_metadata_table(content, dbif=None): +def _create_tgis_metadata_table(content, dbif=None) -> None: """!Create the temporal gis metadata table which stores all metadata information about the temporal database. @@ -1025,7 +1027,7 @@ def _create_tgis_metadata_table(content, dbif=None): class SQLDatabaseInterfaceConnection: - def __init__(self): + def __init__(self) -> None: self.tgis_mapsets = get_available_temporal_mapsets() self.current_mapset = get_current_mapset() self.connections = {} @@ -1052,7 +1054,7 @@ def get_dbmi(self, mapset=None): mapset = decode(mapset) return self.connections[mapset].dbmi - def rollback(self, mapset=None): + def rollback(self, mapset=None) -> None: """ Roll back the last transaction. This must be called in case a new query should be performed after a db error. @@ -1062,7 +1064,7 @@ def rollback(self, mapset=None): if mapset is None: mapset = self.current_mapset - def connect(self): + def connect(self) -> None: """Connect to the DBMI to execute SQL statements Supported backends are sqlite3 and postgresql @@ -1078,7 +1080,7 @@ def connect(self): def is_connected(self): return self.connected - def close(self): + def close(self) -> None: """Close the DBMI connection There may be several temporal databases in a location, hence @@ -1114,7 +1116,7 @@ def mogrify_sql_statement(self, content, mapset=None): return self.connections[mapset].mogrify_sql_statement(content) - def check_table(self, table_name, mapset=None): + def check_table(self, table_name: str, mapset=None): """Check if a table exists in the temporal database :param table_name: The name of the table to be checked for existence @@ -1205,7 +1207,7 @@ def execute_transaction(self, statement, mapset=None): return self.connections[mapset].execute_transaction(statement) - def _create_mapset_error_message(self, mapset): + def _create_mapset_error_message(self, mapset) -> str: return ( "You have no permission to " "access mapset <%(mapset)s>, or " @@ -1228,7 +1230,7 @@ class DBConnection: - postgresql via psycopg2 """ - def __init__(self, backend=None, dbstring=None): + def __init__(self, backend=None, dbstring: str | None = None) -> None: """Constructor of a database connection param backend:The database backend sqlite or pg @@ -1261,14 +1263,14 @@ def __init__(self, backend=None, dbstring=None): "\n dbstring: %s" % (backend, self.dbstring), ) - def __del__(self): + def __del__(self) -> None: if self.connected is True: self.close() def is_connected(self): return self.connected - def rollback(self): + def rollback(self) -> None: """ Roll back the last transaction. This must be called in case a new query should be performed after a db error. @@ -1279,7 +1281,7 @@ def rollback(self): if self.connected: self.connection.rollback() - def connect(self, dbstring=None): + def connect(self, dbstring: str | None = None) -> None: """Connect to the DBMI to execute SQL statements Supported backends are sqlite3 and postgresql @@ -1328,7 +1330,7 @@ def connect(self, dbstring=None): ) ) - def close(self): + def close(self) -> None: """Close the DBMI connection TODO: There may be several temporal databases in a location, hence @@ -1442,7 +1444,7 @@ def mogrify_sql_statement(self, content): return statement - def check_table(self, table_name): + def check_table(self, table_name: str): """Check if a table exists in the temporal database :param table_name: The name of the table to be checked for existence diff --git a/python/grass/temporal/datetime_math.py b/python/grass/temporal/datetime_math.py index a174fc5830a..75518512c5f 100644 --- a/python/grass/temporal/datetime_math.py +++ b/python/grass/temporal/datetime_math.py @@ -9,6 +9,8 @@ :authors: Soeren Gebbert """ +from __future__ import annotations + import copy from datetime import datetime, timedelta @@ -25,53 +27,29 @@ DAY_IN_SECONDS = 86400 SECOND_AS_DAY = 1.1574074074074073e-05 -############################################################################### - - -def relative_time_to_time_delta(value): - """Convert the double value representing days - into a timedelta object. - """ +def relative_time_to_time_delta(value: float) -> timedelta: + """Convert the double value representing days into a timedelta object.""" days = int(value) seconds = value % 1 seconds = round(seconds * DAY_IN_SECONDS) - return timedelta(days, seconds) -############################################################################### - - -def time_delta_to_relative_time(delta): - """Convert the time delta into a - double value, representing days. - """ - +def time_delta_to_relative_time(delta: timedelta) -> float: + """Convert the time delta into a double value, representing days.""" return float(delta.days) + float(delta.seconds * SECOND_AS_DAY) -############################################################################### - - -def relative_time_to_time_delta_seconds(value): - """Convert the double value representing seconds - into a timedelta object. - """ - +def relative_time_to_time_delta_seconds(value: float) -> timedelta: + """Convert the double value representing seconds into a timedelta object.""" days = value / 86400 seconds = int(value % 86400) - return timedelta(days, seconds) -############################################################################### - - -def time_delta_to_relative_time_seconds(delta): - """Convert the time delta into a - double value, representing seconds. - """ +def time_delta_to_relative_time_seconds(delta: timedelta) -> float: + """Convert the time delta into a double value, representing seconds.""" return float(delta.days * DAY_IN_SECONDS) + float(delta.seconds) @@ -79,7 +57,9 @@ def time_delta_to_relative_time_seconds(delta): ############################################################################### -def decrement_datetime_by_string(mydate, increment, mult=1): +def decrement_datetime_by_string( + mydate: datetime, increment: str, mult=1 +) -> datetime | None: """Return a new datetime object decremented with the provided relative dates specified as string. Additional a multiplier can be specified to multiply the increment @@ -144,10 +124,9 @@ def decrement_datetime_by_string(mydate, increment, mult=1): return modify_datetime_by_string(mydate, increment, mult, sign=-1) -############################################################################### - - -def increment_datetime_by_string(mydate, increment, mult=1): +def increment_datetime_by_string( + mydate: datetime, increment: str, mult=1 +) -> datetime | None: """Return a new datetime object incremented with the provided relative dates specified as string. Additional a multiplier can be specified to multiply the increment @@ -219,10 +198,9 @@ def increment_datetime_by_string(mydate, increment, mult=1): return modify_datetime_by_string(mydate, increment, mult, sign=1) -############################################################################### - - -def modify_datetime_by_string(mydate, increment, mult=1, sign=1): +def modify_datetime_by_string( + mydate: datetime, increment: str, mult=1, sign: int = 1 +) -> datetime | None: """Return a new datetime object incremented with the provided relative dates specified as string. Additional a multiplier can be specified to multiply the increment @@ -294,8 +272,8 @@ def modify_datetime_by_string(mydate, increment, mult=1, sign=1): def modify_datetime( - mydate, years=0, months=0, weeks=0, days=0, hours=0, minutes=0, seconds=0 -): + mydate: datetime, years=0, months=0, weeks=0, days=0, hours=0, minutes=0, seconds=0 +) -> datetime: """Return a new datetime object incremented with the provided relative dates and times""" @@ -373,7 +351,7 @@ def modify_datetime( ############################################################################### -def adjust_datetime_to_granularity(mydate, granularity): +def adjust_datetime_to_granularity(mydate: datetime, granularity): """Modify the datetime object to fit the given granularity - Years will start at the first of January @@ -694,10 +672,7 @@ def compute_datetime_delta(start, end): else: d += 24 * 60 * day_diff elif d == 0: - if comp["hour"]: - d = 60 * comp["hour"] - else: - d = 24 * 60 * day_diff + d = 60 * comp["hour"] if comp["hour"] else 24 * 60 * day_diff comp["minute"] = d @@ -725,13 +700,10 @@ def compute_datetime_delta(start, end): return comp -############################################################################### - - -def check_datetime_string(time_string, use_dateutil=True): +def check_datetime_string(time_string: str, use_dateutil: bool = True): """Check if a string can be converted into a datetime object and return the object - In case datutil is not installed the supported ISO string formats are: + In case dateutil is not installed the supported ISO string formats are: - YYYY-mm-dd - YYYY-mm-dd HH:MM:SS @@ -831,10 +803,7 @@ def check_datetime_string(time_string, use_dateutil=True): return _("Unable to parse time string: %s") % time_string -############################################################################### - - -def string_to_datetime(time_string): +def string_to_datetime(time_string: str) -> datetime | None: """Convert a string into a datetime object In case datutil is not installed the supported ISO string formats are: @@ -867,10 +836,7 @@ def string_to_datetime(time_string): return time_object -############################################################################### - - -def datetime_to_grass_datetime_string(dt): +def datetime_to_grass_datetime_string(dt: datetime) -> str: """Convert a python datetime object into a GRASS datetime string .. code-block:: python @@ -914,10 +880,7 @@ def datetime_to_grass_datetime_string(dt): # Check for time zone info in the datetime object if dt.tzinfo is not None: tz = dt.tzinfo.utcoffset(0) - if tz.seconds > 86400 / 2: - tz = (tz.seconds - 86400) / 60 - else: - tz = tz.seconds / 60 + tz = (tz.seconds - 86400) / 60 if tz.seconds > 86400 / 2 else tz.seconds / 60 string = "%.2i %s %.2i %.2i:%.2i:%.2i %+.4i" % ( dt.day, @@ -942,6 +905,8 @@ def datetime_to_grass_datetime_string(dt): ############################################################################### + + suffix_units = { "years": "%Y", "year": "%Y", @@ -958,7 +923,7 @@ def datetime_to_grass_datetime_string(dt): } -def create_suffix_from_datetime(start_time, granularity): +def create_suffix_from_datetime(start_time: datetime, granularity) -> str: """Create a datetime string based on a datetime object and a provided granularity that can be used as suffix for map names. @@ -972,7 +937,7 @@ def create_suffix_from_datetime(start_time, granularity): return start_time.strftime(suffix_units[granularity.split(" ")[1]]) -def create_time_suffix(mapp, end=False): +def create_time_suffix(mapp, end: bool = False): """Create a datetime string based on a map datetime object :param mapp: a temporal map dataset @@ -987,7 +952,7 @@ def create_time_suffix(mapp, end=False): return sstring -def create_numeric_suffix(base, count, zeros): +def create_numeric_suffix(base, count: int, zeros: str) -> str: """Create a string based on count and number of zeros decided by zeros :param base: the basename for new map @@ -999,10 +964,7 @@ def create_numeric_suffix(base, count, zeros): if len(spli) == 2: suff = spli[1] if suff.isdigit(): - if int(suff[0]) == 0: - zero = suff - else: - zero = "0{nu}".format(nu=suff) + zero = suff if int(suff[0]) == 0 else "0{nu}".format(nu=suff) else: zero = "05" else: diff --git a/python/grass/temporal/extract.py b/python/grass/temporal/extract.py index 94a4fd0f1c9..aab18c5dd76 100644 --- a/python/grass/temporal/extract.py +++ b/python/grass/temporal/extract.py @@ -39,11 +39,11 @@ def extract_dataset( expression, base, time_suffix, - nprocs=1, - register_null=False, - layer=1, + nprocs: int = 1, + register_null: bool = False, + layer: int = 1, vtype="point,line,boundary,centroid,area,face", -): +) -> None: """Extract a subset of a space time raster, raster3d or vector dataset A mapcalc expression can be provided to process the temporal extracted @@ -318,7 +318,7 @@ def extract_dataset( ############################################################################### -def run_mapcalc2d(expr): +def run_mapcalc2d(expr) -> None: """Helper function to run r.mapcalc in parallel""" try: gs.run_command( @@ -328,7 +328,7 @@ def run_mapcalc2d(expr): sys.exit(1) -def run_mapcalc3d(expr): +def run_mapcalc3d(expr) -> None: """Helper function to run r3.mapcalc in parallel""" try: gs.run_command( @@ -338,7 +338,7 @@ def run_mapcalc3d(expr): sys.exit(1) -def run_vector_extraction(input, output, layer, type, where): +def run_vector_extraction(input, output, layer, type, where) -> None: """Helper function to run r.mapcalc in parallel""" try: gs.run_command( diff --git a/python/grass/temporal/factory.py b/python/grass/temporal/factory.py index ba7f5e7d4f0..f246700ef44 100644 --- a/python/grass/temporal/factory.py +++ b/python/grass/temporal/factory.py @@ -1,23 +1,18 @@ """ Object factory -Usage: - -.. code-block:: python - - import grass.temporal as tgis - - tgis.register_maps_in_space_time_dataset(type, name, maps) - - -(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. -:authors: Soeren Gebbert +:authors: Soeren Gebbert, Edouard Choinière """ +from __future__ import annotations + +from typing import Literal, overload + from .core import get_tgis_message_interface from .space_time_datasets import ( Raster3DDataset, @@ -31,7 +26,65 @@ ############################################################################### -def dataset_factory(type, id): +@overload +def dataset_factory(type: Literal["strds"], id: str) -> SpaceTimeRasterDataset: + pass + + +@overload +def dataset_factory(type: Literal["str3ds"], id: str) -> SpaceTimeRaster3DDataset: + pass + + +@overload +def dataset_factory(type: Literal["stvds"], id: str) -> SpaceTimeVectorDataset: + pass + + +@overload +def dataset_factory(type: Literal["rast", "raster"], id: str) -> RasterDataset: + pass + + +@overload +def dataset_factory( + type: Literal["raster_3d", "rast3d", "raster3d"], + id: str, +) -> Raster3DDataset: + pass + + +@overload +def dataset_factory(type: Literal["vect", "vector"], id: str) -> VectorDataset: + pass + + +@overload +def dataset_factory( + type: str, id: str +) -> ( + SpaceTimeRasterDataset + | SpaceTimeRaster3DDataset + | SpaceTimeVectorDataset + | RasterDataset + | Raster3DDataset + | VectorDataset + | None +): + pass + + +def dataset_factory( + type: str, id: str | None +) -> ( + SpaceTimeRasterDataset + | SpaceTimeRaster3DDataset + | SpaceTimeVectorDataset + | RasterDataset + | Raster3DDataset + | VectorDataset + | None +): """A factory functions to create space time or map datasets :param type: the dataset type: rast or raster; rast3d, raster3d or raster_3d; @@ -39,20 +92,18 @@ def dataset_factory(type, id): :param id: The id of the dataset ("name@mapset") """ if type == "strds": - sp = SpaceTimeRasterDataset(id) - elif type == "str3ds": - sp = SpaceTimeRaster3DDataset(id) - elif type == "stvds": - sp = SpaceTimeVectorDataset(id) - elif type in {"rast", "raster"}: - sp = RasterDataset(id) - elif type in {"raster_3d", "rast3d", "raster3d"}: - sp = Raster3DDataset(id) - elif type in {"vect", "vector"}: - sp = VectorDataset(id) - else: - msgr = get_tgis_message_interface() - msgr.error(_("Unknown dataset type: %s") % type) - return None - - return sp + return SpaceTimeRasterDataset(id) + if type == "str3ds": + return SpaceTimeRaster3DDataset(id) + if type == "stvds": + return SpaceTimeVectorDataset(id) + if type in {"rast", "raster"}: + return RasterDataset(id) + if type in {"raster_3d", "rast3d", "raster3d"}: + return Raster3DDataset(id) + if type in {"vect", "vector"}: + return VectorDataset(id) + + msgr = get_tgis_message_interface() + msgr.error(_("Unknown dataset type: %s") % type) + return None diff --git a/python/grass/temporal/gui_support.py b/python/grass/temporal/gui_support.py index 41f22edc6b7..07097946652 100644 --- a/python/grass/temporal/gui_support.py +++ b/python/grass/temporal/gui_support.py @@ -18,7 +18,7 @@ ############################################################################### -def tlist_grouped(type, group_type=False, dbif=None): +def tlist_grouped(type, group_type: bool = False, dbif=None): """List of temporal elements grouped by mapsets. Returns a dictionary where the keys are mapset @@ -27,7 +27,7 @@ def tlist_grouped(type, group_type=False, dbif=None): .. code-block:: python - >>> import grass.temporalas tgis + >>> import grass.temporal as tgis >>> tgis.tlist_grouped('strds')['PERMANENT'] ['precipitation', 'temperature'] @@ -37,16 +37,14 @@ def tlist_grouped(type, group_type=False, dbif=None): :return: directory of mapsets/elements """ result = {} + type_ = type dbif, connection_state_changed = init_dbif(dbif) mapset = None - if type == "stds": - types = ["strds", "str3ds", "stvds"] - else: - types = [type] - for type in types: + types = ["strds", "str3ds", "stvds"] if type_ == "stds" else [type_] + for type_ in types: try: - tlist_result = tlist(type=type, dbif=dbif) + tlist_result = tlist(type=type_, dbif=dbif) except gs.ScriptError as e: gs.warning(e) continue @@ -65,10 +63,10 @@ def tlist_grouped(type, group_type=False, dbif=None): result[mapset] = [] if group_type: - if type in result[mapset]: - result[mapset][type].append(name) + if type_ in result[mapset]: + result[mapset][type_].append(name) else: - result[mapset][type] = [ + result[mapset][type_] = [ name, ] else: @@ -90,19 +88,20 @@ def tlist(type, dbif=None): :return: a list of space time dataset ids """ + type_ = type id = None - sp = dataset_factory(type, id) + sp = dataset_factory(type_, id) dbif, connection_state_changed = init_dbif(dbif) mapsets = get_available_temporal_mapsets() output = [] temporal_type = ["absolute", "relative"] - for type in temporal_type: + for type_ in temporal_type: # For each available mapset for mapset in mapsets.keys(): # Table name - if type == "absolute": + if type_ == "absolute": table = sp.get_type() + "_view_abs_time" else: table = sp.get_type() + "_view_rel_time" diff --git a/python/grass/temporal/list_stds.py b/python/grass/temporal/list_stds.py index 9f6b6867766..ea01bfb5607 100644 --- a/python/grass/temporal/list_stds.py +++ b/python/grass/temporal/list_stds.py @@ -150,7 +150,7 @@ def _open_output_file(file, encoding="utf-8", **kwargs): yield stream -def _write_line(items, separator, file): +def _write_line(items, separator, file) -> None: if not separator: separator = "," output = separator.join([f"{item}" for item in items]) @@ -158,8 +158,8 @@ def _write_line(items, separator, file): print(f"{output}", file=stream) -def _write_plain(rows, header, separator, file): - def write_plain_row(items, separator, file): +def _write_plain(rows, header, separator, file) -> None: + def write_plain_row(items, separator, file) -> None: output = separator.join([f"{item}" for item in items]) print(f"{output}", file=file) @@ -171,7 +171,7 @@ def write_plain_row(items, separator, file): write_plain_row(items=row, separator=separator, file=stream) -def _write_json(rows, column_names, file): +def _write_json(rows, column_names, file) -> None: # Lazy import output format-specific dependencies. # pylint: disable=import-outside-toplevel import datetime @@ -197,7 +197,7 @@ def default(self, o): json.dump({"data": dict_rows, "metadata": meta}, stream, cls=ResultsEncoder) -def _write_yaml(rows, column_names, file=sys.stdout): +def _write_yaml(rows, column_names, file=sys.stdout) -> None: # Lazy import output format-specific dependencies. # pylint: disable=import-outside-toplevel import yaml @@ -213,10 +213,10 @@ class NoAliasIndentListSafeDumper(yaml.SafeDumper): when https://github.com/yaml/pyyaml/issues/234 is resolved. """ - def ignore_aliases(self, data): + def ignore_aliases(self, data) -> bool: return True - def increase_indent(self, flow=False, indentless=False): + def increase_indent(self, flow: bool = False, indentless: bool = False): return super().increase_indent(flow=flow, indentless=False) dict_rows = [] @@ -238,7 +238,7 @@ def increase_indent(self, flow=False, indentless=False): ) -def _write_csv(rows, column_names, separator, file=sys.stdout): +def _write_csv(rows, column_names, separator, file=sys.stdout) -> None: # Lazy import output format-specific dependencies. # pylint: disable=import-outside-toplevel import csv @@ -325,10 +325,7 @@ def _get_get_registered_maps_as_objects_delta_gran( msgr.fatal(_("Empty entry in map list, this should not happen")) start, end = map_object.get_temporal_extent_as_tuple() - if end: - delta = end - start - else: - delta = None + delta = end - start if end else None delta_first = start - first_time if map_object.is_time_absolute(): @@ -484,12 +481,12 @@ def list_maps_of_stds( where, separator, method, - no_header=False, + no_header: bool = False, gran=None, dbif=None, outpath=None, output_format=None, -): +) -> None: """List the maps of a space time dataset using different methods :param type: The type of the maps raster, raster3d or vector diff --git a/python/grass/temporal/mapcalc.py b/python/grass/temporal/mapcalc.py index 8761e86160f..b1dbb5ce2db 100644 --- a/python/grass/temporal/mapcalc.py +++ b/python/grass/temporal/mapcalc.py @@ -35,9 +35,9 @@ def dataset_mapcalculator( expression, base, method, - nprocs=1, - register_null=False, - spatial=False, + nprocs: int = 1, + register_null: bool = False, + spatial: bool = False, ): """Perform map-calculations of maps from different space time raster/raster3d datasets, using a specific sampling method @@ -408,7 +408,7 @@ def dataset_mapcalculator( ############################################################################### -def _run_mapcalc2d(expr): +def _run_mapcalc2d(expr) -> None: """Helper function to run r.mapcalc in parallel""" try: gs.run_command( @@ -421,7 +421,7 @@ def _run_mapcalc2d(expr): ############################################################################### -def _run_mapcalc3d(expr): +def _run_mapcalc3d(expr) -> None: """Helper function to run r3.mapcalc in parallel""" try: gs.run_command( @@ -487,7 +487,7 @@ def _operator_parser(expr, first, current): ############################################################################### -def _parse_start_operators(expr, is_time_absolute, current): +def _parse_start_operators(expr, is_time_absolute: bool, current): """ Supported operators for absolute time: - start_doy() - Day of year (doy) from the start time [1 - 366] @@ -586,7 +586,7 @@ def _parse_start_operators(expr, is_time_absolute, current): ############################################################################### -def _parse_end_operators(expr, is_time_absolute, current): +def _parse_end_operators(expr, is_time_absolute: bool, current): """ Supported operators for absolute time: - end_doy() - Day of year (doy) from the end time [1 - 366] @@ -706,7 +706,7 @@ def _parse_end_operators(expr, is_time_absolute, current): ############################################################################### -def _parse_td_operator(expr, is_time_absolute, first, current): +def _parse_td_operator(expr, is_time_absolute: bool, first, current): """Parse the time delta operator td(). This operator represents the size of the current sample time interval in days and fraction of days for absolute time, @@ -732,7 +732,7 @@ def _parse_td_operator(expr, is_time_absolute, first, current): ############################################################################### -def _parse_start_time_operator(expr, is_time_absolute, first, current): +def _parse_start_time_operator(expr, is_time_absolute: bool, first, current): """Parse the start_time() operator. This operator represent the time difference between the start time of the sample space time raster dataset and the start time of the current sample interval or @@ -755,7 +755,7 @@ def _parse_start_time_operator(expr, is_time_absolute, first, current): ############################################################################### -def _parse_end_time_operator(expr, is_time_absolute, first, current): +def _parse_end_time_operator(expr, is_time_absolute: bool, first, current): """Parse the end_time() operator. This operator represent the time difference between the start time of the sample space time raster dataset and the end time of the current sample interval. The time diff --git a/python/grass/temporal/metadata.py b/python/grass/temporal/metadata.py index 4be4c568a76..8c85141e6aa 100644 --- a/python/grass/temporal/metadata.py +++ b/python/grass/temporal/metadata.py @@ -97,7 +97,7 @@ def __init__( ewres=None, min=None, max=None, - ): + ) -> None: SQLDatabaseInterface.__init__(self, table, ident) self.set_id(ident) @@ -110,58 +110,58 @@ def __init__( self.set_min(min) self.set_max(max) - def set_id(self, ident): + def set_id(self, ident) -> None: """Convenient method to set the unique identifier (primary key)""" self.ident = ident self.D["id"] = ident - def set_datatype(self, datatype): + def set_datatype(self, datatype) -> None: """Set the datatype""" self.D["datatype"] = datatype - def set_cols(self, cols): + def set_cols(self, cols) -> None: """Set the number of cols""" if cols is not None: self.D["cols"] = int(cols) else: self.D["cols"] = None - def set_rows(self, rows): + def set_rows(self, rows) -> None: """Set the number of rows""" if rows is not None: self.D["rows"] = int(rows) else: self.D["rows"] = None - def set_number_of_cells(self, number_of_cells): + def set_number_of_cells(self, number_of_cells) -> None: """Set the number of cells""" if number_of_cells is not None: self.D["number_of_cells"] = int(number_of_cells) else: self.D["number_of_cells"] = None - def set_nsres(self, nsres): + def set_nsres(self, nsres) -> None: """Set the north-south resolution""" if nsres is not None: self.D["nsres"] = float(nsres) else: self.D["nsres"] = None - def set_ewres(self, ewres): + def set_ewres(self, ewres) -> None: """Set the east-west resolution""" if ewres is not None: self.D["ewres"] = float(ewres) else: self.D["ewres"] = None - def set_min(self, min): + def set_min(self, min) -> None: """Set the minimum raster value""" if min is not None: self.D["min"] = float(min) else: self.D["min"] = None - def set_max(self, max): + def set_max(self, max) -> None: """Set the maximum raster value""" if max is not None: self.D["max"] = float(max) @@ -242,15 +242,15 @@ def get_max(self): min = property(fget=get_min, fset=set_min) max = property(fget=get_max, fset=set_max) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" self._print_info_body(shell=False) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self._print_info_body(shell=True) - def _print_info_head(self, shell=False): + def _print_info_head(self, shell: bool = False) -> None: """Print information about this class (head part). No header printed in shell style mode. @@ -262,7 +262,7 @@ def _print_info_head(self, shell=False): " +-------------------- Metadata information ----------------------------------+" # noqa: E501 ) - def _print_info_body(self, shell=False): + def _print_info_body(self, shell: bool = False) -> None: """Print information about this class (body part). :param bool shell: True for human readable style otherwise shell style @@ -298,7 +298,7 @@ class RasterMetadata(RasterMetadataBase): The metadata includes the datatype, number of cols, rows and cells and the north-south and east west resolution of the map. Additionally the - minimum and maximum valuesare stored. + minimum and maximum values are stored. Usage: @@ -368,7 +368,7 @@ def __init__( min=None, max=None, semantic_label=None, - ): + ) -> None: RasterMetadataBase.__init__( self, "raster_metadata", @@ -383,7 +383,7 @@ def __init__( max, ) - def set_semantic_label(self, semantic_label): + def set_semantic_label(self, semantic_label) -> None: """Set the semantic label identifier""" self.D["semantic_label"] = semantic_label @@ -396,14 +396,14 @@ def get_semantic_label(self): semantic_label = property(fget=get_semantic_label, fset=set_semantic_label) - def print_info(self): + def print_info(self) -> None: """Print information about this class.""" self._print_info_head(shell=False) self._print_info_body(shell=False) # semantic label section (raster specific only) print(" | Semantic label:............. " + str(self.get_semantic_label())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self._print_info_head(shell=True) self._print_info_body(shell=True) @@ -502,7 +502,7 @@ def __init__( tbres=None, min=None, max=None, - ): + ) -> None: RasterMetadataBase.__init__( self, "raster3d_metadata", @@ -520,14 +520,14 @@ def __init__( self.set_tbres(tbres) self.set_depths(depths) - def set_depths(self, depths): + def set_depths(self, depths) -> None: """Set the number of depths""" if depths is not None: self.D["depths"] = int(depths) else: self.D["depths"] = None - def set_tbres(self, tbres): + def set_tbres(self, tbres) -> None: """Set the top-bottom resolution""" if tbres is not None: self.D["tbres"] = float(tbres) @@ -551,14 +551,14 @@ def get_tbres(self): depths = property(fget=get_depths, fset=set_depths) tbres = property(fget=get_tbres, fset=set_tbres) - def print_info(self): + def print_info(self) -> None: """Print information about this class.""" self._print_info_head(shell=False) self._print_info_body(shell=False) print(" | Number of depths:........... " + str(self.get_depths())) print(" | Top-Bottom resolution:...... " + str(self.get_tbres())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self._print_info_head(shell=True) self._print_info_body(shell=True) @@ -660,7 +660,7 @@ class VectorMetadata(SQLDatabaseInterface): def __init__( self, ident=None, - is_3d=False, + is_3d: bool = False, number_of_points=None, number_of_lines=None, number_of_boundaries=None, @@ -673,7 +673,7 @@ def __init__( number_of_islands=None, number_of_holes=None, number_of_volumes=None, - ): + ) -> None: SQLDatabaseInterface.__init__(self, "vector_metadata", ident) self.set_id(ident) @@ -691,60 +691,60 @@ def __init__( self.set_number_of_holes(number_of_holes) self.set_number_of_volumes(number_of_volumes) - def set_id(self, ident): + def set_id(self, ident) -> None: """Convenient method to set the unique identifier (primary key)""" self.ident = ident self.D["id"] = ident - def set_3d_info(self, is_3d): + def set_3d_info(self, is_3d) -> None: """Set True if the vector map is three dimensional""" self.D["is_3d"] = is_3d - def set_number_of_points(self, number_of_points): + def set_number_of_points(self, number_of_points) -> None: """Set the number of points of the vector map""" self.D["points"] = number_of_points - def set_number_of_lines(self, number_of_lines): + def set_number_of_lines(self, number_of_lines) -> None: """Set the number of lines of the vector map""" self.D["lines"] = number_of_lines - def set_number_of_boundaries(self, number_of_boundaries): + def set_number_of_boundaries(self, number_of_boundaries) -> None: """Set the number of boundaries of the vector map""" self.D["boundaries"] = number_of_boundaries - def set_number_of_centroids(self, number_of_centroids): + def set_number_of_centroids(self, number_of_centroids) -> None: """Set the number of centroids of the vector map""" self.D["centroids"] = number_of_centroids - def set_number_of_faces(self, number_of_faces): + def set_number_of_faces(self, number_of_faces) -> None: """Set the number of faces of the vector map""" self.D["faces"] = number_of_faces - def set_number_of_kernels(self, number_of_kernels): + def set_number_of_kernels(self, number_of_kernels) -> None: """Set the number of kernels of the vector map""" self.D["kernels"] = number_of_kernels - def set_number_of_primitives(self, number_of_primitives): + def set_number_of_primitives(self, number_of_primitives) -> None: """Set the number of primitives of the vector map""" self.D["primitives"] = number_of_primitives - def set_number_of_nodes(self, number_of_nodes): + def set_number_of_nodes(self, number_of_nodes) -> None: """Set the number of nodes of the vector map""" self.D["nodes"] = number_of_nodes - def set_number_of_areas(self, number_of_areas): + def set_number_of_areas(self, number_of_areas) -> None: """Set the number of areas of the vector map""" self.D["areas"] = number_of_areas - def set_number_of_islands(self, number_of_islands): + def set_number_of_islands(self, number_of_islands) -> None: """Set the number of islands of the vector map""" self.D["islands"] = number_of_islands - def set_number_of_holes(self, number_of_holes): + def set_number_of_holes(self, number_of_holes) -> None: """Set the number of holes of the vector map""" self.D["holes"] = number_of_holes - def set_number_of_volumes(self, number_of_volumes): + def set_number_of_volumes(self, number_of_volumes) -> None: """Set the number of volumes of the vector map""" self.D["volumes"] = number_of_volumes @@ -869,7 +869,7 @@ def get_number_of_volumes(self): number_of_holes = property(fget=get_number_of_holes, fset=set_number_of_holes) number_of_volumes = property(fget=get_number_of_volumes, fset=set_number_of_volumes) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" print( " +-------------------- Metadata information ----------------------------------+" # noqa: E501 @@ -888,7 +888,7 @@ def print_info(self): print(" | Number of holes ............ " + str(self.get_number_of_holes())) print(" | Number of volumes .......... " + str(self.get_number_of_volumes())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" print("is_3d=" + str(self.get_3d_info())) print("points=" + str(self.get_number_of_points())) @@ -943,7 +943,7 @@ class STDSMetadataBase(SQLDatabaseInterface): def __init__( self, table=None, ident=None, title=None, description=None, command=None - ): + ) -> None: SQLDatabaseInterface.__init__(self, table, ident) self.set_id(ident) @@ -953,20 +953,20 @@ def __init__( # No setter for this self.D["number_of_maps"] = None - def set_id(self, ident): + def set_id(self, ident) -> None: """Convenient method to set the unique identifier (primary key)""" self.ident = ident self.D["id"] = ident - def set_title(self, title): + def set_title(self, title) -> None: """Set the title""" self.D["title"] = title - def set_description(self, description): + def set_description(self, description) -> None: """Set the number of cols""" self.D["description"] = description - def set_command(self, command): + def set_command(self, command) -> None: """Set the number of cols""" self.D["command"] = command @@ -1013,17 +1013,17 @@ def get_number_of_maps(self): description = property(fget=get_description, fset=set_description) number_of_maps = property(fget=get_number_of_maps) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" self._print_info_body(shell=False) self._print_info_tail(shell=False) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self._print_info_body(shell=True) self._print_info_tail(shell=True) - def _print_info_head(self, shell=False): + def _print_info_head(self, shell: bool = False) -> None: """Print information about this class (head part). No header printed in shell style mode. @@ -1035,13 +1035,13 @@ def _print_info_head(self, shell=False): " +-------------------- Metadata information ----------------------------------+" # noqa: E501 ) - def _print_info_body(self, shell=False): + def _print_info_body(self, shell: bool = False) -> None: """Print information about this class (body part). :param bool shell: True for human readable style otherwise shell style """ - def _print_info_tail(self, shell=False): + def _print_info_tail(self, shell: bool = False) -> None: """Print information about this class (tail part). :param bool shell: True for human readable style otherwise shell style @@ -1061,7 +1061,7 @@ def _print_info_tail(self, shell=False): for token in command.split("\n"): print(" | " + str(token)) - def print_history(self): + def print_history(self) -> None: """Print history information about this class in human readable shell style """ @@ -1165,7 +1165,7 @@ def __init__( title=None, description=None, aggregation_type=None, - ): + ) -> None: STDSMetadataBase.__init__(self, table, ident, title, description) # Initialize the dict to select all values from the db @@ -1179,7 +1179,7 @@ def __init__( self.D["ewres_max"] = None self.D["aggregation_type"] = aggregation_type - def set_aggregation_type(self, aggregation_type): + def set_aggregation_type(self, aggregation_type) -> None: """Set the aggregation type of the dataset (mean, min, max, ...)""" self.D["aggregation_type"] = aggregation_type @@ -1273,7 +1273,7 @@ def get_ewres_max(self): max_max = property(fget=get_max_max) aggregation_type = property(fset=set_aggregation_type, fget=get_aggregation_type) - def _print_info_body(self, shell=False): + def _print_info_body(self, shell: bool = False) -> None: """Print information about this class (body part). :param bool shell: True for human readable style otherwise shell style @@ -1376,7 +1376,9 @@ class STRDSMetadata(STDSRasterMetadataBase): """ - def __init__(self, ident=None, raster_register=None, title=None, description=None): + def __init__( + self, ident=None, raster_register=None, title=None, description=None + ) -> None: STDSRasterMetadataBase.__init__( self, "strds_metadata", ident, title, description ) @@ -1386,7 +1388,7 @@ def __init__(self, ident=None, raster_register=None, title=None, description=Non self.set_raster_register(raster_register) - def set_raster_register(self, raster_register): + def set_raster_register(self, raster_register) -> None: """Set the raster map register table name""" self.D["raster_register"] = raster_register @@ -1448,17 +1450,17 @@ def get_semantic_labels(self): number_of_semantic_labels = property(fget=get_number_of_semantic_labels) semantic_labels = property(fget=get_semantic_labels) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" self._print_info_head(shell=False) super().print_info() - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self._print_info_head(shell=True) super().print_shell_info() - def _print_info_body(self, shell=False): + def _print_info_body(self, shell: bool = False) -> None: """Print information about this class (body part). :param bool shell: True for human readable style otherwise shell style @@ -1561,7 +1563,7 @@ class STR3DSMetadata(STDSRasterMetadataBase): def __init__( self, ident=None, raster3d_register=None, title=None, description=None - ): + ) -> None: STDSRasterMetadataBase.__init__( self, "str3ds_metadata", ident, title, description ) @@ -1570,7 +1572,7 @@ def __init__( self.D["tbres_min"] = None self.D["tbres_max"] = None - def set_raster3d_register(self, raster3d_register): + def set_raster3d_register(self, raster3d_register) -> None: """Set the raster map register table name""" self.D["raster3d_register"] = raster3d_register @@ -1603,17 +1605,17 @@ def get_tbres_max(self): tbres_min = property(fget=get_tbres_min) tbres_max = property(fget=get_tbres_max) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" self._print_info_head(shell=False) super().print_info() - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self._print_info_head(shell=True) super().print_shell_info() - def _print_info_body(self, shell=False): + def _print_info_body(self, shell: bool = False) -> None: """Print information about this class (body part). :param bool shell: True for human readable style otherwise shell style @@ -1714,7 +1716,9 @@ class STVDSMetadata(STDSMetadataBase): """ - def __init__(self, ident=None, vector_register=None, title=None, description=None): + def __init__( + self, ident=None, vector_register=None, title=None, description=None + ) -> None: STDSMetadataBase.__init__(self, "stvds_metadata", ident, title, description) self.set_vector_register(vector_register) @@ -1731,7 +1735,7 @@ def __init__(self, ident=None, vector_register=None, title=None, description=Non self.D["holes"] = None self.D["volumes"] = None - def set_vector_register(self, vector_register): + def set_vector_register(self, vector_register) -> None: """Set the vector map register table name""" self.D["vector_register"] = vector_register @@ -1865,17 +1869,17 @@ def get_number_of_volumes(self): number_of_holes = property(fget=get_number_of_holes) number_of_volumes = property(fget=get_number_of_volumes) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" self._print_info_head(shell=False) super().print_info() - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" self._print_info_head(shell=True) super().print_shell_info() - def _print_info_body(self, shell=False): + def _print_info_body(self, shell: bool = False) -> None: """Print information about this class (body part). :param bool shell: True for human readable style otherwise shell style diff --git a/python/grass/temporal/open_stds.py b/python/grass/temporal/open_stds.py index 3b3a28ea99a..d05212410a8 100644 --- a/python/grass/temporal/open_stds.py +++ b/python/grass/temporal/open_stds.py @@ -35,7 +35,7 @@ def open_old_stds(name, type, dbif=None): :param name: The name of the space time dataset, if the name does not contain the mapset (name@mapset) then the current mapset - will be used to identifiy the space time dataset + will be used to identify the space time dataset :param type: The type of the space time dataset (strd, str3ds, stvds, raster, vector, raster3d) :param dbif: The optional database interface to be used @@ -88,7 +88,7 @@ def open_old_stds(name, type, dbif=None): ############################################################################### -def check_new_stds(name, type, dbif=None, overwrite=False): +def check_new_stds(name, type, dbif=None, overwrite: bool = False): """Check if a new space time dataset of a specific type can be created :param name: The name of the new space time dataset @@ -153,7 +153,7 @@ def check_new_stds(name, type, dbif=None, overwrite=False): def open_new_stds( - name, type, temporaltype, title, descr, semantic, dbif=None, overwrite=False + name, type, temporaltype, title, descr, semantic, dbif=None, overwrite: bool = False ): """Create a new space time dataset of a specific type @@ -210,7 +210,9 @@ def open_new_stds( ############################################################################ -def check_new_map_dataset(name, layer=None, type="raster", overwrite=False, dbif=None): +def check_new_map_dataset( + name, layer=None, type="raster", overwrite: bool = False, dbif=None +): """Check if a new map dataset of a specific type can be created in the temporal database @@ -254,7 +256,12 @@ def check_new_map_dataset(name, layer=None, type="raster", overwrite=False, dbif def open_new_map_dataset( - name, layer=None, type="raster", temporal_extent=None, overwrite=False, dbif=None + name, + layer=None, + type="raster", + temporal_extent=None, + overwrite: bool = False, + dbif=None, ): """Create a new map dataset object of a specific type that can be registered in the temporal database diff --git a/python/grass/temporal/register.py b/python/grass/temporal/register.py index 8b7852ab557..0868b1a2386 100644 --- a/python/grass/temporal/register.py +++ b/python/grass/temporal/register.py @@ -44,10 +44,10 @@ def register_maps_in_space_time_dataset( unit=None, increment=None, dbif=None, - interval=False, - fs="|", - update_cmd_list=True, -): + interval: bool = False, + fs: str = "|", + update_cmd_list: bool = True, +) -> None: """Use this method to register maps in space time datasets. Additionally a start time string and an increment string can be @@ -158,10 +158,7 @@ def register_maps_in_space_time_dataset( # Read the map list from file if file: - if hasattr(file, "readline"): - fd = file - else: - fd = open(file) + fd = file if hasattr(file, "readline") else open(file) line = True while True: @@ -264,10 +261,7 @@ def register_maps_in_space_time_dataset( end = row["end"] # Use the semantic label from file - if "semantic_label" in row: - semantic_label = row["semantic_label"] - else: - semantic_label = None + semantic_label = row.get("semantic_label", None) is_in_db = map_object.is_in_db(dbif, mapset) @@ -470,8 +464,8 @@ def register_maps_in_space_time_dataset( def assign_valid_time_to_map( - ttype, map_object, start, end, unit, increment=None, mult=1, interval=False -): + ttype, map_object, start, end, unit, increment=None, mult=1, interval: bool = False +) -> None: """Assign the valid time to a map dataset :param ttype: The temporal type which should be assigned @@ -596,8 +590,8 @@ def assign_valid_time_to_map( def register_map_object_list( - type, map_list, output_stds, delete_empty=False, unit=None, dbif=None -): + type, map_list, output_stds, delete_empty: bool = False, unit=None, dbif=None +) -> None: """Register a list of AbstractMapDataset objects in the temporal database and optional in a space time dataset. @@ -642,10 +636,7 @@ def register_map_object_list( string = f"{id}|{start}|{end}\n" register_file.write(string) - if output_stds: - output_stds_id = output_stds.get_id() - else: - output_stds_id = None + output_stds_id = output_stds.get_id() if output_stds else None register_maps_in_space_time_dataset( type, output_stds_id, unit=unit, file=filename, dbif=dbif diff --git a/python/grass/temporal/sampling.py b/python/grass/temporal/sampling.py index 425ca484da5..5730901590a 100644 --- a/python/grass/temporal/sampling.py +++ b/python/grass/temporal/sampling.py @@ -34,8 +34,8 @@ def sample_stds_by_stds_topology( header, separator, method, - spatial=False, - print_only=True, + spatial: bool = False, + print_only: bool = True, ): """Sample the input space time datasets with a sample space time dataset, return the created map matrix and optionally @@ -82,19 +82,11 @@ def sample_stds_by_stds_topology( sts = [] for input in inputs: - if input.find("@") >= 0: - id = input - else: - id = input + "@" + mapset - + id = input if input.find("@") >= 0 else input + "@" + mapset st = dataset_factory(intype, id) sts.append(st) - if sampler.find("@") >= 0: - sid = sampler - else: - sid = sampler + "@" + mapset - + sid = sampler if sampler.find("@") >= 0 else sampler + "@" + mapset sst = dataset_factory(sampletype, sid) dbif = SQLDatabaseInterfaceConnection() @@ -156,10 +148,7 @@ def sample_stds_by_stds_topology( map = entry["granule"] start, end = map.get_temporal_extent_as_tuple() - if end: - delta = end - start - else: - delta = None + delta = end - start if end else None delta_first = start - first_time if map.is_time_absolute(): diff --git a/python/grass/temporal/space_time_datasets.py b/python/grass/temporal/space_time_datasets.py index 92721277c9e..97678e5ce23 100644 --- a/python/grass/temporal/space_time_datasets.py +++ b/python/grass/temporal/space_time_datasets.py @@ -9,8 +9,11 @@ :authors: Soeren Gebbert """ +from __future__ import annotations + import getpass from datetime import datetime +from typing import Literal import grass.script.array as garray @@ -177,18 +180,18 @@ class RasterDataset(AbstractMapDataset): """ - def __init__(self, ident): + def __init__(self, ident) -> None: AbstractMapDataset.__init__(self) self.reset(ident) - def is_stds(self): + def is_stds(self) -> Literal[False]: """Return True if this class is a space time dataset :return: True if this class is a space time dataset, False otherwise """ return False - def get_type(self): + def get_type(self) -> Literal["raster"]: return "raster" def get_new_instance(self, ident): @@ -253,7 +256,7 @@ def get_np_array(self): return garray.array(self.get_map_id()) return garray.array() - def reset(self, ident): + def reset(self, ident) -> None: """Reset the internal structure and set the identifier""" self.base = RasterBase(ident=ident) self.absolute_time = RasterAbsoluteTime(ident=ident) @@ -269,7 +272,7 @@ def has_grass_timestamp(self): """ return self.ciface.has_raster_timestamp(self.get_name(), self.get_mapset()) - def read_timestamp_from_grass(self): + def read_timestamp_from_grass(self) -> bool: """Read the timestamp of this map from the map metadata in the grass file system based spatial database and set the internal time stamp that should be inserted/updated @@ -300,7 +303,7 @@ def read_timestamp_from_grass(self): return True - def write_timestamp_to_grass(self): + def write_timestamp_to_grass(self) -> bool: """Write the timestamp of this map into the map metadata in the grass file system based spatial database. @@ -332,7 +335,7 @@ def write_timestamp_to_grass(self): return True - def remove_timestamp_from_grass(self): + def remove_timestamp_from_grass(self) -> bool: """Remove the timestamp from the grass file system based spatial database @@ -350,7 +353,7 @@ def remove_timestamp_from_grass(self): return True - def read_semantic_label_from_grass(self): + def read_semantic_label_from_grass(self) -> bool: """Read the semantic label of this map from the map metadata in the GRASS file system based spatial database and set the internal semantic label that should be inserted/updated @@ -371,7 +374,7 @@ def read_semantic_label_from_grass(self): return True - def write_semantic_label_to_grass(self): + def write_semantic_label_to_grass(self) -> bool: """Write the semantic label of this map into the map metadata in the GRASS file system based spatial database. @@ -398,7 +401,7 @@ def map_exists(self): """ return self.ciface.raster_map_exists(self.get_name(), self.get_mapset()) - def load(self): + def load(self) -> bool: """Load all info from an existing raster map into the internal structure This method checks first if the map exists, in case it exists @@ -462,7 +465,7 @@ def load(self): return False - def set_semantic_label(self, semantic_label): + def set_semantic_label(self, semantic_label) -> None: """Set semantic label identifier Metadata is updated in order to propagate semantic label into @@ -606,18 +609,18 @@ class Raster3DDataset(AbstractMapDataset): """ - def __init__(self, ident): + def __init__(self, ident) -> None: AbstractMapDataset.__init__(self) self.reset(ident) - def is_stds(self): + def is_stds(self) -> Literal[False]: """Return True if this class is a space time dataset :return: True if this class is a space time dataset, False otherwise """ return False - def get_type(self): + def get_type(self) -> Literal["raster3d"]: return "raster3d" def get_new_instance(self, ident): @@ -693,7 +696,7 @@ def get_np_array(self): return garray.array3d(self.get_map_id()) return garray.array3d() - def reset(self, ident): + def reset(self, ident) -> None: """Reset the internal structure and set the identifier""" self.base = Raster3DBase(ident=ident) self.absolute_time = Raster3DAbsoluteTime(ident=ident) @@ -709,7 +712,7 @@ def has_grass_timestamp(self): """ return self.ciface.has_raster3d_timestamp(self.get_name(), self.get_mapset()) - def read_timestamp_from_grass(self): + def read_timestamp_from_grass(self) -> bool: """Read the timestamp of this map from the map metadata in the grass file system based spatial database and set the internal time stamp that should be inserted/updated @@ -740,7 +743,7 @@ def read_timestamp_from_grass(self): return True - def write_timestamp_to_grass(self): + def write_timestamp_to_grass(self) -> bool: """Write the timestamp of this map into the map metadata in the grass file system based spatial database. @@ -772,7 +775,7 @@ def write_timestamp_to_grass(self): return True - def remove_timestamp_from_grass(self): + def remove_timestamp_from_grass(self) -> bool: """Remove the timestamp from the grass file system based spatial database :return: True if success, False on error @@ -796,7 +799,7 @@ def map_exists(self): """ return self.ciface.raster3d_map_exists(self.get_name(), self.get_mapset()) - def load(self): + def load(self) -> bool: """Load all info from an existing 3d raster map into the internal structure This method checks first if the map exists, in case it exists @@ -974,18 +977,18 @@ class VectorDataset(AbstractMapDataset): """ - def __init__(self, ident): + def __init__(self, ident) -> None: AbstractMapDataset.__init__(self) self.reset(ident) - def is_stds(self): + def is_stds(self) -> Literal[False]: """Return True if this class is a space time dataset :return: True if this class is a space time dataset, False otherwise """ return False - def get_type(self): + def get_type(self) -> Literal["vector"]: return "vector" def get_new_instance(self, ident): @@ -1037,7 +1040,7 @@ def spatial_disjoint_union(self, dataset): """ return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) - def reset(self, ident): + def reset(self, ident) -> None: """Reset the internal structure and set the identifier""" self.base = VectorBase(ident=ident) self.absolute_time = VectorAbsoluteTime(ident=ident) @@ -1052,7 +1055,7 @@ def has_grass_timestamp(self): self.get_name(), self.get_mapset(), self.get_layer() ) - def read_timestamp_from_grass(self): + def read_timestamp_from_grass(self) -> bool: """Read the timestamp of this map from the map metadata in the grass file system based spatial database and set the internal time stamp that should be inserted/updated @@ -1081,7 +1084,7 @@ def read_timestamp_from_grass(self): return True - def write_timestamp_to_grass(self): + def write_timestamp_to_grass(self) -> bool: """Write the timestamp of this map into the map metadata in the grass file system based spatial database. @@ -1110,7 +1113,7 @@ def write_timestamp_to_grass(self): return True - def remove_timestamp_from_grass(self): + def remove_timestamp_from_grass(self) -> bool: """Remove the timestamp from the grass file system based spatial database @@ -1135,7 +1138,7 @@ def map_exists(self): """ return self.ciface.vector_map_exists(self.get_name(), self.get_mapset()) - def load(self): + def load(self) -> bool: """Load all info from an existing vector map into the internal structure This method checks first if the map exists, in case it exists @@ -1230,24 +1233,24 @@ class SpaceTimeRasterDataset(AbstractSpaceTimeDataset): ... """ - def __init__(self, ident): + def __init__(self, ident) -> None: AbstractSpaceTimeDataset.__init__(self, ident) - def set_semantic_label(self, semantic_label): + def set_semantic_label(self, semantic_label) -> None: """Set semantic label :param str semantic_label: semantic label (eg. S2_1) """ self.semantic_label = semantic_label - def is_stds(self): + def is_stds(self) -> Literal[True]: """Return True if this class is a space time dataset :return: True if this class is a space time dataset, False otherwise """ return True - def get_type(self): + def get_type(self) -> Literal["strds"]: return "strds" def get_new_instance(self, ident): @@ -1263,7 +1266,7 @@ def get_map_register(self): """Return the name of the map register table""" return self.metadata.get_raster_register() - def set_map_register(self, name): + def set_map_register(self, name) -> None: """Set the name of the map register table""" self.metadata.set_raster_register(name) @@ -1301,7 +1304,7 @@ def spatial_disjoint_union(self, dataset): """ return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) - def reset(self, ident): + def reset(self, ident) -> None: """Reset the internal structure and set the identifier""" self.base = STRDSBase(ident=ident) self.base.set_creator(str(getpass.getuser())) @@ -1346,17 +1349,17 @@ class SpaceTimeRaster3DDataset(AbstractSpaceTimeDataset): ... """ - def __init__(self, ident): + def __init__(self, ident) -> None: AbstractSpaceTimeDataset.__init__(self, ident) - def is_stds(self): + def is_stds(self) -> Literal[True]: """Return True if this class is a space time dataset :return: True if this class is a space time dataset, False otherwise """ return True - def get_type(self): + def get_type(self) -> Literal["str3ds"]: return "str3ds" def get_new_instance(self, ident): @@ -1372,7 +1375,7 @@ def get_map_register(self): """Return the name of the map register table""" return self.metadata.get_raster3d_register() - def set_map_register(self, name): + def set_map_register(self, name) -> None: """Set the name of the map register table""" self.metadata.set_raster3d_register(name) @@ -1422,7 +1425,7 @@ def spatial_disjoint_union(self, dataset): return self.spatial_extent.disjoint_union(dataset.spatial_extent) return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) - def reset(self, ident): + def reset(self, ident) -> None: """Reset the internal structure and set the identifier""" self.base = STR3DSBase(ident=ident) self.base.set_creator(str(getpass.getuser())) @@ -1467,17 +1470,17 @@ class SpaceTimeVectorDataset(AbstractSpaceTimeDataset): ... """ - def __init__(self, ident): + def __init__(self, ident) -> None: AbstractSpaceTimeDataset.__init__(self, ident) - def is_stds(self): + def is_stds(self) -> Literal[True]: """Return True if this class is a space time dataset :return: True if this class is a space time dataset, False otherwise """ return True - def get_type(self): + def get_type(self) -> Literal["stvds"]: return "stvds" def get_new_instance(self, ident): @@ -1493,7 +1496,7 @@ def get_map_register(self): """Return the name of the map register table""" return self.metadata.get_vector_register() - def set_map_register(self, name): + def set_map_register(self, name) -> None: """Set the name of the map register table""" self.metadata.set_vector_register(name) @@ -1531,7 +1534,7 @@ def spatial_disjoint_union(self, dataset): """ return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent) - def reset(self, ident): + def reset(self, ident) -> None: """Reset the internal structure and set the identifier""" self.base = STVDSBase(ident=ident) self.base.set_creator(str(getpass.getuser())) diff --git a/python/grass/temporal/spatial_extent.py b/python/grass/temporal/spatial_extent.py index 7bec3bc35e7..3a76b18ab46 100644 --- a/python/grass/temporal/spatial_extent.py +++ b/python/grass/temporal/spatial_extent.py @@ -70,6 +70,8 @@ :authors: Soeren Gebbert """ +from typing import Literal + from .base import SQLDatabaseInterface @@ -137,7 +139,7 @@ def __init__( top=None, bottom=None, proj="XY", - ): + ) -> None: SQLDatabaseInterface.__init__(self, table, ident) self.set_id(ident) self.set_spatial_extent_from_values(north, south, east, west, top, bottom) @@ -1110,7 +1112,7 @@ def overlap(self, extent) -> bool: or self.get_bottom() >= T ) - def meet_2d(self, extent): + def meet_2d(self, extent) -> bool: """Return True if this extent (A) meets with the provided spatial extent (B) in two dimensions. @@ -1303,7 +1305,7 @@ def disjoint_2d(self, extent) -> bool: or self.meet_2d(extent) ) - def disjoint(self, extent): + def disjoint(self, extent) -> bool: """Return True if this extent is disjoint with the provided spatial extent in three dimensions. @@ -1321,7 +1323,17 @@ def disjoint(self, extent): or self.meet(extent) ) - def spatial_relation_2d(self, extent): + def spatial_relation_2d(self, extent) -> Literal[ + "equivalent", + "contain", + "in", + "cover", + "covered", + "overlap", + "meet", + "disjoint", + "unknown", + ]: """Returns the two dimensional spatial relation between this extent and the provided spatial extent in two dimensions. @@ -1358,7 +1370,17 @@ def spatial_relation_2d(self, extent): return "unknown" - def spatial_relation(self, extent): + def spatial_relation(self, extent) -> Literal[ + "equivalent", + "contain", + "in", + "cover", + "covered", + "overlap", + "meet", + "disjoint", + "unknown", + ]: """Returns the two dimensional spatial relation between this extent and the provided spatial extent in three dimensions. @@ -1667,7 +1689,9 @@ def spatial_relation(self, extent): return "unknown" - def set_spatial_extent_from_values(self, north, south, east, west, top, bottom): + def set_spatial_extent_from_values( + self, north, south, east, west, top, bottom + ) -> None: """Set the three dimensional spatial extent :param north: The northern edge @@ -1685,7 +1709,7 @@ def set_spatial_extent_from_values(self, north, south, east, west, top, bottom): self.set_top(top) self.set_bottom(bottom) - def set_spatial_extent(self, spatial_extent): + def set_spatial_extent(self, spatial_extent) -> None: """Set the three dimensional spatial extent :param spatial_extent: An object of type SpatialExtent or its @@ -1699,7 +1723,7 @@ def set_spatial_extent(self, spatial_extent): self.set_top(spatial_extent.get_top()) self.set_bottom(spatial_extent.get_bottom()) - def set_projection(self, proj): + def set_projection(self, proj) -> None: """Set the projection of the spatial extent it should be XY or LL. As default the projection is XY """ @@ -1708,7 +1732,7 @@ def set_projection(self, proj): else: self.D["proj"] = proj - def set_spatial_extent_from_values_2d(self, north, south, east, west): + def set_spatial_extent_from_values_2d(self, north, south, east, west) -> None: """Set the two dimensional spatial extent from values :param north: The northern edge @@ -1722,7 +1746,7 @@ def set_spatial_extent_from_values_2d(self, north, south, east, west): self.set_east(east) self.set_west(west) - def set_spatial_extent_2d(self, spatial_extent): + def set_spatial_extent_2d(self, spatial_extent) -> None: """Set the three dimensional spatial extent :param spatial_extent: An object of type SpatialExtent or its @@ -1734,47 +1758,47 @@ def set_spatial_extent_2d(self, spatial_extent): self.set_east(spatial_extent.east) self.set_west(spatial_extent.west) - def set_id(self, ident): + def set_id(self, ident) -> None: """Convenient method to set the unique identifier (primary key)""" self.ident = ident self.D["id"] = ident - def set_north(self, north): + def set_north(self, north) -> None: """Set the northern edge of the map""" if north is not None: self.D["north"] = float(north) else: self.D["north"] = None - def set_south(self, south): + def set_south(self, south) -> None: """Set the southern edge of the map""" if south is not None: self.D["south"] = float(south) else: self.D["south"] = None - def set_west(self, west): + def set_west(self, west) -> None: """Set the western edge of the map""" if west is not None: self.D["west"] = float(west) else: self.D["west"] = None - def set_east(self, east): + def set_east(self, east) -> None: """Set the eastern edge of the map""" if east is not None: self.D["east"] = float(east) else: self.D["east"] = None - def set_top(self, top): + def set_top(self, top) -> None: """Set the top edge of the map""" if top is not None: self.D["top"] = float(top) else: self.D["top"] = None - def set_bottom(self, bottom): + def set_bottom(self, bottom) -> None: """Set the bottom edge of the map""" if bottom is not None: self.D["bottom"] = float(bottom) @@ -1884,7 +1908,7 @@ def get_bottom(self): top = property(fget=get_top, fset=set_top) bottom = property(fget=get_bottom, fset=set_bottom) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( @@ -1897,7 +1921,7 @@ def print_info(self): print(" | Top:........................ " + str(self.get_top())) print(" | Bottom:..................... " + str(self.get_bottom())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" print("north=" + str(self.get_north())) print("south=" + str(self.get_south())) @@ -1920,7 +1944,7 @@ def __init__( west=None, top=None, bottom=None, - ): + ) -> None: SpatialExtent.__init__( self, "raster_spatial_extent", ident, north, south, east, west, top, bottom ) @@ -1936,7 +1960,7 @@ def __init__( west=None, top=None, bottom=None, - ): + ) -> None: SpatialExtent.__init__( self, "raster3d_spatial_extent", @@ -1960,7 +1984,7 @@ def __init__( west=None, top=None, bottom=None, - ): + ) -> None: SpatialExtent.__init__( self, "vector_spatial_extent", ident, north, south, east, west, top, bottom ) @@ -1976,7 +2000,7 @@ def __init__( west=None, top=None, bottom=None, - ): + ) -> None: SpatialExtent.__init__( self, "strds_spatial_extent", ident, north, south, east, west, top, bottom ) @@ -1992,7 +2016,7 @@ def __init__( west=None, top=None, bottom=None, - ): + ) -> None: SpatialExtent.__init__( self, "str3ds_spatial_extent", ident, north, south, east, west, top, bottom ) @@ -2008,7 +2032,7 @@ def __init__( west=None, top=None, bottom=None, - ): + ) -> None: SpatialExtent.__init__( self, "stvds_spatial_extent", ident, north, south, east, west, top, bottom ) diff --git a/python/grass/temporal/spatial_topology_dataset_connector.py b/python/grass/temporal/spatial_topology_dataset_connector.py index 7a3d8a34df2..dd5c64fc045 100644 --- a/python/grass/temporal/spatial_topology_dataset_connector.py +++ b/python/grass/temporal/spatial_topology_dataset_connector.py @@ -74,10 +74,10 @@ class SpatialTopologyDatasetConnector: """ - def __init__(self): + def __init__(self) -> None: self.reset_spatial_topology() - def reset_spatial_topology(self): + def reset_spatial_topology(self) -> None: """Reset any information about temporal topology""" self._spatial_topology = {} self._has_spatial_topology = False @@ -147,11 +147,11 @@ def get_number_of_spatial_relations(self): return relations - def set_spatial_topology_build_true(self): + def set_spatial_topology_build_true(self) -> None: """Same as name""" self._has_spatial_topology = True - def set_spatial_topology_build_false(self): + def set_spatial_topology_build_false(self) -> None: """Same as name""" self._has_spatial_topology = False @@ -159,7 +159,7 @@ def is_spatial_topology_build(self): """Check if the temporal topology was build""" return self._has_spatial_topology - def append_equivalent(self, map): + def append_equivalent(self, map) -> None: """Append a map with equivalent spatial extent as this map :param map: This object should be of type AbstractMapDataset @@ -178,7 +178,7 @@ def get_equivalent(self): return None return self._spatial_topology["EQUIVALENT"] - def append_overlap(self, map): + def append_overlap(self, map) -> None: """Append a map that this spatial overlap with this map :param map: This object should be of type AbstractMapDataset @@ -197,7 +197,7 @@ def get_overlap(self): return None return self._spatial_topology["OVERLAP"] - def append_in(self, map): + def append_in(self, map) -> None: """Append a map that this is spatial in this map :param map: This object should be of type AbstractMapDataset @@ -216,7 +216,7 @@ def get_in(self): return None return self._spatial_topology["IN"] - def append_contain(self, map): + def append_contain(self, map) -> None: """Append a map that this map spatially contains :param map: This object should be of type AbstractMapDataset @@ -235,7 +235,7 @@ def get_contain(self): return None return self._spatial_topology["CONTAIN"] - def append_meet(self, map): + def append_meet(self, map) -> None: """Append a map that spatially meet with this map :param map: This object should be of type AbstractMapDataset @@ -254,7 +254,7 @@ def get_meet(self): return None return self._spatial_topology["MEET"] - def append_cover(self, map): + def append_cover(self, map) -> None: """Append a map that spatially cover this map :param map: This object should be of type AbstractMapDataset @@ -273,7 +273,7 @@ def get_cover(self): return None return self._spatial_topology["COVER"] - def append_covered(self, map): + def append_covered(self, map) -> None: """Append a map that is spatially covered by this map :param map: This object should be of type AbstractMapDataset @@ -292,7 +292,7 @@ def get_covered(self): return None return self._spatial_topology["COVERED"] - def _generate_map_list_string(self, map_list, line_wrap=True): + def _generate_map_list_string(self, map_list, line_wrap: bool = True): count = 0 string = "" for map_ in map_list: @@ -316,7 +316,7 @@ def _generate_map_list_string(self, map_list, line_wrap=True): contain = property(fget=get_contain, fset=append_contain) meet = property(fget=get_meet, fset=append_meet) - def print_spatial_topology_info(self): + def print_spatial_topology_info(self) -> None: """Print information about this class in human readable style""" print( @@ -359,7 +359,7 @@ def print_spatial_topology_info(self): + self._generate_map_list_string(self.meet) ) - def print_spatial_topology_shell_info(self): + def print_spatial_topology_shell_info(self) -> None: """Print information about this class in shell style""" if self.equivalent is not None: diff --git a/python/grass/temporal/spatio_temporal_relationships.py b/python/grass/temporal/spatio_temporal_relationships.py index d22bc2bb0da..b04687bc5b0 100644 --- a/python/grass/temporal/spatio_temporal_relationships.py +++ b/python/grass/temporal/spatio_temporal_relationships.py @@ -377,28 +377,28 @@ class SpatioTemporalTopologyBuilder: """ # noqa: E501 - def __init__(self): + def __init__(self) -> None: self._reset() # 0001-01-01 00:00:00 self._timeref = datetime(1, 1, 1) - def _reset(self): + def _reset(self) -> None: self._store = {} self._first = None self._iteratable = False - def _set_first(self, first): + def _set_first(self, first) -> None: self._first = first self._insert(first) - def _detect_first(self): + def _detect_first(self) -> None: if len(self) > 0: prev_ = list(self._store.values())[0] while prev_ is not None: self._first = prev_ prev_ = prev_.prev() - def _insert(self, t): + def _insert(self, t) -> None: self._store[t.get_id()] = t def get_first(self): @@ -408,7 +408,7 @@ def get_first(self): """ return self._first - def _build_internal_iteratable(self, maps, spatial): + def _build_internal_iteratable(self, maps, spatial) -> None: """Build an iteratable temporal topology structure for all maps in the list and store the maps internally @@ -428,7 +428,7 @@ def _build_internal_iteratable(self, maps, spatial): # Detect the first map self._detect_first() - def _build_iteratable(self, maps, spatial): + def _build_iteratable(self, maps, spatial) -> None: """Build an iteratable temporal topology structure for all maps in the list @@ -529,7 +529,7 @@ def _build_rtree(self, maps, spatial=None): return tree - def build(self, mapsA, mapsB=None, spatial=None): + def build(self, mapsA, mapsB=None, spatial=None) -> None: """Build the spatio-temporal topology structure between one or two unordered lists of abstract dataset objects @@ -609,17 +609,17 @@ def __iter__(self): def __getitem__(self, index): return self._store[index.get_id()] - def __len__(self): + def __len__(self) -> int: return len(self._store) - def __contains__(self, _map): - return _map in self._store.values() + def __contains__(self, map_) -> bool: + return map_ in self._store.values() ############################################################################### -def set_temoral_relationship(A, B, relation): +def set_temoral_relationship(A, B, relation) -> None: if relation in {"equal", "equals"}: if A != B: if not B.get_equal() or (B.get_equal() and A not in B.get_equal()): @@ -685,7 +685,7 @@ def set_temoral_relationship(A, B, relation): ############################################################################### -def set_spatial_relationship(A, B, relation): +def set_spatial_relationship(A, B, relation) -> None: if relation == "equivalent": if A != B: if not B.get_equivalent() or ( @@ -731,7 +731,7 @@ def set_spatial_relationship(A, B, relation): ############################################################################### -def print_temporal_topology_relationships(maps1, maps2=None, dbif=None): +def print_temporal_topology_relationships(maps1, maps2=None, dbif=None) -> None: """Print the temporal relationships of the map lists maps1 and maps2 to stdout. @@ -761,7 +761,7 @@ def print_temporal_topology_relationships(maps1, maps2=None, dbif=None): def print_spatio_temporal_topology_relationships( maps1, maps2=None, spatial="2D", dbif=None -): +) -> None: """Print the temporal relationships of the map lists maps1 and maps2 to stdout. @@ -832,13 +832,13 @@ def count_temporal_topology_relationships(maps1, maps2=None, dbif=None): def create_temporal_relation_sql_where_statement( start, end, - use_start=True, - use_during=False, - use_overlap=False, - use_contain=False, - use_equal=False, - use_follows=False, - use_precedes=False, + use_start: bool = True, + use_during: bool = False, + use_overlap: bool = False, + use_contain: bool = False, + use_equal: bool = False, + use_follows: bool = False, + use_precedes: bool = False, ): """Create a SQL WHERE statement for temporal relation selection of maps in space time datasets diff --git a/python/grass/temporal/stds_export.py b/python/grass/temporal/stds_export.py index a01b94e1071..c5f546aa3a4 100644 --- a/python/grass/temporal/stds_export.py +++ b/python/grass/temporal/stds_export.py @@ -53,7 +53,7 @@ def _export_raster_maps_as_gdal( rows, tar, list_file, new_cwd, fs, format_, type_, **kwargs -): +) -> None: kwargs = {key: value for key, value in kwargs.items() if value is not None} for row in rows: name = row["name"] @@ -148,7 +148,7 @@ def _export_raster_maps_as_gdal( ############################################################################ -def _export_raster_maps(rows, tar, list_file, new_cwd, fs): +def _export_raster_maps(rows, tar, list_file, new_cwd, fs) -> None: for row in rows: name = row["name"] start = row["start_time"] @@ -173,7 +173,7 @@ def _export_raster_maps(rows, tar, list_file, new_cwd, fs): ############################################################################ -def _export_vector_maps_as_gml(rows, tar, list_file, new_cwd, fs): +def _export_vector_maps_as_gml(rows, tar, list_file, new_cwd, fs) -> None: for row in rows: name = row["name"] start = row["start_time"] @@ -207,7 +207,7 @@ def _export_vector_maps_as_gml(rows, tar, list_file, new_cwd, fs): ############################################################################ -def _export_vector_maps_as_gpkg(rows, tar, list_file, new_cwd, fs): +def _export_vector_maps_as_gpkg(rows, tar, list_file, new_cwd, fs) -> None: for row in rows: name = row["name"] start = row["start_time"] @@ -242,7 +242,7 @@ def _export_vector_maps_as_gpkg(rows, tar, list_file, new_cwd, fs): ############################################################################ -def _export_vector_maps(rows, tar, list_file, new_cwd, fs): +def _export_vector_maps(rows, tar, list_file, new_cwd, fs) -> None: for row in rows: name = row["name"] start = row["start_time"] @@ -276,7 +276,7 @@ def _export_vector_maps(rows, tar, list_file, new_cwd, fs): ############################################################################ -def _export_raster3d_maps(rows, tar, list_file, new_cwd, fs): +def _export_raster3d_maps(rows, tar, list_file, new_cwd, fs) -> None: for row in rows: name = row["name"] start = row["start_time"] @@ -310,7 +310,7 @@ def export_stds( type_="strds", datatype=None, **kwargs, -): +) -> None: """Export space time datasets as tar archive with optional compression This method should be used to export space time datasets diff --git a/python/grass/temporal/stds_import.py b/python/grass/temporal/stds_import.py index 006ee6a387e..f7030b66d31 100644 --- a/python/grass/temporal/stds_import.py +++ b/python/grass/temporal/stds_import.py @@ -54,8 +54,15 @@ def _import_raster_maps_from_gdal( - maplist, overr, exp, location, link, format_, set_current_region=False, memory=300 -): + maplist, + overr, + exp, + location, + link, + format_, + set_current_region: bool = False, + memory=300, +) -> None: impflags = "" if overr: impflags += "o" @@ -113,7 +120,7 @@ def _import_raster_maps_from_gdal( ############################################################################ -def _import_raster_maps(maplist, set_current_region=False): +def _import_raster_maps(maplist, set_current_region: bool = False) -> None: # We need to disable the projection check because of its # simple implementation impflags = "o" @@ -143,7 +150,7 @@ def _import_raster_maps(maplist, set_current_region=False): ############################################################################ -def _import_vector_maps_from_gml(maplist, overr, exp, location, link): +def _import_vector_maps_from_gml(maplist, overr, exp, location, link) -> None: impflags = "o" if exp or location: impflags += "e" @@ -169,7 +176,7 @@ def _import_vector_maps_from_gml(maplist, overr, exp, location, link): ############################################################################ -def _import_vector_maps(maplist): +def _import_vector_maps(maplist) -> None: # We need to disable the projection check because of its # simple implementation impflags = "o" @@ -208,15 +215,15 @@ def import_stds( title=None, descr=None, location=None, - link=False, - exp=False, - overr=False, - create=False, + link: bool = False, + exp: bool = False, + overr: bool = False, + create: bool = False, stds_type="strds", base=None, - set_current_region=False, + set_current_region: bool = False, memory=300, -): +) -> None: """Import space time datasets of type raster and vector :param input: Name of the input archive file @@ -240,7 +247,7 @@ def import_stds( :param memory: Cache size for raster rows, used in r.in.gdal """ - old_state = gs.raise_on_error + old_state = gs.get_raise_on_error() gs.set_raise_on_error(True) # Check if input file and extraction directory exits diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index 7eaede8956e..e8955a83e54 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -439,6 +439,10 @@ """ +from __future__ import annotations + +from typing import Literal + try: from ply import lex, yacc except ImportError: @@ -655,7 +659,7 @@ def t_LIST(self, t): # pass # Track line numbers. - def t_newline(self, t): + def t_newline(self, t) -> None: r"\n+" t.lineno += len(t.value) @@ -685,13 +689,13 @@ def t_error(self, t): ) # Build the lexer - def build(self, **kwargs): + def build(self, **kwargs) -> None: self.lexer = lex.lex( module=self, optimize=False, nowarn=True, debug=0, **kwargs ) # Just for testing - def test(self, data): + def test(self, data) -> None: self.name_list = {} print(data) self.lexer.input(data) @@ -711,7 +715,7 @@ class GlobalTemporalVar: if-statements can be stored in this class. """ - def __init__(self): + def __init__(self) -> None: self.tfunc = None self.compop = None self.value = None @@ -720,7 +724,7 @@ def __init__(self): self.topology = [] self.td = None - def get_type(self): + def get_type(self) -> Literal["global", "boolean", "operator", "timediff"] | None: if ( self.tfunc is not None and self.compop is not None @@ -749,15 +753,15 @@ def get_type_value(self): return valuelist - def __str__(self): + def __str__(self) -> str: return str(self.tfunc) + str(self.compop) + str(self.value) class FatalError(Exception): - def __init__(self, msg): + def __init__(self, msg) -> None: self.value = msg - def __str__(self): + def __str__(self) -> str: return self.value @@ -782,15 +786,15 @@ class TemporalAlgebraParser: def __init__( self, - pid=None, - run=True, - debug=False, - spatial=False, - register_null=False, - dry_run=False, - nprocs=1, + pid: int | None = None, + run: bool = True, + debug: bool = False, + spatial: bool = False, + register_null: bool = False, + dry_run: bool = False, + nprocs: int = 1, time_suffix=None, - ): + ) -> None: self.run = run # Compute the processes and output but Do not start the processes self.dry_run = dry_run @@ -846,11 +850,13 @@ def __init__( "MEET", ] - def __del__(self): + def __del__(self) -> None: if self.dbif.connected: self.dbif.close() - def setup_common_granularity(self, expression, stdstype="strds", lexer=None): + def setup_common_granularity( + self, expression, stdstype="strds", lexer=None + ) -> bool: """Configure the temporal algebra to use the common granularity of all space time datasets in the expression to generate the map lists. @@ -958,7 +964,7 @@ def parse( maptype="rast", mapclass=RasterDataset, basename=None, - overwrite=False, + overwrite: bool = False, ): """Parse the algebra expression and run the computation @@ -992,16 +998,18 @@ def generate_map_name(self): same object for map name generation in multiple threads. """ self.count += 1 - if self.pid is not None: - pid = self.pid - else: - pid = os.getpid() + pid = self.pid if self.pid is not None else os.getpid() name = "tmp_map_name_%i_%i" % (pid, self.count) self.names[name] = name return name def generate_new_map( - self, base_map, bool_op="and", copy=True, rename=True, remove=False + self, + base_map, + bool_op="and", + copy: bool = True, + rename: bool = True, + remove: bool = False, ): """Generate a new map using the spatio-temporal extent of the base map @@ -1033,7 +1041,9 @@ def generate_new_map( map_new.uid = name return map_new - def overlay_map_extent(self, mapA, mapB, bool_op=None, temp_op="l", copy=False): + def overlay_map_extent( + self, mapA, mapB, bool_op=None, temp_op="l", copy: bool = False + ): """Compute the spatio-temporal extent of two topological related maps :param mapA: The first map @@ -1159,11 +1169,7 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): if returncode == 0: break # Append map to result map list. - elif returncode == 1: - # print(map_new.get_id() + " " + - # str(map_new.get_temporal_extent_as_tuple())) - # print(map_new.condition_value) - # print(map_new.cmd_list) + if returncode == 1: # resultlist.append(map_new) resultdict[map_new.get_id()] = map_new @@ -1181,7 +1187,7 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): resultlist = resultdict.values() return sorted(resultlist, key=AbstractDatasetComparisonKeyStartTime) - def remove_maps(self): + def remove_maps(self) -> None: """Removes empty or intermediate maps of different type.""" map_names = {} @@ -1198,7 +1204,7 @@ def remove_maps(self): self.msgr.message(_("Removing un-needed or empty %s maps") % (key)) self._remove_maps(value, key) - def _remove_maps(self, namelist, map_type): + def _remove_maps(self, namelist, map_type) -> None: """Remove maps of specific type :param namelist: List of map names to be removed @@ -1220,7 +1226,9 @@ def _remove_maps(self, namelist, map_type): if self.dry_run is False: m.run() - def check_stds(self, input, clear=False, stds_type=None, check_type=True): + def check_stds( + self, input, clear: bool = False, stds_type=None, check_type: bool = True + ): """Check if input space time dataset exist in database and return its map list. :param input: Name of space time data set as string or list of maps. @@ -1234,10 +1242,7 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): """ if isinstance(input, str): # Check for mapset in given stds input. - if input.find("@") >= 0: - id_input = input - else: - id_input = input + "@" + self.mapset + id_input = input if input.find("@") >= 0 else input + "@" + self.mapset # Create empty spacetime dataset. if stds_type: stds = dataset_factory(stds_type, id_input) @@ -1249,42 +1254,41 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): _("Space time %s dataset <%s> not found") % (stds.get_new_map_instance(None).get_type(), id_input) ) + # Select temporal dataset entry from database. + stds.select(dbif=self.dbif) + if self.use_granularity: + # We create the maplist out of the map array from none-gap objects + maplist = [] + map_array = stds.get_registered_maps_as_objects_by_granularity( + gran=self.granularity, dbif=self.dbif + ) + for entry in map_array: + # Ignore gap objects + if entry[0].get_id() is not None: + maplist.append(entry[0]) else: - # Select temporal dataset entry from database. - stds.select(dbif=self.dbif) - if self.use_granularity: - # We create the maplist out of the map array from none-gap objects - maplist = [] - map_array = stds.get_registered_maps_as_objects_by_granularity( - gran=self.granularity, dbif=self.dbif - ) - for entry in map_array: - # Ignore gap objects - if entry[0].get_id() is not None: - maplist.append(entry[0]) - else: - maplist = stds.get_registered_maps_as_objects(dbif=self.dbif) - # Create map_value as empty list item. - for map_i in maplist: - if "map_value" not in dir(map_i): - map_i.map_value = [] - if "condition_value" not in dir(map_i): - map_i.condition_value = [] - # Set and check global temporal type variable and map. - if map_i.is_time_absolute() and self.temporaltype is None: - self.temporaltype = "absolute" - elif map_i.is_time_relative() and self.temporaltype is None: - self.temporaltype = "relative" - elif ( - map_i.is_time_absolute() and self.temporaltype == "relative" - ) or (map_i.is_time_relative() and self.temporaltype == "absolute"): - self.msgr.fatal( - _( - "Wrong temporal type of space time dataset " - "<%s> <%s> time is required" - ) - % (id_input, self.temporaltype) + maplist = stds.get_registered_maps_as_objects(dbif=self.dbif) + # Create map_value as empty list item. + for map_i in maplist: + if "map_value" not in dir(map_i): + map_i.map_value = [] + if "condition_value" not in dir(map_i): + map_i.condition_value = [] + # Set and check global temporal type variable and map. + if map_i.is_time_absolute() and self.temporaltype is None: + self.temporaltype = "absolute" + elif map_i.is_time_relative() and self.temporaltype is None: + self.temporaltype = "relative" + elif (map_i.is_time_absolute() and self.temporaltype == "relative") or ( + map_i.is_time_relative() and self.temporaltype == "absolute" + ): + self.msgr.fatal( + _( + "Wrong temporal type of space time dataset " + "<%s> <%s> time is required" ) + % (id_input, self.temporaltype) + ) elif isinstance(input, self.mapclass): # Check if the input is a single map and return it as list with one entry. maplist = [input] @@ -1400,9 +1404,9 @@ def build_spatio_temporal_topology_list( maplistA, maplistB=None, topolist=["EQUAL"], - assign_val=False, - count_map=False, - compare_bool=False, + assign_val: bool = False, + count_map: bool = False, + compare_bool: bool = False, compop=None, aggregate=None, ): @@ -1634,7 +1638,7 @@ def build_spatio_temporal_topology_list( def assign_bool_value( self, map_i, temporal_topo_list=["EQUAL"], spatial_topo_list=[] - ): + ) -> bool: """Function to assign boolean map value based on the map_values from the compared map list by topological relationships. @@ -1668,10 +1672,7 @@ def assign_bool_value( str(relationmap.get_temporal_extent_as_tuple()) + str(boolean), ) - if all(condition_value_list): - resultbool = True - else: - resultbool = False + resultbool = bool(all(condition_value_list)) map_i.condition_value = [resultbool] return resultbool @@ -1770,7 +1771,12 @@ def eval_toperator(self, operator, optype="relation"): return (p.relations, p.temporal, p.function, p.aggregate) def perform_temporal_selection( - self, maplistA, maplistB, topolist=["EQUAL"], inverse=False, assign_val=False + self, + maplistA, + maplistB, + topolist=["EQUAL"], + inverse: bool = False, + assign_val: bool = False, ): """This function performs temporal selection operation. @@ -2266,7 +2272,7 @@ def build_condition_list(self, tvarexpr, thenlist, topolist=["EQUAL"]): # Sort resulting list of maps chronological. return sorted(resultlist, key=AbstractDatasetComparisonKeyStartTime) - def eval_condition_list(self, maplist, inverse=False): + def eval_condition_list(self, maplist, inverse: bool = False): """This function evaluates conditional values of a map list. A recursive function is used to evaluate comparison statements from left to right in the given conditional list. @@ -2296,20 +2302,14 @@ def recurse_compare(conditionlist): ele_index = conditionlist.index(ele) right = conditionlist.pop(ele_index) left = conditionlist.pop(ele_index - 2) - if any([left, right]): - result = True - else: - result = False + result = bool(any([left, right])) conditionlist[ele_index - 2] = result recurse_compare(conditionlist) if ele == "&&": ele_index = conditionlist.index(ele) right = conditionlist.pop(ele_index) left = conditionlist.pop(ele_index - 2) - if all([left, right]): - result = True - else: - result = False + result = bool(all([left, right])) conditionlist[ele_index - 2] = result recurse_compare(conditionlist) @@ -2338,7 +2338,7 @@ def recurse_compare(conditionlist): return inverselist return resultlist - def p_statement_assign(self, t): + def p_statement_assign(self, t) -> None: # The expression should always return a list of maps # This function starts all the work and is the last one that is called from the # parser @@ -2571,24 +2571,24 @@ def p_statement_assign(self, t): if self.debug: print(t[1], "=", t[3]) - def p_stds_1(self, t): + def p_stds_1(self, t) -> None: # Definition of a space time dataset """ stds : NAME """ t[0] = t[1] - def p_paren_expr(self, t): + def p_paren_expr(self, t) -> None: """expr : LPAREN expr RPAREN""" t[0] = t[2] - def p_number(self, t): + def p_number(self, t) -> None: """number : INT | FLOAT """ t[0] = t[1] - def p_expr_strds_function(self, t): + def p_expr_strds_function(self, t) -> None: # Explicitly specify a space time raster dataset # R = A : strds(B) """ @@ -2601,7 +2601,7 @@ def p_expr_strds_function(self, t): if self.debug: print("Opening STRDS: ", t[0]) - def p_expr_str3ds_function(self, t): + def p_expr_str3ds_function(self, t) -> None: # Explicitly specify a space time raster dataset # R = A : str3ds(B) """ @@ -2614,7 +2614,7 @@ def p_expr_str3ds_function(self, t): if self.debug: print("Opening STR3DS: ", t[0]) - def p_expr_stvds_function(self, t): + def p_expr_stvds_function(self, t) -> None: # Explicitly specify a space time vector dataset # R = A : stvds(B) """ @@ -2643,10 +2643,7 @@ def p_expr_tmap_function(self, t): input = t[3] if not isinstance(input, list): # Check for mapset in given stds input. - if input.find("@") >= 0: - id_input = input - else: - id_input = input + "@" + self.mapset + id_input = input if input.find("@") >= 0 else input + "@" + self.mapset # Create empty map dataset. map_i = dataset_factory(self.maptype, id_input) # Check for occurrence of space time dataset. @@ -2655,9 +2652,9 @@ def p_expr_tmap_function(self, t): _("%s map <%s> not found in GRASS spatial database") % (map_i.get_type(), id_input) ) - else: - # Select dataset entry from database. - map_i.select(dbif=self.dbif) + + # Select dataset entry from database. + map_i.select(dbif=self.dbif) else: raise FatalError( _( @@ -2732,7 +2729,7 @@ def p_expr_tmerge_function(self, t): if self.debug: print("merge(", t[3], ",", t[5], ")") - def p_t_hash(self, t): + def p_t_hash(self, t) -> None: """ t_hash_var : stds HASH stds | expr HASH stds @@ -2748,7 +2745,7 @@ def p_t_hash(self, t): ) t[0] = resultlist - def p_t_hash2(self, t): + def p_t_hash2(self, t) -> None: """ t_hash_var : stds T_HASH_OPERATOR stds | stds T_HASH_OPERATOR expr @@ -2765,13 +2762,13 @@ def p_t_hash2(self, t): ) t[0] = resultlist - def p_t_hash_paren(self, t): + def p_t_hash_paren(self, t) -> None: """ t_hash_var : LPAREN t_hash_var RPAREN """ t[0] = t[2] - def p_t_td_var(self, t): + def p_t_td_var(self, t) -> None: """ t_td_var : TD LPAREN stds RPAREN | TD LPAREN expr RPAREN @@ -2801,7 +2798,7 @@ def p_t_td_var(self, t): if self.debug: print("td(" + str(t[3]) + ")") - def p_t_time_var(self, t): + def p_t_time_var(self, t) -> None: # Temporal variables that return a double or integer value """ t_var : START_DOY @@ -2826,7 +2823,7 @@ def p_t_time_var(self, t): t[0] = t[1] - def p_compare_op(self, t): + def p_compare_op(self, t) -> None: # Compare operators that are supported for temporal expressions """ comp_op : CEQUALS @@ -2838,7 +2835,7 @@ def p_compare_op(self, t): """ t[0] = t[1] - def p_t_var_expr_td_hash(self, t): + def p_t_var_expr_td_hash(self, t) -> None: # Examples: # A # B == 2 # td(A) < 31 @@ -2871,7 +2868,7 @@ def p_t_var_expr_td_hash(self, t): if self.debug: print(t[1], t[2], t[3]) - def p_t_var_expr_number(self, t): + def p_t_var_expr_number(self, t) -> None: # Examples: # start_month(A) > 2 # start_day(B) < 14 @@ -2900,7 +2897,7 @@ def p_t_var_expr_number(self, t): if self.debug: print(t[1], t[3], t[5], t[6]) - def p_t_var_expr_time(self, t): + def p_t_var_expr_time(self, t) -> None: # Examples: # start_time(A) == "12:30:00" # start_date(B) <= "2001-01-01" @@ -2937,7 +2934,7 @@ def p_t_var_expr_time(self, t): if self.debug: print(t[1], t[3], t[5], t[6]) - def p_t_var_expr_comp(self, t): + def p_t_var_expr_comp(self, t) -> None: """ t_var_expr : t_var_expr AND AND t_var_expr | t_var_expr OR OR t_var_expr @@ -2969,7 +2966,7 @@ def p_t_var_expr_comp(self, t): if self.debug: print(t[1], t[2] + t[3], t[4]) - def p_t_var_expr_comp_op(self, t): + def p_t_var_expr_comp_op(self, t) -> None: """ t_var_expr : t_var_expr T_COMP_OPERATOR t_var_expr """ @@ -2999,7 +2996,7 @@ def p_t_var_expr_comp_op(self, t): if self.debug: print(t[1], t[2], t[3]) - def p_expr_t_select(self, t): + def p_expr_t_select(self, t) -> None: # Temporal equal selection # The temporal topology relation equals is implicit # Examples: @@ -3026,7 +3023,7 @@ def p_expr_t_select(self, t): if self.debug: print(str(t[1]), "* = ", t[1], t[2], t[3]) - def p_expr_t_not_select(self, t): + def p_expr_t_not_select(self, t) -> None: # Temporal equal selection # The temporal topology relation equals is implicit # Examples: @@ -3053,7 +3050,7 @@ def p_expr_t_not_select(self, t): if self.debug: print(t[1] + "* = ", t[1], t[2], t[3]) - def p_expr_t_select_operator(self, t): + def p_expr_t_select_operator(self, t) -> None: # Temporal equal selection # The temporal topology relation equals is implicit # Examples: @@ -3079,10 +3076,7 @@ def p_expr_t_select_operator(self, t): # Evaluate temporal operator. operators = self.eval_toperator(t[2], optype="select") # Check for negative selection. - if operators[2] == "!:": - negation = True - else: - negation = False + negation = operators[2] == "!:" # Perform selection. selectlist = self.perform_temporal_selection( maplistA, maplistB, topolist=operators[0], inverse=negation @@ -3098,7 +3092,7 @@ def p_expr_t_select_operator(self, t): if self.debug: print(t[1] + "* = ", t[1], t[2], t[3]) - def p_expr_condition_if(self, t): + def p_expr_condition_if(self, t) -> None: # Examples # if( start_date() < "2005-06-01", A:B) """ @@ -3122,7 +3116,7 @@ def p_expr_condition_if(self, t): if self.debug: print(str(t[5]) + "* = ", "if condition", str(t[3]), " then ", str(t[5])) - def p_expr_condition_if_relation(self, t): + def p_expr_condition_if_relation(self, t) -> None: # Examples # if({equal} start_date() < "2005-06-01", A:B) """ @@ -3155,7 +3149,7 @@ def p_expr_condition_if_relation(self, t): str(t[7]), ) - def p_expr_condition_elif(self, t): + def p_expr_condition_elif(self, t) -> None: # Examples # if( start_date() < "2005-06-01", if(start_time() < "12:30:00", A:B), A!:B) """ @@ -3196,7 +3190,7 @@ def p_expr_condition_elif(self, t): str(t[7]), ) - def p_expr_condition_elif_relation(self, t): + def p_expr_condition_elif_relation(self, t) -> None: # Examples # if({equal}, start_date() < "2005-06-01", # if(start_time() < "12:30:00", A:B), A!:B) @@ -3256,7 +3250,7 @@ def p_expr_condition_elif_relation(self, t): str(t[9]), ) - def p_expr_t_buff(self, t): + def p_expr_t_buff(self, t) -> None: # Examples # buff_t(A : B, "10 minutes") # Select the part of A that is temporally # equal to B and create a buffer of 10 minutes @@ -3297,7 +3291,7 @@ def p_expr_t_buff(self, t): elif len(t) == 7: print(str(t[3]) + "* = buff_t(", str(t[3]), ",", str(t[5]), ")") - def p_expr_t_snap(self, t): + def p_expr_t_snap(self, t) -> None: # Examples # tsnap(A : B) # Snap the maps of A temporally. """ @@ -3316,7 +3310,7 @@ def p_expr_t_snap(self, t): if self.debug: print(str(t[3]) + "* = tsnap(", str(t[3]), ")") - def p_expr_t_shift(self, t): + def p_expr_t_shift(self, t) -> None: # Examples # tshift(A : B, "10 minutes") # Shift the selection from A temporally # by 10 minutes. @@ -3355,7 +3349,7 @@ def p_expr_t_shift(self, t): elif len(t) == 7: print(str(t[3]) + "* = tshift(", str(t[3]), ",", str(t[5]), ")") - def p_expr_time_const(self, t): + def p_expr_time_const(self, t) -> None: # Examples # start_doy(A, -1) # Get the start DOY from the preceding map # of the time series as a numerical constant @@ -3404,8 +3398,7 @@ def p_error(self, t): "syntax error on line %d, position %i token %s near '%s' expression " "'%s'" % (t.lineno, t.lexpos, t.type, t.value, self.expression) ) - else: - raise SyntaxError("Unexpected syntax error") + raise SyntaxError("Unexpected syntax error") if __name__ == "__main__": diff --git a/python/grass/temporal/temporal_extent.py b/python/grass/temporal/temporal_extent.py index 29594ea8b72..692632db08f 100644 --- a/python/grass/temporal/temporal_extent.py +++ b/python/grass/temporal/temporal_extent.py @@ -81,7 +81,7 @@ class TemporalExtent(SQLDatabaseInterface): """ - def __init__(self, table=None, ident=None, start_time=None, end_time=None): + def __init__(self, table=None, ident=None, start_time=None, end_time=None) -> None: SQLDatabaseInterface.__init__(self, table, ident) self.set_id(ident) @@ -861,7 +861,7 @@ def overlaps(self, extent) -> bool: ) def overlapped(self, extent) -> bool: - """Return True if this temporal extent (A) overlapps the provided + """Return True if this temporal extent (A) overlaps the provided temporal extent (B) :: @@ -967,16 +967,16 @@ def temporal_relation(self, extent): return "precedes" return None - def set_id(self, ident): + def set_id(self, ident) -> None: """Convenient method to set the unique identifier (primary key)""" self.ident = ident self.D["id"] = ident - def set_start_time(self, start_time): + def set_start_time(self, start_time) -> None: """Set the valid start time of the extent""" self.D["start_time"] = start_time - def set_end_time(self, end_time): + def set_end_time(self, end_time) -> None: """Set the valid end time of the extent""" self.D["end_time"] = end_time @@ -1007,13 +1007,13 @@ def get_end_time(self): start_time = property(fget=get_start_time, fset=set_start_time) end_time = property(fget=get_end_time, fset=set_end_time) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" # 0123456789012345678901234567890 print(" | Start time:................. " + str(self.get_start_time())) print(" | End time:................... " + str(self.get_end_time())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" print("start_time='{}'".format(str(self.get_start_time()))) print("end_time='{}'".format(str(self.get_end_time()))) @@ -1028,10 +1028,10 @@ class AbsoluteTemporalExtent(TemporalExtent): start_time and end_time must be of type datetime """ - def __init__(self, table=None, ident=None, start_time=None, end_time=None): + def __init__(self, table=None, ident=None, start_time=None, end_time=None) -> None: TemporalExtent.__init__(self, table, ident, start_time, end_time) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( @@ -1039,7 +1039,7 @@ def print_info(self): ) TemporalExtent.print_info(self) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" TemporalExtent.print_shell_info(self) @@ -1048,21 +1048,21 @@ def print_shell_info(self): class RasterAbsoluteTime(AbsoluteTemporalExtent): - def __init__(self, ident=None, start_time=None, end_time=None): + def __init__(self, ident=None, start_time=None, end_time=None) -> None: AbsoluteTemporalExtent.__init__( self, "raster_absolute_time", ident, start_time, end_time ) class Raster3DAbsoluteTime(AbsoluteTemporalExtent): - def __init__(self, ident=None, start_time=None, end_time=None): + def __init__(self, ident=None, start_time=None, end_time=None) -> None: AbsoluteTemporalExtent.__init__( self, "raster3d_absolute_time", ident, start_time, end_time ) class VectorAbsoluteTime(AbsoluteTemporalExtent): - def __init__(self, ident=None, start_time=None, end_time=None): + def __init__(self, ident=None, start_time=None, end_time=None) -> None: AbsoluteTemporalExtent.__init__( self, "vector_absolute_time", ident, start_time, end_time ) @@ -1122,17 +1122,17 @@ def __init__( end_time=None, granularity=None, map_time=None, - ): + ) -> None: AbsoluteTemporalExtent.__init__(self, table, ident, start_time, end_time) self.set_granularity(granularity) self.set_map_time(map_time) - def set_granularity(self, granularity): + def set_granularity(self, granularity) -> None: """Set the granularity of the space time dataset""" self.D["granularity"] = granularity - def set_map_time(self, map_time): + def set_map_time(self, map_time) -> None: """Set the type of the map time Registered maps may have different types of time: @@ -1171,14 +1171,14 @@ def get_map_time(self): granularity = property(fget=get_granularity, fset=set_granularity) map_time = property(fget=get_map_time, fset=set_map_time) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" AbsoluteTemporalExtent.print_info(self) # 0123456789012345678901234567890 print(" | Granularity:................ " + str(self.get_granularity())) print(" | Temporal type of maps:...... " + str(self.get_map_time())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" AbsoluteTemporalExtent.print_shell_info(self) print("granularity='{}'".format(str(self.get_granularity()))) @@ -1189,21 +1189,27 @@ def print_shell_info(self): class STRDSAbsoluteTime(STDSAbsoluteTime): - def __init__(self, ident=None, start_time=None, end_time=None, granularity=None): + def __init__( + self, ident=None, start_time=None, end_time=None, granularity=None + ) -> None: STDSAbsoluteTime.__init__( self, "strds_absolute_time", ident, start_time, end_time, granularity ) class STR3DSAbsoluteTime(STDSAbsoluteTime): - def __init__(self, ident=None, start_time=None, end_time=None, granularity=None): + def __init__( + self, ident=None, start_time=None, end_time=None, granularity=None + ) -> None: STDSAbsoluteTime.__init__( self, "str3ds_absolute_time", ident, start_time, end_time, granularity ) class STVDSAbsoluteTime(STDSAbsoluteTime): - def __init__(self, ident=None, start_time=None, end_time=None, granularity=None): + def __init__( + self, ident=None, start_time=None, end_time=None, granularity=None + ) -> None: STDSAbsoluteTime.__init__( self, "stvds_absolute_time", ident, start_time, end_time, granularity ) @@ -1251,11 +1257,11 @@ class RelativeTemporalExtent(TemporalExtent): def __init__( self, table=None, ident=None, start_time=None, end_time=None, unit=None - ): + ) -> None: TemporalExtent.__init__(self, table, ident, start_time, end_time) self.set_unit(unit) - def set_unit(self, unit): + def set_unit(self, unit) -> None: """Set the unit of the relative time. Valid units are: - years @@ -1295,7 +1301,7 @@ def temporal_relation(self, map): # Properties unit = property(fget=get_unit, fset=set_unit) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( @@ -1304,7 +1310,7 @@ def print_info(self): TemporalExtent.print_info(self) print(" | Relative time unit:......... " + str(self.get_unit())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" TemporalExtent.print_shell_info(self) print("unit=" + str(self.get_unit())) @@ -1314,21 +1320,21 @@ def print_shell_info(self): class RasterRelativeTime(RelativeTemporalExtent): - def __init__(self, ident=None, start_time=None, end_time=None, unit=None): + def __init__(self, ident=None, start_time=None, end_time=None, unit=None) -> None: RelativeTemporalExtent.__init__( self, "raster_relative_time", ident, start_time, end_time, unit ) class Raster3DRelativeTime(RelativeTemporalExtent): - def __init__(self, ident=None, start_time=None, end_time=None, unit=None): + def __init__(self, ident=None, start_time=None, end_time=None, unit=None) -> None: RelativeTemporalExtent.__init__( self, "raster3d_relative_time", ident, start_time, end_time, unit ) class VectorRelativeTime(RelativeTemporalExtent): - def __init__(self, ident=None, start_time=None, end_time=None, unit=None): + def __init__(self, ident=None, start_time=None, end_time=None, unit=None) -> None: RelativeTemporalExtent.__init__( self, "vector_relative_time", ident, start_time, end_time, unit ) @@ -1393,17 +1399,17 @@ def __init__( unit=None, granularity=None, map_time=None, - ): + ) -> None: RelativeTemporalExtent.__init__(self, table, ident, start_time, end_time, unit) self.set_granularity(granularity) self.set_map_time(map_time) - def set_granularity(self, granularity): + def set_granularity(self, granularity) -> None: """Set the granularity of the space time dataset""" self.D["granularity"] = granularity - def set_map_time(self, map_time): + def set_map_time(self, map_time) -> None: """Set the type of the map time Registered maps may have different types of time: @@ -1442,14 +1448,14 @@ def get_map_time(self): granularity = property(fget=get_granularity, fset=set_granularity) map_time = property(fget=get_map_time, fset=set_map_time) - def print_info(self): + def print_info(self) -> None: """Print information about this class in human readable style""" RelativeTemporalExtent.print_info(self) # 0123456789012345678901234567890 print(" | Granularity:................ " + str(self.get_granularity())) print(" | Temporal type of maps:...... " + str(self.get_map_time())) - def print_shell_info(self): + def print_shell_info(self) -> None: """Print information about this class in shell style""" RelativeTemporalExtent.print_shell_info(self) print("granularity=" + str(self.get_granularity())) @@ -1468,7 +1474,7 @@ def __init__( unit=None, granularity=None, map_time=None, - ): + ) -> None: STDSRelativeTime.__init__( self, "strds_relative_time", @@ -1490,7 +1496,7 @@ def __init__( unit=None, granularity=None, map_time=None, - ): + ) -> None: STDSRelativeTime.__init__( self, "str3ds_relative_time", @@ -1512,7 +1518,7 @@ def __init__( unit=None, granularity=None, map_time=None, - ): + ) -> None: STDSRelativeTime.__init__( self, "stvds_relative_time", diff --git a/python/grass/temporal/temporal_granularity.py b/python/grass/temporal/temporal_granularity.py index dbe25beca04..a3b6d09bbec 100644 --- a/python/grass/temporal/temporal_granularity.py +++ b/python/grass/temporal/temporal_granularity.py @@ -37,7 +37,7 @@ ############################################################################### -def check_granularity_string(granularity, temporal_type): +def check_granularity_string(granularity, temporal_type) -> bool: """Check if the granularity string is valid :param granularity: The granularity string @@ -494,7 +494,7 @@ def compute_absolute_time_granularity(maps): # Keep the temporal extent to compare to the following/next map previous_start, previous_end = start, end - # Create a list with a single time unit only + # Create a set with a single time unit only dlist = set() assigned_time_unit = None time_unit_multipliers = { @@ -529,11 +529,8 @@ def compute_absolute_time_granularity(maps): if not dlist: return None - if len(dlist) > 1: - # Find greatest common divisor - granularity = gcd_list(dlist) - else: - granularity = dlist.pop() + # Find greatest common divisor to get a single time unit + granularity = gcd_list(dlist) if len(dlist) > 1 else dlist.pop() if granularity is None: return None @@ -1179,7 +1176,7 @@ def gran_plural_unit(gran): ######################################################################## -def gran_to_gran(from_gran, to_gran="days", shell=False): +def gran_to_gran(from_gran, to_gran="days", shell: bool = False): """Converts the computed absolute granularity of a STDS to a smaller granularity based on the Gregorian calendar hierarchy that 1 year equals 12 months or 365.2425 days or 24 * 365.2425 hours or 86400 * diff --git a/python/grass/temporal/temporal_operator.py b/python/grass/temporal/temporal_operator.py index 7d91ed0f65c..6eabede2959 100644 --- a/python/grass/temporal/temporal_operator.py +++ b/python/grass/temporal/temporal_operator.py @@ -228,7 +228,7 @@ class TemporalOperatorLexer: t_ignore = " \t\n" # Track line numbers. - def t_newline(self, t): + def t_newline(self, t) -> None: r"\n+" t.lineno += len(t.value) @@ -268,13 +268,13 @@ def t_error(self, t): ) # Build the lexer - def build(self, **kwargs): + def build(self, **kwargs) -> None: self.lexer = lex.lex( module=self, optimize=False, nowarn=True, debug=0, **kwargs ) # Just for testing - def test(self, data): + def test(self, data) -> None: self.name_list = {} print(data) self.lexer.input(data) @@ -291,7 +291,7 @@ def test(self, data): class TemporalOperatorParser: """The temporal operator class""" - def __init__(self): + def __init__(self) -> None: self.lexer = TemporalOperatorLexer() self.lexer.build() self.parser = yacc.yacc(module=self, debug=0) @@ -352,16 +352,16 @@ def p_relation_operator(self, t): # Check for correct type. if not self.optype == "relation": raise SyntaxError('Wrong optype "%s" must be "relation"' % self.optype) + + # Set three operator components. + if isinstance(t[2], list): + self.relations = t[2] else: - # Set three operator components. - if isinstance(t[2], list): - self.relations = t[2] - else: - self.relations = [t[2]] - self.temporal = None - self.function = None + self.relations = [t[2]] + self.temporal = None + self.function = None - t[0] = t[2] + t[0] = t[2] def p_relation_bool_operator(self, t): # {||, during} @@ -374,17 +374,17 @@ def p_relation_bool_operator(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "boolean"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = "l" - self.function = t[2] + t[3] - self.aggregate = t[2] + self.relations = [t[5]] + self.temporal = "l" + self.function = t[2] + t[3] + self.aggregate = t[2] - t[0] = t[2] + t[0] = t[2] def p_relation_bool_combi_operator(self, t): # {||, during, &} @@ -401,17 +401,17 @@ def p_relation_bool_combi_operator(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "boolean"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = "l" - self.function = t[2] + t[3] - self.aggregate = t[7] + self.relations = [t[5]] + self.temporal = "l" + self.function = t[2] + t[3] + self.aggregate = t[7] - t[0] = t[2] + t[0] = t[2] def p_relation_bool_combi_operator2(self, t): # {||, during, left} @@ -424,17 +424,17 @@ def p_relation_bool_combi_operator2(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "boolean"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = t[7] - self.function = t[2] + t[3] - self.aggregate = t[2] + self.relations = [t[5]] + self.temporal = t[7] + self.function = t[2] + t[3] + self.aggregate = t[2] - t[0] = t[2] + t[0] = t[2] def p_relation_bool_combi_operator3(self, t): # {||, during, |, left} @@ -451,17 +451,17 @@ def p_relation_bool_combi_operator3(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "relation"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = t[9] - self.function = t[2] + t[3] - self.aggregate = t[7] + self.relations = [t[5]] + self.temporal = t[9] + self.function = t[2] + t[3] + self.aggregate = t[7] - t[0] = t[2] + t[0] = t[2] def p_select_relation_operator(self, t): # {!:} @@ -477,27 +477,28 @@ def p_select_relation_operator(self, t): """ if not self.optype == "select": raise SyntaxError('Wrong optype "%s" must be "select"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal", "equivalent"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal", "equivalent"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] def p_hash_relation_operator(self, t): # {#} @@ -513,27 +514,28 @@ def p_hash_relation_operator(self, t): """ if not self.optype == "hash": raise SyntaxError('Wrong optype "%s" must be "hash"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] def p_raster_relation_operator(self, t): # {+} @@ -549,27 +551,28 @@ def p_raster_relation_operator(self, t): """ if not self.optype == "raster": raise SyntaxError('Wrong optype "%s" must be "raster"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] def p_overlay_relation_operator(self, t): # {+} @@ -585,29 +588,30 @@ def p_overlay_relation_operator(self, t): """ if not self.optype == "overlay": raise SyntaxError('Wrong optype "%s" must be "overlay"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] - - def p_relation(self, t): + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] + + def p_relation(self, t) -> None: # The list of relations. Temporal and spatial relations are supported """ relation : EQUAL @@ -630,7 +634,7 @@ def p_relation(self, t): """ t[0] = t[1] - def p_over(self, t): + def p_over(self, t) -> None: # The the over keyword """ relation : OVER @@ -638,7 +642,7 @@ def p_over(self, t): over_list = ["overlaps", "overlapped"] t[0] = over_list - def p_relationlist(self, t): + def p_relationlist(self, t) -> None: # The list of relations. """ relationlist : relation OR relation @@ -652,7 +656,7 @@ def p_relationlist(self, t): rel_list.append(t[3]) t[0] = rel_list - def p_temporal_operator(self, t): + def p_temporal_operator(self, t) -> None: # The list of relations. """ temporal : LEFTREF @@ -663,7 +667,7 @@ def p_temporal_operator(self, t): """ t[0] = t[1] - def p_select_operator(self, t): + def p_select_operator(self, t) -> None: # The list of relations. """ select : T_SELECT @@ -671,7 +675,7 @@ def p_select_operator(self, t): """ t[0] = t[1] - def p_arithmetic_operator(self, t): + def p_arithmetic_operator(self, t) -> None: # The list of relations. """ arithmetic : MOD @@ -682,7 +686,7 @@ def p_arithmetic_operator(self, t): """ t[0] = t[1] - def p_overlay_operator(self, t): + def p_overlay_operator(self, t) -> None: # The list of relations. """ overlay : AND diff --git a/python/grass/temporal/temporal_raster3d_algebra.py b/python/grass/temporal/temporal_raster3d_algebra.py index cd26f8cb220..93817952fff 100644 --- a/python/grass/temporal/temporal_raster3d_algebra.py +++ b/python/grass/temporal/temporal_raster3d_algebra.py @@ -11,6 +11,8 @@ """ +from __future__ import annotations + try: from ply import yacc except ImportError: @@ -30,14 +32,14 @@ class TemporalRaster3DAlgebraParser(TemporalRasterBaseAlgebraParser): def __init__( self, - pid=None, - run=False, - debug=True, - spatial=False, - register_null=False, - dry_run=False, - nprocs=1, - ): + pid: int | None = None, + run: bool = False, + debug: bool = True, + spatial: bool = False, + register_null: bool = False, + dry_run: bool = False, + nprocs: int = 1, + ) -> None: TemporalRasterBaseAlgebraParser.__init__( self, pid=pid, @@ -52,7 +54,7 @@ def __init__( self.m_mapcalc = pymod.Module("r3.mapcalc") self.m_mremove = pymod.Module("g.remove") - def parse(self, expression, basename=None, overwrite=False): + def parse(self, expression, basename=None, overwrite: bool = False): # Check for space time dataset type definitions from temporal algebra lx = TemporalRasterAlgebraLexer() lx.build() @@ -81,14 +83,14 @@ def parse(self, expression, basename=None, overwrite=False): return self.process_chain_dict - def p_statement_assign(self, t): + def p_statement_assign(self, t) -> None: # The expression should always return a list of maps. """ statement : stds EQUALS expr """ TemporalRasterBaseAlgebraParser.p_statement_assign(self, t) - def p_ts_neighbor_operation(self, t): + def p_ts_neighbor_operation(self, t) -> None: # Examples: # A[1,0,-1] # B[-2] diff --git a/python/grass/temporal/temporal_raster_algebra.py b/python/grass/temporal/temporal_raster_algebra.py index 1785183cc50..5b49da5841a 100644 --- a/python/grass/temporal/temporal_raster_algebra.py +++ b/python/grass/temporal/temporal_raster_algebra.py @@ -52,6 +52,8 @@ """ +from __future__ import annotations + try: from ply import yacc except ImportError: @@ -71,15 +73,15 @@ class TemporalRasterAlgebraParser(TemporalRasterBaseAlgebraParser): def __init__( self, - pid=None, - run=False, - debug=True, - spatial=False, - register_null=False, - dry_run=False, - nprocs=1, + pid: int | None = None, + run: bool = False, + debug: bool = True, + spatial: bool = False, + register_null: bool = False, + dry_run: bool = False, + nprocs: int = 1, time_suffix=None, - ): + ) -> None: TemporalRasterBaseAlgebraParser.__init__( self, pid=pid, @@ -98,7 +100,7 @@ def __init__( self.m_mapcalc = pymod.Module("r.mapcalc") self.m_mremove = pymod.Module("g.remove") - def parse(self, expression, basename=None, overwrite=False): + def parse(self, expression, basename=None, overwrite: bool = False): # Check for space time dataset type definitions from temporal algebra lx = TemporalRasterAlgebraLexer() lx.build() @@ -127,14 +129,14 @@ def parse(self, expression, basename=None, overwrite=False): return self.process_chain_dict - def p_statement_assign(self, t): + def p_statement_assign(self, t) -> None: # The expression should always return a list of maps. """ statement : stds EQUALS expr """ TemporalRasterBaseAlgebraParser.p_statement_assign(self, t) - def p_ts_neighbour_operation(self, t): + def p_ts_neighbour_operation(self, t) -> None: # Spatial and temporal neighbour operations via indexing # Examples: # A[1,0] diff --git a/python/grass/temporal/temporal_raster_base_algebra.py b/python/grass/temporal/temporal_raster_base_algebra.py index 7e4d47fd136..b533d96e6f6 100644 --- a/python/grass/temporal/temporal_raster_base_algebra.py +++ b/python/grass/temporal/temporal_raster_base_algebra.py @@ -41,6 +41,8 @@ """ +from __future__ import annotations + import copy import grass.pygrass.modules as pymod @@ -68,7 +70,7 @@ class TemporalRasterAlgebraLexer(TemporalAlgebraLexer): """Lexical analyzer for the GRASS GIS temporal algebra""" - def __init__(self): + def __init__(self) -> None: TemporalAlgebraLexer.__init__(self) # Supported r.mapcalc functions. @@ -170,15 +172,15 @@ class TemporalRasterBaseAlgebraParser(TemporalAlgebraParser): def __init__( self, - pid=None, - run=True, - debug=False, - spatial=False, - register_null=False, - dry_run=False, - nprocs=1, + pid: int | None = None, + run: bool = True, + debug: bool = False, + spatial: bool = False, + register_null: bool = False, + dry_run: bool = False, + nprocs: int = 1, time_suffix=None, - ): + ) -> None: TemporalAlgebraParser.__init__( self, pid=pid, @@ -203,15 +205,15 @@ def build_spatio_temporal_topology_list( maplistA, maplistB=None, topolist=["EQUAL"], - assign_val=False, - count_map=False, - compare_bool=False, - compare_cmd=False, + assign_val: bool = False, + count_map: bool = False, + compare_bool: bool = False, + compare_cmd: bool = False, compop=None, aggregate=None, - new=False, - convert=False, - operator_cmd=False, + new: bool = False, + convert: bool = False, + operator_cmd: bool = False, ): """Build temporal topology for two space time data sets, copy map objects for given relation into map list. @@ -420,7 +422,7 @@ def compare_cmd_value( aggregate, temporal_topo_list=["EQUAL"], spatial_topo_list=[], - convert=False, + convert: bool = False, ): """Function to evaluate two map lists with boolean values by boolean comparison operator. @@ -550,7 +552,7 @@ def set_temporal_extent_list( maplist, topolist=["EQUAL"], temporal="l", - cmd_bool=False, + cmd_bool: bool = False, cmd_type=None, operator=None, ): @@ -610,7 +612,7 @@ def set_temporal_extent_list( if returncode == 0: break # Append map to result map list. - elif returncode == 1: + if returncode == 1: # print(map_new.cmd_list) # resultlist.append(map_new) if cmd_bool: @@ -643,7 +645,7 @@ def build_condition_cmd_list( condition_topolist=["EQUAL"], conclusion_topolist=["EQUAL"], temporal="l", - null=False, + null: bool = False, ): """This function build the r.mapcalc command strings for spatial conditionals. For Example: 'if(a1 == 1, b1, c2)' @@ -742,7 +744,7 @@ def build_condition_cmd_list( cmd_type="condition", ) - def p_statement_assign(self, t): + def p_statement_assign(self, t) -> None: # This function executes the processing of raster/raster3d algebra # that was build based on the expression """ @@ -960,10 +962,7 @@ def p_expr_spmap_function(self, t): input = t[3] if not isinstance(input, list): # Check for mapset in given stds input. - if input.find("@") >= 0: - id_input = input - else: - id_input = input + "@" + self.mapset + id_input = input if input.find("@") >= 0 else input + "@" + self.mapset # Create empty map dataset. map_i = dataset_factory(self.maptype, id_input) # Check for occurrence of space time dataset. @@ -972,12 +971,11 @@ def p_expr_spmap_function(self, t): _("%s map <%s> not found in GRASS spatial database") % (map_i.get_type(), id_input) ) - else: - # Select dataset entry from database. - map_i.select(dbif=self.dbif) - # Create command list for map object. - cmdstring = "(%s)" % (map_i.get_map_id()) - map_i.cmd_list = cmdstring + # Select dataset entry from database. + map_i.select(dbif=self.dbif) + # Create command list for map object. + cmdstring = "(%s)" % (map_i.get_map_id()) + map_i.cmd_list = cmdstring # Return map object. t[0] = cmdstring else: @@ -986,7 +984,7 @@ def p_expr_spmap_function(self, t): if self.debug: print("map(" + t[3] + ")") - def p_arith1_operation(self, t): + def p_arith1_operation(self, t) -> None: # A % B # A / B # A * B @@ -1061,7 +1059,7 @@ def p_arith1_operation(self, t): for map in resultlist: print(map.cmd_list) - def p_arith1_operation_numeric1(self, t): + def p_arith1_operation_numeric1(self, t) -> None: # A % 1 # A / 4 # A * 5 @@ -1111,7 +1109,7 @@ def p_arith1_operation_numeric1(self, t): for map in resultlist: print(map.cmd_list) - def p_arith1_operation_numeric2(self, t): + def p_arith1_operation_numeric2(self, t) -> None: # 1 % A # 4 / A # 5 * A @@ -1161,7 +1159,7 @@ def p_arith1_operation_numeric2(self, t): for map in resultlist: print(map.cmd_list) - def p_arith2_operation(self, t): + def p_arith2_operation(self, t) -> None: # A + B # A - B # A + td(B) @@ -1230,7 +1228,7 @@ def p_arith2_operation(self, t): for map in resultlist: print(map.cmd_list) - def p_arith2_operation_numeric1(self, t): + def p_arith2_operation_numeric1(self, t) -> None: # A + 2 # A - 3 # A + map(b4) @@ -1272,7 +1270,7 @@ def p_arith2_operation_numeric1(self, t): for map in resultlist: print(map.cmd_list) - def p_arith2_operation_numeric2(self, t): + def p_arith2_operation_numeric2(self, t) -> None: # 2 + A # 3 - A # map(b2) + A @@ -1314,7 +1312,7 @@ def p_arith2_operation_numeric2(self, t): for map in resultlist: print(map.cmd_list) - def p_arith1_operation_relation(self, t): + def p_arith1_operation_relation(self, t) -> None: # A {*, equal, l} B # A {*, equal, l} td(B) # A {*, equal, l} B {/, during, r} C @@ -1353,7 +1351,7 @@ def p_arith1_operation_relation(self, t): for map in resultlist: print(map.cmd_list) - def p_arith2_operation_relation(self, t): + def p_arith2_operation_relation(self, t) -> None: # A {+, equal, l} B # A {+, equal, l} td(b) # A {+, equal, l} B {-, during, r} C @@ -1392,7 +1390,7 @@ def p_arith2_operation_relation(self, t): for map in resultlist: print(map.cmd_list) - def p_arith_operation_numeric_string(self, t): + def p_arith_operation_numeric_string(self, t) -> None: # 1 + 1 # 1 - 1 # 1 * 1 @@ -1412,7 +1410,7 @@ def p_arith_operation_numeric_string(self, t): if self.debug: print(numstring) - def p_mapcalc_function(self, t): + def p_mapcalc_function(self, t) -> None: # Supported mapcalc functions. """ mapcalc_arith : ABS @@ -1433,7 +1431,7 @@ def p_mapcalc_function(self, t): if self.debug: print(t[1]) - def p_mapcalc_operation1(self, t): + def p_mapcalc_operation1(self, t) -> None: # sin(A) # log(B) """ @@ -1462,7 +1460,7 @@ def p_mapcalc_operation1(self, t): for map in resultlist: print(map.cmd_list) - def p_mapexpr_operation(self, t): + def p_mapexpr_operation(self, t) -> None: # sin(map(a)) """ mapexpr : mapcalc_arith LPAREN mapexpr RPAREN @@ -1478,7 +1476,7 @@ def p_mapexpr_operation(self, t): if self.debug: print(mapstring) - def p_s_var_expr_1(self, t): + def p_s_var_expr_1(self, t) -> None: # isnull(A) """ s_var_expr : ISNULL LPAREN stds RPAREN @@ -1506,7 +1504,7 @@ def p_s_var_expr_1(self, t): for map in resultlist: print(map.cmd_list) - def p_s_var_expr_2(self, t): + def p_s_var_expr_2(self, t) -> None: # isntnull(A) """ s_var_expr : ISNTNULL LPAREN stds RPAREN @@ -1534,7 +1532,7 @@ def p_s_var_expr_2(self, t): for map in resultlist: print(map.cmd_list) - def p_s_var_expr_3(self, t): + def p_s_var_expr_3(self, t) -> None: # A <= 2 """ s_var_expr : stds comp_op number @@ -1562,7 +1560,7 @@ def p_s_var_expr_3(self, t): for map in resultlist: print(map.cmd_list) - def p_s_var_expr_4(self, t): + def p_s_var_expr_4(self, t) -> None: # exist(B) """ s_var_expr : EXIST LPAREN stds RPAREN @@ -1590,7 +1588,7 @@ def p_s_var_expr_4(self, t): for map in resultlist: print(map.cmd_list) - def p_s_var_expr_comp(self, t): + def p_s_var_expr_comp(self, t) -> None: # A <= 2 || B == 10 # A < 3 && A > 1 """ @@ -1625,7 +1623,7 @@ def p_s_var_expr_comp(self, t): for map in resultlist: print(map.cmd_list) - def p_s_var_expr_comp_op(self, t): + def p_s_var_expr_comp_op(self, t) -> None: # A <= 2 {||} B == 10 # A < 3 {&&, equal} A > 1 """ @@ -1659,7 +1657,7 @@ def p_s_var_expr_comp_op(self, t): for map in resultlist: print(map.cmd_list) - def p_s_expr_condition_if(self, t): + def p_s_expr_condition_if(self, t) -> None: # if(s_var_expr, B) # if(A == 1, B) """ @@ -1685,7 +1683,7 @@ def p_s_expr_condition_if(self, t): for map in resultlist: print(map.cmd_list) - def p_s_numeric_condition_if(self, t): + def p_s_numeric_condition_if(self, t) -> None: # if(s_var_expr, 1) # if(A == 5, 10) """ @@ -1716,7 +1714,7 @@ def p_s_numeric_condition_if(self, t): for map in resultlist: print(map.cmd_list) - def p_s_expr_condition_if_relation(self, t): + def p_s_expr_condition_if_relation(self, t) -> None: # if({equal||during}, s_var_expr, A) """ expr : IF LPAREN T_REL_OPERATOR COMMA s_var_expr COMMA stds RPAREN @@ -1744,7 +1742,7 @@ def p_s_expr_condition_if_relation(self, t): for map in resultlist: print(map.cmd_list) - def p_s_expr_condition_elif(self, t): + def p_s_expr_condition_elif(self, t) -> None: # if(s_var_expr, A, B) """ expr : IF LPAREN s_var_expr COMMA stds COMMA stds RPAREN @@ -1777,7 +1775,7 @@ def p_s_expr_condition_elif(self, t): for map in resultlist: print(map.cmd_list) - def p_s_numeric_condition_elif(self, t): + def p_s_numeric_condition_elif(self, t) -> None: # if(s_var_expr, 1, 2) # if(A == 5, 10, 0) """ @@ -1825,7 +1823,7 @@ def p_s_numeric_condition_elif(self, t): for map in resultlist: print(map.cmd_list) - def p_s_numeric_expr_condition_elif(self, t): + def p_s_numeric_expr_condition_elif(self, t) -> None: # if(s_var_expr, 1, A) # if(A == 5 && C > 5, A, null()) """ @@ -1880,7 +1878,7 @@ def p_s_numeric_expr_condition_elif(self, t): for map in resultlist: print(map.cmd_list) - def p_s_numeric_expr_condition_elif_relation(self, t): + def p_s_numeric_expr_condition_elif_relation(self, t) -> None: # if({during},s_var_expr, 1, A) # if({during}, A == 5, A, null()) """ @@ -1938,7 +1936,7 @@ def p_s_numeric_expr_condition_elif_relation(self, t): for map in resultlist: print(map.cmd_list) - def p_s_expr_condition_elif_relation(self, t): + def p_s_expr_condition_elif_relation(self, t) -> None: # if({equal||during}, s_var_expr, A, B) """ expr : IF LPAREN T_REL_OPERATOR COMMA s_var_expr COMMA stds COMMA stds RPAREN @@ -1974,7 +1972,7 @@ def p_s_expr_condition_elif_relation(self, t): for map in resultlist: print(map.cmd_list) - def p_ts_var_expr1(self, t): + def p_ts_var_expr1(self, t) -> None: # Combination of spatial and temporal conditional expressions. # Examples: # A <= 2 || start_date <= 2013-01-01 @@ -2020,7 +2018,7 @@ def p_ts_var_expr1(self, t): t[0] = resultlist - def p_hash_operation(self, t): + def p_hash_operation(self, t) -> None: # Calculate the number of maps within an interval of another map from a # second space time dataset. # A # B diff --git a/python/grass/temporal/temporal_topology_dataset_connector.py b/python/grass/temporal/temporal_topology_dataset_connector.py index 61b32472de5..f832729b569 100644 --- a/python/grass/temporal/temporal_topology_dataset_connector.py +++ b/python/grass/temporal/temporal_topology_dataset_connector.py @@ -112,10 +112,10 @@ class TemporalTopologyDatasetConnector: """ - def __init__(self): + def __init__(self) -> None: self.reset_temporal_topology() - def reset_temporal_topology(self): + def reset_temporal_topology(self) -> None: """Reset any information about temporal topology""" self._temporal_topology = {} self._has_temporal_topology = False @@ -205,11 +205,11 @@ def get_number_of_temporal_relations(self): return relations - def set_temporal_topology_build_true(self): + def set_temporal_topology_build_true(self) -> None: """Same as name""" self._has_temporal_topology = True - def set_temporal_topology_build_false(self): + def set_temporal_topology_build_false(self) -> None: """Same as name""" self._has_temporal_topology = False @@ -217,7 +217,7 @@ def is_temporal_topology_build(self): """Check if the temporal topology was build""" return self._has_temporal_topology - def set_next(self, map): + def set_next(self, map) -> None: """Set the map that is temporally as closest located after this map. Temporally located means that the start time of the "next" map is @@ -229,7 +229,7 @@ def set_next(self, map): """ self._temporal_topology["NEXT"] = map - def set_prev(self, map): + def set_prev(self, map) -> None: """Set the map that is temporally as closest located before this map. Temporally located means that the start time of the "previous" map @@ -261,7 +261,7 @@ def prev(self): return None return self._temporal_topology["PREV"] - def append_equal(self, map): + def append_equal(self, map) -> None: """Append a map with equivalent temporal extent as this map :param map: This object should be of type AbstractMapDataset @@ -281,7 +281,7 @@ def get_equal(self): return None return self._temporal_topology["EQUAL"] - def append_starts(self, map): + def append_starts(self, map) -> None: """Append a map that this map temporally starts with :param map: This object should be of type AbstractMapDataset @@ -300,7 +300,7 @@ def get_starts(self): return None return self._temporal_topology["STARTS"] - def append_started(self, map): + def append_started(self, map) -> None: """Append a map that this map temporally started with :param map: This object should be of type AbstractMapDataset @@ -319,7 +319,7 @@ def get_started(self): return None return self._temporal_topology["STARTED"] - def append_finishes(self, map): + def append_finishes(self, map) -> None: """Append a map that this map temporally finishes with :param map: This object should be of type AbstractMapDataset @@ -338,7 +338,7 @@ def get_finishes(self): return None return self._temporal_topology["FINISHES"] - def append_finished(self, map): + def append_finished(self, map) -> None: """Append a map that this map temporally finished with :param map: This object should be of type AbstractMapDataset @@ -357,7 +357,7 @@ def get_finished(self): return None return self._temporal_topology["FINISHED"] - def append_overlaps(self, map): + def append_overlaps(self, map) -> None: """Append a map that this map temporally overlaps :param map: This object should be of type AbstractMapDataset @@ -376,7 +376,7 @@ def get_overlaps(self): return None return self._temporal_topology["OVERLAPS"] - def append_overlapped(self, map): + def append_overlapped(self, map) -> None: """Append a map that this map temporally overlapped :param map: This object should be of type AbstractMapDataset @@ -395,7 +395,7 @@ def get_overlapped(self): return None return self._temporal_topology["OVERLAPPED"] - def append_follows(self, map): + def append_follows(self, map) -> None: """Append a map that this map temporally follows :param map: This object should be of type AbstractMapDataset @@ -414,7 +414,7 @@ def get_follows(self): return None return self._temporal_topology["FOLLOWS"] - def append_precedes(self, map): + def append_precedes(self, map) -> None: """Append a map that this map temporally precedes :param map: This object should be of type AbstractMapDataset @@ -433,7 +433,7 @@ def get_precedes(self): return None return self._temporal_topology["PRECEDES"] - def append_during(self, map): + def append_during(self, map) -> None: """Append a map that this map is temporally located during This includes temporal relationships starts and finishes @@ -454,7 +454,7 @@ def get_during(self): return None return self._temporal_topology["DURING"] - def append_contains(self, map): + def append_contains(self, map) -> None: """Append a map that this map temporally contains This includes temporal relationships started and finished @@ -475,7 +475,7 @@ def get_contains(self): return None return self._temporal_topology["CONTAINS"] - def _generate_map_list_string(self, map_list, line_wrap=True): + def _generate_map_list_string(self, map_list, line_wrap: bool = True): count = 0 string = "" for map_ in map_list: @@ -503,7 +503,7 @@ def _generate_map_list_string(self, map_list, line_wrap=True): finishes = property(fget=get_finishes, fset=append_finishes) finished = property(fget=get_finished, fset=append_finished) - def print_temporal_topology_info(self): + def print_temporal_topology_info(self) -> None: """Print information about this class in human readable style""" print( @@ -570,7 +570,7 @@ def print_temporal_topology_info(self): + self._generate_map_list_string(self.finished) ) - def print_temporal_topology_shell_info(self): + def print_temporal_topology_shell_info(self) -> None: """Print information about this class in shell style""" if self.next() is not None: diff --git a/python/grass/temporal/temporal_vector_algebra.py b/python/grass/temporal/temporal_vector_algebra.py index 551c69783f5..099a56b89e5 100644 --- a/python/grass/temporal/temporal_vector_algebra.py +++ b/python/grass/temporal/temporal_vector_algebra.py @@ -42,6 +42,8 @@ """ +from __future__ import annotations + try: from ply import yacc except ImportError: @@ -66,7 +68,7 @@ class TemporalVectorAlgebraLexer(TemporalAlgebraLexer): """Lexical analyzer for the GRASS GIS temporal vector algebra""" - def __init__(self): + def __init__(self) -> None: TemporalAlgebraLexer.__init__(self) # Buffer functions from v.buffer @@ -142,7 +144,13 @@ class TemporalVectorAlgebraParser(TemporalAlgebraParser): ), # 2 ) - def __init__(self, pid=None, run=False, debug=True, spatial=False): + def __init__( + self, + pid: int | None = None, + run: bool = False, + debug: bool = True, + spatial: bool = False, + ) -> None: TemporalAlgebraParser.__init__(self, pid, run, debug, spatial) self.m_overlay = pygrass.Module("v.overlay", quiet=True, run_=False) @@ -151,7 +159,7 @@ def __init__(self, pid=None, run=False, debug=True, spatial=False): self.m_mremove = pygrass.Module("g.remove", quiet=True, run_=False) self.m_buffer = pygrass.Module("v.buffer", quiet=True, run_=False) - def parse(self, expression, basename=None, overwrite=False): + def parse(self, expression, basename: str | None = None, overwrite: bool = False): # Check for space time dataset type definitions from temporal algebra lx = TemporalVectorAlgebraLexer() lx.build() @@ -183,15 +191,15 @@ def build_spatio_temporal_topology_list( maplistA, maplistB=None, topolist=["EQUAL"], - assign_val=False, - count_map=False, - compare_bool=False, - compare_cmd=False, + assign_val: bool = False, + count_map: bool = False, + compare_bool: bool = False, + compare_cmd: bool = False, compop=None, aggregate=None, - new=False, - convert=False, - overlay_cmd=False, + new: bool = False, + convert: bool = False, + overlay_cmd: bool = False, ): """Build temporal topology for two space time data sets, copy map objects for given relation into map list. @@ -205,9 +213,9 @@ def build_spatio_temporal_topology_list( :param count_map: Boolean if the number of topological related maps should be returned. :param compare_bool: Boolean for comparing boolean map values based on - related map list and compariosn operator. + related map list and comparison operator. :param compare_cmd: Boolean for comparing command list values based on - related map list and compariosn operator. + related map list and comparison operator. :param compop: Comparison operator, && or ||. :param aggregate: Aggregation operator for relation map list, & or |. :param new: Boolean if new temporary maps should be created. @@ -386,7 +394,7 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): if returncode == 0: break # Append map to result map list. - elif returncode == 1: + if returncode == 1: # resultlist.append(map_new) resultdict[map_new.get_id()] = map_new if returncode == 0: @@ -573,7 +581,7 @@ def p_statement_assign(self, t): dbif.close() t[0] = t[3] - def p_overlay_operation(self, t): + def p_overlay_operation(self, t) -> None: """ expr : stds AND stds | expr AND stds @@ -620,7 +628,7 @@ def p_overlay_operation(self, t): if self.debug: print(str(t[1]) + t[2] + str(t[3])) - def p_overlay_operation_relation(self, t): + def p_overlay_operation_relation(self, t) -> None: """ expr : stds T_OVERLAY_OPERATOR stds | expr T_OVERLAY_OPERATOR stds @@ -651,7 +659,7 @@ def p_overlay_operation_relation(self, t): if self.debug: print(str(t[1]) + t[2] + str(t[3])) - def p_buffer_operation(self, t): + def p_buffer_operation(self, t) -> None: """ expr : buff_function LPAREN stds COMMA number RPAREN | buff_function LPAREN expr COMMA number RPAREN @@ -694,7 +702,7 @@ def p_buffer_operation(self, t): t[0] = resultlist - def p_buff_function(self, t): + def p_buff_function(self, t) -> None: """buff_function : BUFF_POINT | BUFF_LINE | BUFF_AREA diff --git a/python/grass/temporal/testsuite/test_register_function.py b/python/grass/temporal/testsuite/test_register_function.py index a58ec7d739a..ca2fec9d80f 100644 --- a/python/grass/temporal/testsuite/test_register_function.py +++ b/python/grass/temporal/testsuite/test_register_function.py @@ -13,14 +13,15 @@ import os import grass.script as gs -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestRasterRegisterFunctions(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" os.putenv("GRASS_OVERWRITE", "1") # Use always the current mapset as temporal database @@ -30,11 +31,11 @@ def setUpClass(cls): cls.runModule("g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.del_temp_region() - def setUp(self): + def setUp(self) -> None: """Create the test maps and the space time raster datasets""" self.runModule( "r.mapcalc", overwrite=True, quiet=True, expression="register_map_1 = 1" @@ -68,7 +69,7 @@ def setUp(self): overwrite=True, ) - def tearDown(self): + def tearDown(self) -> None: """Remove maps from temporal database""" self.runModule( "t.unregister", @@ -86,7 +87,7 @@ def tearDown(self): self.strds_abs.delete() self.strds_rel.delete() - def test_absolute_time_strds_1(self): + def test_absolute_time_strds_1(self) -> None: """Test the registration of maps with absolute time in a space time raster dataset """ @@ -116,7 +117,7 @@ def test_absolute_time_strds_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 3)) - def test_absolute_time_strds_2(self): + def test_absolute_time_strds_2(self) -> None: """Test the registration of maps with absolute time in a space time raster dataset. The timestamps are set using the C-Interface beforehand, @@ -155,7 +156,7 @@ def test_absolute_time_strds_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 3)) - def test_absolute_time_strds_3(self): + def test_absolute_time_strds_3(self) -> None: """Test the registration of maps with absolute time in a space time raster dataset. The timestamps are set via method arguments and with the c-interface. The timestamps of the @@ -188,7 +189,7 @@ def test_absolute_time_strds_3(self): self.assertEqual(start, datetime.datetime(2001, 2, 1)) self.assertEqual(end, datetime.datetime(2001, 2, 2)) - def test_absolute_time_strds_4(self): + def test_absolute_time_strds_4(self) -> None: """Test the registration of maps with absolute time in a space time raster dataset. The timestamps are set via method arguments and with the c-interface. The timestamps of the method @@ -222,7 +223,7 @@ def test_absolute_time_strds_4(self): self.assertEqual(start, datetime.datetime(2001, 2, 1)) self.assertEqual(end, datetime.datetime(2001, 2, 2)) - def test_absolute_time_1(self): + def test_absolute_time_1(self) -> None: """Test the registration of maps with absolute time using register_maps_in_space_time_dataset() and register_map_object_list() """ @@ -260,7 +261,7 @@ def test_absolute_time_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 3)) - def test_absolute_time_2(self): + def test_absolute_time_2(self) -> None: """Test the registration of maps with absolute time using register_maps_in_space_time_dataset() and register_map_object_list() with empty map deletion @@ -305,7 +306,7 @@ def test_absolute_time_2(self): map_3 = tgis.VectorDataset("register_map_null@" + tgis.get_current_mapset()) self.assertEqual(map_3.map_exists(), False) - def test_history_raster(self): + def test_history_raster(self) -> None: """Test that raster maps are registered with the history (creator and creation time) of the raster map itself (and from a different mapset (PERMANENT) @@ -329,7 +330,7 @@ def test_history_raster(self): # Test that registered creator of the map is not the current user self.assertEqual(map_1.base.get_creator(), "helena") - def test_history_vector(self): + def test_history_vector(self) -> None: """Test that vector maps are registered with the history (creator and creation time) of the vector map itself (and from a different mapset (PERMANENT) @@ -353,7 +354,7 @@ def test_history_vector(self): # Test that registered creator of the map is not the current user self.assertTrue(map_1.base.get_creator(), "helena") - def test_absolute_time_3(self): + def test_absolute_time_3(self) -> None: """Test the registration of maps with absolute time. The timestamps are set using the C-Interface beforehand, so that the register function needs @@ -382,7 +383,7 @@ def test_absolute_time_3(self): start, end = map.get_absolute_time() self.assertEqual(start, datetime.datetime(2001, 1, 1, 18, 30, 1)) - def test_relative_time_strds_1(self): + def test_relative_time_strds_1(self) -> None: """Test the registration of maps with relative time in a space time raster dataset """ @@ -417,7 +418,7 @@ def test_relative_time_strds_1(self): self.assertEqual(end, 2) self.assertEqual(unit, "day") - def test_relative_time_strds_2(self): + def test_relative_time_strds_2(self) -> None: """Test the registration of maps with relative time in a space time raster dataset. The timestamps are set for the maps using the C-interface before registration. @@ -460,7 +461,7 @@ def test_relative_time_strds_2(self): self.assertEqual(end, 2000000) self.assertEqual(unit, "seconds") - def test_relative_time_1(self): + def test_relative_time_1(self) -> None: """Test the registration of maps with relative time""" tgis.register_maps_in_space_time_dataset( type="raster", @@ -486,7 +487,7 @@ def test_relative_time_1(self): self.assertEqual(end, 2) self.assertEqual(unit, "day") - def test_relative_time_2(self): + def test_relative_time_2(self) -> None: """Test the registration of maps with relative time""" tgis.register_maps_in_space_time_dataset( type="raster", @@ -512,7 +513,7 @@ def test_relative_time_2(self): self.assertEqual(end, 2000000) self.assertEqual(unit, "seconds") - def test_relative_time_3(self): + def test_relative_time_3(self) -> None: """Test the registration of maps with relative time. The timestamps are set beforehand using the C-interface. """ @@ -549,7 +550,7 @@ def test_relative_time_3(self): class TestVectorRegisterFunctions(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" os.putenv("GRASS_OVERWRITE", "1") # Use always the current mapset as temporal database @@ -559,11 +560,11 @@ def setUpClass(cls): cls.runModule("g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.del_temp_region() - def setUp(self): + def setUp(self) -> None: """Create the test maps and the space time raster datasets""" self.runModule( "v.random", @@ -615,7 +616,7 @@ def setUp(self): overwrite=True, ) - def tearDown(self): + def tearDown(self) -> None: """Remove maps from temporal database""" self.runModule( "t.unregister", @@ -640,7 +641,7 @@ def tearDown(self): self.stvds_abs.delete() self.stvds_rel.delete() - def test_absolute_time_stvds_1(self): + def test_absolute_time_stvds_1(self) -> None: """Test the registration of maps with absolute time in a space time raster dataset """ @@ -670,7 +671,7 @@ def test_absolute_time_stvds_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 3)) - def test_absolute_time_stvds_2(self): + def test_absolute_time_stvds_2(self) -> None: """Test the registration of maps with absolute time in a space time raster dataset. The timestamps are set using the C-Interface beforehand, @@ -709,7 +710,7 @@ def test_absolute_time_stvds_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 3)) - def test_absolute_time_stvds_3(self): + def test_absolute_time_stvds_3(self) -> None: """Test the registration of maps with absolute time in a space time raster dataset. The timestamps are set via method arguments and with the C-interface. The timestamps of the method @@ -741,7 +742,7 @@ def test_absolute_time_stvds_3(self): self.assertEqual(start, datetime.datetime(2001, 2, 1)) self.assertEqual(end, datetime.datetime(2001, 2, 2)) - def test_absolute_time_1(self): + def test_absolute_time_1(self) -> None: """Register vector maps in the temporal database and in addition in a stvds using the object method @@ -781,7 +782,7 @@ def test_absolute_time_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 3)) - def test_absolute_time_2(self): + def test_absolute_time_2(self) -> None: """Register vector maps in the temporal database and in addition in a stvds using the object method deleting empty maps @@ -832,17 +833,17 @@ def test_absolute_time_2(self): class TestRegisterFails(TestCase): - def test_error_handling_1(self): + def test_error_handling_1(self) -> None: # start option is missing self.assertModuleFail( "t.register", input="test", end="2001-01-01", maps=("a", "b") ) - def test_error_handling_2(self): + def test_error_handling_2(self) -> None: # No input definition self.assertModuleFail("t.register", input="test", start="2001-01-01") - def test_error_handling_3(self): + def test_error_handling_3(self) -> None: # File and maps are mutually exclusive self.assertModuleFail( "t.register", @@ -852,17 +853,17 @@ def test_error_handling_3(self): file="maps.txt", ) - def test_error_handling_4(self): + def test_error_handling_4(self) -> None: # Increment needs start self.assertModuleFail( "t.register", input="test", increment="1 day", maps=("a", "b") ) - def test_error_handling_5(self): + def test_error_handling_5(self) -> None: # Interval needs start self.assertModuleFail("t.register", flags="i", input="test", maps=("a", "b")) - def test_error_handling_6(self): + def test_error_handling_6(self) -> None: # Increment and end are mutually exclusive self.assertModuleFail( "t.register", @@ -873,7 +874,7 @@ def test_error_handling_6(self): maps=("a", "b"), ) - def test_error_handling_7(self): + def test_error_handling_7(self) -> None: # Interval and end are mutually exclusive self.assertModuleFail( "t.register", @@ -887,7 +888,7 @@ def test_error_handling_7(self): class TestRegisterMapsetAccess(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" os.putenv("GRASS_OVERWRITE", "1") tgis.init() @@ -910,7 +911,7 @@ def setUpClass(cls): cls.del_temp_region() - def setUp(self): + def setUp(self) -> None: """Create the space time raster dataset""" self.strds_abs = tgis.open_new_stds( name="register_test_abs", @@ -958,7 +959,7 @@ def setUp(self): tgis.init() self.assertNotEqual(self.currmapset, tgis.get_current_mapset()) - def tearDown(self): + def tearDown(self) -> None: """Remove raster maps from current mapset""" # switch to old mapset @@ -986,7 +987,7 @@ def tearDown(self): ) gs.try_rmdir(mapset_path) - def test_mapset_access_1(self): + def test_mapset_access_1(self) -> None: """Test the registration of maps from a different mapset.""" self.strds_abs_2 = tgis.open_new_stds( diff --git a/python/grass/temporal/testsuite/test_temporal_doctests.py b/python/grass/temporal/testsuite/test_temporal_doctests.py index a0b2f4d2d9c..cc80c3225cb 100644 --- a/python/grass/temporal/testsuite/test_temporal_doctests.py +++ b/python/grass/temporal/testsuite/test_temporal_doctests.py @@ -8,6 +8,7 @@ import grass.gunittest.case import grass.gunittest.main import grass.gunittest.utils + import grass.temporal doctest.DocFileCase = type( diff --git a/python/grass/temporal/testsuite/unittests_temporal_algebra.py b/python/grass/temporal/testsuite/unittests_temporal_algebra.py index 99ae3eaac00..30011d30f95 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_algebra.py +++ b/python/grass/temporal/testsuite/unittests_temporal_algebra.py @@ -9,16 +9,17 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalAlgebra(TestCase): """Class for testing temporal algebra""" @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -115,16 +116,16 @@ def setUpClass(cls): end="2001-01-04", ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A,B,C,D", quiet=True) cls.del_temp_region() - def test_temporal_select1(self): + def test_temporal_select1(self) -> None: """Testing the temporal select operator with equal relations.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -143,7 +144,7 @@ def test_temporal_select1(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_select2(self): + def test_temporal_select2(self) -> None: """Testing the temporal select operator with equal relations.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -162,7 +163,7 @@ def test_temporal_select2(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_select3(self): + def test_temporal_select3(self) -> None: """Testing the temporal select operator with equal relations.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -181,7 +182,7 @@ def test_temporal_select3(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_select_operators1(self): + def test_temporal_select_operators1(self) -> None: """Testing the temporal select operator. Including temporal relations.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -203,7 +204,7 @@ def test_temporal_select_operators1(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_select_operators2(self): + def test_temporal_select_operators2(self) -> None: """Testing the temporal select operator. Including temporal relations.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -225,7 +226,7 @@ def test_temporal_select_operators2(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_select_operators3(self): + def test_temporal_select_operators3(self) -> None: """Testing the temporal select operator. Including temporal relations and negation operation.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) @@ -248,7 +249,7 @@ def test_temporal_select_operators3(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_select_operators4(self): + def test_temporal_select_operators4(self) -> None: """Testing the temporal select operator. Including temporal relations and temporal operators.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) @@ -276,7 +277,7 @@ def test_temporal_select_operators4(self): self.assertEqual(result_strds.check_temporal_topology(), False) self.assertEqual(result_strds.get_granularity(), "2 days") - def test_temporal_select_operators5(self): + def test_temporal_select_operators5(self) -> None: """Testing the temporal select operator. Including temporal relations and temporal operators.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) @@ -304,7 +305,7 @@ def test_temporal_select_operators5(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "2 days") - def test_temporal_extent1(self): + def test_temporal_extent1(self) -> None: """Testing the temporal extent operators.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -326,7 +327,7 @@ def test_temporal_extent1(self): self.assertEqual(result_strds.check_temporal_topology(), False) self.assertEqual(result_strds.get_granularity(), "2 days") - def test_temporal_extent2(self): + def test_temporal_extent2(self) -> None: """Testing the temporal extent operators.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -348,7 +349,7 @@ def test_temporal_extent2(self): self.assertEqual(result_strds.check_temporal_topology(), False) self.assertEqual(result_strds.get_granularity(), "2 days") - def test_temporal_extent3(self): + def test_temporal_extent3(self) -> None: """Testing the temporal extent operators.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -375,7 +376,7 @@ def test_temporal_extent3(self): self.assertEqual(result_strds.check_temporal_topology(), False) self.assertEqual(result_strds.get_granularity(), "2 days") - def test_temporal_hash1(self): + def test_temporal_hash1(self) -> None: """Testing the hash function in conditional statement.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -397,7 +398,7 @@ def test_temporal_hash1(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_hash_operator1(self): + def test_temporal_hash_operator1(self) -> None: """Testing the hash operator function in conditional statement.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -419,7 +420,7 @@ def test_temporal_hash_operator1(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_temporal_hash_operator2(self): + def test_temporal_hash_operator2(self) -> None: """Testing the hash operator function in conditional statement.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -441,7 +442,7 @@ def test_temporal_hash_operator2(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_tmap_function1(self): + def test_tmap_function1(self) -> None: """Testing the tmap function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -463,7 +464,7 @@ def test_tmap_function1(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_tmap_function2(self): + def test_tmap_function2(self) -> None: """Testing the tmap function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -485,7 +486,7 @@ def test_tmap_function2(self): self.assertEqual(result_strds.check_temporal_topology(), True) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_merge_function1(self): + def test_merge_function1(self) -> None: """Testing the merge function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -504,7 +505,7 @@ def test_merge_function1(self): self.assertEqual(result_strds.check_temporal_topology(), False) self.assertEqual(result_strds.get_granularity(), "1 day") - def test_merge_function2(self): + def test_merge_function2(self) -> None: """Testing the merge function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser(run=True, debug=True) temporal_algebra_parser.parse( @@ -531,7 +532,7 @@ class TestTemporalAlgebraDryRun(TestCase): """Class for testing dry runs of the temporal algebra""" @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -629,12 +630,12 @@ def setUpClass(cls): ) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A,B,C,D", quiet=True) cls.del_temp_region() - def test_merge_function1(self): + def test_merge_function1(self) -> None: """Testing the merge function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True @@ -650,7 +651,7 @@ def test_merge_function1(self): self.assertEqual(parser_content["STDS"]["name"], "R") self.assertEqual(parser_content["STDS"]["stdstype"], "strds") - def test_merge_function2(self): + def test_merge_function2(self) -> None: """Testing the merge function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True @@ -666,7 +667,7 @@ def test_merge_function2(self): self.assertEqual(parser_content["STDS"]["name"], "R") self.assertEqual(parser_content["STDS"]["stdstype"], "strds") - def test_merge_function3(self): + def test_merge_function3(self) -> None: """Testing the merge function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True @@ -682,7 +683,7 @@ def test_merge_function3(self): self.assertEqual(parser_content["STDS"]["name"], "R") self.assertEqual(parser_content["STDS"]["stdstype"], "strds") - def test_shift1(self): + def test_shift1(self) -> None: """Testing the shift function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True @@ -698,7 +699,7 @@ def test_shift1(self): self.assertEqual(parser_content["STDS"]["name"], "R") self.assertEqual(parser_content["STDS"]["stdstype"], "strds") - def test_shift2(self): + def test_shift2(self) -> None: """Testing the shift function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True @@ -714,7 +715,7 @@ def test_shift2(self): self.assertEqual(parser_content["STDS"]["name"], "R") self.assertEqual(parser_content["STDS"]["stdstype"], "strds") - def test_buffer1(self): + def test_buffer1(self) -> None: """Testing the shift function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True @@ -730,7 +731,7 @@ def test_buffer1(self): self.assertEqual(parser_content["STDS"]["name"], "R") self.assertEqual(parser_content["STDS"]["stdstype"], "strds") - def test_buff2(self): + def test_buff2(self) -> None: """Testing the shift function.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True @@ -746,7 +747,7 @@ def test_buff2(self): self.assertEqual(parser_content["STDS"]["name"], "R") self.assertEqual(parser_content["STDS"]["stdstype"], "strds") - def test_time_constant(self): + def test_time_constant(self) -> None: """Testing the time constant functions.""" temporal_algebra_parser = tgis.TemporalAlgebraParser( run=True, debug=False, dry_run=True diff --git a/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py b/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py index 7e0db57a8ce..e9ea1c3251c 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py +++ b/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py @@ -8,16 +8,16 @@ """ import datetime -import os -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalAlgebraGranularity(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -132,17 +132,17 @@ def setUpClass(cls): end="2001-01-04", ) - def tearDown(self): + def tearDown(self) -> None: pass # self.runModule("t.remove", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" # cls.runModule("t.remove", flags="rf", inputs="A,B,C,D", quiet=True) cls.del_temp_region() - def test_common_granularity_1(self): + def test_common_granularity_1(self) -> None: """Testing the common granularity function.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) expr = "R = A : B" @@ -174,7 +174,7 @@ def test_common_granularity_1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 month") - def test_common_granularity_2(self): + def test_common_granularity_2(self) -> None: """Testing the common granularity function year to month samping.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) expr = "R = A : C" @@ -193,7 +193,7 @@ def test_common_granularity_2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 month") - def test_common_granularity_3(self): + def test_common_granularity_3(self) -> None: """Testing the common granularity function with gaps.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) expr = "R = A : D" @@ -212,7 +212,7 @@ def test_common_granularity_3(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 month") - def test_common_granularity_4(self): + def test_common_granularity_4(self) -> None: """Testing the common granularity function year to month with gaps.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) expr = "R = C : D" @@ -231,7 +231,7 @@ def test_common_granularity_4(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 month") - def test_common_granularity_4(self): + def test_common_granularity_4(self) -> None: """Testing the common granularity function year to month with gaps.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) expr = "R = C : D" @@ -250,7 +250,7 @@ def test_common_granularity_4(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 month") - def test_common_granularity_5(self): + def test_common_granularity_5(self) -> None: """Testing the common granularity function year to month with gaps.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) expr = "R = A : C : D" @@ -269,7 +269,7 @@ def test_common_granularity_5(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 month") - def test_common_granularity_6(self): + def test_common_granularity_6(self) -> None: """Testing the common granularity function year to month with gaps.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) expr = "R = if(start_month(A) > 2, A : C : D)" diff --git a/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py b/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py index cf0e9c82bb7..81ad3b47b64 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py +++ b/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py @@ -8,16 +8,16 @@ """ import datetime -import os -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalAlgebraMixedDatasets(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -93,14 +93,14 @@ def setUpClass(cls): ) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", type="str3ds", inputs="A", quiet=True) cls.runModule("t.remove", flags="rf", type="strds", inputs="B", quiet=True) cls.runModule("t.remove", flags="rf", type="stvds", inputs="C", quiet=True) cls.del_temp_region() - def test_temporal_select_operators1(self): + def test_temporal_select_operators1(self) -> None: """Testing the temporal select operator. Including temporal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -135,7 +135,7 @@ def test_temporal_select_operators1(self): self.assertEqual(pc["STDS"]["name"], "R") self.assertEqual(pc["STDS"]["stdstype"], "str3ds") - def test_temporal_select_operators2(self): + def test_temporal_select_operators2(self) -> None: """Testing the temporal select operator. Including temporal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -170,7 +170,7 @@ def test_temporal_select_operators2(self): self.assertEqual(pc["STDS"]["name"], "R") self.assertEqual(pc["STDS"]["stdstype"], "str3ds") - def test_temporal_select_operators3(self): + def test_temporal_select_operators3(self) -> None: """Testing the temporal select operator. Including temporal relations and negation operation.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) @@ -192,7 +192,7 @@ def test_temporal_select_operators3(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_select_operators4(self): + def test_temporal_select_operators4(self) -> None: """Testing the temporal select operator. Including temporal relations and temporal operators.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) @@ -212,7 +212,7 @@ def test_temporal_select_operators4(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_select_operators5(self): + def test_temporal_select_operators5(self) -> None: """Testing the temporal select operator. Including temporal relations and temporal operators.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) @@ -232,7 +232,7 @@ def test_temporal_select_operators5(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_hash_operator1(self): + def test_temporal_hash_operator1(self) -> None: """Testing the hash operator function in conditional statement.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -253,7 +253,7 @@ def test_temporal_hash_operator1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_hash_operator2(self): + def test_temporal_hash_operator2(self) -> None: """Testing the hash operator function in conditional statement.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -274,7 +274,7 @@ def test_temporal_hash_operator2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_different_stds_handling1(self): + def test_different_stds_handling1(self) -> None: """Testing the handling of different stds types as output.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -295,7 +295,7 @@ def test_different_stds_handling1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_different_stds_handling2(self): + def test_different_stds_handling2(self) -> None: """Testing the handling of different stds types as output.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True, dry_run=True) pc = ta.parse( diff --git a/python/grass/temporal/testsuite/unittests_temporal_conditionals.py b/python/grass/temporal/testsuite/unittests_temporal_conditionals.py index ff0703aec1d..eacc31bd1f1 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_conditionals.py +++ b/python/grass/temporal/testsuite/unittests_temporal_conditionals.py @@ -8,16 +8,16 @@ """ import datetime -import os -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalConditionals(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -135,16 +135,16 @@ def setUpClass(cls): end="2001-01-04", ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A,B,C,D,E", quiet=True) cls.del_temp_region() - def test_temporal_condition_1(self): + def test_temporal_condition_1(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -164,7 +164,7 @@ def test_temporal_condition_1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_2(self): + def test_temporal_condition_2(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse(expression="R = if(td(A) == 1, A)", basename="r", overwrite=True) @@ -180,7 +180,7 @@ def test_temporal_condition_2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_3(self): + def test_temporal_condition_3(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -200,7 +200,7 @@ def test_temporal_condition_3(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_4(self): + def test_temporal_condition_4(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -220,7 +220,7 @@ def test_temporal_condition_4(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_5(self): + def test_temporal_condition_5(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -238,7 +238,7 @@ def test_temporal_condition_5(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_6(self): + def test_temporal_condition_6(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -258,7 +258,7 @@ def test_temporal_condition_6(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_7(self): + def test_temporal_condition_7(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -278,7 +278,7 @@ def test_temporal_condition_7(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_condition_8(self): + def test_temporal_condition_8(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -298,7 +298,7 @@ def test_temporal_condition_8(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_condition_9(self): + def test_temporal_condition_9(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -318,7 +318,7 @@ def test_temporal_condition_9(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_condition_10(self): + def test_temporal_condition_10(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -338,7 +338,7 @@ def test_temporal_condition_10(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_condition_11(self): + def test_temporal_condition_11(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -358,7 +358,7 @@ def test_temporal_condition_11(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_condition_12(self): + def test_temporal_condition_12(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -378,7 +378,7 @@ def test_temporal_condition_12(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_conditional_13(self): + def test_temporal_conditional_13(self) -> None: """Testing the hash operator function in conditional statement.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -399,7 +399,7 @@ def test_temporal_conditional_13(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_else_1(self): + def test_temporal_condition_else_1(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -419,7 +419,7 @@ def test_temporal_condition_else_1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_else_2(self): + def test_temporal_condition_else_2(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -439,7 +439,7 @@ def test_temporal_condition_else_2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_else_3(self): + def test_temporal_condition_else_3(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( @@ -459,7 +459,7 @@ def test_temporal_condition_else_3(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_condition_else_4(self): + def test_temporal_condition_else_4(self) -> None: """Testing the temporal select operator with equal relations.""" ta = tgis.TemporalAlgebraParser(run=True, debug=True) ta.parse( diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py b/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py index f2d8a215bdb..090d9638f22 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py @@ -10,14 +10,15 @@ import datetime import grass.script as gs -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalRaster3dAlgebra(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -49,16 +50,16 @@ def setUpClass(cls): interval=True, ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", type="str3ds", flags="rf", inputs="D", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" # cls.runModule("t.remove", type="str3ds", flags="rf", inputs="A", quiet=True) cls.del_temp_region() - def test_temporal_neighbors_1(self): + def test_temporal_neighbors_1(self) -> None: """Simple temporal neighborhood computation test""" A = tgis.open_old_stds("A", type="str3ds") A.print_info() @@ -76,7 +77,7 @@ def test_temporal_neighbors_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 1, 4)) - def test_temporal_neighbors_2(self): + def test_temporal_neighbors_2(self) -> None: """Simple temporal neighborhood computation test""" A = tgis.open_old_stds("A", type="str3ds") A.print_info() diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra.py b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra.py index 430c9c7c18a..ad4114d4e3e 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra.py @@ -9,14 +9,15 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalRasterAlgebra(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -116,17 +117,17 @@ def setUpClass(cls): end="2001-01-04", ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", flags="rf", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A,B,C,D", quiet=True) cls.runModule("t.unregister", maps="singletmap", quiet=True) cls.del_temp_region() - def test_temporal_extent1(self): + def test_temporal_extent1(self) -> None: """Testing the temporal extent operators.""" ta = tgis.TemporalRasterAlgebraParser(run=True, debug=True) ta.parse(expression="R = A {:,during,r} C", basename="r", overwrite=True) @@ -152,7 +153,7 @@ def test_temporal_extent1(self): self.assertEqual(pc["STDS"]["name"], "R") self.assertEqual(pc["STDS"]["stdstype"], "strds") - def test_temporal_conditional_time_dimension_bug(self): + def test_temporal_conditional_time_dimension_bug(self) -> None: """Testing the conditional time dimension bug, that uses the time dimension of the conditional statement instead the time dimension of the then/else statement.""" @@ -174,7 +175,7 @@ def test_temporal_conditional_time_dimension_bug(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_simple_arith_hash_1(self): + def test_simple_arith_hash_1(self) -> None: """Simple arithmetic test including the hash operator using the granularity option for map name creation @@ -214,7 +215,7 @@ def test_simple_arith_hash_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_simple_arith_td_1(self): + def test_simple_arith_td_1(self) -> None: """Simple arithmetic test with time suffix option R = A + td(A) @@ -254,7 +255,7 @@ def test_simple_arith_td_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_simple_arith_td_2(self): + def test_simple_arith_td_2(self) -> None: """Simple arithmetic test R = A / td(A) @@ -280,7 +281,7 @@ def test_simple_arith_td_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_simple_arith_td_3(self): + def test_simple_arith_td_3(self) -> None: """Simple arithmetic test R = A {+,equal} td(A) @@ -307,7 +308,7 @@ def test_simple_arith_td_3(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_simple_arith_td_4(self): + def test_simple_arith_td_4(self) -> None: """Simple arithmetic test R = A {/, equal} td(A) @@ -334,7 +335,7 @@ def test_simple_arith_td_4(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_simple_arith_if_1(self): + def test_simple_arith_if_1(self) -> None: """Simple arithmetic test with if condition R = if({equal}, start_date(A) >= "2001-01-02", A + A) @@ -362,7 +363,7 @@ def test_simple_arith_if_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_simple_arith_if_2(self): + def test_simple_arith_if_2(self) -> None: """Simple arithmetic test with if condition R = if({equal}, A#A == 1, A - A) @@ -396,7 +397,7 @@ def test_simple_arith_if_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_complex_arith_if_1(self): + def test_complex_arith_if_1(self) -> None: """Complex arithmetic test with if condition R = if(start_date(A) < "2001-01-03" && A#A == 1, A{+, starts,l}C, A{+, finishes,l}C) @@ -426,7 +427,7 @@ def test_complex_arith_if_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 1, 4)) - def test_simple_arith_1(self): + def test_simple_arith_1(self) -> None: """Simple arithmetic test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -442,7 +443,7 @@ def test_simple_arith_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_simple_arith_2(self): + def test_simple_arith_2(self) -> None: """Simple arithmetic test that creates an empty strds""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -452,7 +453,7 @@ def test_simple_arith_2(self): D.select() self.assertEqual(D.metadata.get_number_of_maps(), 0) - def test_simple_arith_3(self): + def test_simple_arith_3(self) -> None: """Simple arithmetic test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A / A + A*A/A", basename="r", overwrite=True) @@ -466,7 +467,7 @@ def test_simple_arith_3(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_temporal_intersection_1(self): + def test_temporal_intersection_1(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A {+,equal,i} B", basename="r", overwrite=True) @@ -474,7 +475,7 @@ def test_temporal_intersection_1(self): D.select() self.assertEqual(D.metadata.get_number_of_maps(), 0) - def test_temporal_intersection_2(self): + def test_temporal_intersection_2(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A {+,during,i} B", basename="r", overwrite=True) @@ -488,7 +489,7 @@ def test_temporal_intersection_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_temporal_intersection_3(self): + def test_temporal_intersection_3(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A {+,starts,i} B", basename="r", overwrite=True) @@ -502,7 +503,7 @@ def test_temporal_intersection_3(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 4)) - def test_temporal_intersection_4(self): + def test_temporal_intersection_4(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -518,7 +519,7 @@ def test_temporal_intersection_4(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_temporal_intersection_5(self): + def test_temporal_intersection_5(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -534,7 +535,7 @@ def test_temporal_intersection_5(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_temporal_intersection_6(self): + def test_temporal_intersection_6(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = B {+,overlaps,u} C", basename="r", overwrite=True) @@ -548,7 +549,7 @@ def test_temporal_intersection_6(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 4)) - def test_temporal_intersection_7(self): + def test_temporal_intersection_7(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = B {+,overlapped,u} C", basename="r", overwrite=True) @@ -562,7 +563,7 @@ def test_temporal_intersection_7(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_temporal_intersection_8(self): + def test_temporal_intersection_8(self) -> None: """Simple temporal intersection test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -580,7 +581,7 @@ def test_temporal_intersection_8(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 1, 5)) - def test_temporal_neighbors_1(self): + def test_temporal_neighbors_1(self) -> None: """Simple temporal neighborhood computation test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A[-1] + A[1]", basename="r", overwrite=True) @@ -594,7 +595,7 @@ def test_temporal_neighbors_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 1, 4)) - def test_temporal_neighbors_2(self): + def test_temporal_neighbors_2(self) -> None: """Simple temporal neighborhood computation test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A[0,0,-1] + A[0,0,1]", basename="r", overwrite=True) @@ -608,7 +609,7 @@ def test_temporal_neighbors_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 1, 4)) - def test_tmap_function1(self): + def test_tmap_function1(self) -> None: """Testing the tmap function.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = tmap(singletmap)", basename="r", overwrite=True) @@ -625,7 +626,7 @@ def test_tmap_function1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_tmap_function2(self): + def test_tmap_function2(self) -> None: """Testing the tmap function.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = tmap(singletmap) + 1", basename="r", overwrite=True) @@ -642,7 +643,7 @@ def test_tmap_function2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_map_function1(self): + def test_map_function1(self) -> None: """Testing the map function.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = map(singlemap) + A", basename="r", overwrite=True) @@ -659,7 +660,7 @@ def test_map_function1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_map_function2(self): + def test_map_function2(self) -> None: """Testing the map function.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A * map(singlemap)", basename="r", overwrite=True) @@ -676,7 +677,7 @@ def test_map_function2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_select(self): + def test_temporal_select(self) -> None: """Testing the temporal select operator.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A : A", basename="r", overwrite=True) @@ -692,7 +693,7 @@ def test_temporal_select(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_select(self): + def test_temporal_select(self) -> None: """Testing the temporal select operator.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A : D", basename="r", overwrite=True) @@ -708,7 +709,7 @@ def test_temporal_select(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_select_operators1(self): + def test_temporal_select_operators1(self) -> None: """Testing the temporal select operator. Including temporal relations.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A : D", basename="r", overwrite=True) @@ -724,7 +725,7 @@ def test_temporal_select_operators1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_select_operators2(self): + def test_temporal_select_operators2(self) -> None: """Testing the temporal select operator. Including temporal relations.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A {!:,during} C", basename="r", overwrite=True) @@ -740,7 +741,7 @@ def test_temporal_select_operators2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_select_operators3(self): + def test_temporal_select_operators3(self) -> None: """Testing the temporal select operator. Including temporal relations and different temporal operators (lr|+&)""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -757,7 +758,7 @@ def test_temporal_select_operators3(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_select_operators4(self): + def test_temporal_select_operators4(self) -> None: """Testing the temporal select operator. Including temporal relations and different temporal operators (lr|+&)""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -779,7 +780,7 @@ def test_temporal_select_operators4(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_hash_operator1(self): + def test_temporal_hash_operator1(self) -> None: """Testing the temporal hash operator in the raster algebra.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = if(A # D == 1, A)", basename="r", overwrite=True) @@ -795,7 +796,7 @@ def test_temporal_hash_operator1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_hash_operator2(self): + def test_temporal_hash_operator2(self) -> None: """Testing the temporal hash operator in the raster algebra.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A # D", basename="r", overwrite=True) @@ -811,7 +812,7 @@ def test_temporal_hash_operator2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_hash_operator3(self): + def test_temporal_hash_operator3(self) -> None: """Testing the temporal hash operator in the raster algebra.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = C {#,contains} A", basename="r", overwrite=True) @@ -827,7 +828,7 @@ def test_temporal_hash_operator3(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_hash_operator4(self): + def test_temporal_hash_operator4(self) -> None: """Testing the temporal hash operator in the raster algebra.""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -847,7 +848,7 @@ def test_temporal_hash_operator4(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_raster_arithmetic_relation_1(self): + def test_raster_arithmetic_relation_1(self) -> None: """Arithmetic test with temporal intersection""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = B {+,contains,l} A ", basename="r", overwrite=True) @@ -863,7 +864,7 @@ def test_raster_arithmetic_relation_1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_raster_arithmetic_relation_2(self): + def test_raster_arithmetic_relation_2(self) -> None: """Arithmetic test with temporal intersection""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = B {*,contains,l} A ", basename="r", overwrite=True) @@ -879,7 +880,7 @@ def test_raster_arithmetic_relation_2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_raster_arithmetic_relation_3(self): + def test_raster_arithmetic_relation_3(self) -> None: """Arithmetic test with temporal intersection""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = B {+,contains,l} A ", basename="r", overwrite=True) @@ -895,7 +896,7 @@ def test_raster_arithmetic_relation_3(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "2 days") - def test_raster_arithmetic_relation_4(self): + def test_raster_arithmetic_relation_4(self) -> None: """Arithmetic test with temporal intersection""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = B {+,contains,r} A ", basename="r", overwrite=True) @@ -911,7 +912,7 @@ def test_raster_arithmetic_relation_4(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_raster_arithmetic_relation_5(self): + def test_raster_arithmetic_relation_5(self) -> None: """Complex arithmetic test with temporal intersection""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -931,7 +932,7 @@ def test_raster_arithmetic_relation_5(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_capacity_1(self): + def test_capacity_1(self) -> None: """Arithmetic test with temporal intersection""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = (((((((A + A) - A) * A) / A) % A) - td(A)) - (A # A))" diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py index f96ed12899f..d9e15fc2174 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_equal_ts.py @@ -9,15 +9,16 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.utils import xfail_windows +import grass.temporal as tgis + class TestTemporalRasterAlgebraImplicitAggregation(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -55,18 +56,18 @@ def setUpClass(cls): type="raster", name=None, maps="singletmap", start="2001-01-01" ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", flags="rf", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A", quiet=True) cls.runModule("t.unregister", maps="singletmap", quiet=True) cls.del_temp_region() @xfail_windows - def test_simple_operator(self): + def test_simple_operator(self) -> None: """Test implicit aggregation R = A + A @@ -93,7 +94,7 @@ def test_simple_operator(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), None) - def test_complex_operator(self): + def test_complex_operator(self) -> None: """Test implicit aggregation R = A {+,equal,l} A @@ -120,7 +121,7 @@ def test_complex_operator(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), None) - def test_single_map_complex_operator(self): + def test_single_map_complex_operator(self) -> None: """Test implicit aggregation R = singletmap {+,equal,l} A @@ -152,7 +153,7 @@ def test_single_map_complex_operator(self): self.assertEqual(D.get_granularity(), None) @xfail_windows - def test_single_map_simple_operator(self): + def test_single_map_simple_operator(self) -> None: """Test implicit aggregation R = singletmap + A @@ -179,7 +180,7 @@ def test_single_map_simple_operator(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), None) - def test_single_map_complex_operator_right_ts(self): + def test_single_map_complex_operator_right_ts(self) -> None: """Test implicit aggregation TODO: Is this the correct result? Implicit aggregation and full permutation? diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_grs.py b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_grs.py index 273176d14fa..15c95d6ea27 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_grs.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_grs.py @@ -9,14 +9,15 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalRasterAlgebra(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -141,12 +142,12 @@ def setUpClass(cls): end="2001-07-01", ) - def tearDown(self): + def tearDown(self) -> None: return self.runModule("t.remove", flags="rf", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: return """Remove the temporary region """ @@ -154,7 +155,7 @@ def tearDownClass(cls): cls.runModule("t.unregister", maps="singletmap", quiet=True) cls.del_temp_region() - def test_1(self): + def test_1(self) -> None: """Simple arithmetik test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = if(C == 9, A - 1)" @@ -189,7 +190,7 @@ def test_1(self): self.assertEqual(pc["STDS"]["name"], "R") self.assertEqual(pc["STDS"]["stdstype"], "strds") - def test_2(self): + def test_2(self) -> None: """Simple arithmetik test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = A + B + C" @@ -224,7 +225,7 @@ def test_2(self): self.assertEqual(pc["STDS"]["name"], "R") self.assertEqual(pc["STDS"]["stdstype"], "strds") - def test_3(self): + def test_3(self) -> None: """Simple arithmetik test with null map""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = A + B + C + tmap(nullmap)" @@ -259,7 +260,7 @@ def test_3(self): self.assertEqual(pc["STDS"]["name"], "R") self.assertEqual(pc["STDS"]["stdstype"], "strds") - def test_4(self): + def test_4(self) -> None: """Simple arithmetik test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = if(D == 11, A - 1, A + 1)" @@ -281,7 +282,7 @@ def test_4(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_simple_arith_hash_1(self): + def test_simple_arith_hash_1(self) -> None: """Simple arithmetic test including the hash operator""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = A + (A # A)", basename="r", overwrite=True) @@ -295,7 +296,7 @@ def test_simple_arith_hash_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 7, 1)) - def test_simple_arith_hash_2(self): + def test_simple_arith_hash_2(self) -> None: """Simple arithmetic test including the hash operator""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = (A + A) # A", basename="r", overwrite=True) @@ -309,7 +310,7 @@ def test_simple_arith_hash_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 7, 1)) - def test_simple_arith_td_1(self): + def test_simple_arith_td_1(self) -> None: """Simple arithmetic test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = A + td(A:D)" @@ -331,7 +332,7 @@ def test_simple_arith_td_1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_simple_arith_if_1(self): + def test_simple_arith_if_1(self) -> None: """Simple arithmetic test with if condition""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = 'R = if(start_date(A) >= "2001-02-01", A + A)' @@ -351,7 +352,7 @@ def test_simple_arith_if_1(self): self.assertEqual(start, datetime.datetime(2001, 2, 1)) self.assertEqual(end, datetime.datetime(2001, 7, 1)) - def test_simple_arith_if_2(self): + def test_simple_arith_if_2(self) -> None: """Simple arithmetic test with if condition""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = if(A#A == 1, A - A)" @@ -371,7 +372,7 @@ def test_simple_arith_if_2(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 7, 1)) - def test_complex_arith_if_1(self): + def test_complex_arith_if_1(self) -> None: """Complex arithmetic test with if condition""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = 'R = if(start_date(A) < "2001-03-01" && A#A == 1, A+C, A-C)' @@ -391,7 +392,7 @@ def test_complex_arith_if_1(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 7, 1)) - def test_temporal_neighbors(self): + def test_temporal_neighbors(self) -> None: """Simple temporal neighborhood computation test""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = (A[0,0,-1] : D) + (A[0,0,1] : D)" @@ -411,7 +412,7 @@ def test_temporal_neighbors(self): self.assertEqual(start, datetime.datetime(2001, 1, 2)) self.assertEqual(end, datetime.datetime(2001, 5, 6)) - def test_map(self): + def test_map(self) -> None: """Test STDS + single map without timestamp""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = A + map(singletmap)" @@ -431,7 +432,7 @@ def test_map(self): self.assertEqual(start, datetime.datetime(2001, 1, 1)) self.assertEqual(end, datetime.datetime(2001, 7, 1)) - def test_tmap_map(self): + def test_tmap_map(self) -> None: """Test STDS + single map with and without timestamp""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) expr = "R = tmap(singletmap) + A + map(singletmap)" diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_spatial_topology.py b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_spatial_topology.py index 481eae5d59d..5f5c3557f26 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_spatial_topology.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster_algebra_spatial_topology.py @@ -9,14 +9,15 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalRasterAlgebraSpatialTopology(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -89,17 +90,17 @@ def setUpClass(cls): type="raster", name=None, maps="singletmap", start="2001-01-01" ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", flags="rf", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A,B", quiet=True) cls.runModule("t.unregister", maps="singletmap", quiet=True) cls.del_temp_region() - def test_equal_equivalent_sum(self): + def test_equal_equivalent_sum(self) -> None: """Spatial topology distinction with equal timestamps STRDS A and B have identical time stamps, hence the differentiation @@ -131,7 +132,7 @@ def test_equal_equivalent_sum(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), None) - def test_equal_overlap_sum(self): + def test_equal_overlap_sum(self) -> None: """Spatial topology distinction with equal timestamps STRDS A and B have identical time stamps, hence the differentiation @@ -161,7 +162,7 @@ def test_equal_overlap_sum(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), None) - def test_equal_overlap_sum_with_null(self): + def test_equal_overlap_sum_with_null(self) -> None: """Spatial topology distinction with equal timestamps STRDS A and B have identical time stamps, hence the differentiation @@ -193,7 +194,7 @@ def test_equal_overlap_sum_with_null(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), None) - def test_equal_contain_sum(self): + def test_equal_contain_sum(self) -> None: """Spatial topology distinction with equal timestamps STRDS A and B have identical time stamps, hence the differentiation @@ -220,7 +221,7 @@ def test_equal_contain_sum(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), None) - def test_equal_equivalent_contain_sum(self): + def test_equal_equivalent_contain_sum(self) -> None: """Spatial topology distinction with equal timestamps STRDS A and B have identical time stamps, hence the differentiation @@ -255,7 +256,7 @@ def test_equal_equivalent_contain_sum(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), None) - def test_equal_equivalent_compare(self): + def test_equal_equivalent_compare(self) -> None: """Test implicit aggregation STRDS A and B have identical time stamps, hence the differentiation diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals.py b/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals.py index 813f469c2ce..f38e95412ed 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals.py @@ -9,14 +9,15 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalRasterAlgebraConditionals(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -104,16 +105,16 @@ def setUpClass(cls): interval=True, ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", flags="rf", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A,B,C,D", quiet=True) cls.del_temp_region() - def test_temporal_conditional_time_dimension_bug(self): + def test_temporal_conditional_time_dimension_bug(self) -> None: """Testing the conditional time dimension bug, that uses the time dimension of the conditional statement instead the time dimension of the then/else statement.""" @@ -135,7 +136,7 @@ def test_temporal_conditional_time_dimension_bug(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_temporal_conditional_1(self): + def test_temporal_conditional_1(self) -> None: """Testing the conditional time dimension bug, that uses the time dimension of the conditional statement instead the time dimension of the then/else statement.""" @@ -155,7 +156,7 @@ def test_temporal_conditional_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_temporal_conditional_relation_1(self): + def test_temporal_conditional_relation_1(self) -> None: """Testing the conditional time dimension bug, that uses the time dimension of the conditional statement instead the time dimension of the then/else statement.""" @@ -177,7 +178,7 @@ def test_temporal_conditional_relation_1(self): self.assertEqual(R.check_temporal_topology(), False) self.assertEqual(R.get_granularity(), "2 days") - def test_spatial_conditional_1(self): + def test_spatial_conditional_1(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -198,7 +199,7 @@ def test_spatial_conditional_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_2(self): + def test_spatial_conditional_2(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -219,7 +220,7 @@ def test_spatial_conditional_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_3(self): + def test_spatial_conditional_3(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -236,7 +237,7 @@ def test_spatial_conditional_3(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_4(self): + def test_spatial_conditional_4(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -253,7 +254,7 @@ def test_spatial_conditional_4(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_5(self): + def test_spatial_conditional_5(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -274,7 +275,7 @@ def test_spatial_conditional_5(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "2 days") - def test_spatial_conditional_relation_1(self): + def test_spatial_conditional_relation_1(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -293,7 +294,7 @@ def test_spatial_conditional_relation_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_relation_2(self): + def test_spatial_conditional_relation_2(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -313,7 +314,7 @@ def test_spatial_conditional_relation_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_numeric_relation_1(self): + def test_spatial_conditional_numeric_relation_1(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -331,7 +332,7 @@ def test_spatial_conditional_numeric_relation_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_numeric_relation_2(self): + def test_spatial_conditional_numeric_relation_2(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -352,7 +353,7 @@ def test_spatial_conditional_numeric_relation_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_numeric_1(self): + def test_spatial_conditional_numeric_1(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = if(A > 2, 0, A)", basename="r", overwrite=True) @@ -368,7 +369,7 @@ def test_spatial_conditional_numeric_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_numeric_2(self): + def test_spatial_conditional_numeric_2(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = if(A > 2, A, 8)", basename="r", overwrite=True) @@ -384,7 +385,7 @@ def test_spatial_conditional_numeric_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_numeric_3(self): + def test_spatial_conditional_numeric_3(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = if(A > 2, 1, 0)", basename="r", overwrite=True) @@ -400,7 +401,7 @@ def test_spatial_conditional_numeric_3(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatial_conditional_numeric_4(self): + def test_spatial_conditional_numeric_4(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse(expression="R = if(A > 2, null())", basename="r", overwrite=True) @@ -416,7 +417,7 @@ def test_spatial_conditional_numeric_4(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_1(self): + def test_spatiotemporal_conditional_1(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -436,7 +437,7 @@ def test_spatiotemporal_conditional_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_2(self): + def test_spatiotemporal_conditional_2(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -456,7 +457,7 @@ def test_spatiotemporal_conditional_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_relation_1(self): + def test_spatiotemporal_conditional_relation_1(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -476,7 +477,7 @@ def test_spatiotemporal_conditional_relation_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_relation_2(self): + def test_spatiotemporal_conditional_relation_2(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -496,7 +497,7 @@ def test_spatiotemporal_conditional_relation_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_numeric_relation_1(self): + def test_spatiotemporal_conditional_numeric_relation_1(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -516,7 +517,7 @@ def test_spatiotemporal_conditional_numeric_relation_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_numeric_relation_2(self): + def test_spatiotemporal_conditional_numeric_relation_2(self) -> None: """Testing the spatial conditionals combined by AND/OR operators. Evaluation""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) @@ -537,7 +538,7 @@ def test_spatiotemporal_conditional_numeric_relation_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_numeric_1(self): + def test_spatiotemporal_conditional_numeric_1(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -557,7 +558,7 @@ def test_spatiotemporal_conditional_numeric_1(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_numeric_2(self): + def test_spatiotemporal_conditional_numeric_2(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -577,7 +578,7 @@ def test_spatiotemporal_conditional_numeric_2(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_numeric_3(self): + def test_spatiotemporal_conditional_numeric_3(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( @@ -597,7 +598,7 @@ def test_spatiotemporal_conditional_numeric_3(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_spatiotemporal_conditional_numeric_4(self): + def test_spatiotemporal_conditional_numeric_4(self) -> None: """Testing the spatial conditionals with numeric conclusions""" tra = tgis.TemporalRasterAlgebraParser(run=True, debug=True) tra.parse( diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py b/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py index dd0a9dc8adf..ba70f1e9982 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster_conditionals_complement_else.py @@ -9,14 +9,15 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalRasterAlgebraConditionalComplements(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -67,16 +68,16 @@ def setUpClass(cls): interval=True, ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", flags="rf", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule("t.remove", flags="rf", inputs="A,B", quiet=True) cls.del_temp_region() - def test_temporal_conditional_complement(self): + def test_temporal_conditional_complement(self) -> None: """Test the conditional expression that evaluate if then else statements so that the else statement is a complement operation @@ -112,7 +113,7 @@ def test_temporal_conditional_complement(self): self.assertEqual(R.check_temporal_topology(), True) self.assertEqual(R.get_granularity(), "1 day") - def test_temporal_conditional_complement_right_side_timestamps(self): + def test_temporal_conditional_complement_right_side_timestamps(self) -> None: """Test the conditional expression that evaluate if then else statements so that the else statement is a complement operation diff --git a/python/grass/temporal/testsuite/unittests_temporal_vector_algebra.py b/python/grass/temporal/testsuite/unittests_temporal_vector_algebra.py index 7c07a7edc6a..9d7b3cff4c1 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_vector_algebra.py +++ b/python/grass/temporal/testsuite/unittests_temporal_vector_algebra.py @@ -9,14 +9,15 @@ import datetime -import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.main import test +import grass.temporal as tgis + class TestTemporalVectorAlgebra(TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: """Initiate the temporal GIS and set the region""" tgis.init(True) # Raise on error instead of exit(1) cls.use_temp_region() @@ -146,18 +147,18 @@ def setUpClass(cls): end="2001-01-04", ) - def tearDown(self): + def tearDown(self) -> None: self.runModule("t.remove", type="stvds", inputs="R", quiet=True) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: """Remove the temporary region""" cls.runModule( "t.remove", flags="rf", inputs="A,B,C,D", type="stvds", quiet=True ) cls.del_temp_region() - def test_temporal_select(self): + def test_temporal_select(self) -> None: """Testing the temporal select operator.""" tva = tgis.TemporalVectorAlgebraParser(run=True, debug=True) tva.parse(expression="R = A : A", basename="r", overwrite=True) @@ -175,7 +176,7 @@ def test_temporal_select(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_extent1(self): + def test_temporal_extent1(self) -> None: """Testing the temporal extent operators.""" ta = tgis.TemporalVectorAlgebraParser(run=True, debug=True) ta.parse(expression="R = A {:,during,r} C", basename="r", overwrite=True) @@ -192,7 +193,7 @@ def test_temporal_extent1(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_select_operators(self): + def test_temporal_select_operators(self) -> None: """Testing the temporal select operator. Including temporal relations.""" tva = tgis.TemporalVectorAlgebraParser(run=True, debug=True) tva.parse(expression="R = A {:,during} C", basename="r", overwrite=True) @@ -210,7 +211,7 @@ def test_temporal_select_operators(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_buff_operators_1(self): + def test_temporal_buff_operators_1(self) -> None: """Testing the bufferoperator.""" tva = tgis.TemporalVectorAlgebraParser(run=True, debug=True) tva.parse(expression="R = buff_p(A,0.5)", basename="r", overwrite=True) @@ -228,7 +229,7 @@ def test_temporal_buff_operators_1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_buff_operators_2(self): + def test_temporal_buff_operators_2(self) -> None: """Testing the bufferoperator.""" tva = tgis.TemporalVectorAlgebraParser(run=True, debug=True) tva.parse(expression="R = buff_a(buff_p(A,1),10)", basename="r", overwrite=True) @@ -246,7 +247,7 @@ def test_temporal_buff_operators_2(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_overlay_operators_1(self): + def test_temporal_overlay_operators_1(self) -> None: """Testing the spatial overlay operator.""" tva = tgis.TemporalVectorAlgebraParser(run=True, debug=True) tva.parse( @@ -266,7 +267,7 @@ def test_temporal_overlay_operators_1(self): self.assertEqual(D.check_temporal_topology(), True) self.assertEqual(D.get_granularity(), "1 day") - def test_temporal_overlay_operators_2(self): + def test_temporal_overlay_operators_2(self) -> None: """Testing the spatial overlay operator.""" tva = tgis.TemporalVectorAlgebraParser(run=True, debug=True) tva.parse( @@ -288,7 +289,7 @@ def test_temporal_overlay_operators_2(self): self.assertEqual(D.check_temporal_topology(), False) self.assertEqual(D.get_granularity(), "2 days") - def test_temporal_overlay_operators_3(self): + def test_temporal_overlay_operators_3(self) -> None: """Testing the spatial overlay operator.""" tva = tgis.TemporalVectorAlgebraParser(run=True, debug=True) tva.parse( diff --git a/python/grass/temporal/unit_tests.py b/python/grass/temporal/unit_tests.py index ea4e4bb62c4..8275e012f25 100644 --- a/python/grass/temporal/unit_tests.py +++ b/python/grass/temporal/unit_tests.py @@ -1,5 +1,5 @@ """ -Depricazed unittests +Deprecated unittests (C) 2008-2011 by the GRASS Development Team This program is free software under the GNU General Public @@ -36,7 +36,7 @@ ############################################################################### -def test_increment_datetime_by_string(): +def test_increment_datetime_by_string() -> None: # First test print("# Test 1") dt = datetime(2001, 9, 1, 0, 0, 0) @@ -105,7 +105,7 @@ def test_increment_datetime_by_string(): ############################################################################### -def test_adjust_datetime_to_granularity(): +def test_adjust_datetime_to_granularity() -> None: # First test print("Test 1") dt = datetime(2001, 8, 8, 12, 30, 30) @@ -223,7 +223,7 @@ def test_adjust_datetime_to_granularity(): ############################################################################### -def test_compute_datetime_delta(): +def test_compute_datetime_delta() -> None: print("Test 1") start = datetime(2001, 1, 1, 0, 0, 0) end = datetime(2001, 1, 1, 0, 0, 0) @@ -566,7 +566,7 @@ def test_compute_datetime_delta(): core.fatal("Compute datetime delta is wrong %s" % (delta)) -def test_compute_absolute_time_granularity(): +def test_compute_absolute_time_granularity() -> None: # First we test intervals print("Test 1") maps = [] @@ -886,7 +886,7 @@ def test_compute_absolute_time_granularity(): ############################################################################### -def test_spatial_extent_intersection(): +def test_spatial_extent_intersection() -> None: # Generate the extents A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) @@ -970,7 +970,7 @@ def test_spatial_extent_intersection(): ############################################################################### -def test_spatial_relations(): +def test_spatial_relations() -> None: # Generate the extents A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) @@ -1352,56 +1352,56 @@ def test_spatial_relations(): ############################################################################### -def test_temporal_topology_builder(): +def test_temporal_topology_builder() -> None: map_listA = [] - _map = RasterDataset(ident="1@a") - _map.set_absolute_time(datetime(2001, 1, 1), datetime(2001, 2, 1)) - map_listA.append(copy.copy(_map)) - _map = RasterDataset(ident="2@a") - _map.set_absolute_time(datetime(2001, 2, 1), datetime(2001, 3, 1)) - map_listA.append(copy.copy(_map)) - _map = RasterDataset(ident="3@a") - _map.set_absolute_time(datetime(2001, 3, 1), datetime(2001, 4, 1)) - map_listA.append(copy.copy(_map)) - _map = RasterDataset(ident="4@a") - _map.set_absolute_time(datetime(2001, 4, 1), datetime(2001, 5, 1)) - map_listA.append(copy.copy(_map)) - _map = RasterDataset(ident="5@a") - _map.set_absolute_time(datetime(2001, 5, 1), datetime(2001, 6, 1)) - map_listA.append(copy.copy(_map)) + map_ = RasterDataset(ident="1@a") + map_.set_absolute_time(datetime(2001, 1, 1), datetime(2001, 2, 1)) + map_listA.append(copy.copy(map_)) + map_ = RasterDataset(ident="2@a") + map_.set_absolute_time(datetime(2001, 2, 1), datetime(2001, 3, 1)) + map_listA.append(copy.copy(map_)) + map_ = RasterDataset(ident="3@a") + map_.set_absolute_time(datetime(2001, 3, 1), datetime(2001, 4, 1)) + map_listA.append(copy.copy(map_)) + map_ = RasterDataset(ident="4@a") + map_.set_absolute_time(datetime(2001, 4, 1), datetime(2001, 5, 1)) + map_listA.append(copy.copy(map_)) + map_ = RasterDataset(ident="5@a") + map_.set_absolute_time(datetime(2001, 5, 1), datetime(2001, 6, 1)) + map_listA.append(copy.copy(map_)) tb = SpatioTemporalTopologyBuilder() tb.build(map_listA) count = 0 - for _map in tb: - print("[%s]" % (_map.get_name())) - _map.print_topology_info() - if _map.get_id() != map_listA[count].get_id(): + for map_ in tb: + print("[%s]" % (map_.get_name())) + map_.print_topology_info() + if map_.get_id() != map_listA[count].get_id(): core.fatal( "Error building temporal topology <%s> != <%s>" - % (_map.get_id(), map_listA[count].get_id()) + % (map_.get_id(), map_listA[count].get_id()) ) count += 1 map_listB = [] - _map = RasterDataset(ident="1@b") - _map.set_absolute_time(datetime(2001, 1, 14), datetime(2001, 3, 14)) - map_listB.append(copy.copy(_map)) - _map = RasterDataset(ident="2@b") - _map.set_absolute_time(datetime(2001, 2, 1), datetime(2001, 4, 1)) - map_listB.append(copy.copy(_map)) - _map = RasterDataset(ident="3@b") - _map.set_absolute_time(datetime(2001, 2, 14), datetime(2001, 4, 30)) - map_listB.append(copy.copy(_map)) - _map = RasterDataset(ident="4@b") - _map.set_absolute_time(datetime(2001, 4, 2), datetime(2001, 4, 30)) - map_listB.append(copy.copy(_map)) - _map = RasterDataset(ident="5@b") - _map.set_absolute_time(datetime(2001, 5, 1), datetime(2001, 5, 14)) - map_listB.append(copy.copy(_map)) + map_ = RasterDataset(ident="1@b") + map_.set_absolute_time(datetime(2001, 1, 14), datetime(2001, 3, 14)) + map_listB.append(copy.copy(map_)) + map_ = RasterDataset(ident="2@b") + map_.set_absolute_time(datetime(2001, 2, 1), datetime(2001, 4, 1)) + map_listB.append(copy.copy(map_)) + map_ = RasterDataset(ident="3@b") + map_.set_absolute_time(datetime(2001, 2, 14), datetime(2001, 4, 30)) + map_listB.append(copy.copy(map_)) + map_ = RasterDataset(ident="4@b") + map_.set_absolute_time(datetime(2001, 4, 2), datetime(2001, 4, 30)) + map_listB.append(copy.copy(map_)) + map_ = RasterDataset(ident="5@b") + map_.set_absolute_time(datetime(2001, 5, 1), datetime(2001, 5, 14)) + map_listB.append(copy.copy(map_)) tb = SpatioTemporalTopologyBuilder() tb.build(map_listB) @@ -1417,13 +1417,13 @@ def test_temporal_topology_builder(): core.fatal("Error building temporal topology") count = 0 - for _map in tb: - print("[%s]" % (_map.get_map_id())) - _map.print_topology_shell_info() - if _map.get_id() != map_listB[count].get_id(): + for map_ in tb: + print("[%s]" % (map_.get_map_id())) + map_.print_topology_shell_info() + if map_.get_id() != map_listB[count].get_id(): core.fatal( "Error building temporal topology <%s> != <%s>" - % (_map.get_id(), map_listB[count].get_id()) + % (map_.get_id(), map_listB[count].get_id()) ) count += 1 @@ -1431,20 +1431,20 @@ def test_temporal_topology_builder(): tb.build(map_listA, map_listB) count = 0 - for _map in tb: - print("[%s]" % (_map.get_map_id())) - _map.print_topology_shell_info() - if _map.get_id() != map_listA[count].get_id(): + for map_ in tb: + print("[%s]" % (map_.get_map_id())) + map_.print_topology_shell_info() + if map_.get_id() != map_listA[count].get_id(): core.fatal( "Error building temporal topology <%s> != <%s>" - % (_map.get_id(), map_listA[count].get_id()) + % (map_.get_id(), map_listA[count].get_id()) ) count += 1 count = 0 - for _map in map_listB: - print("[%s]" % (_map.get_map_id())) - _map.print_topology_shell_info() + for map_ in map_listB: + print("[%s]" % (map_.get_map_id())) + map_.print_topology_shell_info() # Probing some relations if map_listA[3].get_follows()[0] != map_listB[1]: @@ -1465,31 +1465,31 @@ def test_temporal_topology_builder(): ############################################################################### -def test_map_list_sorting(): +def test_map_list_sorting() -> None: map_list = [] - _map = RasterDataset(ident="1@a") - _map.set_absolute_time(datetime(2001, 2, 1), datetime(2001, 3, 1)) - map_list.append(copy.copy(_map)) - _map = RasterDataset(ident="2@a") - _map.set_absolute_time(datetime(2001, 1, 1), datetime(2001, 2, 1)) - map_list.append(copy.copy(_map)) - _map = RasterDataset(ident="3@a") - _map.set_absolute_time(datetime(2001, 3, 1), datetime(2001, 4, 1)) - map_list.append(copy.copy(_map)) + map_ = RasterDataset(ident="1@a") + map_.set_absolute_time(datetime(2001, 2, 1), datetime(2001, 3, 1)) + map_list.append(copy.copy(map_)) + map_ = RasterDataset(ident="2@a") + map_.set_absolute_time(datetime(2001, 1, 1), datetime(2001, 2, 1)) + map_list.append(copy.copy(map_)) + map_ = RasterDataset(ident="3@a") + map_.set_absolute_time(datetime(2001, 3, 1), datetime(2001, 4, 1)) + map_list.append(copy.copy(map_)) print("Original") - for _map in map_list: + for map_ in map_list: print( - _map.get_temporal_extent_as_tuple()[0], - _map.get_temporal_extent_as_tuple()[1], + map_.get_temporal_extent_as_tuple()[0], + map_.get_temporal_extent_as_tuple()[1], ) print("Sorted by start time") new_list = sorted(map_list, key=AbstractDatasetComparisonKeyStartTime) - for _map in new_list: + for map_ in new_list: print( - _map.get_temporal_extent_as_tuple()[0], - _map.get_temporal_extent_as_tuple()[1], + map_.get_temporal_extent_as_tuple()[0], + map_.get_temporal_extent_as_tuple()[1], ) if new_list[0] != map_list[1]: @@ -1501,10 +1501,10 @@ def test_map_list_sorting(): print("Sorted by end time") new_list = sorted(map_list, key=AbstractDatasetComparisonKeyEndTime) - for _map in new_list: + for map_ in new_list: print( - _map.get_temporal_extent_as_tuple()[0], - _map.get_temporal_extent_as_tuple()[1], + map_.get_temporal_extent_as_tuple()[0], + map_.get_temporal_extent_as_tuple()[1], ) if new_list[0] != map_list[1]: @@ -1518,7 +1518,7 @@ def test_map_list_sorting(): ############################################################################### -def test_1d_rtree(): +def test_1d_rtree() -> None: """Testing the rtree ctypes wrapper""" tree = rtree.RTreeCreateTree(-1, 0, 1) @@ -1548,7 +1548,7 @@ def test_1d_rtree(): ############################################################################### -def test_2d_rtree(): +def test_2d_rtree() -> None: """Testing the rtree ctypes wrapper""" tree = rtree.RTreeCreateTree(-1, 0, 2) @@ -1580,7 +1580,7 @@ def test_2d_rtree(): ############################################################################### -def test_3d_rtree(): +def test_3d_rtree() -> None: """Testing the rtree ctypes wrapper""" tree = rtree.RTreeCreateTree(-1, 0, 3) @@ -1622,7 +1622,7 @@ def test_3d_rtree(): ############################################################################### -def test_4d_rtree(): +def test_4d_rtree() -> None: """Testing the rtree ctypes wrapper""" tree = rtree.RTreeCreateTree(-1, 0, 4) diff --git a/python/grass/temporal/univar_statistics.py b/python/grass/temporal/univar_statistics.py index 96a9f65474d..f5b25414b43 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. @@ -34,7 +34,9 @@ ############################################################################### -def compute_univar_stats(registered_map_info, stats_module, fs, rast_region=False): +def compute_univar_stats( + registered_map_info, stats_module, fs, rast_region: bool = False +): """Compute univariate statistics for a map of a space time raster or raster3d dataset @@ -57,7 +59,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() @@ -103,7 +105,7 @@ def compute_univar_stats(registered_map_info, stats_module, fs, rast_region=Fals for perc in stats_module.inputs.percentile: perc_value = stats[ "percentile_" - f"{str(perc).rstrip('0').rstrip('.').replace('.','_')}" + f"{str(perc).rstrip('0').rstrip('.').replace('.', '_')}" ] string += f"{fs}{perc_value}" string += eol @@ -116,14 +118,14 @@ def print_gridded_dataset_univar_statistics( output, where, extended, - no_header=False, - fs="|", - rast_region=False, + no_header: bool = False, + fs: str = "|", + rast_region: bool = False, region_relation=None, zones=None, percentile=None, - nprocs=1, -): + nprocs: int = 1, +) -> None: """Print univariate statistics for a space time raster or raster3d dataset. Returns None if the space time raster dataset is empty or if applied filters (where, region_relation) do not return any maps to process. @@ -139,7 +141,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 +155,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 +185,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"] @@ -220,7 +219,7 @@ def print_gridded_dataset_univar_statistics( cols.extend( [ "percentile_" - f"{str(perc).rstrip('0').rstrip('.').replace('.','_')}" + f"{str(perc).rstrip('0').rstrip('.').replace('.', '_')}" for perc in percentile ] ) @@ -235,7 +234,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 @@ -278,8 +277,17 @@ def print_gridded_dataset_univar_statistics( def print_vector_dataset_univar_statistics( - input, output, twhere, layer, type, column, where, extended, no_header=False, fs="|" -): + input, + output, + twhere, + layer, + type, + column, + where, + extended, + no_header: bool = False, + fs: str = "|", +) -> None: """Print univariate statistics for a space time vector dataset :param input: The name of the space time dataset @@ -304,10 +312,7 @@ def print_vector_dataset_univar_statistics( mapset = get_current_mapset() - if input.find("@") >= 0: - id = input - else: - id = input + "@" + mapset + id = input if input.find("@") >= 0 else input + "@" + mapset sp = dataset_factory("stvds", id) 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/python/libgrass_interface_generator/ctypesgen/parser/yacc.py b/python/libgrass_interface_generator/ctypesgen/parser/yacc.py index f30cadb7a1a..9b57d110231 100644 --- a/python/libgrass_interface_generator/ctypesgen/parser/yacc.py +++ b/python/libgrass_interface_generator/ctypesgen/parser/yacc.py @@ -311,7 +311,7 @@ def restart(self): # certain kinds of advanced parsing situations where the lexer and parser interact with # each other or change states (i.e., manipulation of scope, lexer states, etc.). # - # See: http://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions + # See: https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions def set_defaulted_states(self): self.defaulted_states = {} for state, actions in self.action.items(): diff --git a/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py b/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py index ab88af4dc40..4a201aa5702 100755 --- a/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py +++ b/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py @@ -7,7 +7,7 @@ # From: -# http://stackoverflow.com/questions/1036409/recursively-convert-python-object-graph-to-dictionary +# https://stackoverflow.com/questions/1036409/recursively-convert-python-object-graph-to-dictionary def todict(obj, classkey="Klass"): if isinstance(obj, dict): for k in obj.keys(): diff --git a/raster/Makefile b/raster/Makefile index 91ff54d0863..a8f00ee9c7c 100644 --- a/raster/Makefile +++ b/raster/Makefile @@ -147,6 +147,10 @@ htmldir: parsubdirs $(HTMLDIR)/r.in.png: # no-op - override Html.make rule for .png image files +$(MDDIR)/source/r.in.png: + # no-op - override Html.make rule for .png image files $(HTMLDIR)/r.out.png: # no-op - override Html.make rule for .png image files +$(MDDIR)/source/r.out.png: + # no-op - override Html.make rule for .png image files diff --git a/raster/r.basins.fill/r.basins.fill.html b/raster/r.basins.fill/r.basins.fill.html index a92e242d198..854bd94ef38 100644 --- a/raster/r.basins.fill/r.basins.fill.html +++ b/raster/r.basins.fill/r.basins.fill.html @@ -22,7 +22,6 @@

    DESCRIPTION

    If the resulting map layer from this program appears to have holes within a subbasin, the program should be rerun with a higher number of passes. -

    NOTES

    @@ -32,8 +31,8 @@

    NOTES

    SEE ALSO

    -See Appendix A of the GRASS Tutorial: +See Appendix A of the GRASS +Tutorial: r.watershed for further details on the combined use of r.basins.fill and r.watershed. diff --git a/raster/r.basins.fill/testsuite/testrbf.py b/raster/r.basins.fill/testsuite/testrbf.py index b9937b05689..4077a2113a4 100644 --- a/raster/r.basins.fill/testsuite/testrbf.py +++ b/raster/r.basins.fill/testsuite/testrbf.py @@ -5,8 +5,8 @@ Author: Sunveer Singh Copyright: (C) 2017 by Sunveer Singh and the GRASS Development Team Licence: This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. + License (>=v2). Read the file COPYING that comes with GRASS + for details. """ import unittest @@ -47,8 +47,8 @@ def setUpClass(cls): def tearDownClass(cls): cls.del_temp_region() - def tearDown(cls): - cls.runModule("g.remove", flags="f", type="raster", name=cls.output) + def tearDown(self): + self.runModule("g.remove", flags="f", type="raster", name=self.output) def test_no1(self): lakes = "lakes" diff --git a/raster/r.buffer/r.buffer.html b/raster/r.buffer/r.buffer.html index e9f9fbd6ffc..e0033f0345c 100644 --- a/raster/r.buffer/r.buffer.html +++ b/raster/r.buffer/r.buffer.html @@ -97,7 +97,7 @@

    EXAMPLE

    -
    +
    Distances to road
    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 d3a6d507bc1..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 @@ -20,7 +22,7 @@

    NOTES

    A GRASS virtual raster can be regarded as a simplified version of GDAL's -virtual raster format. +virtual raster format. The GRASS equivalent is simpler because issues like nodata, projection, resolution, resampling, masking are already handled by native GRASS raster routines. @@ -48,18 +50,29 @@

    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

    The equivalent GDAL utility -gdalbuildvrt +gdalbuildvrt

    AUTHOR

    diff --git a/raster/r.carve/r.carve.html b/raster/r.carve/r.carve.html index f8d82200013..f10fdcb6312 100644 --- a/raster/r.carve/r.carve.html +++ b/raster/r.carve/r.carve.html @@ -65,13 +65,13 @@

    EXAMPLE

    - - - - - -
    + r.carve example: original DEM
    Fig: Original 1m LiDAR based DEM with vector streams map on top
    + r.carve example: original DEM shaded
    @@ -79,13 +79,13 @@

    EXAMPLE

    + r.carve example: carved DEM
    Fig: Carved 1m LiDAR based DEM
    + r.carve example: carved DEM shaded
    @@ -93,13 +93,13 @@

    EXAMPLE

    + r.carve example: original DEM flow accumulated
    Fig: Flow accumulation in original 1m LiDAR based DEM
    + r.carve example: carved DEM flow accumulation
    diff --git a/raster/r.category/r.category.html b/raster/r.category/r.category.html index 4dba832a98c..b0d5dc7c9bb 100644 --- a/raster/r.category/r.category.html +++ b/raster/r.category/r.category.html @@ -68,8 +68,8 @@

    Default and dynamic category labels

    In the format line

      -
    • $1 refers to the value num*5.0+1000 (ie, using the first 2 coefficients) -
    • $2 refers to the value num*5.0+1005 (ie, using the last 2 coefficients) +
    • $1 refers to the value num*5.0+1000 (ie, using the first 2 coefficients)
    • +
    • $2 refers to the value num*5.0+1005 (ie, using the last 2 coefficients)
    $1.2 will print $1 with 2 decimal places.

    Also, the form $?xxx$yyy$ translates into yyy if the category is 1, xxx 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.clump/main.c b/raster/r.clump/main.c index 74b41d96214..733816df070 100644 --- a/raster/r.clump/main.c +++ b/raster/r.clump/main.c @@ -131,7 +131,9 @@ int main(int argc, char *argv[]) } INPUT = opt_in->answers[0]; - strcpy(name, INPUT); + if (G_strlcpy(name, INPUT, sizeof(name)) >= sizeof(name)) { + G_fatal_error(_("Input raster name <%s> is too long"), INPUT); + } OUTPUT = NULL; out_fd = -1; @@ -155,8 +157,12 @@ int main(int argc, char *argv[]) G_debug(1, "Creating support files..."); /* build title */ - if (opt_title->answer != NULL) - strcpy(title, opt_title->answer); + if (opt_title->answer != NULL) { + if (G_strlcpy(title, opt_title->answer, sizeof(title)) >= + sizeof(title)) { + G_fatal_error(_("Title <%s> is too long"), opt_title->answer); + } + } else sprintf(title, "clump of <%s@%s>", name, G_mapset()); Rast_put_cell_title(OUTPUT, title); 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.composite/r.composite.html b/raster/r.composite/r.composite.html index 4bd8e49cbe4..0ddd72592ea 100644 --- a/raster/r.composite/r.composite.html +++ b/raster/r.composite/r.composite.html @@ -47,7 +47,7 @@

    SEE ALSO

    r.rgb

    -Wikipedia Entry: Floyd-Steinberg dithering +Wikipedia Entry: Floyd-Steinberg dithering

    AUTHOR

    diff --git a/raster/r.contour/r.contour.html b/raster/r.contour/r.contour.html index 722f8494cb9..4023410ea94 100644 --- a/raster/r.contour/r.contour.html +++ b/raster/r.contour/r.contour.html @@ -50,7 +50,7 @@

    EXAMPLES

    -r.contours example
    +r.contours example
    Contour lines shown on shaded terrain map
    diff --git a/raster/r.contour/testsuite/test_r_contour.py b/raster/r.contour/testsuite/test_r_contour.py index c9ee4c9876a..49617ef043d 100644 --- a/raster/r.contour/testsuite/test_r_contour.py +++ b/raster/r.contour/testsuite/test_r_contour.py @@ -32,10 +32,11 @@ def setUpClass(cls): def tearDownClass(cls): cls.del_temp_region() - cls.runModule("g.remove", type="vector", flags="f", name=cls.output) - cls.runModule("g.remove", type="vector", flags="f", name=cls.output + "_cut") cls.runModule( - "g.remove", type="vector", flags="f", name=cls.output + "_cut_flag_t" + "g.remove", + type="vector", + flags="f", + name=(cls.output, cls.output + "_cut", cls.output + "_cut_flag_t"), ) if os.path.isfile("testReport"): diff --git a/raster/r.external.out/r.external.out.html b/raster/r.external.out/r.external.out.html index baf48466ed3..86c490587d4 100644 --- a/raster/r.external.out/r.external.out.html +++ b/raster/r.external.out/r.external.out.html @@ -31,7 +31,7 @@

    Storing results from raster data analysis directly as GeoTIFF

    # prepare sample analysis g.region raster=elevation -p -# perform GRASS calculation (here: filter by height, write > 120m, NULL otherwise) +# perform GRASS calculation (here: filter by height, write > 120m, NULL otherwise) # this will store the output map directly as GeoTIFF, so we use .tif extension: r.mapcalc "elev_filt.tif = if(elevation > 120.0, elevation, null() )" @@ -70,7 +70,7 @@

    Complete workflow using only external geodata while processing in GRASS GIS<

    REFERENCES

    -GDAL Pages: http://www.gdal.org/
    +GDAL Pages: https://gdal.org/

    SEE ALSO

    diff --git a/raster/r.external/r.external.html b/raster/r.external/r.external.html index f20c3e059d6..1c69b2d3c3f 100644 --- a/raster/r.external/r.external.html +++ b/raster/r.external/r.external.html @@ -62,7 +62,7 @@

    Processing workflow without data import and export

    REFERENCES

    -GDAL Pages: http://www.gdal.org/
    +GDAL Pages: https://gdal.org/

    SEE ALSO

    diff --git a/raster/r.fill.dir/r.fill.dir.html b/raster/r.fill.dir/r.fill.dir.html index 17173ea3dd3..4e802ea28b7 100644 --- a/raster/r.fill.dir/r.fill.dir.html +++ b/raster/r.fill.dir/r.fill.dir.html @@ -82,24 +82,24 @@

    NOTES

  • The r.fill.dir module can be used not only to fill depression, but also to detect water bodies or potential water bodies based on -the nature of the terrain and the digital elevation model used. +the nature of the terrain and the digital elevation model used.
  • Not all depressions are errors in digital elevation models. In fact, many are wetlands and as Jenkins and McCauley (2006) note careless use of depression filling may lead to unintended consequences such -as loss of wetlands. +as loss of wetlands.
  • Although many hydrological algorithms require depression filling, advanced algorithms such as those implemented in r.watershed and r.sim.water do not require -depressionless digital elevation model to work. +depressionless digital elevation model to work.
  • The flow direction map can be visualized with -d.rast.arrow. +d.rast.arrow.
  • @@ -133,7 +133,7 @@

    EXAMPLES

    r.univar -e elev_lid792_1m_diff # vectorize filled areas (here all fills are of positive value, see r.univar output) -r.mapcalc "elev_lid792_1m_fill_area = if(elev_lid792_1m_diff > 0.0, 1, null() )" +r.mapcalc "elev_lid792_1m_fill_area = if(elev_lid792_1m_diff > 0.0, 1, null() )" r.to.vect input=elev_lid792_1m_fill_area output=elev_lid792_1m_fill_area type=area # generate shaded terrain for better visibility of results @@ -154,18 +154,18 @@

    REFERENCES

    • Beasley, D.B. and L.F. Huggins. 1982. ANSWERS (areal nonpoint source watershed environmental -response simulation): User's manual. U.S. EPA-905/9-82-001, Chicago, IL, 54 p. +response simulation): User's manual. U.S. EPA-905/9-82-001, Chicago, IL, 54 p.
    • Jenkins, D. G., and McCauley, L. A. 2006. GIS, SINKS, FILL, and disappearing wetlands: unintended consequences in algorithm development and use. In Proceedings of the 2006 ACM symposium on applied computing - (pp. 277-282). + (pp. 277-282).
    • Jenson, S.K., and J.O. Domingue. 1988. Extracting topographic structure from digital elevation model data for geographic information system analysis. Photogram. -Engr. and Remote Sens. 54: 1593-1600. +Engr. and Remote Sens. 54: 1593-1600.
    • Young, R.A., C.A. Onstad, D.D. Bosch and W.P. Anderson. 1985. Agricultural nonpoint surface pollution models (AGNPS) I and II model documentation. St. Paul: Minn. Pollution -control Agency and Washington D.C., USDA-Agricultural Research Service. +control Agency and Washington D.C., USDA-Agricultural Research Service.

    SEE ALSO

    diff --git a/raster/r.fill.stats/r.fill.stats.html b/raster/r.fill.stats/r.fill.stats.html index 3151d2c245a..bd966fa3f05 100644 --- a/raster/r.fill.stats/r.fill.stats.html +++ b/raster/r.fill.stats/r.fill.stats.html @@ -433,7 +433,7 @@

    Lidar point cloud example

    -Point density and ground surface +Point density and ground surface

    Binning of Lidar and resulting ground surface with filled gaps. Note the remaining NULL cells (white) in the resulting ground surface. @@ -476,7 +476,7 @@

    Outlier removal and gap-filling of SRTM elevation data

    d.histogram elev_srtm_30m # remove SRTM outliers, i.e. SRTM below 50m (esp. lakes), leading to no data areas -r.mapcalc "elev_srtm_30m_filt = if(elev_srtm_30m < 50.0, null(), elev_srtm_30m)" +r.mapcalc "elev_srtm_30m_filt = if(elev_srtm_30m < 50.0, null(), elev_srtm_30m)" d.histogram elev_srtm_30m_filt d.rast elev_srtm_30m_filt @@ -509,7 +509,7 @@

    SEE ALSO

    -Inverse Distance Weighting in Wikipedia +Inverse Distance Weighting in Wikipedia

    AUTHOR

    diff --git a/raster/r.flow/r.flow.html b/raster/r.flow/r.flow.html index 79f0e7ab4b7..28ea66a6c23 100644 --- a/raster/r.flow/r.flow.html +++ b/raster/r.flow/r.flow.html @@ -128,11 +128,11 @@

    Algorithm background

  • r.flow has an option to compute slope and aspect internally thus making the program capable to process much larger data sets than r.flowmd. It has also 2 additional options for handling of large data sets but it is not -known that they work properly. +known that they work properly.
  • the programs handle the special cases when the flowline passes exactly -(or very close) through the grid vertices differently. +(or very close) through the grid vertices differently.
  • r.flowmd has the simplified multiple flow addition so the results are -smoother. +smoother.
  • In conclusion, r.flowmd produces nicer results but is slower and it does not @@ -189,26 +189,26 @@

    REFERENCES

    • Mitasova, H., L. Mitas, 1993, Interpolation by regularized spline with tension : I. Theory and implementation. Mathematical Geology 25, p. 641-655. -(online) +(online)
    • Mitasova and Hofierka 1993 : Interpolation by Regularized Spline with Tension: II. Application to Terrain Modeling and Surface Geometry Analysis. Mathematical Geology 25(6), 657-669 -(online). +(online).
    • Mitasova, H., Mitas, L., Brown, W.M., Gerdes, D.P., Kosinovsky, I., Baker, T., 1995: Modeling spatially and temporally distributed phenomena: New methods and tools for GRASS GIS. International Journal of Geographical -Information Systems 9(4), 433-446. +Information Systems 9(4), 433-446.
    • Mitasova, H., J. Hofierka, M. Zlocha, L.R. Iverson, 1996, Modeling topographic potential for erosion and deposition using GIS. Int. Journal of Geographical Information Science, 10(5), 629-641. (reply to a comment to this paper appears in 1997 in Int. Journal of Geographical Information -Science, Vol. 11, No. 6) +Science, Vol. 11, No. 6)
    • Mitasova, H.(1993): Surfaces and modeling. Grassclippings (winter and -spring) p.18-19. +spring) p.18-19.

    SEE ALSO

    diff --git a/raster/r.geomorphon/r.geomorphon.html b/raster/r.geomorphon/r.geomorphon.html index 0eb675451f3..57f744392bd 100644 --- a/raster/r.geomorphon/r.geomorphon.html +++ b/raster/r.geomorphon/r.geomorphon.html @@ -54,39 +54,39 @@

    What is geomorphon:

    OPTIONS

    -
    -
    -m
    -
    All distance parameters (search, skip, flat distances) are supplied as meters instead of cells (default). To avoid situation when supplied distances is smaller than one cell program first check if supplied distance is longer than one cell in both NS and WE directions. For LatLong projection only NS distance checked, because in latitude angular unit comprise always bigger or equal distance than longitude one. If distance is supplied in cells, For all projections is recalculated into meters according formula: number_of_cells*resolution_along_NS_direction. It is important if geomorphons are calculated for large areas in LatLong projection.
    -
    elevation
    -
    Digital elevation model. Data can be of any type and any projection. During calculation DEM is stored as floating point raster.
    -
    search
    -
    Determines length on the geodesic distances in all eight directions where line-of-sight is calculated. To speed up calculation is determines only these cells which centers falls into the distance.
    -
    skip
    -
    Determines length on the geodesic distances at the beginning of calculation all eight directions where line-of-sight is yet calculated. To speed up calculation this distance is always recalculated into number of cell which are skipped at the beginning of every line-of-sight and is equal in all direction. This parameter eliminates forms of very small extend, smaller than skip parameter.
    -
    flat
    -
    The difference (in degrees) between zenith and nadir line-of-sight which indicate flat direction. If higher threshold produce more flat maps. If resolution of the map is low (more than 1 km per cell) threshold should be very small (much smaller than 1 degree) because on such distance 1 degree of difference means several meters of high difference.
    -
    dist
    -
    >Flat distance. This is additional parameter defining the distance above which the threshold starts to decrease to avoid problems with pseudo-flat line-of-sights if real elevation difference appears on the distance where its value is higher (TO BE CORRECTED).
    -
    comparison
    -
    Comparison mode for zenith/nadir line-of-sight search. "anglev1" is +
    +
    -m
    +
    All distance parameters (search, skip, flat distances) are supplied as meters instead of cells (default). To avoid situation when supplied distances is smaller than one cell program first check if supplied distance is longer than one cell in both NS and WE directions. For LatLong projection only NS distance checked, because in latitude angular unit comprise always bigger or equal distance than longitude one. If distance is supplied in cells, For all projections is recalculated into meters according formula: number_of_cells*resolution_along_NS_direction. It is important if geomorphons are calculated for large areas in LatLong projection.
    +
    elevation
    +
    Digital elevation model. Data can be of any type and any projection. During calculation DEM is stored as floating point raster.
    +
    search
    +
    Determines length on the geodesic distances in all eight directions where line-of-sight is calculated. To speed up calculation is determines only these cells which centers falls into the distance.
    +
    skip
    +
    Determines length on the geodesic distances at the beginning of calculation all eight directions where line-of-sight is yet calculated. To speed up calculation this distance is always recalculated into number of cell which are skipped at the beginning of every line-of-sight and is equal in all direction. This parameter eliminates forms of very small extend, smaller than skip parameter.
    +
    flat
    +
    The difference (in degrees) between zenith and nadir line-of-sight which indicate flat direction. If higher threshold produce more flat maps. If resolution of the map is low (more than 1 km per cell) threshold should be very small (much smaller than 1 degree) because on such distance 1 degree of difference means several meters of high difference.
    +
    dist
    +
    Flat distance. This is additional parameter defining the distance above which the threshold starts to decrease to avoid problems with pseudo-flat line-of-sights if real elevation difference appears on the distance where its value is higher (TO BE CORRECTED).
    +
    comparison
    +
    Comparison mode for zenith/nadir line-of-sight search. "anglev1" is the original r.geomorphon comparison mode. "anglev2" is an improved mode, which better handles angle thresholds and zenith/nadir angles that are exactly equal. "anglev2_distance" in addition to that takes the zenith/nadir distances into account when the angles are exactly -equal.
    -
    forms
    -
    Returns geomorphic map with 10 most popular terrestrial forms. Legend for forms, its definition by the number of + and - and its idealized visualisation are presented at the image. +equal.
    +
    forms
    +
    Returns geomorphic map with 10 most popular terrestrial forms. Legend for forms, its definition by the number of + and - and its idealized visualisation are presented at the image.

    Forms represented by geomorphons:

    forms legend
    -
    -
    ternary
    -
    returns code of one of 498 unique ternary patterns for every cell. The code is a decimal representation of 8-tuple minimalised patterns written in ternary system. Full list of patterns is available in source code directory as patterns.txt. This map can be used to create alternative form classification using supervised approach.
    -
    positive and negative
    -
    returns codes binary patterns for zenith (positive) and nadir (negative) line of sights. The code is a decimal representation of 8-tuple minimalised patterns written in binary system. Full list of patterns is available in source code directory as patterns.txt.
    -
    coordinates
    -
    The central point of a single geomorphon to profile. The central +
    +
    ternary
    +
    returns code of one of 498 unique ternary patterns for every cell. The code is a decimal representation of 8-tuple minimalised patterns written in ternary system. Full list of patterns is available in source code directory as patterns.txt. This map can be used to create alternative form classification using supervised approach.
    +
    positive and negative
    +
    returns codes binary patterns for zenith (positive) and nadir (negative) line of sights. The code is a decimal representation of 8-tuple minimalised patterns written in binary system. Full list of patterns is available in source code directory as patterns.txt.
    +
    coordinates
    +
    The central point of a single geomorphon to profile. The central point must be within the computational region, which should be large enough to accommodate the search radius. Setting the region larger than that will not produce more accurate data, but in the current @@ -94,32 +94,32 @@

    Forms represented by geomorphons:

    remember to align the region to the raster cells. Profiling is mutually exclusive with any raster outputs, but other parameters and flags (such as elevation, search, comparison, -m and --e) work as usual.
    -
    profiledata
    -
    The output file name for the complete profile data, "-" means to +-e) work as usual.
    +
    profiledata
    +
    The output file name for the complete profile data, "-" means to write to the standard output. The data is in a machine-readable format and it includes assorted values describing the computation context and -parameters, as well as its intermediate and final results.
    -
    profileformat
    -
    Format of the profile data: "json", "yaml" or "xml".
    - -

    NOTE: parameters below are experimental. The usefulness of these parameters are currently under investigation.

    -
    -
    intensity
    -
    returns average difference between central cell of geomorphon and eight cells in visibility neighbourhood. This parameter shows local (as is visible) exposition/abasement of the form in the terrain.
    -
    range
    -
    returns difference between minimum and maximum values of visibility neighbourhood.
    -
    variance
    -
    returns variance (difference between particular values and mean value) of visibility neighbourhood.
    -
    extend
    -
    returns area of the polygon created by the 8 points where line-of-sight cuts the terrain (see image in description section).
    -
    azimuth
    -
    returns orientation of the polygon constituting geomorphon. This orientation is currently calculated as a orientation of least square fit line to the eight verticles of this polygon.
    -
    elongation
    -
    returns proportion between sides of the bounding box rectangle calculated for geomorphon rotated to fit least square line.
    -
    width
    -
    returns length of the shorter side of the bounding box rectangle calculated for geomorphon rotated to fit least square line.
    -
    +parameters, as well as its intermediate and final results. +
    profileformat
    +
    Format of the profile data: "json", "yaml" or "xml".
    + +

    NOTE: parameters below are experimental. The usefulness of these parameters are currently under investigation.

    +
    +
    intensity
    +
    returns average difference between central cell of geomorphon and eight cells in visibility neighbourhood. This parameter shows local (as is visible) exposition/abasement of the form in the terrain.
    +
    range
    +
    returns difference between minimum and maximum values of visibility neighbourhood.
    +
    variance
    +
    returns variance (difference between particular values and mean value) of visibility neighbourhood.
    +
    extend
    +
    returns area of the polygon created by the 8 points where line-of-sight cuts the terrain (see image in description section).
    +
    azimuth
    +
    returns orientation of the polygon constituting geomorphon. This orientation is currently calculated as a orientation of least square fit line to the eight verticles of this polygon.
    +
    elongation
    +
    returns proportion between sides of the bounding box rectangle calculated for geomorphon rotated to fit least square line.
    +
    width
    +
    returns length of the shorter side of the bounding box rectangle calculated for geomorphon rotated to fit least square line.
    +

    NOTES

    @@ -187,7 +187,7 @@

    REFERENCES

    109-112 (PDF)
  • Jasiewicz, J., Stepinski, T., 2013, Geomorphons - a pattern recognition approach to classification and mapping of landforms, -Geomorphology, vol. 182, 147-156 (DOI: 10.1016/j.geomorph.2012.11.005)
  • +Geomorphology, vol. 182, 147-156 (DOI: 10.1016/j.geomorph.2012.11.005)

    SEE ALSO

    diff --git a/raster/r.grow.distance/r.grow.distance.html b/raster/r.grow.distance/r.grow.distance.html index bc2788aae44..0b6866be1e6 100644 --- a/raster/r.grow.distance/r.grow.distance.html +++ b/raster/r.grow.distance/r.grow.distance.html @@ -91,12 +91,12 @@

    Distance from the streams network

    -
    +
    Euclidean distance from the streams network in meters (map subset)
    -
    +
    Euclidean distance from the streams network in meters (detail, numbers shown with d.rast.num)
    @@ -111,7 +111,7 @@

    Distance from sea in meters in latitude-longitude CRS

    -
    +
    Geodesic distances to sea in meters
    @@ -127,9 +127,9 @@

    SEE ALSO

    -Wikipedia Entry: +Wikipedia Entry: Euclidean Metric
    -Wikipedia Entry: +Wikipedia Entry: Manhattan Metric
    diff --git a/raster/r.gwflow/r.gwflow.html b/raster/r.gwflow/r.gwflow.html index 2dbef39f74a..05dbe88d878 100644 --- a/raster/r.gwflow/r.gwflow.html +++ b/raster/r.gwflow/r.gwflow.html @@ -95,7 +95,7 @@

    EXAMPLE

    #now create the input raster maps for confined and unconfined aquifers r.mapcalc expression="phead = if(row() == 1 , 50, 40)" r.mapcalc expression="status = if(row() == 1 , 2, 1)" -r.mapcalc expression="well = if(row() == 20 && col() == 20 , -0.01, 0)" +r.mapcalc expression="well = if(row() == 20 && col() == 20 , -0.01, 0)" r.mapcalc expression="hydcond = 0.00025" r.mapcalc expression="recharge = 0" r.mapcalc expression="top_conf = 20.0" diff --git a/raster/r.his/testsuite/test_r_his.py b/raster/r.his/testsuite/test_r_his.py new file mode 100644 index 00000000000..da56d633b6d --- /dev/null +++ b/raster/r.his/testsuite/test_r_his.py @@ -0,0 +1,91 @@ +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + + +class TestRHis(TestCase): + hue = "elevation" + intensity = "elevation_shaded_50" + saturation = "elevation" + red = "shadedmap_r" + green = "shadedmap_g" + blue = "shadedmap_b" + bgcolor = "none" + + @classmethod + def setUpClass(cls): + cls.use_temp_region() + cls.runModule("g.region", raster="elevation") + cls.elev_shade = "elevation_shaded_relief" + cls.runModule("r.relief", input="elevation", output=cls.elev_shade) + cls.runModule( + "r.mapcalc", expression=f"{cls.intensity} = {cls.elev_shade} * 1.5" + ) + cls.runModule("r.colors", map=cls.intensity, color="grey255") + + @classmethod + def tearDownClass(cls): + cls.runModule( + "g.remove", type="raster", flags="f", name=[cls.intensity, cls.elev_shade] + ) + cls.del_temp_region() + + def tearDown(self): + """Remove d.his generated rasters after each test method""" + self.runModule("g.remove", type="raster", flags="f", pattern="shadedmap_*") + + def test_bgcolor_none(self): + """Test r.his with bgcolor 'none'""" + self.runModule( + "r.his", + hue=self.hue, + intensity=self.intensity, + saturation=self.saturation, + red=self.red, + green=self.green, + blue=self.blue, + bgcolor=self.bgcolor, + ) + + red_value = "null_cells=5696\nmin=3\nmax=255\nmean=156.41168\nstddev=34.434612" + blue_value = "null_cells=5696\nmin=0\nmax=127\nmean=36.05560\nstddev=37.61216" + green_value = "null_cells=5696\nmin=1\nmax=255\nmean=129.62880\nstddev=34.48307" + + self.assertRasterFitsUnivar( + raster=self.red, reference=red_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.blue, reference=blue_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.green, reference=green_value, precision=1e-5 + ) + + def test_with_bgcolor_rgb(self): + """Test r.his with bgcolor '0:0:0'""" + self.runModule( + "r.his", + hue=self.hue, + intensity=self.intensity, + saturation=self.saturation, + red=self.red, + green=self.green, + blue=self.blue, + bgcolor="0:0:0", + ) + + red_value = "null_cells=0\nmin=0\nmax=255\nmean=155.97172\nstddev=35.36988" + blue_value = "null_cells=0\nmin=0\nmax=127\nmean=35.95417\nstddev=37.60774" + green_value = "null_cells=0\nmin=0\nmax=255\nmean=129.26418\nstddev=35.11225" + self.assertRasterFitsUnivar( + raster=self.red, reference=red_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.blue, reference=blue_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.green, reference=green_value, precision=1e-5 + ) + + +if __import__("__main__"): + test() diff --git a/raster/r.horizon/r.horizon.html b/raster/r.horizon/r.horizon.html index 513af64b8c4..71f8599dd70 100644 --- a/raster/r.horizon/r.horizon.html +++ b/raster/r.horizon/r.horizon.html @@ -7,10 +7,10 @@

    DESCRIPTION

    • point: as a series of horizon heights in the specified directions from the given point(s). The results are -written to the stdout. +written to the stdout.
    • raster: in this case the output is one or more raster maps, with each point in a raster giving the horizon -height in a specific direction. One raster is created for each direction. +height in a specific direction. One raster is created for each direction.

    @@ -31,7 +31,7 @@

    DESCRIPTION

    orientation (North=0, clockwise).

    -Activating the -l flag allows to additionally print the distance +Activating the -l flag allows additionally printing the distance to each horizon angle.

    Input parameters:

    diff --git a/raster/r.in.ascii/testsuite/test_r_in_ascii.py b/raster/r.in.ascii/testsuite/test_r_in_ascii.py index cff31b7b3e2..8db06f83517 100644 --- a/raster/r.in.ascii/testsuite/test_r_in_ascii.py +++ b/raster/r.in.ascii/testsuite/test_r_in_ascii.py @@ -5,13 +5,12 @@ Author: Sunveer Singh, Google Code-in 2017 Copyright: (C) 2017 by Sunveer Singh and the GRASS Development Team Licence: This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. + License (>=v2). Read the file COPYING that comes with GRASS + for details. """ from grass.gunittest.case import TestCase from grass.gunittest.main import test -from grass.script.core import read_command INPUT_NOQUOTES = """north: 4299000.00 south: 4247000.00 diff --git a/raster/r.in.gdal/r.in.gdal.html b/raster/r.in.gdal/r.in.gdal.html index f21f5682226..76de4e4eec5 100644 --- a/raster/r.in.gdal/r.in.gdal.html +++ b/raster/r.in.gdal/r.in.gdal.html @@ -20,7 +20,7 @@

    GDAL supported raster formats

    Full details on all GDAL supported formats are available at:

    -http://www.gdal.org/formats_list.html +https://gdal.org/formats_list.html

    Selected formats out of the more than 140 supported formats: @@ -162,7 +162,7 @@

    Support for Ground Control Points

    If the target project does not exist, a new project will be created matching the CRS definition of the GCPs. The target of the output group will be set to the new project, and -i.rectify can now be used without any further +i.rectify can now be used without any further preparation.

    Some satellite images (e.g. NOAA/AVHRR, ENVISAT) can contain hundreds @@ -363,7 +363,7 @@

    GLOBE DEM

    Raster file import over network

    Since GDAL 2.x it is possible to import raster data over the network -(see GDAL Virtual File Systems) +(see GDAL Virtual File Systems) including Cloud Optimized GeoTIFF, i.e. access uncompressed and compressed raster data via a http(s) or ftp connection. As an example the import of the global SRTMGL1 V003 tiles at 1 arc second (about 30 meters) @@ -398,7 +398,7 @@

    HDF

    REFERENCES

    -GDAL Pages: http://www.gdal.org/ +GDAL Pages: https://gdal.org/

    SEE ALSO

    diff --git a/raster/r.in.lidar/r.in.lidar.html b/raster/r.in.lidar/r.in.lidar.html index 6cff187c089..f92ad0485a8 100644 --- a/raster/r.in.lidar/r.in.lidar.html +++ b/raster/r.in.lidar/r.in.lidar.html @@ -517,11 +517,11 @@

    Multiple file input

    On Linux and OSX, this file can be automatically generated with the command:
    -ls /home/user/data/*.laz > /home/user/data/filelist.txt
    +ls /home/user/data/*.laz > /home/user/data/filelist.txt
     
    On Windows:
    -dir /b c:\users\user\data\*.laz > c:\users\user\data\filelist.txt
    +dir /b c:\users\user\data\*.laz > c:\users\user\data\filelist.txt
     
    The mean height above ground example above would then be: @@ -554,11 +554,11 @@

    KNOWN ISSUES

  • The "nan" value (as defined in C language) can leak into coeff_var raster maps. Cause is unknown. Possible work-around is: r.null setnull=nan or - r.mapcalc 'no_nan = if(map == map, map, null())'. + r.mapcalc 'no_nan = if(map == map, map, null())'.
  • Only one method can be applied for a single run and multiple map output from a single run (e.g. method=string[,string,...] output=name[,name,...] - or n=string mean=string) is no supported. + or n=string mean=string) is no supported.
  • @@ -597,14 +597,14 @@

    REFERENCES

  • V. Petras, A. Petrasova, J. Jeziorska, H. Mitasova (2016): Processing UAV and lidar point clouds in GRASS GIS. -XXIII ISPRS Congress 2016 [ISPRS Archives, ResearchGate] +XXIII ISPRS Congress 2016 [ISPRS Archives, ResearchGate]
  • -ASPRS LAS format +ASPRS LAS format
  • -LAS library +LAS library
  • -LAS library C API documentation +LAS library C API documentation
  • AUTHORS

    diff --git a/raster/r.in.mat/r.in.mat.html b/raster/r.in.mat/r.in.mat.html index b0bba2cb478..be0f521dca2 100644 --- a/raster/r.in.mat/r.in.mat.html +++ b/raster/r.in.mat/r.in.mat.html @@ -7,13 +7,13 @@

    DESCRIPTION


    Specifically, the following array variables will be read:
      -
    • map_data -
    • map_name -
    • map_title -
    • map_northern_edge -
    • map_southern_edge -
    • map_eastern_edge -
    • map_western_edge +
    • map_data
    • +
    • map_name
    • +
    • map_title
    • +
    • map_northern_edge
    • +
    • map_southern_edge
    • +
    • map_eastern_edge
    • +
    • map_western_edge
    Any other variables in the MAT-file will be simply skipped over.
    diff --git a/raster/r.in.pdal/grassrasterwriter.h b/raster/r.in.pdal/grassrasterwriter.h index 4db8852aa8a..0ec1da774a3 100644 --- a/raster/r.in.pdal/grassrasterwriter.h +++ b/raster/r.in.pdal/grassrasterwriter.h @@ -32,7 +32,7 @@ extern "C" { #include /* Binning code wrapped as a PDAL Writer class */ -#ifdef HAVE_PDAL_NOFILENAMEWRITER +#if PDAL_VERSION_MAJOR >= 2 && PDAL_VERSION_MINOR >= 7 class GrassRasterWriter : public pdal::NoFilenameWriter, public pdal::Streamable { #else diff --git a/raster/r.in.pdal/info.cpp b/raster/r.in.pdal/info.cpp index 47ebd01fe28..d9f506a9ace 100644 --- a/raster/r.in.pdal/info.cpp +++ b/raster/r.in.pdal/info.cpp @@ -1,7 +1,7 @@ /* * r.in.pdal Functions printing out various information on input LAS files * - * Copyright 2021 by Maris Nartiss, and The GRASS Development Team + * Copyright 2021-2024 by Maris Nartiss, and The GRASS Development Team * Author: Maris Nartiss * * This program is free software licensed under the GPL (>=v2). @@ -12,8 +12,14 @@ #include "info.h" #include +#ifdef PDAL_USE_NOSRS +void get_extent(struct StringList *infiles, double *min_x, double *max_x, + double *min_y, double *max_y, double *min_z, double *max_z, + bool nosrs) +#else void get_extent(struct StringList *infiles, double *min_x, double *max_x, double *min_y, double *max_y, double *min_z, double *max_z) +#endif { pdal::StageFactory factory; bool first = 1; @@ -25,15 +31,27 @@ void get_extent(struct StringList *infiles, double *min_x, double *max_x, std::string pdal_read_driver = factory.inferReaderDriver(infile); if (pdal_read_driver.empty()) - G_fatal_error("Cannot determine input file type of <%s>", infile); + G_fatal_error(_("Cannot determine input file type of <%s>"), + infile); pdal::PointTable table; pdal::Options las_opts; pdal::Option las_opt("filename", infile); las_opts.add(las_opt); +#ifdef PDAL_USE_NOSRS + if (nosrs) { + pdal::Option nosrs_opt("nosrs", true); + las_opts.add(nosrs_opt); + } +#endif pdal::LasReader las_reader; las_reader.setOptions(las_opts); - las_reader.prepare(table); + try { + las_reader.prepare(table); + } + catch (const std::exception &err) { + G_fatal_error(_("PDAL error: %s"), err.what()); + } const pdal::LasHeader &las_header = las_reader.header(); if (first) { *min_x = las_header.minX(); @@ -62,16 +80,28 @@ void get_extent(struct StringList *infiles, double *min_x, double *max_x, } } +#ifdef PDAL_USE_NOSRS +void print_extent(struct StringList *infiles, bool nosrs) +#else void print_extent(struct StringList *infiles) +#endif { double min_x, max_x, min_y, max_y, min_z, max_z; +#ifdef PDAL_USE_NOSRS + get_extent(infiles, &min_x, &max_x, &min_y, &max_y, &min_z, &max_z, nosrs); +#else get_extent(infiles, &min_x, &max_x, &min_y, &max_y, &min_z, &max_z); +#endif fprintf(stdout, "n=%f s=%f e=%f w=%f b=%f t=%f\n", max_y, min_y, max_x, min_x, min_z, max_z); } +#ifdef PDAL_USE_NOSRS +void print_lasinfo(struct StringList *infiles, bool nosrs) +#else void print_lasinfo(struct StringList *infiles) +#endif { pdal::StageFactory factory; pdal::MetadataNode meta_node; @@ -86,15 +116,27 @@ void print_lasinfo(struct StringList *infiles) std::string pdal_read_driver = factory.inferReaderDriver(infile); if (pdal_read_driver.empty()) - G_fatal_error("Cannot determine input file type of <%s>", infile); + G_fatal_error(_("Cannot determine input file type of <%s>"), + infile); pdal::PointTable table; pdal::Options las_opts; pdal::Option las_opt("filename", infile); las_opts.add(las_opt); +#ifdef PDAL_USE_NOSRS + if (nosrs) { + pdal::Option nosrs_opt("nosrs", true); + las_opts.add(nosrs_opt); + } +#endif pdal::LasReader las_reader; las_reader.setOptions(las_opts); - las_reader.prepare(table); + try { + las_reader.prepare(table); + } + catch (const std::exception &err) { + G_fatal_error(_("PDAL error: %s"), err.what()); + } const pdal::LasHeader &h = las_reader.header(); pdal::PointLayoutPtr point_layout = table.layout(); const pdal::Dimension::IdList &dims = point_layout->dims(); @@ -115,9 +157,9 @@ void print_lasinfo(struct StringList *infiles) std::cout << "Point format: " << (int)h.pointFormat() << "\n"; std::cout << "Point offset: " << h.pointOffset() << "\n"; std::cout << "Point count: " << h.pointCount() << "\n"; - for (size_t i = 0; i < pdal::LasHeader::RETURN_COUNT; ++i) - std::cout << "Point count by return[" << i + 1 << "]: " - << const_cast(h).pointCountByReturn(i) + for (size_t k = 0; k < pdal::LasHeader::RETURN_COUNT; ++k) + std::cout << "Point count by return[" << k + 1 << "]: " + << const_cast(h).pointCountByReturn(k) << "\n"; std::cout << "Scales X/Y/Z: " << h.scaleX() << "/" << h.scaleY() << "/" << h.scaleZ() << "\n"; diff --git a/raster/r.in.pdal/info.h b/raster/r.in.pdal/info.h index 7f8d0138ab1..387efd21ef0 100644 --- a/raster/r.in.pdal/info.h +++ b/raster/r.in.pdal/info.h @@ -27,15 +27,29 @@ #pragma clang diagnostic pop #endif +#include +#if (PDAL_VERSION_MAJOR >= 2 && PDAL_VERSION_MINOR > 4) || \ + (PDAL_VERSION_MAJOR == 2 && PDAL_VERSION_MINOR == 4 && \ + PDAL_VERSION_PATCH == 3) +#define PDAL_USE_NOSRS 1 +#endif + extern "C" { #include #include #include "string_list.h" } +#ifdef PDAL_USE_NOSRS +void get_extent(struct StringList *, double *, double *, double *, double *, + double *, double *, bool); +void print_extent(struct StringList *, bool); +void print_lasinfo(struct StringList *, bool); +#else void get_extent(struct StringList *, double *, double *, double *, double *, double *, double *); void print_extent(struct StringList *); void print_lasinfo(struct StringList *); +#endif #endif // INFO_H diff --git a/raster/r.in.pdal/main.cpp b/raster/r.in.pdal/main.cpp index 36d09558eea..fe17e80cb08 100644 --- a/raster/r.in.pdal/main.cpp +++ b/raster/r.in.pdal/main.cpp @@ -4,12 +4,12 @@ * * AUTHOR(S): Vaclav Petras * Based on r.in.xyz and r.in.lidar by Markus Metz, - * Hamish Bowman, Volker Wichmann + * Hamish Bowman, Volker Wichmann, Maris Nartiss * * PURPOSE: Imports LAS LiDAR point clouds to a raster map using * aggregate statistics. * - * COPYRIGHT: (C) 2019-2021 by Vaclav Petras and the GRASS Development Team + * COPYRIGHT: (C) 2019-2024 by Vaclav Petras and the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with @@ -446,12 +446,20 @@ int main(int argc, char *argv[]) /* If we print extent, there is no need to validate rest of the input */ if (print_extent_flag->answer) { +#ifdef PDAL_USE_NOSRS + print_extent(&infiles, over_flag->answer); +#else print_extent(&infiles); +#endif exit(EXIT_SUCCESS); } if (print_info_flag->answer) { +#ifdef PDAL_USE_NOSRS + print_lasinfo(&infiles, over_flag->answer); +#else print_lasinfo(&infiles); +#endif exit(EXIT_SUCCESS); } @@ -507,7 +515,12 @@ int main(int argc, char *argv[]) if (extents_flag->answer) { double min_x, max_x, min_y, max_y, min_z, max_z; +#ifdef PDAL_USE_NOSRS + get_extent(&infiles, &min_x, &max_x, &min_y, &max_y, &min_z, &max_z, + over_flag->answer); +#else get_extent(&infiles, &min_x, &max_x, &min_y, &max_y, &min_z, &max_z); +#endif region.east = xmax = max_x; region.west = xmin = min_x; @@ -711,16 +724,24 @@ int main(int argc, char *argv[]) std::string pdal_read_driver = factory.inferReaderDriver(infile); if (pdal_read_driver.empty()) - G_fatal_error("Cannot determine input file type of <%s>", infile); + G_fatal_error(_("Cannot determine input file type of <%s>"), + infile); pdal::Options las_opts; pdal::Option las_opt("filename", infile); las_opts.add(las_opt); +#ifdef PDAL_USE_NOSRS + if (over_flag->answer) { + pdal::Option nosrs_opt("nosrs", true); + las_opts.add(nosrs_opt); + } +#endif // stages created by factory are destroyed with the factory pdal::Stage *reader = factory.createStage(pdal_read_driver); if (!reader) - G_fatal_error("PDAL reader creation failed, a wrong format of <%s>", - infile); + G_fatal_error( + _("PDAL reader creation failed, a wrong format of <%s>"), + infile); reader->setOptions(las_opts); readers.push_back(reader); merge_filter.setInput(*reader); @@ -779,7 +800,12 @@ int main(int argc, char *argv[]) // consumption, so using 10k in case it is faster for some cases pdal::point_count_t point_table_capacity = 10000; pdal::FixedPointTable point_table(point_table_capacity); - binning_writer.prepare(point_table); + try { + binning_writer.prepare(point_table); + } + catch (const std::exception &err) { + G_fatal_error(_("PDAL error: %s"), err.what()); + } // getting projection is possible only after prepare if (over_flag->answer) { diff --git a/raster/r.in.pdal/r.in.pdal.html b/raster/r.in.pdal/r.in.pdal.html index 92cd25205e8..cefc1984bef 100644 --- a/raster/r.in.pdal/r.in.pdal.html +++ b/raster/r.in.pdal/r.in.pdal.html @@ -575,11 +575,11 @@

    Multiple file input

    On Linux and OSX, this file can be automatically generated with the command:
    -ls /home/user/data/*.laz > /home/user/data/filelist.txt
    +ls /home/user/data/*.laz > /home/user/data/filelist.txt
     
    On Windows:
    -dir /b c:\users\user\data\*.laz > c:\users\user\data\filelist.txt
    +dir /b c:\users\user\data\*.laz > c:\users\user\data\filelist.txt
     
    The mean height above ground example above would then be: @@ -612,7 +612,7 @@

    KNOWN ISSUES

  • Only one method can be applied for a single run and multiple map output from a single run (e.g. method=string[,string,...] output=name[,name,...] - or n=string mean=string) is no supported. + or n=string mean=string) is no supported.
  • If you encounter any problems (or solutions!) please contact the GRASS @@ -647,12 +647,12 @@

    REFERENCES

  • V. Petras, A. Petrasova, J. Jeziorska, H. Mitasova (2016): Processing UAV and lidar point clouds in GRASS GIS. -XXIII ISPRS Congress 2016 [ISPRS Archives, ResearchGate] +XXIII ISPRS Congress 2016 [ISPRS Archives, ResearchGate]
  • -ASPRS LAS format +ASPRS LAS format
  • -PDAL - Point Data Abstraction Library +PDAL - Point Data Abstraction Library
  • AUTHORS

    diff --git a/raster/r.in.pdal/testsuite/test_r_in_pdal_binning.py b/raster/r.in.pdal/testsuite/test_r_in_pdal_binning.py index a8a793f5bc7..c256224590d 100644 --- a/raster/r.in.pdal/testsuite/test_r_in_pdal_binning.py +++ b/raster/r.in.pdal/testsuite/test_r_in_pdal_binning.py @@ -68,8 +68,12 @@ def tearDown(self): This is executed after each test run. """ - self.runModule("g.remove", flags="f", type="raster", name=self.bin_raster) - self.runModule("g.remove", flags="f", type="raster", name=self.ref_raster) + self.runModule( + "g.remove", + flags="f", + type="raster", + name=(self.bin_raster, self.ref_raster), + ) @unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal") def test_method_n(self): diff --git a/raster/r.in.pdal/testsuite/test_r_in_pdal_print.py b/raster/r.in.pdal/testsuite/test_r_in_pdal_print.py new file mode 100644 index 00000000000..2c613ab88e2 --- /dev/null +++ b/raster/r.in.pdal/testsuite/test_r_in_pdal_print.py @@ -0,0 +1,113 @@ +""" +Name: r.in.pdal info printing and error handling tests +Purpose: Validates output of LAS file property printing and handling + of broken LAS files + +Author: Maris Nartiss +Copyright: (C) 2024 by Maris Nartiss and the GRASS Development Team +Licence: This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" + +import os +import pathlib +import shutil +import unittest +from tempfile import TemporaryDirectory + +from grass.script import core as grass +from grass.script import read_command +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + + +class InfoTest(TestCase): + """ + Test printing of extent and metadata + + This test requires pdal CLI util to be available. + """ + + @classmethod + @unittest.skipIf(shutil.which("pdal") is None, "Cannot find pdal utility") + def setUpClass(cls): + """Ensures expected computational region and generated data""" + cls.use_temp_region() + cls.runModule("g.region", n=18, s=0, e=18, w=0, res=6) + + cls.data_dir = os.path.join(pathlib.Path(__file__).parent.absolute(), "data") + cls.point_file = os.path.join(cls.data_dir, "points.csv") + cls.tmp_dir = TemporaryDirectory() + cls.las_file = os.path.join(cls.tmp_dir.name, "points.las") + grass.call( + [ + "pdal", + "translate", + "-i", + cls.point_file, + "-o", + cls.las_file, + "-r", + "text", + "-w", + "las", + "--writers.las.format=0", + "--writers.las.extra_dims=all", + "--writers.las.minor_version=4", + ] + ) + cls.broken_las = os.path.join(cls.tmp_dir.name, "broken.las") + pathlib.Path(cls.broken_las).write_bytes(b"LASF") + + @classmethod + def tearDownClass(cls): + """Remove the temporary region and generated data""" + cls.tmp_dir.cleanup() + cls.del_temp_region() + + @unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal") + def test_extent_bad(self): + """A broken LAS file should result in an error""" + self.assertModuleFail("r.in.pdal", input=self.broken_las, flags="g", quiet=True) + + @unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal") + def test_info_bad(self): + """A broken LAS file should result in an error""" + self.assertModuleFail("r.in.pdal", input=self.broken_las, flags="p", quiet=True) + + @unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal") + def test_extent_good(self): + """Reported extent should match provided data""" + out = read_command("r.in.pdal", input=self.las_file, flags="g", quiet=True) + for kvp in out.strip().split(" "): + key, value = kvp.split("=") + if key == "n": + self.assertAlmostEqual(float(value), 17, places=6) + continue + if key == "s": + self.assertAlmostEqual(float(value), 1, places=6) + continue + if key == "e": + self.assertAlmostEqual(float(value), 17, places=6) + continue + if key == "w": + self.assertAlmostEqual(float(value), 1, places=6) + continue + if key == "t": + self.assertAlmostEqual(float(value), 28, places=6) + continue + if key == "b": + self.assertAlmostEqual(float(value), 1, places=6) + + @unittest.skipIf(shutil.which("r.in.pdal") is None, "Cannot find r.in.pdal") + def test_info_good(self): + """Validate successful file info printing""" + out = read_command("r.in.pdal", input=self.las_file, flags="p", quiet=True) + self.assertIn("File version = 1.4", out) + self.assertIn("File signature: LASF", out) + self.assertIn("Point count: 53", out) + + +if __name__ == "__main__": + test() diff --git a/raster/r.in.pdal/testsuite/test_r_in_pdal_selection.py b/raster/r.in.pdal/testsuite/test_r_in_pdal_selection.py index b7d5acd6b28..4796702d2f6 100644 --- a/raster/r.in.pdal/testsuite/test_r_in_pdal_selection.py +++ b/raster/r.in.pdal/testsuite/test_r_in_pdal_selection.py @@ -67,8 +67,12 @@ def tearDown(self): This is executed after each test run. """ - self.runModule("g.remove", flags="f", type="raster", name=self.imp_raster) - self.runModule("g.remove", flags="f", type="raster", name=self.ref_raster) + self.runModule( + "g.remove", + flags="f", + type="raster", + name=(self.imp_raster, self.ref_raster), + ) try: self.runModule("g.remove", flags="f", type="raster", name=self.base_raster) except AttributeError: diff --git a/raster/r.in.poly/poly2rast.c b/raster/r.in.poly/poly2rast.c index e81d6f421a3..bb707d03e25 100644 --- a/raster/r.in.poly/poly2rast.c +++ b/raster/r.in.poly/poly2rast.c @@ -90,6 +90,7 @@ int poly_to_rast(char *input_file, char *raster_map, char *title, int nrows, if (stat < 0) { Rast_unopen(rfd); + fclose(ifd); return 1; } @@ -98,6 +99,7 @@ int poly_to_rast(char *input_file, char *raster_map, char *title, int nrows, Rast_short_history(raster_map, "raster", &history); Rast_command_history(&history); Rast_write_history(raster_map, &history); + fclose(ifd); return 0; } diff --git a/raster/r.in.poly/r.in.poly.html b/raster/r.in.poly/r.in.poly.html index 71673f807a5..d47212a162d 100644 --- a/raster/r.in.poly/r.in.poly.html +++ b/raster/r.in.poly/r.in.poly.html @@ -8,7 +8,7 @@

    DESCRIPTION

    The input file is an ASCII text file containing the polygon, linear, and point feature definitions. The format of this file is described in the -INPUT FORMAT section below. +INPUT FORMAT section below.

    The number of raster rows to hold in memory is per default 4096. @@ -31,7 +31,6 @@

    NOTES

    Polygons are filled, i.e. they define an area. -

    Input Format

    The input format for the input file consists of diff --git a/raster/r.in.xyz/r.in.xyz.html b/raster/r.in.xyz/r.in.xyz.html index 15d9f3565aa..70103d8e778 100644 --- a/raster/r.in.xyz/r.in.xyz.html +++ b/raster/r.in.xyz/r.in.xyz.html @@ -41,9 +41,9 @@

    DESCRIPTION

      -
    • Variance and derivatives use the biased estimator (n). [subject to change] +
    • Variance and derivatives use the biased estimator (n). [subject to change]
    • Coefficient of variance is given in percentage and defined as -(stddev/mean)*100. +(stddev/mean)*100.

    @@ -212,7 +212,7 @@

    Import of x,y,z ASCII into DEM

    @@ -245,7 +245,7 @@ 

    Import of x,y,z ASCII into DEM

    Import of LiDAR data and DEM creation

    -Import the Jockey's +Import the Jockey's Ridge, NC, LIDAR dataset (compressed file "lidaratm2.txt.gz"), and process it into a clean DEM: @@ -289,14 +289,14 @@

    TODO

  • Support for multiple map output from a single run.
    method=string[,string,...] output=name[,name,...]
    This can be easily handled by a wrapper script, with the added - benefit of it being very simple to parallelize that way. + benefit of it being very simple to parallelize that way.
  • KNOWN ISSUES

    • "nan" can leak into coeff_var maps. -
      Cause unknown. Possible work-around: "r.null setnull=nan" +
      Cause unknown. Possible work-around: "r.null setnull=nan"
    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.kappa/r.kappa.html b/raster/r.kappa/r.kappa.html index b9a57ec0915..ad7c77a2b65 100644 --- a/raster/r.kappa/r.kappa.html +++ b/raster/r.kappa/r.kappa.html @@ -116,7 +116,7 @@

    NOTES

    "On the performance of Matthews correlation coefficient (MCC) for imbalanced dataset". -

    EXAMPLE

    +

    EXAMPLE

    Example for North Carolina sample dataset: diff --git a/raster/r.kappa/testsuite/test_r_kappa.py b/raster/r.kappa/testsuite/test_r_kappa.py index 620a4f4979b..ff11f477925 100644 --- a/raster/r.kappa/testsuite/test_r_kappa.py +++ b/raster/r.kappa/testsuite/test_r_kappa.py @@ -51,8 +51,9 @@ def setUpClass(cls): def tearDownClass(cls): """Remove temporary data""" cls.del_temp_region() - cls.runModule("g.remove", flags="f", type="raster", name=cls.ref_1) - cls.runModule("g.remove", flags="f", type="raster", name=cls.class_1) + cls.runModule( + "g.remove", flags="f", type="raster", name=(cls.ref_1, cls.class_1) + ) def test_m(self): """Test printing matrix only @@ -119,8 +120,9 @@ def setUpClass(cls): def tearDownClass(cls): """Remove temporary data""" cls.del_temp_region() - cls.runModule("g.remove", flags="f", type="raster", name=cls.ref_1) - cls.runModule("g.remove", flags="f", type="raster", name=cls.class_1) + cls.runModule( + "g.remove", flags="f", type="raster", name=(cls.ref_1, cls.class_1) + ) def match(self, pat, ref): if pat == "NA" or ref == "NA": @@ -233,8 +235,9 @@ def setUpClass(cls): def tearDownClass(cls): """Remove temporary data""" cls.del_temp_region() - cls.runModule("g.remove", flags="f", type="raster", name=cls.ref_1) - cls.runModule("g.remove", flags="f", type="raster", name=cls.class_1) + cls.runModule( + "g.remove", flags="f", type="raster", name=(cls.ref_1, cls.class_1) + ) def match(self, pat, ref): if pat == "NA" or ref == "NA": diff --git a/raster/r.lake/r.lake.html b/raster/r.lake/r.lake.html index ee18eb6d8cc..4d12be899c6 100644 --- a/raster/r.lake/r.lake.html +++ b/raster/r.lake/r.lake.html @@ -1,7 +1,7 @@

    DESCRIPTION

    The module fills a lake to a target water level from a given start point. The user -can think of it as r.grow with additional +can think of it as r.grow with additional checks for elevation. The resulting raster map contains cells with values representing lake depth and NULL for all other cells beyond the lake. Lake depth is reported relative to specified water level @@ -44,24 +44,24 @@

    NOTES

    r.mapcalc equivalent - for GRASS hackers

    This module was initially created as a script using -r.mapcalc. +r.mapcalc. This had some limitations - it was slow and no checks where done to find out required iteration count. The shell script -code (using r.mapcalc) used +code (using r.mapcalc) used in the original script is shown below:
     ${seedmap} = if( ${dem}, \
    -if( if( isnull(${seedmap}),0,${seedmap}>0), ${wlevel}-${dem}, \
    +if( if( isnull(${seedmap}),0,${seedmap} > 0), ${wlevel}-${dem}, \
      if( \
    -  if(isnull(${seedmap}[-1,0]),0, ${seedmap}[-1,0]>0 && ${wlevel}>${dem}) ||\
    -  if(isnull(${seedmap}[-1,1]),0, ${seedmap}[-1,1]>0 && ${wlevel}>${dem}) ||\
    -  if(isnull(${seedmap}[0,1]), 0, ${seedmap}[0,1]>0  && ${wlevel}>${dem}) ||\
    -  if(isnull(${seedmap}[1,1]), 0, ${seedmap}[1,1]>0  && ${wlevel}>${dem}) ||\
    -  if(isnull(${seedmap}[1,0]), 0, ${seedmap}[1,0]>0  && ${wlevel}>${dem}) ||\
    -  if(isnull(${seedmap}[1,-1]),0, ${seedmap}[1,-1]>0 && ${wlevel}>${dem}) ||\
    -  if(isnull(${seedmap}[0,-1]),0, ${seedmap}[0,-1]>0 && ${wlevel}>${dem}) ||\
    -  if(isnull(${seedmap}[-1,-1]),0, ${seedmap}[-1,-1]>0 && ${wlevel}>${dem}),\
    +  if(isnull(${seedmap}[-1,0]),0, ${seedmap}[-1,0] > 0 && ${wlevel} > ${dem}) ||\
    +  if(isnull(${seedmap}[-1,1]),0, ${seedmap}[-1,1] > 0 && ${wlevel} > ${dem}) ||\
    +  if(isnull(${seedmap}[0,1]), 0, ${seedmap}[0,1] > 0  && ${wlevel} > ${dem}) ||\
    +  if(isnull(${seedmap}[1,1]), 0, ${seedmap}[1,1] > 0  && ${wlevel} > ${dem}) ||\
    +  if(isnull(${seedmap}[1,0]), 0, ${seedmap}[1,0] > 0  && ${wlevel} > ${dem}) ||\
    +  if(isnull(${seedmap}[1,-1]),0, ${seedmap}[1,-1] > 0 && ${wlevel} > ${dem}) ||\
    +  if(isnull(${seedmap}[0,-1]),0, ${seedmap}[0,-1] > 0 && ${wlevel} > ${dem}) ||\
    +  if(isnull(${seedmap}[-1,-1]),0, ${seedmap}[-1,-1] > 0 && ${wlevel} > ${dem}),\
      ${wlevel}-${dem}, null() )))
     
    @@ -100,7 +100,7 @@

    EXAMPLE

    -
    +
    Small flooding along a street (r.lake, using Lidar 1m DEM)
    diff --git a/raster/r.li/r.li.cwed/r.li.cwed.html b/raster/r.li/r.li.cwed/r.li.cwed.html index 0fe92bd560e..461eec731b6 100644 --- a/raster/r.li/r.li.cwed/r.li.cwed.html +++ b/raster/r.li/r.li.cwed/r.li.cwed.html @@ -12,12 +12,12 @@

    DESCRIPTION

    landscape between patch types i and k
  • dik: dissimilarity (edge contrast weight) between patch types i and k
  • -
  • Area: total landscape area
    -
    +
  • Area: total landscape area
  • + The input file contains a row for each couple of patch type that we want to consider in the calculation. Each row must be saved using this syntax:
    -patchType1,patchType2,dissimilarityBetweenPatchType1andPatchType2
    +patchType1,patchType2,dissimilarityBetweenPatchType1andPatchType2

    NOTES

    @@ -60,7 +60,7 @@

    EXAMPLES

    SEE ALSO

    -r.li - package overview
    +r.li (package overview), g.gui.rlisetup
    diff --git a/raster/r.li/r.li.daemon/r.li.daemon.html b/raster/r.li/r.li.daemon/r.li.daemon.html index d2640a03fba..2d3cc5c4901 100644 --- a/raster/r.li/r.li.daemon/r.li.daemon.html +++ b/raster/r.li/r.li.daemon/r.li.daemon.html @@ -24,35 +24,35 @@

    DESCRIPTION

    To write a new index only two steps are needed:

      -
    1. - Define a function and insert its declaration on file index.h in r.li.daemon - folder, which contains all index declarations. This function must be of this kind: -
      +    
    2. + Define a function and insert its declaration on file index.h in r.li.daemon + folder, which contains all index declarations. This function must be of this kind: +
               int index(int fd, char ** par, area_des ad, double * result)
      -	
      - where:
        -
      • fd is the raster map descriptor -
      • par is a matrix for special parameter (like argv in main) -
      • ad is the area descriptor -
      • result is where to put the index calculation result -
      - This function has to return 1 on success and 0 otherwise. - This function type is defined using typedef named rli_func. -
    3. - Create a main for command line arguments parsing, and call the function -
      +    
      + where:
        +
      • fd is the raster map descriptor
      • +
      • par is a matrix for special parameter (like argv in main)
      • +
      • ad is the area descriptor
      • +
      • result is where to put the index calculation result
      • +
      + This function has to return 1 on success and 0 otherwise. + This function type is defined using typedef named rli_func.
    4. +
    5. + Create a main for command line arguments parsing, and call the function +
               int calculateIndex(char *file, rli_func *f,
                                  char **parameters, char *raster, char *output);
      -	
      - from the r.li library, for starting raster analysis.
      - It follows the meaning of parameters: -
        -
      • file name of configuration file created using g.gui.rlisetup -
      • f pointer to index function defined above -
      • parameters pointer to index special parameters -
      • raster name of raster to use -
      • output output file name -
      +
    6. + from the r.li library, for starting raster analysis.
      + It follows the meaning of parameters: +
        +
      • file name of configuration file created using g.gui.rlisetup
      • +
      • f pointer to index function defined above
      • +
      • parameters pointer to index special parameters
      • +
      • raster name of raster to use
      • +
      • output output file name
      • +
    Compile it using a changed Makefile based on the file for r.li.patchdensity. diff --git a/raster/r.li/r.li.dominance/r.li.dominance.html b/raster/r.li/r.li.dominance/r.li.dominance.html index 13bef4620f4..bccf6f01e04 100644 --- a/raster/r.li/r.li.dominance/r.li.dominance.html +++ b/raster/r.li/r.li.dominance/r.li.dominance.html @@ -37,7 +37,7 @@

    EXAMPLES

    Forest map (Spearfish sample dataset) example:
     g.region raster=landcover.30m -p
    -r.mapcalc "forests = if(landcover.30m >= 41 && landcover.30m <= 43,1,null())"
    +r.mapcalc "forests = if(landcover.30m >= 41 && landcover.30m <= 43,1,null())"
     r.li.dominance input=forests conf=movwindow7 out=forests_dominance_mov7
     r.univar forests_dominance_mov7
     
    @@ -60,7 +60,7 @@

    EXAMPLES

    SEE ALSO

    -r.li - package overview
    +r.li (package overview), g.gui.rlisetup
    diff --git a/raster/r.li/r.li.edgedensity/r.li.edgedensity.html b/raster/r.li/r.li.edgedensity/r.li.edgedensity.html index 229a3e28686..e96f26e02b7 100644 --- a/raster/r.li/r.li.edgedensity/r.li.edgedensity.html +++ b/raster/r.li/r.li.edgedensity/r.li.edgedensity.html @@ -3,12 +3,12 @@

    DESCRIPTION

    r.li.edgedensity calculates:

      -
    • the density of all edges of patch type k - r.li.edgedensity formula 1 - , or -
    • the density of all edges in the sampling area if k is - not specified, - r.li.edgedensity formula 2 +
    • the density of all edges of patch type k +r.li.edgedensity formula 1 +, or
    • +
    • the density of all edges in the sampling area if k is +not specified, +r.li.edgedensity formula 2

    with:

      @@ -58,7 +58,7 @@

      EXAMPLES

      Forest map (Spearfish sample dataset) example:
       g.region raster=landcover.30m -p
      -r.mapcalc "forests = if(landcover.30m >= 41 && landcover.30m <= 43,1,null())"
      +r.mapcalc "forests = if(landcover.30m >= 41 && landcover.30m <= 43,1,null())"
       r.li.edgedensity input=forests conf=movwindow7 out=forests_edgedens_mov7
       r.univar forests_edgedens_mov7
       
      @@ -81,7 +81,7 @@

      EXAMPLES

      SEE ALSO

      -r.li - package overview
      +r.li (package overview), g.gui.rlisetup
      diff --git a/raster/r.li/r.li.html b/raster/r.li/r.li.html index 0ad8e5b6d77..a7685ca55ec 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

      @@ -62,11 +39,11 @@

      NOTES

    • run g.gui.rlisetup: create a configuration file selecting the parts of raster map to be analyzed. This file allows re-running an analysis easily. It is stored on Windows in the directory C:\Users\userxy\AppData\Roaming\GRASS8\r.li\, on GNU/Linux in - $HOME/.grass8/r.li/. + $HOME/.grass8/r.li/.
    • run one or more of the r.li.[index] modules (e.g., r.li.patchdensity) to calculate the selected index - using on the areas selected on configuration file. + using on the areas selected on configuration file.
    • As far as the user just use r.ros together with r.spread, there is no need to - concern about these output units. + concern about these output units.

      REFERENCES

      diff --git a/raster/r.series.interp/r.series.interp.html b/raster/r.series.interp/r.series.interp.html index a05b792afbf..77df2a89d91 100644 --- a/raster/r.series.interp/r.series.interp.html +++ b/raster/r.series.interp/r.series.interp.html @@ -7,7 +7,7 @@

      DESCRIPTION

      The following interpolation methods are supported.
        -
      • linear: Linear interpolation. At least two input maps and data positions are required. +
      • linear: Linear interpolation. At least two input maps and data positions are required.

      EXAMPLES

      diff --git a/raster/r.series/benchmark/benchmark_r_series.py b/raster/r.series/benchmark/benchmark_r_series.py index ecf4432f2dd..72c9c3bd23c 100644 --- a/raster/r.series/benchmark/benchmark_r_series.py +++ b/raster/r.series/benchmark/benchmark_r_series.py @@ -37,8 +37,7 @@ def benchmark(size, label, results): overwrite=True, ) results.append(bm.benchmark_nprocs(module, label=label, max_nprocs=16, repeat=3)) - Module("g.remove", quiet=True, flags="f", type="raster", name=reference) - Module("g.remove", quiet=True, flags="f", type="raster", name=output) + Module("g.remove", quiet=True, flags="f", type="raster", name=(reference, output)) def generate_map(rows, cols, fname): diff --git a/raster/r.series/r.series.html b/raster/r.series/r.series.html index 0d1c12b5bb9..1a743a5a49a 100644 --- a/raster/r.series/r.series.html +++ b/raster/r.series/r.series.html @@ -12,29 +12,29 @@

      DESCRIPTION

      Following methods are available:
        -
      • average: average value -
      • count: count of non-NULL cells -
      • median: median value -
      • mode: most frequently occurring value -
      • minimum: lowest value -
      • min_raster: raster map number with the minimum time-series value -
      • maximum: highest value -
      • max_raster: raster map number with the maximum time-series value -
      • stddev: standard deviation -
      • range: range of values (max - min) -
      • sum: sum of values -
      • variance: statistical variance -
      • diversity: number of different values -
      • slope: linear regression slope -
      • offset: linear regression offset -
      • detcoeff: linear regression coefficient of determination -
      • tvalue: linear regression t-value -
      • quart1: first quartile -
      • quart3: third quartile -
      • perc90: ninetieth percentile -
      • quantile: arbitrary quantile -
      • skewness: skewness -
      • kurtosis: kurtosis +
      • average: average value
      • +
      • count: count of non-NULL cells
      • +
      • median: median value
      • +
      • mode: most frequently occurring value
      • +
      • minimum: lowest value
      • +
      • min_raster: raster map number with the minimum time-series value
      • +
      • maximum: highest value
      • +
      • max_raster: raster map number with the maximum time-series value
      • +
      • stddev: standard deviation
      • +
      • range: range of values (max - min)
      • +
      • sum: sum of values
      • +
      • variance: statistical variance
      • +
      • diversity: number of different values
      • +
      • slope: linear regression slope
      • +
      • offset: linear regression offset
      • +
      • detcoeff: linear regression coefficient of determination
      • +
      • tvalue: linear regression t-value
      • +
      • quart1: first quartile
      • +
      • quart3: third quartile
      • +
      • perc90: ninetieth percentile
      • +
      • quantile: arbitrary quantile
      • +
      • skewness: skewness
      • +
      • kurtosis: kurtosis
      Note that most parameters accept multiple answers, allowing multiple @@ -196,7 +196,7 @@

      EXAMPLES

      Example to use the file option of r.series:

      -cat > input.txt << EOF
      +cat > input.txt << EOF
       map1
       map2
       map3
      @@ -211,7 +211,7 @@ 

      EXAMPLES

      weights we can leave it out:
      -cat > input.txt << EOF
      +cat > input.txt << EOF
       map1
       map2|0.75
       map3
      diff --git a/raster/r.series/testsuite/test_r_series.py b/raster/r.series/testsuite/test_r_series.py
      index 93bfd129242..e067a26e1da 100644
      --- a/raster/r.series/testsuite/test_r_series.py
      +++ b/raster/r.series/testsuite/test_r_series.py
      @@ -18,13 +18,13 @@ def setUpClass(cls):
               call_module("r.mapcalc", expression=f"{cls.sum_mapcalc} = {cls.elevation} * 4")
       
           @classmethod
      -    def tearDownClass(self):
      -        self.del_temp_region()
      +    def tearDownClass(cls):
      +        cls.del_temp_region()
               call_module(
                   "g.remove",
                   flags="f",
                   type_="raster",
      -            name=self.sum_mapcalc,
      +            name=cls.sum_mapcalc,
               )
       
           def tearDown(self):
      diff --git a/raster/r.sim/r.sim.sediment/r.sim.sediment.html b/raster/r.sim/r.sim.sediment/r.sim.sediment.html
      index 025fa3f72b1..caebb9c308c 100644
      --- a/raster/r.sim/r.sim.sediment/r.sim.sediment.html
      +++ b/raster/r.sim/r.sim.sediment/r.sim.sediment.html
      @@ -71,7 +71,7 @@ 

      REFERENCES

      In: Landscape erosion and landscape evolution modeling, Harmon R. and Doe W. eds., Kluwer Academic/Plenum Publishers, pp. 321-347.

      - + Neteler, M. and Mitasova, H., 2008, Open Source GIS: A GRASS GIS Approach. Third Edition. The International Series in Engineering and Computer Science: Volume 773. Springer New York Inc, p. 406. diff --git a/raster/r.sim/r.sim.water/r.sim.water.html b/raster/r.sim/r.sim.water/r.sim.water.html index 3c920473ca9..af54dea4490 100644 --- a/raster/r.sim/r.sim.water/r.sim.water.html +++ b/raster/r.sim/r.sim.water/r.sim.water.html @@ -208,37 +208,37 @@

      REFERENCES

      and short term terrain evolution in Open Source GIS. In: C.T. Miller, M.W. Farthing, V.G. Gray, G.F. Pinder eds., Proceedings of the XVth International Conference on Computational Methods in Water -Resources (CMWR XV), June 13-17 2004, Chapel Hill, NC, USA, Elsevier, pp. 1479-1490. +Resources (CMWR XV), June 13-17 2004, Chapel Hill, NC, USA, Elsevier, pp. 1479-1490.
    • Mitasova H, Mitas, L., 2000, Modeling spatial processes in multiscale framework: exploring duality between particles and fields, -plenary talk at GIScience2000 conference, Savannah, GA. +plenary talk at GIScience2000 conference, Savannah, GA.
    • Mitas, L., and Mitasova, H., 1998, Distributed soil erosion simulation -for effective erosion prevention. Water Resources Research, 34(3), 505-516. +for effective erosion prevention. Water Resources Research, 34(3), 505-516.
    • Mitasova, H., Mitas, L., 2001, Multiscale soil erosion simulations for land use management, In: Landscape erosion and landscape evolution modeling, Harmon R. and Doe W. eds., -Kluwer Academic/Plenum Publishers, pp. 321-347. +Kluwer Academic/Plenum Publishers, pp. 321-347.
    • Hofierka, J, Mitasova, H., Mitas, L., 2002. GRASS and modeling landscape processes using duality between particles and fields. Proceedings of the Open source GIS - GRASS users conference 2002 - Trento, Italy, 11-13 September 2002. -PDF +PDF
    • Hofierka, J., Knutova, M., 2015, Simulating aspects of a flash flood using the Monte Carlo method and GRASS GIS: a case study of the Malá Svinka Basin (Slovakia), Open Geosciences. Volume 7, Issue 1, ISSN (Online) 2391-5447, DOI: 10.1515/geo-2015-0013, -April 2015 +April 2015
    • Neteler, M. and Mitasova, H., 2008, -Open Source GIS: A GRASS GIS Approach. Third Edition. -The International Series in Engineering and Computer Science: Volume 773. Springer New York Inc, p. 406. +Open Source GIS: A GRASS GIS Approach. Third Edition. +The International Series in Engineering and Computer Science: Volume 773. Springer New York Inc, p. 406.

    SEE ALSO

    diff --git a/raster/r.sim/r.sim.water/testsuite/data/depth_complex.pack b/raster/r.sim/r.sim.water/testsuite/data/depth_complex.pack new file mode 100644 index 00000000000..60f9de2be64 Binary files /dev/null and b/raster/r.sim/r.sim.water/testsuite/data/depth_complex.pack differ diff --git a/raster/r.sim/r.sim.water/testsuite/data/depth_default.pack b/raster/r.sim/r.sim.water/testsuite/data/depth_default.pack new file mode 100644 index 00000000000..579863ecca9 Binary files /dev/null and b/raster/r.sim/r.sim.water/testsuite/data/depth_default.pack differ diff --git a/raster/r.sim/r.sim.water/testsuite/data/discharge_complex.pack b/raster/r.sim/r.sim.water/testsuite/data/discharge_complex.pack new file mode 100644 index 00000000000..01810de0cb6 Binary files /dev/null and b/raster/r.sim/r.sim.water/testsuite/data/discharge_complex.pack differ diff --git a/raster/r.sim/r.sim.water/testsuite/data/discharge_default.pack b/raster/r.sim/r.sim.water/testsuite/data/discharge_default.pack new file mode 100644 index 00000000000..914eabcda47 Binary files /dev/null and b/raster/r.sim/r.sim.water/testsuite/data/discharge_default.pack differ diff --git a/raster/r.sim/r.sim.water/testsuite/test_r_sim_water.py b/raster/r.sim/r.sim.water/testsuite/test_r_sim_water.py new file mode 100644 index 00000000000..44ea662276a --- /dev/null +++ b/raster/r.sim/r.sim.water/testsuite/test_r_sim_water.py @@ -0,0 +1,201 @@ +import unittest + +from grass.gunittest.case import TestCase + + +class TestRSimWater(TestCase): + """Test r.sim.water""" + + # Set up the necessary raster maps for testing + elevation = "elevation" + dx = "tmp_dx" + dy = "tmp_dy" + depth = "tmp_depth" + discharge = "tmp_discharge" + rain = "tmp_rain" + mannings = "tmp_mannings" + infil = "tmp_infil" + reference_depth_default = "depth_default" + reference_discharge_default = "discharge_default" + reference_depth_complex = "depth_complex" + reference_discharge_complex = "discharge_complex" + + @classmethod + def setUpClass(cls): + """Set up region, create necessary data""" + cls.runModule("g.region", n=224000, s=223000, e=637000, w=636000, res=10) + cls.runModule("r.slope.aspect", elevation=cls.elevation, dx=cls.dx, dy=cls.dy) + cls.runModule( + "r.unpack", + input="data/depth_default.pack", + output=cls.reference_depth_default, + ) + cls.runModule( + "r.unpack", + input="data/discharge_default.pack", + output=cls.reference_discharge_default, + ) + cls.runModule( + "r.random.surface", output=cls.rain, distance=200, seed=1, high=100 + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.mannings} = if (x() > 636500 && y() > 223500, 0.3, 0.01)", + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.infil} = if (x() < 636500 && y() > 223500, 0.001, 0)", + ) + cls.runModule( + "r.unpack", + input="data/depth_complex.pack", + output=cls.reference_depth_complex, + ) + cls.runModule( + "r.unpack", + input="data/discharge_complex.pack", + output=cls.reference_discharge_complex, + ) + + @classmethod + def tearDownClass(cls): + """Clean up test environment""" + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=[ + cls.elevation, + cls.dx, + cls.dy, + cls.reference_depth_default, + cls.reference_discharge_default, + cls.rain, + cls.mannings, + cls.infil, + cls.reference_depth_complex, + cls.reference_discharge_complex, + ], + ) + + def tearDown(self): + """Clean up test environment""" + self.runModule( + "g.remove", + flags="f", + type="raster", + pattern=f"{self.depth}*,{self.discharge}*", + ) + + def test_default(self): + """Test r.sim.water execution with defaults""" + # Run the r.sim.water simulation + self.assertModule( + "r.sim.water", + elevation=self.elevation, + dx=self.dx, + dy=self.dy, + depth=self.depth, + discharge=self.discharge, + random_seed=1, + ) + + # Assert that the output rasters exist + self.assertRasterExists(self.depth) + self.assertRasterExists(self.discharge) + # Assert that the output rasters are the same + self.assertRastersEqual( + self.depth, reference=self.reference_depth_default, precision="0.000001" + ) + self.assertRastersEqual( + self.discharge, + reference=self.reference_discharge_default, + precision="0.000001", + ) + + def test_complex(self): + """Test r.sim.water execution with more complex inputs""" + # Run the r.sim.water simulation + self.assertModule( + "r.sim.water", + flags="t", + elevation=self.elevation, + dx=self.dx, + dy=self.dy, + rain=self.rain, + man=self.mannings, + infil=self.infil, + depth=self.depth, + discharge=self.discharge, + niterations=15, + output_step=5, + diffusion_coeff=0.9, + hmax=0.25, + halpha=3.9, + hbeta=0.6, + random_seed=1, + ) + + # Assert that the output rasters exist + self.assertRasterExists(f"{self.depth}.05") + self.assertRasterExists(f"{self.depth}.10") + self.assertRasterExists(f"{self.depth}.15") + # Assert that the output rasters are the same + self.assertRastersEqual( + f"{self.depth}.15", + reference=self.reference_depth_complex, + precision="0.000001", + ) + self.assertRastersEqual( + f"{self.discharge}.15", + reference=self.reference_discharge_complex, + precision="0.000001", + ) + + +@unittest.skip("runs too long") +class TestRSimWaterLarge(TestCase): + """Test r.sim.water with large region""" + + # Set up the necessary raster maps for testing + elevation = "elevation" + dx = "tmp_dx" + dy = "tmp_dy" + depth = "tmp_depth" + + @classmethod + def setUpClass(cls): + """Set up region, create necessary data""" + cls.runModule("g.region", raster=cls.elevation) + cls.runModule("r.slope.aspect", elevation=cls.elevation, dx=cls.dx, dy=cls.dy) + + @classmethod + def tearDownClass(cls): + """Clean up test environment""" + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=[cls.elevation, cls.dx, cls.dy, cls.depth], + ) + + def test_default(self): + """Test r.sim.water execution with defaults""" + # Run the r.sim.water simulation + self.assertModule( + "r.sim.water", + elevation=self.elevation, + dx=self.dx, + dy=self.dy, + depth=self.depth, + random_seed=1, + ) + self.assertRasterFitsUnivar( + self.depth, reference="sum=30364.327529", precision=1e-6 + ) + + +if __name__ == "__main__": + from grass.gunittest.main import test + + test() diff --git a/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect.py b/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect.py index 220b813e323..522a938f26c 100644 --- a/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect.py +++ b/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect.py @@ -42,11 +42,13 @@ def benchmark(size, label, results): overwrite=True, ) results.append(bm.benchmark_nprocs(module, label=label, max_nprocs=16, repeat=3)) - Module("g.remove", quiet=True, flags="f", type="raster", name=reference) - Module("g.remove", quiet=True, flags="f", type="raster", name=slope) - Module("g.remove", quiet=True, flags="f", type="raster", name=aspect) - Module("g.remove", quiet=True, flags="f", type="raster", name=pcurv) - Module("g.remove", quiet=True, flags="f", type="raster", name=tcurv) + Module( + "g.remove", + quiet=True, + flags="f", + type="raster", + name=(reference, slope, aspect, pcurv, tcurv), + ) def generate_map(rows, cols, fname): diff --git a/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect_memory.py b/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect_memory.py index c8f5ac09f00..31824233bbc 100644 --- a/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect_memory.py +++ b/raster/r.slope.aspect/benchmark/benchmark_r_slope_aspect_memory.py @@ -46,10 +46,13 @@ def benchmark(memory, label, results, reference): ) results.append(bm.benchmark_nprocs(module, label=label, max_nprocs=20, repeat=10)) - Module("g.remove", quiet=True, flags="f", type="raster", name=slope) - Module("g.remove", quiet=True, flags="f", type="raster", name=aspect) - Module("g.remove", quiet=True, flags="f", type="raster", name=pcurv) - Module("g.remove", quiet=True, flags="f", type="raster", name=tcurv) + Module( + "g.remove", + quiet=True, + flags="f", + type="raster", + name=(slope, aspect, pcurv, tcurv), + ) def generate_map(rows, cols, fname): diff --git a/raster/r.slope.aspect/r.slope.aspect.html b/raster/r.slope.aspect/r.slope.aspect.html index a76bd33e477..eb737fb968d 100644 --- a/raster/r.slope.aspect/r.slope.aspect.html +++ b/raster/r.slope.aspect/r.slope.aspect.html @@ -30,7 +30,7 @@

    DESCRIPTION

    # convert angles from CCW from East to CW from North # modulus (%) can not be used with floating point aspect values r.mapcalc "azimuth_aspect = if(ccw_aspect == 0, 0, \ - if(ccw_aspect < 90, 90 - ccw_aspect, \ + if(ccw_aspect < 90, 90 - ccw_aspect, \ 450 - ccw_aspect)))" @@ -240,15 +240,15 @@

    Classification of major aspect directions in compass orientation

    # generate compass orientation and classify four major directions (N, E, S, W) r.mapcalc "aspect_4_directions = eval( \\ compass=(450 - myaspect ) % 360, \\ - if(compass >=0. && compass < 45., 1) \\ - + if(compass >=45. && compass < 135., 2) \\ - + if(compass >=135. && compass < 225., 3) \\ - + if(compass >=225. && compass < 315., 4) \\ - + if(compass >=315., 1) \\ + if(compass >=0. && compass < 45., 1) \\ + + if(compass >=45. && compass < 135., 2) \\ + + if(compass >=135. && compass < 225., 3) \\ + + if(compass >=225. && compass < 315., 4) \\ + + if(compass >=315., 1) \\ )" # assign text labels -r.category aspect_4_directions separator=comma rules=- << EOF +r.category aspect_4_directions separator=comma rules=- << EOF 1,north 2,east 3,south @@ -256,7 +256,7 @@

    Classification of major aspect directions in compass orientation

    EOF # assign color table -r.colors aspect_4_directions rules=- << EOF +r.colors aspect_4_directions rules=- << EOF 1 253,184,99 2 178,171,210 3 230,97,1 @@ -273,13 +273,13 @@

    REFERENCES

    • Horn, B. K. P. (1981). Hill Shading and the Reflectance Map, Proceedings -of the IEEE, 69(1):14-47. +of the IEEE, 69(1):14-47.
    • Mitasova, H. (1985). Cartographic aspects of computer surface modeling. PhD thesis. -Slovak Technical University , Bratislava +Slovak Technical University , Bratislava
    • Hofierka, J., Mitasova, H., Neteler, M., 2009. Geomorphometry in GRASS GIS. In: Hengl, T. and Reuter, H.I. (Eds), Geomorphometry: Concepts, Software, Applications. Developments in Soil Science, vol. 33, Elsevier, 387-410 pp, -http://www.geomorphometry.org +http://www.geomorphometry.org

    SEE ALSO

    diff --git a/raster/r.solute.transport/r.solute.transport.html b/raster/r.solute.transport/r.solute.transport.html index 0046ac48f9f..ff77a35f419 100644 --- a/raster/r.solute.transport/r.solute.transport.html +++ b/raster/r.solute.transport/r.solute.transport.html @@ -108,7 +108,7 @@

    EXAMPLE

    gs.run_command("r.mapcalc", expression="phead = if(col() == 1 , 50, 40)") gs.run_command("r.mapcalc", expression="phead = if(col() ==200 , 45 + row()/40, phead)") gs.run_command("r.mapcalc", expression="status = if(col() == 1 || col() == 200 , 2, 1)") -gs.run_command("r.mapcalc", expression="well = if((row() == 50 && col() == 175) || (row() == 10 && col() == 135) , -0.001, 0)") +gs.run_command("r.mapcalc", expression="well = if((row() == 50 && col() == 175) || (row() == 10 && col() == 135) , -0.001, 0)") gs.run_command("r.mapcalc", expression="hydcond = 0.00005") gs.run_command("r.mapcalc", expression="recharge = 0") gs.run_command("r.mapcalc", expression="top_conf = 20") diff --git a/raster/r.spread/r.spread.html b/raster/r.spread/r.spread.html index 1980e61aae5..68c32171270 100644 --- a/raster/r.spread/r.spread.html +++ b/raster/r.spread/r.spread.html @@ -12,9 +12,9 @@

    DESCRIPTION

    1. the uneven conditions from location to location, which can be called -spatial heterogeneity, and +spatial heterogeneity, and
    2. the uneven conditions in different directions, which can be called -anisotropy. +anisotropy.

    The anisotropy of spread occurs when any of the determining factors diff --git a/raster/r.stats.quantile/r.stats.quantile.html b/raster/r.stats.quantile/r.stats.quantile.html index 4c387281b7b..28deded4876 100644 --- a/raster/r.stats.quantile/r.stats.quantile.html +++ b/raster/r.stats.quantile/r.stats.quantile.html @@ -5,7 +5,7 @@

    DESCRIPTION

    in a "base layer". It provides quantile calculations as selected "zonal statistics". -

    NOTES

    +

    NOTES

    r.stats.quantile is intended to be a partial replacement for r.statistics, with support @@ -46,10 +46,9 @@

    REFERENCES

    diff --git a/raster/r.stats.zonal/r.stats.zonal.html b/raster/r.stats.zonal/r.stats.zonal.html index 9e5d83bef01..b611e531c2b 100644 --- a/raster/r.stats.zonal/r.stats.zonal.html +++ b/raster/r.stats.zonal/r.stats.zonal.html @@ -9,7 +9,7 @@

    DESCRIPTION

    Notably, the output of this module is spatial: The resulting values are recorded as cell values in the output raster map. -

    NOTES

    +

    NOTES

    r.stats.zonal is intended to be a partial replacement for r.statistics, with support diff --git a/raster/r.stats/cell_stats.c b/raster/r.stats/cell_stats.c index f07f1451a42..51e46b6acc3 100644 --- a/raster/r.stats/cell_stats.c +++ b/raster/r.stats/cell_stats.c @@ -66,6 +66,10 @@ int cell_stats(int fd[], int with_percents, int with_counts, int with_areas, sort_cell_stats(do_sort); print_cell_stats(fmt, with_percents, with_counts, with_areas, with_labels, fs); + for (i = 0; i < nfiles; i++) { + G_free(cell[i]); + } + G_free(cell); return 0; } diff --git a/raster/r.stream.extract/r.stream.extract.html b/raster/r.stream.extract/r.stream.extract.html index 22877936c93..acc9030d0b0 100644 --- a/raster/r.stream.extract/r.stream.extract.html +++ b/raster/r.stream.extract/r.stream.extract.html @@ -258,7 +258,7 @@

    REFERENCES

  • Holmgren, P. (1994). Multiple flow direction algorithms for runoff modelling in grid based elevation models: An empirical evaluation. -Hydrological Processes Vol 8(4), pp 327-334. DOI: 10.1002/hyp.3360080405
  • +Hydrological Processes Vol 8(4), pp 327-334. DOI: 10.1002/hyp.3360080405
  • Montgomery, D.R., Foufoula-Georgiou, E. (1993). Channel network source representation using digital elevation models. Water Resources Research Vol 29(12), pp 3925-3934.
  • diff --git a/raster/r.sun/TODO b/raster/r.sun/TODO index 3e54873977e..4d31c0314df 100644 --- a/raster/r.sun/TODO +++ b/raster/r.sun/TODO @@ -16,10 +16,10 @@ Update https://grasswiki.osgeo.org/wiki/R.sun #### -Fix http://trac.osgeo.org/grass/ticket/498 +Fix https://trac.osgeo.org/grass/ticket/498 pseudo-data test-case -http://trac.osgeo.org/grass/ticket/498#comment:22 +https://trac.osgeo.org/grass/ticket/498#comment:22 #spearfish (further north than NC so more defined shadows) g.region -d r.mapcalc "undulates = (2 + sin( row() * 2 ) + cos( col() * 2 )) * 500" diff --git a/raster/r.sun/r.sun.html b/raster/r.sun/r.sun.html index 189633f9f48..677748dae6a 100644 --- a/raster/r.sun/r.sun.html +++ b/raster/r.sun/r.sun.html @@ -13,8 +13,8 @@

    DESCRIPTION

    For latitude-longitude coordinates it requires that the elevation map is in meters. The rules are:

      -
    • lat/lon coordinates: elevation in meters; -
    • Other coordinates: elevation in the same unit as the easting-northing coordinates. +
    • lat/lon coordinates: elevation in meters;
    • +
    • Other coordinates: elevation in the same unit as the easting-northing coordinates.
    The solar geometry of the model is based on the works of Krcho (1990), later @@ -294,8 +294,8 @@

    EXAMPLES

    We can compute the day of year from a specific date in Python:
    ->>> import datetime
    ->>> datetime.datetime(2014, 6, 21).timetuple().tm_yday
    +>>> import datetime
    +>>> datetime.datetime(2014, 6, 21).timetuple().tm_yday
     172
     
    @@ -317,53 +317,53 @@

    REFERENCES

  • Hofierka, J., Suri, M. (2002): The solar radiation model for Open source GIS: implementation and applications. International GRASS users conference in Trento, Italy, September 2002. -(PDF) +(PDF)
  • Hofierka, J. (1997). Direct solar radiation modelling within an open GIS environment. Proceedings of JEC-GI'97 conference in Vienna, Austria, IOS -Press Amsterdam, 575-584. +Press Amsterdam, 575-584.
  • Jenco, M. (1992). Distribution of direct solar radiation on georelief and its modelling by means of complex digital model of terrain (in Slovak). Geograficky -casopis, 44, 342-355. +casopis, 44, 342-355.
  • Kasten, F. (1996). The Linke turbidity factor based on improved values of -the integral Rayleigh optical thickness. Solar Energy, 56 (3), 239-244. +the integral Rayleigh optical thickness. Solar Energy, 56 (3), 239-244.
  • Kasten, F., Young, A. T. (1989). Revised optical air mass tables and approximation -formula. Applied Optics, 28, 4735-4738. +formula. Applied Optics, 28, 4735-4738.
  • Kittler, R., Mikler, J. (1986): Basis of the utilization of solar radiation -(in Slovak). VEDA, Bratislava, p. 150. +(in Slovak). VEDA, Bratislava, p. 150.
  • Krcho, J. (1990). Morfometrická analza a digitálne modely georeliéfu (Morphometric analysis and digital models of georelief, in Slovak). -VEDA, Bratislava. +VEDA, Bratislava.
  • Muneer, T. (1990). Solar radiation model for Europe. Building services engineering -research and technology, 11, 4, 153-163. +research and technology, 11, 4, 153-163.
  • Neteler, M., Mitasova, H. (2002): Open Source GIS: A GRASS GIS Approach, Kluwer Academic Publishers. (Appendix explains formula; -r.sun script download) +r.sun script download)
  • Page, J. ed. (1986). Prediction of solar radiation on inclined surfaces. Solar energy R&D in the European Community, series F - Solar radiation data, -Dordrecht (D. Reidel), 3, 71, 81-83. +Dordrecht (D. Reidel), 3, 71, 81-83.
  • Page, J., Albuisson, M., Wald, L. (2001). The European solar radiation atlas: -a valuable digital tool. Solar Energy, 71, 81-83. +a valuable digital tool. Solar Energy, 71, 81-83.
  • Rigollier, Ch., Bauer, O., Wald, L. (2000). On the clear sky model of the ESRA - European Solar radiation Atlas - with respect to the Heliosat method. -Solar energy, 68, 33-48. +Solar energy, 68, 33-48.
  • Scharmer, K., Greif, J., eds., (2000). The European solar radiation atlas, Vol. 2: Database and exploitation software. Paris (Les Presses de l'École -des Mines). +des Mines).
  • Joint Research Centre: GIS solar radiation database for Europe and -Solar radiation and GIS +Solar radiation and GIS
  • AUTHORS

    diff --git a/raster/r.sunmask/r.sunmask.html b/raster/r.sunmask/r.sunmask.html index 27a2ee35f7a..7b43ac502ef 100644 --- a/raster/r.sunmask/r.sunmask.html +++ b/raster/r.sunmask/r.sunmask.html @@ -80,7 +80,7 @@

    NOTES

    correction for atmosphere refraction. The output without -g flag contains related indications. -

    EXAMPLE

    +

    EXAMPLE

    Example for North Carolina sample data set for the calculation of sun position angles and more: diff --git a/raster/r.support/r.support.html b/raster/r.support/r.support.html index 111e46f653d..379f1190c67 100644 --- a/raster/r.support/r.support.html +++ b/raster/r.support/r.support.html @@ -5,40 +5,55 @@

    DESCRIPTION

    history, semantic label elements and title is supported. Category labels can also be copied from another raster map. -

    Raster band management

    +

    Raster semantic labels and band management

    + Raster semantic label concept is similar to dimension name in other GIS and -remote sensing applications. Most common usage will be assigning a -remote sensing platform sensor band ID to the raster, although any -identifier is supported. Raster semantic label is suggested to work with -imagery classification tools.
    +remote sensing applications. Most common usage will be assigning a remote +sensing platform sensor band identifier to the raster map metadata, although +any identifier is supported (see i.band.library). +Raster semantic label is suggested to work with imagery classification tools.

    EXAMPLES

    -These examples are based on the North Carolina dataset, more specifically the landuse raster map. +These examples are based on the North Carolina dataset, more specifically +the landuse raster map. Copy the landuse map to the current mapset -
    g.copy raster=landuse,my_landuse
    +
    +
    +g.copy raster=landuse,my_landuse
     

    Update statistics

    -
    r.support -s map=my_landuse
    +
    +
    +r.support -s map=my_landuse
     

    Update Title

    -
    r.support map=my_landuse title="Landuse copied"
    +
    +
    +r.support map=my_landuse title="Landuse copied"
     

    Append to History Metadata

    -
    r.support map=my_landuse history="Copied from PERMANENT mapset"
    +
    +
    +r.support map=my_landuse history="Copied from PERMANENT mapset"
     

    Update Units Display

    -
    r.support map=my_landuse units=meter
    +
    +
    +r.support map=my_landuse units=meter
     

    Set semantic label

    + Note: landuse map doesn't confirm to CORINE specification. This is an example only. -
    r.support map=my_landuse semantic_label=CORINE_LULC
    +
    +
    +r.support map=my_landuse semantic_label=CORINE_LULC
     

    NOTES

    @@ -57,12 +72,14 @@

    NOTES

    SEE ALSO

    +i.band.library, r.category, r.describe, r.info, r.null, r.region, r.report, +r.semantic.label, r.timestamp 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.surf.fractal/r.surf.fractal.html b/raster/r.surf.fractal/r.surf.fractal.html index d564cbec4e1..2a2a3e3a060 100644 --- a/raster/r.surf.fractal/r.surf.fractal.html +++ b/raster/r.surf.fractal/r.surf.fractal.html @@ -11,7 +11,7 @@

    DESCRIPTION

    NOTE

    -This module requires the FFTW library +This module requires the FFTW library for computing Discrete Fourier Transforms.

    EXAMPLE

    diff --git a/raster/r.surf.idw/r.surf.idw.html b/raster/r.surf.idw/r.surf.idw.html index dac9c6ead76..dd985fbc178 100644 --- a/raster/r.surf.idw/r.surf.idw.html +++ b/raster/r.surf.idw/r.surf.idw.html @@ -17,7 +17,7 @@

    DESCRIPTION

    The -e flag is the error analysis option that interpolates values only for those cells of the input raster map which have non-zero values and -outputs the difference (see NOTES below). +outputs the difference (see NOTES below).

    The npoints parameter defines the number of nearest data points used to determine the interpolated value of an output raster cell. @@ -66,8 +66,8 @@

    NOTES

    for the former may include unacceptable nonconformities in the surface pattern. - -

    +

    Surface-generation error analysis

    + The -e flag option provides a standard surface-generation error analysis facility. It produces an output raster map of the difference of interpolated values minus input values for those cells diff --git a/raster/r.terraflow/r.terraflow.html b/raster/r.terraflow/r.terraflow.html index 29fa310c5dc..80f7e5463dd 100644 --- a/raster/r.terraflow/r.terraflow.html +++ b/raster/r.terraflow/r.terraflow.html @@ -44,12 +44,12 @@

    DESCRIPTION

    • On plateaus (flat areas that spill out) r.terraflow routes flow so that globally the flow goes towards the spill cells of -the plateaus. +the plateaus.
    • On sinks (flat areas that do not spill out, including one-cell pits) r.terraflow assigns flow by flooding the terrain until all the sinks are filled and assigning flow directions on the filled -terrain. +terrain.

    In order to flood the terrain, r.terraflow identifies all @@ -163,7 +163,7 @@

    EXAMPLES

    -
    +
    Flow accumulation
      -
    • no-data (null), if the respective point in the elevation map is no-data (null) -
    • -1, if the point is not visible -
    • the difference in elevation between the point and the viewpoint, if the point is visible. +
    • no-data (null), if the respective point in the elevation map is no-data (null)
    • +
    • -1, if the point is not visible
    • +
    • the difference in elevation between the point and the viewpoint, if the point is visible.

    @@ -58,8 +58,6 @@

    NOTES

    r.mapcalc can be used to create a negative of the viewshed map. - -

    By default the elevations are not adjusted for the curvature of the earth. The user can turn this on with flag @@ -163,10 +161,10 @@

    The algorithm

    - +
    - - + + @@ -187,7 +185,7 @@

    EXAMPLES

    -r.viewshed example
    +r.viewshed example
    Viewshed shown on shaded terrain (observer position in the north-east quadrant with white dot; 5m above ground)
    diff --git a/raster/r.viewshed/testsuite/test_r_viewshed.py b/raster/r.viewshed/testsuite/test_r_viewshed.py index b6825c62018..a341d8e97b5 100644 --- a/raster/r.viewshed/testsuite/test_r_viewshed.py +++ b/raster/r.viewshed/testsuite/test_r_viewshed.py @@ -1,6 +1,5 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test -from grass.gunittest.gmodules import call_module class TestViewshed(TestCase): @@ -15,10 +14,10 @@ def setUpClass(cls): def tearDownClass(cls): cls.del_temp_region() - def tearDown(cls): + def tearDown(self): """Remove viewshed map after each test method""" # TODO: eventually, removing maps should be handled through testing framework functions - cls.runModule("g.remove", flags="f", type="raster", name=cls.viewshed) + self.runModule("g.remove", flags="f", type="raster", name=self.viewshed) def test_limits(self): """Test if results is in expected limits""" 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/raster/r.walk/r.walk.html b/raster/r.walk/r.walk.html index 2523b7fc0b6..ed964d94082 100644 --- a/raster/r.walk/r.walk.html +++ b/raster/r.walk/r.walk.html @@ -166,13 +166,13 @@

    REFERENCES

    • Aitken, R. 1977. Wilderness areas in Scotland. Unpublished Ph.D. thesis. - University of Aberdeen. + University of Aberdeen.
    • Steno Fontanari, University of Trento, Italy, Ingegneria per l'Ambiente e - il Territorio, 2000-2001. + il Territorio, 2000-2001.
    • Svilluppo di metodologie GIS per la determinazione dell'accessibilità territoriale come supporto alle decisioni nella gestione ambientale.
    • Langmuir, E. 1984. Mountaincraft and leadership. The Scottish - Sports Council/MLTB. Cordee, Leicester. + Sports Council/MLTB. Cordee, Leicester.

    SEE ALSO

    diff --git a/raster/r.water.outlet/main.c b/raster/r.water.outlet/main.c index 12135f500b7..ad060205d2f 100644 --- a/raster/r.water.outlet/main.c +++ b/raster/r.water.outlet/main.c @@ -75,8 +75,14 @@ int main(int argc, char *argv[]) G_get_window(&window); - strcpy(drain_name, opt.input->answer); - strcpy(basin_name, opt.output->answer); + if (G_strlcpy(drain_name, opt.input->answer, sizeof(drain_name)) >= + sizeof(drain_name)) { + G_fatal_error(_("Drain name <%s> is too long"), opt.input->answer); + } + if (G_strlcpy(basin_name, opt.output->answer, sizeof(basin_name)) >= + sizeof(basin_name)) { + G_fatal_error(_("Basin name <%s> is too long"), opt.output->answer); + } if (!G_scan_easting(opt.coords->answers[0], &E, G_projection())) G_fatal_error(_("Illegal east coordinate '%s'"), diff --git a/raster/r.water.outlet/r.water.outlet.html b/raster/r.water.outlet/r.water.outlet.html index 7504ec1e722..2ce1c848e89 100644 --- a/raster/r.water.outlet/r.water.outlet.html +++ b/raster/r.water.outlet/r.water.outlet.html @@ -52,7 +52,7 @@

    EXAMPLE

    -
    +
    Figure: Watershed draped over flow accumulation
    diff --git a/raster/r.watershed/front/r.watershed.html b/raster/r.watershed/front/r.watershed.html index abe352a6948..8e9babef09d 100644 --- a/raster/r.watershed/front/r.watershed.html +++ b/raster/r.watershed/front/r.watershed.html @@ -360,11 +360,11 @@

    Further processing of output layers

  • Use a resample of the basins catchment raster map as a MASK.
    The equivalent vector map method is similar using v.select or - v.overlay. + v.overlay.
  • Use the r.cost module with a - point in the river as a starting point. + point in the river as a starting point.
  • Use the v.net.iso module - with a node in the river as a starting point. + with a node in the river as a starting point.
  • All individual river networks in the stream segments output can be @@ -408,7 +408,7 @@

    Further processing of output layers

    The following command performs these replacements:
    -r.mapcalc "drainage_degrees = if(drainage > 0, 45. * drainage, null())"
    +r.mapcalc "drainage_degrees = if(drainage > 0, 45. * drainage, null())"
     
    Alternatively, the user can use the -a flag or later the @@ -471,7 +471,7 @@

    Convert r.watershed streams map output to a vector map

    r.mapcalc 'MASK = if(!isnull(elevation.dem))' r.mapcalc "rwater.course = \ - if( abs(rwater.accum) > $mean_of_abs, \ + if( abs(rwater.accum) > $mean_of_abs, \ abs(rwater.accum), \ null() )" r.colors -g rwater.course col=bcyr @@ -515,45 +515,44 @@

    REFERENCES

    Proceedings of International Geographic Information Systems (IGIS) Symposium '89, pp 275-281 (Baltimore, MD, 18-19 March 1989).
    URL: -http://chuck.ehlschlaeger.info/older/IGIS/paper.html +http://chuck.ehlschlaeger.info/older/IGIS/paper.html
  • Holmgren P. (1994). Multiple flow direction algorithms for runoff modelling in grid based elevation models: An empirical evaluation. Hydrological Processes Vol 8(4), 327-334.
    -DOI: 10.1002/hyp.3360080405 +DOI: 10.1002/hyp.3360080405
  • Kinner D., Mitasova H., Harmon R., Toma L., Stallard R. (2005). GIS-based Stream Network Analysis for The Chagres River Basin, Republic of Panama. The Rio Chagres: A Multidisciplinary Profile of a Tropical Watershed, R. Harmon (Ed.), Springer/Kluwer, p.83-95.
    URL: -http://fatra.cnr.ncsu.edu/~hmitaso/measwork/panama/panama.html +http://fatra.cnr.ncsu.edu/~hmitaso/measwork/panama/panama.html
  • McCool et al. (1987). Revised Slope Steepness Factor for the Universal -Soil Loss Equation, Transactions of the ASAE Vol 30(5). +Soil Loss Equation, Transactions of the ASAE Vol 30(5).
  • Metz M., Mitasova H., Harmon R. (2011). Efficient extraction of drainage networks from massive, radar-based elevation models with least cost path search, Hydrol. Earth Syst. Sci. Vol 15, 667-678.
    -DOI: 10.5194/hess-15-667-2011 +DOI: 10.5194/hess-15-667-2011
  • Moore I.D., Grayson R.B., Ladson A.R. (1991). Digital terrain modelling: a review of hydrogical, geomorphological, and biological applications, Hydrological Processes, Vol 5(1), 3-30
    -DOI: 10.1002/hyp.3360050103 +DOI: 10.1002/hyp.3360050103
  • Quinn P., K. Beven K., Chevallier P., Planchon O. (1991). The prediction of hillslope flow paths for distributed hydrological modelling using Digital Elevation Models, Hydrological Processes Vol 5(1), p.59-79.
    -DOI: 10.1002/hyp.3360050106 +DOI: 10.1002/hyp.3360050106
  • Weltz M. A., Renard K.G., Simanton J. R. (1987). Revised Universal Soil Loss Equation for Western Rangelands, U.S.A./Mexico Symposium of Strategies for Classification and Management of Native Vegetation for -Food Production In Arid Zones (Tucson, AZ, 12-16 Oct. 1987). -
  • +Food Production In Arid Zones (Tucson, AZ, 12-16 Oct. 1987).

    SEE ALSO

    diff --git a/raster/r.watershed/ram/do_cum.c b/raster/r.watershed/ram/do_cum.c index c882b82bb46..0bebc9dee46 100644 --- a/raster/r.watershed/ram/do_cum.c +++ b/raster/r.watershed/ram/do_cum.c @@ -218,6 +218,8 @@ int do_cum(void) } } G_free(astar_pts); + G_free(contour); + G_free(dist_to_nbr); return 0; } @@ -632,6 +634,7 @@ int do_cum_mfd(void) G_free(dist_to_nbr); G_free(weight); + G_free(contour); return 0; } diff --git a/raster/r.watershed/seg/close_maps.c b/raster/r.watershed/seg/close_maps.c index 1669bbd89c3..56320428c32 100644 --- a/raster/r.watershed/seg/close_maps.c +++ b/raster/r.watershed/seg/close_maps.c @@ -325,6 +325,8 @@ int close_maps(void) } Rast_close(fd); + G_free(afbuf); + G_free(cbuf); Rast_init_colors(&colors); Rast_make_aspect_colors(&colors, -8, 8); diff --git a/raster/r.watershed/seg/do_cum.c b/raster/r.watershed/seg/do_cum.c index bd5bbebbed9..f7918ecdb5c 100644 --- a/raster/r.watershed/seg/do_cum.c +++ b/raster/r.watershed/seg/do_cum.c @@ -232,6 +232,8 @@ int do_cum(void) G_percent(do_points, do_points, 1); /* finish it */ seg_close(&astar_pts); + G_free(dist_to_nbr); + G_free(contour); return 0; } diff --git a/raster/r.what.color/r.what.color.html b/raster/r.what.color/r.what.color.html index 607c0732613..34eeb560af1 100644 --- a/raster/r.what.color/r.what.color.html +++ b/raster/r.what.color/r.what.color.html @@ -53,8 +53,8 @@

    DESCRIPTION

    Common formats:

      -
    • Tcl/Tk: format="#%02x%02x%02x" -
    • WxPython: format='"#%02x%02x%02x"' or format='"(%d,%d,%d)"' +
    • Tcl/Tk: format="#%02x%02x%02x"
    • +
    • WxPython: format='"#%02x%02x%02x"' or format='"(%d,%d,%d)"'

    SEE ALSO

    diff --git a/raster/r.what/testsuite/testrw.py b/raster/r.what/testsuite/testrw.py index 8184f534720..fdaf7eec98c 100644 --- a/raster/r.what/testsuite/testrw.py +++ b/raster/r.what/testsuite/testrw.py @@ -5,8 +5,8 @@ Author: Sunveer Singh, Google Code-in 2018 Copyright: (C) 2018 by Sunveer Singh and the GRASS Development Team Licence: This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. + License (>=v2). Read the file COPYING that comes with GRASS + for details. """ from grass.gunittest.case import TestCase diff --git a/raster/rasterintro.html b/raster/rasterintro.html index 93d05f35410..4f4f5e1c743 100644 --- a/raster/rasterintro.html +++ b/raster/rasterintro.html @@ -18,12 +18,12 @@

    Raster maps in general

    As a general rule in GRASS GIS:
    1. Raster output maps have their bounds and resolution equal to those -of the current computational region. +of the current computational region.
    2. Raster input maps are automatically cropped/padded and rescaled -(using nearest-neighbour resampling) to match the current region. +(using nearest-neighbour resampling) to match the current region.
    3. Raster input maps are automatically masked if a raster map named MASK exists. The MASK is only applied when reading maps - from the disk. + from the disk.
    There are a few exceptions to this: @@ -198,8 +198,8 @@

    Raster map statistics

    (d.polar). Univariate statistics (r.univar) and -reports are also available (r.report,r.stats, r.volume). +reports are also available (r.report, +r.stats, r.volume). Since r.univar may be slow for extended statistics these can be calculated using @@ -267,7 +267,7 @@

    2D raster maps

    • 32bit signed integer (CELL),
    • single-precision floating-point (FCELL), and
    • -
    • double-precision floating-point (DCELL). +
    • double-precision floating-point (DCELL).
    In most GRASS GIS resources, 2D raster maps are usually called "raster" maps. @@ -361,4 +361,5 @@

    See also

  • Introduction into temporal data processing
  • Database management
  • Projections and spatial transformations
  • +
  • Graphical User Interface
  • diff --git a/raster3d/r3.flow/r3.flow.html b/raster3d/r3.flow/r3.flow.html index f4f9510e7df..5b1fcf26a3f 100644 --- a/raster3d/r3.flow/r3.flow.html +++ b/raster3d/r3.flow/r3.flow.html @@ -41,7 +41,7 @@

    Attributes

    NOTES

    r3.flow uses Runge-Kutta with adaptive step size -(Cash-Karp method). +(Cash-Karp method).

    EXAMPLES

    @@ -54,9 +54,9 @@

    EXAMPLES

    g.region res=25 res3=25 t=100 b=0 n=1000 s=0 w=0 e=1000 -p3 # now create the input raster maps for a confined aquifer -r3.mapcalc expression="phead = if(row() == 1 && depth() == 4, 50, 40)" -r3.mapcalc expression="status = if(row() == 1 && depth() == 4, 2, 1)" -r3.mapcalc expression="well = if(row() == 20 && col() == 20 && depth() == 2, -0.25, 0)" +r3.mapcalc expression="phead = if(row() == 1 && depth() == 4, 50, 40)" +r3.mapcalc expression="status = if(row() == 1 && depth() == 4, 2, 1)" +r3.mapcalc expression="well = if(row() == 20 && col() == 20 && depth() == 2, -0.25, 0)" r3.mapcalc expression="hydcond = 0.00025" r3.mapcalc expression="syield = 0.0001" r.mapcalc expression="recharge = 0.0" diff --git a/raster3d/r3.gwflow/r3.gwflow.html b/raster3d/r3.gwflow/r3.gwflow.html index 7ced5f01ba8..8df4a38140c 100644 --- a/raster3d/r3.gwflow/r3.gwflow.html +++ b/raster3d/r3.gwflow/r3.gwflow.html @@ -4,7 +4,7 @@

    DESCRIPTION

    confined groundwater flow in three dimensions based on volume maps and the current 3D region settings. All initial- and boundary-conditions must be provided as volume maps. -The unit of the current coordinate refernce system must be meters. +The unit of the current coordinate reference system must be meters.

    This module is sensitive to mask settings. All cells which are outside the mask are ignored and handled as no flow boundaries.

    The module calculates the piezometric head and optionally the water @@ -78,9 +78,9 @@

    EXAMPLE 1

    g.region res=25 res3=25 t=100 b=0 n=1000 s=0 w=0 e=1000 -p3 #now create the input raster maps for a confined aquifer -r3.mapcalc expression="phead = if(row() == 1 && depth() == 4, 50, 40)" -r3.mapcalc expression="status = if(row() == 1 && depth() == 4, 2, 1)" -r3.mapcalc expression="well = if(row() == 20 && col() == 20 && depth() == 2, -0.25, 0)" +r3.mapcalc expression="phead = if(row() == 1 && depth() == 4, 50, 40)" +r3.mapcalc expression="status = if(row() == 1 && depth() == 4, 2, 1)" +r3.mapcalc expression="well = if(row() == 20 && col() == 20 && depth() == 2, -0.25, 0)" r3.mapcalc expression="hydcond = 0.00025" r3.mapcalc expression="syield = 0.0001" r.mapcalc expression="recharge = 0.0" @@ -105,14 +105,14 @@

    EXAMPLE 2

    g.region res=15 res3=15 t=500 b=0 n=1000 s=0 w=0 e=1000 #now create the input raster maps for a confined aquifer -r3.mapcalc expression="phead = if(col() == 1 && depth() == 33, 50, 40)" -r3.mapcalc expression="status = if(col() == 1 && depth() == 33, 2, 1)" -r3.mapcalc expression="well = if(row() == 20 && col() == 20 && depth() == 3, -0.25, 0)" -r3.mapcalc expression="well = if(row() == 50 && col() == 50 && depth() == 3, -0.25, well)" +r3.mapcalc expression="phead = if(col() == 1 && depth() == 33, 50, 40)" +r3.mapcalc expression="status = if(col() == 1 && depth() == 33, 2, 1)" +r3.mapcalc expression="well = if(row() == 20 && col() == 20 && depth() == 3, -0.25, 0)" +r3.mapcalc expression="well = if(row() == 50 && col() == 50 && depth() == 3, -0.25, well)" r3.mapcalc expression="hydcond = 0.0025" -r3.mapcalc expression="hydcond = if(depth() < 30 && depth() > 23 && col() < 60, 0.000025, hydcond)" -r3.mapcalc expression="hydcond = if(depth() < 20 && depth() > 13 && col() > 7, 0.000025, hydcond)" -r3.mapcalc expression="hydcond = if(depth() < 10 && depth() > 7 && col() < 60, 0.000025, hydcond)" +r3.mapcalc expression="hydcond = if(depth() < 30 && depth() > 23 && col() < 60, 0.000025, hydcond)" +r3.mapcalc expression="hydcond = if(depth() < 20 && depth() > 13 && col() > 7, 0.000025, hydcond)" +r3.mapcalc expression="hydcond = if(depth() < 10 && depth() > 7 && col() < 60, 0.000025, hydcond)" r3.mapcalc expression="syield = 0.0001" r3.gwflow solver=cg phead=phead statuyield=status hc_x=hydcond hc_y=hydcond \ diff --git a/raster3d/r3.in.ascii/r3.in.ascii.html b/raster3d/r3.in.ascii/r3.in.ascii.html index 0316fa76029..6d20844e70c 100644 --- a/raster3d/r3.in.ascii/r3.in.ascii.html +++ b/raster3d/r3.in.ascii/r3.in.ascii.html @@ -16,8 +16,8 @@

    NOTES

    that is visualized in the following picture, independently from the specified ordering in the ASCII input file:
    -
    -
    [SDF][SDF][SDF][SDF]
    The sweep-line.
    +
    +
    @@ -47,7 +47,7 @@

    Format

    The supported row/depth ordering is documented in the r3.out.ascii manual page. The order of the data in the input file does not specify the data order in the generated output 3D raster map which is in any case -north -> south, west -> east, bottom -> top order. +north -> south, west -> east, bottom -> top order. So dependent on the order information the data is automatically imported into the correct internal coordinate system.

    The version and order options are not mandatory. In case no version and @@ -61,7 +61,7 @@

    EXAMPLES

    4x3x2 sample. Note in case no specific ordering is specified in the input file the upper-left (NW) corner of the bottom level comes first. The according -order option is: nsbt for north -> south, bottom -> top ordering. This is +order option is: nsbt for north -> south, bottom -> top ordering. This is identical with r.in.ascii for single level data. So the y coordinate is 0 at the northern edge. diff --git a/raster3d/r3.in.bin/r3.in.bin.html b/raster3d/r3.in.bin/r3.in.bin.html index a1735a49d6f..e3c58afc5e0 100644 --- a/raster3d/r3.in.bin/r3.in.bin.html +++ b/raster3d/r3.in.bin/r3.in.bin.html @@ -12,8 +12,8 @@

    DESCRIPTION

    NOTES

    -The write order of the rows (north->south to south->north) and -the write order of the depths (bottom->top to top->bottom) can be switched. +The write order of the rows (north->south to south->north) and +the write order of the depths (bottom->top to top->bottom) can be switched.

    Have a look at r3.out.ascii to manual page that describes the internal layout of the 3D raster maps and the supported diff --git a/raster3d/r3.in.lidar/r3.in.lidar.html b/raster3d/r3.in.lidar/r3.in.lidar.html index 2edddfceb9e..902893b84e5 100644 --- a/raster3d/r3.in.lidar/r3.in.lidar.html +++ b/raster3d/r3.in.lidar/r3.in.lidar.html @@ -26,17 +26,17 @@

    NOTES

  • This module is new and partially experimental. Please don't rely on its interface and be critical towards its outputs. - Please report issues on the mailing list or in the bug tracker. + Please report issues on the mailing list or in the bug tracker
  • .
  • No reprojection is performed, you need to reproject ahead or - use a GRASS project with the coordinate system that matches that of the data. + use a GRASS project with the coordinate system that matches that of the data.
  • Some temporary maps are created but not cleaned up. Use of - --overwrite might be necessary even when not desired. + --overwrite might be necessary even when not desired.
  • Expects points to have intensity and causing random (undefined) result for related outputs (sum, mean, proportional_sum) - when the intensity is not present but the outputs were requested. + when the intensity is not present but the outputs were requested.
  • EXAMPLES

    @@ -174,14 +174,14 @@

    REFERENCES

    Processing UAV and lidar point clouds in GRASS GIS. XXIII ISPRS Congress 2016 [ISPRS Archives, -ResearchGate] +ResearchGate]
  • -ASPRS LAS format +ASPRS LAS format
  • -LAS library +LAS library
  • -LAS library C API documentation +LAS library C API documentation
  • SEE ALSO

    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.mkdspf/r3.mkdspf.html b/raster3d/r3.mkdspf/r3.mkdspf.html index e73217df618..b8a4f584f60 100644 --- a/raster3d/r3.mkdspf/r3.mkdspf.html +++ b/raster3d/r3.mkdspf/r3.mkdspf.html @@ -3,10 +3,10 @@

    DESCRIPTION

    Creates a display file from an existing grid3 file according to specified threshold levels. The display file is a display list of polygons that represent isosurfaces of the data volume. If -specific levels are given, additional optional parameters -are ignored. Min or max may be used alone or together -to specify a sub-range of the data. The step -parameter is given precedence over tnum. +specific levels are given, additional optional parameters +are ignored. Min or max may be used alone or together +to specify a sub-range of the data. The step +parameter is given precedence over tnum.

    Flags:

    @@ -53,7 +53,7 @@

    NOTES

    EXAMPLES

    -With grid3 data (phdata) in the range 3-7, +With grid3 data (phdata) in the range 3-7, we only want to see isosurface values for the range 4-6. Any of these commands will produce the same results:
    diff --git a/raster3d/r3.null/testsuite/test.r3.null.sh b/raster3d/r3.null/testsuite/test.r3.null.sh
    index 1cf93110b24..d6a6ec35810 100755
    --- a/raster3d/r3.null/testsuite/test.r3.null.sh
    +++ b/raster3d/r3.null/testsuite/test.r3.null.sh
    @@ -56,14 +56,7 @@ diff data/test_volume_double_null_1.ref test_volume_double_null_1.txt
     diff data/test_volume_double_null_2.ref test_volume_double_null_2.txt
     
     # Cleanup
    -g.remove -f type=raster_3d name=test_volume_float_1
    -g.remove -f type=raster_3d name=test_volume_float_2
    -g.remove -f type=raster_3d name=test_volume_float_null_1
    -g.remove -f type=raster_3d name=test_volume_float_null_2
    -g.remove -f type=raster_3d name=test_volume_double_1
    -g.remove -f type=raster_3d name=test_volume_double_2
    -g.remove -f type=raster_3d name=test_volume_double_null_1
    -g.remove -f type=raster_3d name=test_volume_double_null_2
    +g.remove -f type=raster_3d name=test_volume_float_1,test_volume_float_2,test_volume_float_null_1,test_volume_float_null_2,test_volume_double_1,test_volume_double_2,test_volume_double_null_1,test_volume_double_null_2
     rm test_volume_float_1.txt
     rm test_volume_float_2.txt
     rm test_volume_float_null_1.txt
    diff --git a/raster3d/r3.out.ascii/r3.out.ascii.html b/raster3d/r3.out.ascii/r3.out.ascii.html
    index 8f5f0ed0f11..5cb54e7fef9 100644
    --- a/raster3d/r3.out.ascii/r3.out.ascii.html
    +++ b/raster3d/r3.out.ascii/r3.out.ascii.html
    @@ -72,8 +72,8 @@ 

    NOTES

    The internal storage scheme of 3D raster maps is visualized in the following picture:

    -
    -
    The volume coordinate system and tile layout of the imported voxel map
    +
    +
    diff --git a/raster3d/r3.out.bin/r3.out.bin.html b/raster3d/r3.out.bin/r3.out.bin.html index e2c2ee3621c..16af9096bc2 100644 --- a/raster3d/r3.out.bin/r3.out.bin.html +++ b/raster3d/r3.out.bin/r3.out.bin.html @@ -7,8 +7,8 @@

    DESCRIPTION

    NOTES

    -The write order of the rows (north->south to south->north) and -the write order of the depths (bottom->top to top->bottom) can be switched. +The write order of the rows (north->south to south->north) and +the write order of the depths (bottom->top to top->bottom) can be switched.

    The region parameters are printed to stderr when setting the verbose flag. Export of little and big endian byte order is supported. diff --git a/raster3d/r3.out.netcdf/main.c b/raster3d/r3.out.netcdf/main.c index 6bcdcbaf9f5..144c9085eef 100644 --- a/raster3d/r3.out.netcdf/main.c +++ b/raster3d/r3.out.netcdf/main.c @@ -17,7 +17,7 @@ * here: * http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.6/cf-conventions.html#coordinate-system * https://cf-pcmdi.llnl.gov/trac/wiki/Cf2CrsWkt - * http://trac.osgeo.org/gdal/wiki/NetCDF_ProjectionTestingStatus + * https://trac.osgeo.org/gdal/wiki/NetCDF_ProjectionTestingStatus * *****************************************************************************/ diff --git a/raster3d/r3.out.netcdf/r3.out.netcdf.html b/raster3d/r3.out.netcdf/r3.out.netcdf.html index 9fb256a06d3..2dc69701d4d 100644 --- a/raster3d/r3.out.netcdf/r3.out.netcdf.html +++ b/raster3d/r3.out.netcdf/r3.out.netcdf.html @@ -22,7 +22,7 @@

    NOTES

    Spatial coordinates are exported as cell centered coordinates. The projection can be optionally stored in the metadata as crs attributes . The netCDF projection metadata storage follows the spatial_ref GDAL/netCDF suggestion -here +here and the netCDF CF 1.6 convention here using WKT projection information. Additional a PROJ string is 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/raster3d/r3.showdspf/main_ogl.c b/raster3d/r3.showdspf/main_ogl.c index 55b3097e2cf..da6e90a3721 100644 --- a/raster3d/r3.showdspf/main_ogl.c +++ b/raster3d/r3.showdspf/main_ogl.c @@ -1159,7 +1159,7 @@ void do__draw(file_info *Headp, struct dspec *D_spec) fdraw_polys(D_spec); break; case 2: - case3: + case 3: gdraw_polys(D_spec); break; } diff --git a/raster3d/r3.showdspf/r3.showdspf.html b/raster3d/r3.showdspf/r3.showdspf.html index 97f1322a882..d42bd61494f 100644 --- a/raster3d/r3.showdspf/r3.showdspf.html +++ b/raster3d/r3.showdspf/r3.showdspf.html @@ -42,7 +42,7 @@

    DESCRIPTION

    E(x,y,z)int# end display along (x,y,z)axis # S int# specular highlight control R resets display along axis to show all data - F grid3name colortablename load new color file + F grid3name colortablename load new color file C toggles the clear flag c clears the display (no thresholds) @@ -72,14 +72,14 @@

    Hints:

    the mouse pointer in the graphics window and drag with the left mouse to rotate the bounding box. To zoom in and out, drag right or left with the middle mouse. When satisfied with the new viewing -position, click with the right mouse. +position, click with the right mouse.
  • To quickly view a series of isosurfaces, enter a series of + or - -characters, i.e. +++++++ +characters, i.e. +++++++
  • Scripts using above commands on separate lines may be directed to r3.showdspf as standard input. -Use the # sign as the first character on a line to indicate a comment. +Use the # sign as the first character on a line to indicate a comment.
  • EXAMPLES

    diff --git a/raster3d/r3.showdspf/r3.showdspf_opengl_mods.html b/raster3d/r3.showdspf/r3.showdspf_opengl_mods.html index 09f15f9b2ed..74fb1338ba8 100644 --- a/raster3d/r3.showdspf/r3.showdspf_opengl_mods.html +++ b/raster3d/r3.showdspf/r3.showdspf_opengl_mods.html @@ -2,7 +2,7 @@ - modifications made to <em>r3.showdspf</em> + modifications made to r3.showdspf diff --git a/raster3d/r3.stats/r3.stats.html b/raster3d/r3.stats/r3.stats.html index dd9978f67d2..1e68ab3af65 100644 --- a/raster3d/r3.stats/r3.stats.html +++ b/raster3d/r3.stats/r3.stats.html @@ -17,7 +17,7 @@

    NOTES

    equal value groups effect the memory consumption and the calculation time. The user can expect a huge time consumption to calculate the equal value groups (flag -e) if large region settings occur for maps which -have many equal value groups (> 100000). +have many equal value groups (> 100000).

    EXAMPLES

    @@ -61,7 +61,7 @@

    Generic example

    r3.stats input=volmap nsteps=10 #the result should look like this - num | minimum <= value | value < maximum | volume | perc | cell count + num | minimum <= value | value < maximum | volume | perc | cell count 1 1.000000000 1.900000000 60000000.000 10.00000 60 2 1.900000000 2.800000000 60000000.000 10.00000 60 3 2.800000000 3.700000000 60000000.000 10.00000 60 diff --git a/raster3d/raster3dintro.html b/raster3d/raster3dintro.html index b51748b4dd8..c56e1cfcc33 100644 --- a/raster3d/raster3dintro.html +++ b/raster3d/raster3dintro.html @@ -21,7 +21,7 @@

    3D raster maps in general

    r3.retile after import or creation.
    -
    +
    The 3D raster map coordinate system and the internal tile layout of the RASTER3D library @@ -203,6 +203,7 @@

    See also

  • Introduction into image processing
  • Introduction into temporal data processing
  • Projections and spatial transformations
  • +
  • Graphical User Interface
  • wxGUI 3D View Mode
  • m.nviz.image
  • diff --git a/renovate.json5 b/renovate.json5 index b5c0aeba9b8..12451b04103 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -5,11 +5,11 @@ ":semanticCommits", ":semanticCommitTypeAll(CI)", - // allows to use comments starting with + // allows using comments starting with // "# renovate: " to update _VERSION // environment variables in GitHub Action files. "customManagers:githubActionsVersions", - // allows to use comments starting with + // allows using comments starting with // "# renovate: " to update _VERSION // ENV or ARG in a Dockerfile. "customManagers:dockerfileVersions", 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.html b/scripts/d.correlate/d.correlate.html index bf6add70fca..f669cc24687 100644 --- a/scripts/d.correlate/d.correlate.html +++ b/scripts/d.correlate/d.correlate.html @@ -24,7 +24,7 @@

    EXAMPLE

    -Scatterplot of two LANDSAT TM7 channels
    +Scatterplot of two LANDSAT TM7 channels
    Scatterplot of two LANDSAT TM7 channels
    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/d.polar/d.polar.html b/scripts/d.polar/d.polar.html index fad50649371..d1bbc2e6586 100644 --- a/scripts/d.polar/d.polar.html +++ b/scripts/d.polar/d.polar.html @@ -62,7 +62,7 @@

    REFERENCES

    J. Hofierka, H. Mitasova, and M. Neteler (2009): Terrain parameterization in GRASS. In T. Hengl and H.I. Reuter, editors, Geomorphometry: concepts, software, applications. Elsevier -(DOI) +(DOI)

    AUTHORS

    diff --git a/scripts/d.rast.edit/d.rast.edit.html b/scripts/d.rast.edit/d.rast.edit.html index 75233316e38..cde4f96947a 100644 --- a/scripts/d.rast.edit/d.rast.edit.html +++ b/scripts/d.rast.edit/d.rast.edit.html @@ -77,8 +77,8 @@

    EXAMPLE

    g.region raster=elev_lid792_1m -p # pan to area of interest and edit raster cells (I used "102" as value to modify cells -# Use: File > Save to save -# then: File > Exit +# Use: File > Save to save +# then: File > Exit d.rast.edit input=elev_lid792_1m output=elev_lid792_1m_modified # comparison of raster statistics diff --git a/scripts/d.rast.edit/d.rast.edit.py b/scripts/d.rast.edit/d.rast.edit.py index eafe5f7b15a..102d7e447d8 100755 --- a/scripts/d.rast.edit/d.rast.edit.py +++ b/scripts/d.rast.edit/d.rast.edit.py @@ -77,6 +77,8 @@ import sys import math import atexit +from string import digits + import grass.script as gs from grass.script.setup import set_gui_path @@ -293,10 +295,7 @@ def paint_cell(self, dc, r, c): px, py = -dy, dx r, g, b, a = wx.Colour(fill).Get() - if r + g + b > 384: - line = "black" - else: - line = "white" + line = "black" if r + g + b > 384 else "white" dc.SetPen(wx.Pen(line)) dc.DrawLine(x0, y0, x1, y1) @@ -448,7 +447,7 @@ def OnClose(self, ev): def OnReturn(self, ev): self.app.brush = self.newval.GetValue() - if self.app.brush != "*" and self.app.brush.strip("0123456789") != "": + if self.app.brush != "*" and self.app.brush.strip(digits) != "": self.app.brush = "*" self.brush_update() @@ -645,28 +644,9 @@ def update_status(self, row, col): if self.angles: self.status["aspect"] = self.angles[row][col] - def force_color(self, val): - run("g.region", rows=1, cols=1) - run("r.mapcalc", expression="%s = %d" % (self.tempmap, val)) - run("r.colors", map=self.tempmap, rast=self.inmap) - run("r.out.ppm", input=self.tempmap, out=self.tempfile) - run("g.remove", flags="f", type="raster", name=self.tempmap) - - tempimg = wx.Image(self.tempfile) - gs.try_remove(self.tempfile) - - rgb = tempimg.get(0, 0) - color = "#%02x%02x%02x" % rgb - self.colors[val] = color - tempimg.delete() - def get_color(self, val): if val not in self.colors: - try: - self.force_color(val) - except Exception: - self.colors[val] = "#ffffff" - + self.colors[val] = "#ffffff" return self.colors[val] def refresh_canvas(self): diff --git a/scripts/d.rast.leg/d.rast.leg.py b/scripts/d.rast.leg/d.rast.leg.py index 85cb423f9e9..74576113577 100755 --- a/scripts/d.rast.leg/d.rast.leg.py +++ b/scripts/d.rast.leg/d.rast.leg.py @@ -132,16 +132,10 @@ def main(): if not nlines: nlines = None - if rast: - lmap = rast - else: - lmap = map + lmap = rast or map kv = gs.raster_info(map=lmap) - if kv["datatype"] == "CELL": - leg_at = None - else: - leg_at = "%f,95,5,10" % VSpacing + leg_at = None if kv["datatype"] == "CELL" else "%f,95,5,10" % VSpacing # checking for histogram causes more problems than it solves # histfiledir = grass.find_file(lmap, 'cell_misc')['file'] 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.droptable/db.droptable.py b/scripts/db.droptable/db.droptable.py index 571638748cf..39408221acc 100755 --- a/scripts/db.droptable/db.droptable.py +++ b/scripts/db.droptable/db.droptable.py @@ -56,14 +56,8 @@ def main(): gs.run_command("db.connect", flags="c", quiet=True) kv = gs.db_connection() - if options["database"]: - database = options["database"] - else: - database = kv["database"] - if options["driver"]: - driver = options["driver"] - else: - driver = kv["driver"] + database = options["database"] or kv["database"] + driver = options["driver"] or kv["driver"] # schema needed for PG? if force: diff --git a/scripts/db.in.ogr/db.in.ogr.html b/scripts/db.in.ogr/db.in.ogr.html index 322f22840f0..70e7dddc1b1 100644 --- a/scripts/db.in.ogr/db.in.ogr.html +++ b/scripts/db.in.ogr/db.in.ogr.html @@ -1,7 +1,7 @@

    DESCRIPTION

    db.in.ogr imports attribute tables in various formats as -supported by the OGR library +supported by the OGR library on the local system (DBF, CSV, PostgreSQL, SQLite, MySQL, ODBC, etc.). Optionally a unique key (ID) column can be added to the table. @@ -12,7 +12,7 @@

    Import CSV file

    Limited type recognition can be done for Integer, Real, String, Date, Time and DateTime columns through a descriptive file with same name as the CSV file, but .csvt extension -(see details here). +(see details here).
     # NOTE: create koeppen_gridcode.csvt first for automated type recognition
    diff --git a/scripts/db.in.ogr/db.in.ogr.py b/scripts/db.in.ogr/db.in.ogr.py
    index a95919f4936..b7d7b01b51e 100755
    --- a/scripts/db.in.ogr/db.in.ogr.py
    +++ b/scripts/db.in.ogr/db.in.ogr.py
    @@ -115,8 +115,7 @@ def main():
                         "db.execute", input="-", stdin="DROP TABLE %s" % output
                     )
                     break
    -            else:
    -                gs.fatal(_("Table <%s> already exists") % output)
    +            gs.fatal(_("Table <%s> already exists") % output)
     
         # treat DB as real vector map...
         layer = db_table or None
    diff --git a/scripts/db.in.ogr/testsuite/test_db_in_ogr.py b/scripts/db.in.ogr/testsuite/test_db_in_ogr.py
    index 423917e1b93..b79efa1f096 100644
    --- a/scripts/db.in.ogr/testsuite/test_db_in_ogr.py
    +++ b/scripts/db.in.ogr/testsuite/test_db_in_ogr.py
    @@ -8,7 +8,6 @@
     from grass.gunittest.main import test
     from grass.gunittest.gmodules import SimpleModule
     
    -from grass.script.core import run_command
     from grass.script.utils import decode
     
     import os
    diff --git a/scripts/db.out.ogr/db.out.ogr.html b/scripts/db.out.ogr/db.out.ogr.html
    index 5a2727dd566..cf07de25e96 100644
    --- a/scripts/db.out.ogr/db.out.ogr.html
    +++ b/scripts/db.out.ogr/db.out.ogr.html
    @@ -30,7 +30,7 @@ 

    Export of GRASS GIS attribute table into a PostgreSQL table

     db.out.ogr input=precip_30ynormals \
    -	   output="PG:host=localhost dbname=meteo user=neteler" \
    +           output="PG:host=localhost dbname=meteo user=neteler" \
                format=PostgreSQL
     # verify
     echo "SELECT * FROM precip_30ynormals" | psql meteo
    diff --git a/scripts/db.out.ogr/db.out.ogr.py b/scripts/db.out.ogr/db.out.ogr.py
    index 4a840755b20..4fe5b4f9854 100755
    --- a/scripts/db.out.ogr/db.out.ogr.py
    +++ b/scripts/db.out.ogr/db.out.ogr.py
    @@ -67,15 +67,11 @@ def main():
         layer = options["layer"]
         format = options["format"]
         output = options["output"]
    -    table = options["table"]
     
         if format.lower() == "dbf":
             format = "ESRI_Shapefile"
     
    -    if format.lower() == "csv":
    -        olayer = basename(output, "csv")
    -    else:
    -        olayer = None
    +    olayer = basename(output, "csv") if format.lower() == "csv" else None
     
         # is there a simpler way of testing for --overwrite?
         dbffile = input + ".dbf"
    diff --git a/scripts/db.univar/db.univar.py b/scripts/db.univar/db.univar.py
    index 97dfbdb7dbe..4654e3011a0 100755
    --- a/scripts/db.univar/db.univar.py
    +++ b/scripts/db.univar/db.univar.py
    @@ -118,10 +118,7 @@ def main():
         perc = [float(p) for p in perc.split(",")]
     
         if not output_format:
    -        if shellstyle:
    -            output_format = "shell"
    -        else:
    -            output_format = "plain"
    +        output_format = "shell" if shellstyle else "plain"
         elif shellstyle:
             # This can be a message or warning in future versions.
             # In version 9, -g may be removed.
    diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py
    index 194f498d49c..f14a742ca06 100644
    --- a/scripts/g.extension/g.extension.py
    +++ b/scripts/g.extension/g.extension.py
    @@ -1608,10 +1608,7 @@ def install_extension_win(name):
         source, url = resolve_source_code(url="{0}/{1}.zip".format(base_url, name))
     
         # to hide non-error messages from subprocesses
    -    if gs.verbosity() <= 2:
    -        outdev = open(os.devnull, "w")
    -    else:
    -        outdev = sys.stdout
    +    outdev = open(os.devnull, "w") if gs.verbosity() <= 2 else sys.stdout
     
         # download Addons ZIP file
         os.chdir(TMPDIR)  # this is just to not leave something behind
    @@ -1961,10 +1958,7 @@ def install_extension_std_platforms(name, source, url, branch):
         path_to_src_code_message = _("Path to the source code:")
     
         # to hide non-error messages from subprocesses
    -    if gs.verbosity() <= 2:
    -        outdev = open(os.devnull, "w")
    -    else:
    -        outdev = sys.stdout
    +    outdev = open(os.devnull, "w") if gs.verbosity() <= 2 else sys.stdout
     
         os.chdir(TMPDIR)  # this is just to not leave something behind
         srcdir = os.path.join(TMPDIR, name)
    @@ -2578,10 +2572,7 @@ def resolve_known_host_service(url, name, branch):
                             )
                             return None, None
         if match:
    -        if not actual_start:
    -            actual_start = match["url_start"]
    -        else:
    -            actual_start = ""
    +        actual_start = match["url_start"] if not actual_start else ""
             if "branch" in match["url_end"]:
                 suffix = match["url_end"].format(
                     name=name,
    diff --git a/scripts/g.manual/g.manual.py b/scripts/g.manual/g.manual.py
    index f4ecf961076..345a6d1714a 100755
    --- a/scripts/g.manual/g.manual.py
    +++ b/scripts/g.manual/g.manual.py
    @@ -132,10 +132,7 @@ def main():
         elif flags["t"]:
             special = "topics"
     
    -    if flags["m"]:
    -        start = start_man
    -    else:
    -        start = start_browser
    +    start = start_man if flags["m"] else start_browser
     
         entry = options["entry"]
         gisbase = os.environ["GISBASE"]
    diff --git a/scripts/i.band.library/i.band.library.html b/scripts/i.band.library/i.band.library.html
    index b5d98d2607b..196f1319e3a 100644
    --- a/scripts/i.band.library/i.band.library.html
    +++ b/scripts/i.band.library/i.band.library.html
    @@ -95,11 +95,11 @@ 

    Band reference and semantic label relation

    NOTES

    -Semantic label concept is supported by temporal GRASS modules, -see t.register, -t.rast.list, -t.info -and t.rast.mapcalc +Semantic label concept is supported by temporal GRASS modules, see +t.register, +t.rast.list, +t.info +and t.rast.mapcalc modules for examples.

    Image collections

    diff --git a/scripts/i.in.spotvgt/i.in.spotvgt.py b/scripts/i.in.spotvgt/i.in.spotvgt.py index cd744d4c252..9885caea5ec 100755 --- a/scripts/i.in.spotvgt/i.in.spotvgt.py +++ b/scripts/i.in.spotvgt/i.in.spotvgt.py @@ -20,7 +20,7 @@ ############################################################################# # # REQUIREMENTS: -# - gdal: http://www.gdal.org +# - gdal: https://gdal.org # # Notes: # * According to the faq (http://www.vgt.vito.be/faq/faq.html), SPOT vegetation @@ -125,9 +125,7 @@ def main(): # check for gdalinfo (just to check if installation is complete) if not gs.find_program("gdalinfo", "--help"): - gs.fatal( - _("'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)") - ) + gs.fatal(_("'gdalinfo' not found, install GDAL tools first (https://gdal.org)")) pid = str(os.getpid()) tmpfile = gs.tempfile() @@ -136,11 +134,7 @@ def main(): spotdir = os.path.dirname(infile) spotname = gs.basename(infile, "hdf") - - if rast: - name = rast - else: - name = spotname + name = rast or spotname if not gs.overwrite() and gs.find_file(name)["file"]: gs.fatal(_("<%s> already exists. Aborting.") % name) diff --git a/scripts/i.oif/i.oif.py b/scripts/i.oif/i.oif.py index 0dabbe7cb38..cb156675927 100755 --- a/scripts/i.oif/i.oif.py +++ b/scripts/i.oif/i.oif.py @@ -90,10 +90,7 @@ def main(): stddev[band] = float(kv["stddev"]) else: # run all bands in parallel - if "WORKERS" in os.environ: - workers = int(os.environ["WORKERS"]) - else: - workers = len(bands) + workers = int(os.environ["WORKERS"]) if "WORKERS" in os.environ else len(bands) proc = {} pout = {} @@ -142,10 +139,7 @@ def main(): _("The Optimum Index Factor analysis result (best combination shown first):") ) - if shell: - fmt = "%s,%s,%s:%.4f\n" - else: - fmt = "%s, %s, %s: %.4f\n" + fmt = "%s,%s,%s:%.4f\n" if shell else "%s, %s, %s: %.4f\n" if not output or output == "-": for v, p in oif: diff --git a/scripts/i.pansharpen/i.pansharpen.html b/scripts/i.pansharpen/i.pansharpen.html index 9a50b84bc4e..6fd17725e86 100644 --- a/scripts/i.pansharpen/i.pansharpen.html +++ b/scripts/i.pansharpen/i.pansharpen.html @@ -19,7 +19,7 @@

    DESCRIPTION

    panchromatic band is then substituted for the intensity channel (I), combined with the original hue (H) and saturation (S) channels, and transformed back to RGB color space at the higher resolution of the panchromatic band. The -algorithm for this can be represented as: RGB -> IHS -> [pan]HS -> RGB. +algorithm for this can be represented as: RGB -> IHS -> [pan]HS -> RGB.

    With a Brovey pan sharpening, each of the 3 lower resolution bands and panchromatic band are combined using the following algorithm to calculate @@ -172,7 +172,7 @@

    Pan sharpening comparison example

    Results:

    -
    The coordinate system and tile layout of a voxel map in GRASS
    +
     R, G, B composite of Landsat at 30m @@ -216,29 +216,29 @@

    REFERENCES

    Roller, N.E.G. and Cox, S., (1980). Comparison of Landsat MSS and merged MSS/RBV data for analysis of natural vegetation. Proc. of the 14th International Symposium on Remote Sensing - of Environment, San Jose, Costa Rica, 23-30 April, pp. 1001-1007 + of Environment, San Jose, Costa Rica, 23-30 April, pp. 1001-1007
  • Amarsaikhan, D., Douglas, T. (2004). Data fusion and multisource image - classification. International Journal of Remote Sensing, 25(17), 3529-3539. + classification. International Journal of Remote Sensing, 25(17), 3529-3539.
  • Behnia, P. (2005). Comparison between four methods for data fusion of ETM+ - multispectral and pan images. Geo-spatial Information Science, 8(2), 98-103. + multispectral and pan images. Geo-spatial Information Science, 8(2), 98-103.
  • Du, Q., Younan, N. H., King, R., Shah, V. P. (2007). On the Performance Evaluation of Pan-Sharpening Techniques. Geoscience and Remote Sensing - Letters, IEEE, 4(4), 518-522. + Letters, IEEE, 4(4), 518-522.
  • Karathanassi, V., Kolokousis, P., Ioannidou, S. (2007). A comparison study on fusion methods using evaluation indicators. International Journal - of Remote Sensing, 28(10), 2309-2341. + of Remote Sensing, 28(10), 2309-2341.
  • Neteler, M, D. Grasso, I. Michelazzi, L. Miori, S. Merler, and C. Furlanello (2005). An integrated toolbox for image registration, fusion and classification. International Journal of Geoinformatics, 1(1):51-61 - (PDF) + (PDF)
  • Pohl, C, and J.L van Genderen (1998). Multisensor image fusion in remote - sensing: concepts, methods and application. Int. J. of Rem. Sens., 19, 823-854. + sensing: concepts, methods and application. Int. J. of Rem. Sens., 19, 823-854.
  • SEE ALSO

    diff --git a/scripts/i.pansharpen/i.pansharpen.py b/scripts/i.pansharpen/i.pansharpen.py index 79e3013a05e..4ae241dd28f 100755 --- a/scripts/i.pansharpen/i.pansharpen.py +++ b/scripts/i.pansharpen/i.pansharpen.py @@ -93,6 +93,7 @@ # %end import os +from grass.exceptions import CalledModuleError try: import numpy as np @@ -526,7 +527,7 @@ def brovey(pan, ms1, ms2, ms3, out, pid, sproc): pb.wait(), pg.wait(), pr.wait() try: pb.terminate(), pg.terminate(), pr.terminate() - except Exception: + except OSError: pass # Cleanup @@ -583,7 +584,7 @@ def ihs(pan, ms1, ms2, ms3, out, pid, sproc): name=panmatch, errors="ignore", ) - except: + except CalledModuleError: pass @@ -709,7 +710,7 @@ def pca(pan, ms1, ms2, ms3, out, pid, sproc): pb.wait(), pg.wait(), pr.wait() try: pb.terminate(), pg.terminate(), pr.terminate() - except Exception: + except OSError: pass # Cleanup @@ -758,10 +759,7 @@ def matchhist(original, target, matched): ) for n in range(256): - if str(n) in stats_dict: - num_cells = stats_dict[str(n)] - else: - num_cells = 0 + num_cells = stats_dict.get(str(n), 0) cum_cells += num_cells diff --git a/scripts/i.spectral/i.spectral.html b/scripts/i.spectral/i.spectral.html index 128a0679ec9..01d747e3836 100644 --- a/scripts/i.spectral/i.spectral.html +++ b/scripts/i.spectral/i.spectral.html @@ -18,7 +18,7 @@

    EXAMPLE

    -
    +
    Spectral plot of 3 different land cover types: (1) water, (2) green vegetation, and (3) highway
    diff --git a/scripts/i.spectral/i.spectral.py b/scripts/i.spectral/i.spectral.py index 171eac7359c..07efd8af31f 100755 --- a/scripts/i.spectral/i.spectral.py +++ b/scripts/i.spectral/i.spectral.py @@ -136,10 +136,7 @@ def draw_gnuplot(what, xlabels, output, img_format, coord_legend): cmd = [] for i, row in enumerate(what): - if not coord_legend: - title = "Pick " + str(i + 1) - else: - title = str(tuple(row[0:2])) + title = "Pick " + str(i + 1) if not coord_legend else str(tuple(row[0:2])) x_datafile = os.path.join(tmp_dir, "data_%d" % i) cmd.append(" '%s' title '%s'" % (x_datafile, title)) diff --git a/scripts/i.tasscap/i.tasscap.html b/scripts/i.tasscap/i.tasscap.html index d197df7faf0..2bb244e32d8 100644 --- a/scripts/i.tasscap/i.tasscap.html +++ b/scripts/i.tasscap/i.tasscap.html @@ -15,10 +15,10 @@

    DESCRIPTION

    The following tasseled cap components are generated:
      -
    • tasscap.1: corresponds to brightness, -
    • tasscap.2: corresponds to greenness, -
    • tasscap.3: corresponds to wetness, -
    • tasscap.4: corresponds to atmospheric haze (only selected sensors: Landsat 5,7,8). +
    • tasscap.1: corresponds to brightness,
    • +
    • tasscap.2: corresponds to greenness,
    • +
    • tasscap.3: corresponds to wetness,
    • +
    • tasscap.4: corresponds to atmospheric haze (only selected sensors: Landsat 5,7,8).

    EXAMPLE

    @@ -39,7 +39,7 @@

    EXAMPLE

    - +
     'Brightness' Tasseled Cap component 1 diff --git a/scripts/m.proj/m.proj.py b/scripts/m.proj/m.proj.py index 4540b3dcd0a..a018606fff9 100755 --- a/scripts/m.proj/m.proj.py +++ b/scripts/m.proj/m.proj.py @@ -236,14 +236,8 @@ def main(): gcore.debug("output file=[%s]" % outfile) # set up output style - if not decimal: - outfmt = ["-w5"] - else: - outfmt = ["-f", "%.8f"] - if not copy_input: - copyinp = [] - else: - copyinp = ["-E"] + outfmt = ["-w5"] if not decimal else ["-f", "%.8f"] + copyinp = [] if not copy_input else ["-E"] # do the conversion # Convert cs2cs DMS format to GRASS DMS format: diff --git a/scripts/r.buffer.lowmem/r.buffer.lowmem.py b/scripts/r.buffer.lowmem/r.buffer.lowmem.py index 2916ad95e7d..8866c21faeb 100755 --- a/scripts/r.buffer.lowmem/r.buffer.lowmem.py +++ b/scripts/r.buffer.lowmem/r.buffer.lowmem.py @@ -92,10 +92,7 @@ def main(): s = gs.read_command("g.proj", flags="j") kv = gs.parse_key_val(s) - if kv["+proj"] == "longlat": - metric = "geodesic" - else: - metric = "squared" + metric = "geodesic" if kv["+proj"] == "longlat" else "squared" gs.run_command( "r.grow.distance", input=input, metric=metric, distance=temp_dist, flags="m" diff --git a/scripts/r.fillnulls/r.fillnulls.html b/scripts/r.fillnulls/r.fillnulls.html index 269b07631b2..29c5e42480e 100644 --- a/scripts/r.fillnulls/r.fillnulls.html +++ b/scripts/r.fillnulls/r.fillnulls.html @@ -71,7 +71,7 @@

    EXAMPLE

    d.histogram elev_srtm_30m # remove SRTM outliers, i.e. SRTM below 50m (esp. lakes), leading to no data areas -r.mapcalc "elev_srtm_30m_filt = if(elev_srtm_30m < 50.0, null(), elev_srtm_30m)" +r.mapcalc "elev_srtm_30m_filt = if(elev_srtm_30m < 50.0, null(), elev_srtm_30m)" d.histogram elev_srtm_30m_filt d.rast elev_srtm_30m_filt @@ -103,22 +103,22 @@

    REFERENCES

  • Mitas, L., Mitasova, H., 1999, Spatial Interpolation. In: P.Longley, M.F. Goodchild, D.J. Maguire, D.W.Rhind (Eds.), Geographical Information Systems: Principles, Techniques, Management and Applications, Wiley, -pp.481-492 +pp.481-492
  • Mitasova H., Mitas L.,  Brown W.M.,  D.P. Gerdes, I. Kosinovsky, Baker, T.1995, Modeling spatially and temporally distributed phenomena: New methods and tools for GRASS GIS. International Journal of GIS, 9 (4), special issue on Integrating GIS and Environmental modeling, -433-446. +433-446.
  • Mitasova H. and Mitas L. 1993: Interpolation by Regularized Spline with Tension: I. -Theory and Implementation, Mathematical Geology 25, 641-655. +Theory and Implementation, Mathematical Geology 25, 641-655.
  • Mitasova H. and Hofierka L. 1993: Interpolation by Regularized Spline with Tension: II. Application to Terrain Modeling and Surface Geometry Analysis, -Mathematical Geology 25, 657-667. +Mathematical Geology 25, 657-667.
  • SEE ALSO

    diff --git a/scripts/r.fillnulls/testsuite/test_r_fillnulls.py b/scripts/r.fillnulls/testsuite/test_r_fillnulls.py index 975fd5330f2..dda6d99ed95 100644 --- a/scripts/r.fillnulls/testsuite/test_r_fillnulls.py +++ b/scripts/r.fillnulls/testsuite/test_r_fillnulls.py @@ -4,8 +4,6 @@ @author: Sanjeet Bhatti """ -import os - from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule diff --git a/scripts/r.grow/r.grow.html b/scripts/r.grow/r.grow.html index cbf0088ca3c..b1b037fe5bd 100644 --- a/scripts/r.grow/r.grow.html +++ b/scripts/r.grow/r.grow.html @@ -80,8 +80,8 @@

    SEE ALSO

    r.patch -

    Wikipedia Entry: Euclidean Metric
    -Wikipedia Entry: Manhattan Metric +

    Wikipedia Entry: Euclidean Metric
    +Wikipedia Entry: Manhattan Metric

    AUTHORS

    diff --git a/scripts/r.grow/testsuite/test_grow.py b/scripts/r.grow/testsuite/test_grow.py new file mode 100644 index 00000000000..80421da2fec --- /dev/null +++ b/scripts/r.grow/testsuite/test_grow.py @@ -0,0 +1,92 @@ +from grass.gunittest.case import TestCase +from grass.gunittest.main import test +from grass.gunittest.gmodules import SimpleModule + + +class TestRGrow(TestCase): + + @classmethod + def setUpClass(cls): + """Set up a small region and test map.""" + cls.output = "test_grow" + cls.runModule("g.region", n=10, s=0, e=10, w=0, res=1) + + # Create a test map with a centered 3x3 block of 1s + cls.runModule( + "r.mapcalc", + expression="test_map = if(row() > 3 && row() < 7 && col() > 3 && col() < 7, 1, null())", + overwrite=True, + ) + + @classmethod + def tearDownClass(cls): + """Clean up test maps after all tests.""" + cls.runModule("g.remove", type="raster", name="test_map,test_grow", flags="f") + + def tearDown(self): + """Remove output map after each test to prevent conflicts.""" + self.runModule("g.remove", type="raster", name=self.output, flags="f") + + def test_default_growth(self): + """Test default growth using Euclidean metric.""" + module = SimpleModule( + "r.grow", input="test_map", output=self.output, overwrite=True + ) + self.assertModule(module) + + self.assertRasterFitsUnivar(raster=self.output, reference="n=21") + + def test_grow_with_manhattan_metric(self): + """Test growth with Manhattan metric and float radius of 2""" + module = SimpleModule( + "r.grow", + input="test_map", + output=self.output, + radius=2, + metric="manhattan", + overwrite=True, + ) + self.assertModule(module) + + self.assertRasterFitsUnivar(raster=self.output, reference="n=21") + + def test_grow_with_maximum_metric(self): + """Test growth with Maximum metric.""" + module = SimpleModule( + "r.grow", + input="test_map", + output=self.output, + metric="maximum", + overwrite=True, + ) + self.assertModule(module) + + self.assertRasterFitsUnivar(raster=self.output, reference="n=25") + + def test_shrink_with_negative_radius(self): + """Test shrinking with a negative radius of -2 to reduce area size.""" + module = SimpleModule( + "r.grow", input="test_map", radius="-2", output=self.output, overwrite=True + ) + self.assertModule(module) + + self.assertRasterFitsUnivar(raster=self.output, reference="n=1") + + def test_old_value_replacement(self): + """Test replacing the original cells with -1 and new ones with 2.""" + module = SimpleModule( + "r.grow", + input="test_map", + output=self.output, + old=-1, + new="2", + overwrite=True, + ) + self.assertModule(module) + + expected_values = {"n": 21, "sum": 15, "min": -1, "max": 2} + self.assertRasterFitsUnivar(raster=self.output, reference=expected_values) + + +if __name__ == "__main__": + test() diff --git a/scripts/r.grow/testsuite/test_r_grow.py b/scripts/r.grow/testsuite/test_r_grow.py index 3d54b9ab993..1c9488b4180 100644 --- a/scripts/r.grow/testsuite/test_r_grow.py +++ b/scripts/r.grow/testsuite/test_r_grow.py @@ -7,7 +7,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule -from grass.script.core import run_command class TestRGrow(TestCase): diff --git a/scripts/r.import/testsuite/test_r_import.py b/scripts/r.import/testsuite/test_r_import.py index 0e4ec3839e5..075b3a363cf 100755 --- a/scripts/r.import/testsuite/test_r_import.py +++ b/scripts/r.import/testsuite/test_r_import.py @@ -13,9 +13,9 @@ class TestRImportRegion(TestCase): def setUpClass(cls): cls.runModule("g.region", raster="elevation") - def tearDown(cls): + def tearDown(self): """Remove imported map after each test method""" - cls.runModule("g.remove", flags="f", type="raster", name=cls.imported) + self.runModule("g.remove", flags="f", type="raster", name=self.imported) def test_import_estimate(self): """Test e flag""" diff --git a/scripts/r.in.aster/r.in.aster.py b/scripts/r.in.aster/r.in.aster.py index 24722293dde..626d27e7976 100755 --- a/scripts/r.in.aster/r.in.aster.py +++ b/scripts/r.in.aster/r.in.aster.py @@ -152,10 +152,7 @@ def main(): # Band 3b is not included ASTER L1T if proctype == "L1T": allbands.remove("3b") - if band == "all": - bandlist = allbands - else: - bandlist = band.split(",") + bandlist = allbands if band == "all" else band.split(",") # initialize datasets for L1A, L1B, L1T if proctype in {"L1A", "L1B", "L1T"}: diff --git a/scripts/r.in.srtm/r.in.srtm.py b/scripts/r.in.srtm/r.in.srtm.py index 66c0792338c..e14a3443096 100755 --- a/scripts/r.in.srtm/r.in.srtm.py +++ b/scripts/r.in.srtm/r.in.srtm.py @@ -76,6 +76,7 @@ import atexit import grass.script as gs import zipfile as zfile +from grass.exceptions import CalledModuleError tmpl1sec = """BYTEORDER M @@ -177,10 +178,7 @@ def main(): infile = infile[:-4] (fdir, tile) = os.path.split(infile) - if not output: - tileout = tile - else: - tileout = output + tileout = output or tile if ".hgt" in input: suff = ".hgt" @@ -230,7 +228,13 @@ def main(): try: zf = zfile.ZipFile(zipfile) zf.extractall() - except (FileNotFoundError, PermissionError, OSError, zipfile.BadZipFile): + except ( + zfile.BadZipfile, + zfile.LargeZipFile, + FileNotFoundError, + PermissionError, + OSError, + ): gs.fatal(_("Unable to unzip file.")) gs.message(_("Converting input file to BIL...")) @@ -277,7 +281,7 @@ def main(): try: gs.run_command("r.in.gdal", input=bilfile, out=tileout, errors="fatal") - except: + except CalledModuleError: gs.fatal(_("Unable to import data")) # nice color table diff --git a/scripts/r.in.wms/r.in.wms.html b/scripts/r.in.wms/r.in.wms.html index ff95f3851ea..0031627991c 100644 --- a/scripts/r.in.wms/r.in.wms.html +++ b/scripts/r.in.wms/r.in.wms.html @@ -22,7 +22,7 @@

    NOTES

    When using GDAL WMS driver (driver=WMS_GDAL), the GDAL library needs to be built with WMS support, -see GDAL WMS manual page +see GDAL WMS manual page for details.

    Tiled WMS

    diff --git a/scripts/r.in.wms/srs.py b/scripts/r.in.wms/srs.py index 4d6b9a4283a..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 ValueError: + 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_cap_parsers.py b/scripts/r.in.wms/wms_cap_parsers.py index 56b1d0ce48c..e9704651c7b 100644 --- a/scripts/r.in.wms/wms_cap_parsers.py +++ b/scripts/r.in.wms/wms_cap_parsers.py @@ -105,8 +105,7 @@ def __init__(self, cap_file, force_version=None): raise ParseError( _("Missing version attribute root node in Capabilities XML file") ) - else: - wms_version = self.getroot().attrib["version"] + wms_version = self.getroot().attrib["version"] if wms_version == "1.3.0": self.proj_tag = "CRS" @@ -501,10 +500,7 @@ def _find(self, etreeElement, tag, ns=None): """!Find child element. If the element is not found it raises xml.etree.ElementTree.ParseError. """ - if not ns: - res = etreeElement.find(tag) - else: - res = etreeElement.find(ns(tag)) + res = etreeElement.find(tag) if not ns else etreeElement.find(ns(tag)) if res is None: raise ParseError( @@ -521,10 +517,7 @@ def _findall(self, etreeElement, tag, ns=None): """!Find all children element. If no element is found it raises xml.etree.ElementTree.ParseError. """ - if not ns: - res = etreeElement.findall(tag) - else: - res = etreeElement.findall(ns(tag)) + res = etreeElement.findall(tag) if not ns else etreeElement.findall(ns(tag)) if not res: raise ParseError( diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index 01a436e4df7..e46eace4b72 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -18,10 +18,10 @@ """ import socket -import grass.script as gs - from time import sleep +import grass.script as gs + try: from osgeo import gdal except ImportError: @@ -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): @@ -155,8 +150,7 @@ def _download(self): sleep(sleep_time) continue - else: - gs.fatal(_("Unable to write data into tempfile.\n%s") % str(e)) + gs.fatal(_("Unable to write data into tempfile.\n%s") % str(e)) finally: temp_tile_opened.close() @@ -292,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, ] @@ -335,18 +329,18 @@ def _computeRequestData(self, bbox, tl_corner, tile_span, tile_size, mat_num_bbo # request data bbox specified in row and col number self.t_num_bbox = {} - self.t_num_bbox["min_col"] = int( - floor((bbox["minx"] - tl_corner["minx"]) / tile_span["x"] + epsilon) + self.t_num_bbox["min_col"] = floor( + (bbox["minx"] - tl_corner["minx"]) / tile_span["x"] + epsilon ) - self.t_num_bbox["max_col"] = int( - floor((bbox["maxx"] - tl_corner["minx"]) / tile_span["x"] - epsilon) + self.t_num_bbox["max_col"] = floor( + (bbox["maxx"] - tl_corner["minx"]) / tile_span["x"] - epsilon ) - self.t_num_bbox["min_row"] = int( - floor((tl_corner["maxy"] - bbox["maxy"]) / tile_span["y"] + epsilon) + self.t_num_bbox["min_row"] = floor( + (tl_corner["maxy"] - bbox["maxy"]) / tile_span["y"] + epsilon ) - self.t_num_bbox["max_row"] = int( - floor((tl_corner["maxy"] - bbox["miny"]) / tile_span["y"] - epsilon) + self.t_num_bbox["max_row"] = floor( + (tl_corner["maxy"] - bbox["miny"]) / tile_span["y"] - epsilon ) # Does required bbox intersects bbox of data available on server? @@ -995,10 +989,7 @@ def _parseTilePattern(self, group_t_patts, bbox, region): res["y"] = (bbox["maxy"] - bbox["miny"]) / region["rows"] res["x"] = (bbox["maxx"] - bbox["minx"]) / region["cols"] - if res["x"] < res["y"]: - comp_res = "x" - else: - comp_res = "y" + comp_res = "x" if res["x"] < res["y"] else "y" t_res = {} best_patt = None diff --git a/scripts/r.mapcalc.simple/r.mapcalc.simple.html b/scripts/r.mapcalc.simple/r.mapcalc.simple.html index 84d2aeeb0a9..47481b58836 100644 --- a/scripts/r.mapcalc.simple/r.mapcalc.simple.html +++ b/scripts/r.mapcalc.simple/r.mapcalc.simple.html @@ -27,10 +27,10 @@

    NOTES

    • The input raster map names and the output map raster name are separate from the expression (formula) which uses generic - variable names (A, B, C, ...). -
    • The output raster name is not included in the expression. + variable names (A, B, C, ...).
    • +
    • The output raster name is not included in the expression.
    • The expression is expected to be a single short one liner - without the function eval(). + without the function eval().
    Differences to r.mapcalc.simple module in GRASS GIS 5 and 6: @@ -38,23 +38,23 @@

    NOTES

    • The primary purpose is not being a GUI front end to r.mapcalc, but a wrapper which allows easy building of - interfaces to r.mapcalc (including GUIs). + interfaces to r.mapcalc (including GUIs).
    • Whitespace (most notably spaces) are allowed - (in the same way as for r.mapcalc). + (in the same way as for r.mapcalc).
    • The variable names are case-insensitive to allow the original uppercase as well as lowercase as in option names - (unless the -c flag is used). + (unless the -c flag is used).
    • Option names for each map are just one letter (not amap, etc.).
    • Output option name is output as for other modules - (not outfile). -
    • Raster map names can be optionally quoted (the -q flag). + (not outfile).
    • +
    • Raster map names can be optionally quoted (the -q flag).
    • There is no expert mode - (which was just running r.mapcalc). + (which was just running r.mapcalc).
    • The expression option is first, so it is possible to omit its name in the command line - (just like with r.mapcalc). + (just like with r.mapcalc).
    • Overwriting of outputs is done in the same way as with other - modules, so there is no flag to not overwrite outputs. + modules, so there is no flag to not overwrite outputs.

    EXAMPLES

    diff --git a/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py b/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py index d400ccc7980..f133da22f7d 100644 --- a/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py +++ b/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py @@ -24,8 +24,9 @@ def setUpClass(cls): def tearDownClass(cls): map_output1 = "test1" map_output2 = "test2" - cls.runModule("g.remove", flags="f", type="raster", name=map_output1) - cls.runModule("g.remove", flags="f", type="raster", name=map_output2) + cls.runModule( + "g.remove", flags="f", type="raster", name=(map_output1, map_output2) + ) cls.del_temp_region() def test_rmapcalcsimple(self): diff --git a/scripts/r.out.xyz/r.out.xyz.py b/scripts/r.out.xyz/r.out.xyz.py index ae8e04de4d6..6df97f3c202 100755 --- a/scripts/r.out.xyz/r.out.xyz.py +++ b/scripts/r.out.xyz/r.out.xyz.py @@ -48,10 +48,7 @@ def main(): output = options["output"] donodata = flags["i"] - if donodata: - statsflags = "1g" - else: - statsflags = "1gn" + statsflags = "1g" if donodata else "1gn" parameters = { "flags": statsflags, "input": options["input"], diff --git a/scripts/r.pack/r.pack.py b/scripts/r.pack/r.pack.py index 5029f93c6d2..1f517a427af 100644 --- a/scripts/r.pack/r.pack.py +++ b/scripts/r.pack/r.pack.py @@ -63,8 +63,8 @@ def main(): global tmp tmp = grass.tempdir() - tmp_dir = os.path.join(tmp, infile) - os.mkdir(tmp_dir) + tmp_dir = Path(tmp, infile) + tmp_dir.mkdir(exist_ok=True) grass.debug("tmp_dir = %s" % tmp_dir) gfile = grass.find_file(name=infile, element="cell", mapset=mapset) @@ -150,7 +150,7 @@ def main(): os.path.join(f_tmp_dir, element), ) - if not os.listdir(tmp_dir): + if not any(tmp_dir.iterdir()): grass.fatal(_("No raster map components found")) # copy projection info diff --git a/scripts/r.reclass.area/r.reclass.area.py b/scripts/r.reclass.area/r.reclass.area.py index 5d6fc1292bc..01e474659bc 100755 --- a/scripts/r.reclass.area/r.reclass.area.py +++ b/scripts/r.reclass.area/r.reclass.area.py @@ -152,10 +152,7 @@ def reclass(inf, outf, lim, clump, diag, les): if len(f) < 5: continue hectares = float(f[4]) * 0.0001 - if lesser: - test = hectares <= limit - else: - test = hectares >= limit + test = hectares <= limit if lesser else hectares >= limit if test: rules += "%s = %s %s\n" % (f[0], f[2], f[3]) if rules: diff --git a/scripts/r.reclass.area/testsuite/test_r_reclass_area.py b/scripts/r.reclass.area/testsuite/test_r_reclass_area.py index c8009ce5a1d..96c922bda05 100644 --- a/scripts/r.reclass.area/testsuite/test_r_reclass_area.py +++ b/scripts/r.reclass.area/testsuite/test_r_reclass_area.py @@ -26,8 +26,12 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.del_temp_region() - cls.runModule("g.remove", type="raster", flags="f", name=cls.output + "Greater") - cls.runModule("g.remove", type="raster", flags="f", name=cls.output + "Lesser") + cls.runModule( + "g.remove", + type="raster", + flags="f", + name=(cls.output + "Greater", cls.output + "Lesser"), + ) def test_reclassaeaGreater(self): """Testing r.reclass.area with greater""" diff --git a/scripts/r.reclass.area/testsuite/testrra.py b/scripts/r.reclass.area/testsuite/testrra.py index e6e2300875b..5e11bf6aecc 100644 --- a/scripts/r.reclass.area/testsuite/testrra.py +++ b/scripts/r.reclass.area/testsuite/testrra.py @@ -5,8 +5,8 @@ Author: Sunveer Singh, Google Code-in 2018 Copyright: (C) 2018 by Sunveer Singh and the GRASS Development Team Licence: This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. + License (>=v2). Read the file COPYING that comes with GRASS + for details. """ from grass.gunittest.case import TestCase @@ -26,8 +26,8 @@ def setUpClass(cls): def tearDownClass(cls): cls.del_temp_region() - def tearDown(cls): - cls.runModule("g.remove", type="raster", flags="f", name=cls.output) + def tearDown(self): + self.runModule("g.remove", type="raster", flags="f", name=self.output) def test_flag_c(self): """Testing flag c""" diff --git a/scripts/r.semantic.label/r.semantic.label.html b/scripts/r.semantic.label/r.semantic.label.html index 9ebcfce10a6..f36b93eb6b1 100644 --- a/scripts/r.semantic.label/r.semantic.label.html +++ b/scripts/r.semantic.label/r.semantic.label.html @@ -25,10 +25,10 @@

    NOTES

    Semantic labels are supported by temporal GRASS modules. Name of STRDS can be extended by band identifier in order to filter the result by a semantic label. See -t.register, -t.rast.list, -t.info -and t.rast.mapcalc +t.register, +t.rast.list, +t.info +and t.rast.mapcalc modules for examples.

    EXAMPLES

    @@ -79,7 +79,7 @@

    SEE ALSO

    i.band.library, r.info, - r.support + r.support

    AUTHORS

    diff --git a/scripts/r.unpack/r.unpack.py b/scripts/r.unpack/r.unpack.py index 575d465ebb5..dd595b4722b 100644 --- a/scripts/r.unpack/r.unpack.py +++ b/scripts/r.unpack/r.unpack.py @@ -92,10 +92,7 @@ def main(): return 0 - if options["output"]: - map_name = options["output"] - else: - map_name = data_names[0].split("@")[0] + map_name = options["output"] or data_names[0].split("@")[0] gfile = grass.find_file(name=map_name, element="cell", mapset=".") if gfile["file"]: diff --git a/scripts/r3.in.xyz/r3.in.xyz.py b/scripts/r3.in.xyz/r3.in.xyz.py index b17d59506b7..5b2c8be4a65 100755 --- a/scripts/r3.in.xyz/r3.in.xyz.py +++ b/scripts/r3.in.xyz/r3.in.xyz.py @@ -226,10 +226,7 @@ def main(): addl_opts["flags"] = "i" if scan_only or shell_style: - if shell_style: - doShell = "g" - else: - doShell = "" + doShell = "g" if shell_style else "" grass.run_command( "r.in.xyz", flags="s" + doShell, @@ -243,10 +240,7 @@ def main(): ) sys.exit() - if dtype == "float": - data_type = "FCELL" - else: - data_type = "DCELL" + data_type = "FCELL" if dtype == "float" else "DCELL" region = grass.region(region3d=True) diff --git a/scripts/v.build.all/v.build.all.py b/scripts/v.build.all/v.build.all.py index 69b0837209f..8691ecddc32 100755 --- a/scripts/v.build.all/v.build.all.py +++ b/scripts/v.build.all/v.build.all.py @@ -31,10 +31,7 @@ def main(): vectors = grass.list_grouped("vect")[mapset] num_vectors = len(vectors) - if grass.verbosity() < 2: - quiet = True - else: - quiet = False + quiet = grass.verbosity() < 2 i = 1 for vect in vectors: diff --git a/scripts/v.clip/v.clip.html b/scripts/v.clip/v.clip.html index b4d93121d9a..17d364d713c 100644 --- a/scripts/v.clip/v.clip.html +++ b/scripts/v.clip/v.clip.html @@ -22,7 +22,7 @@

    NOTES

    and/or lines can be achieved using v.overlay. Clipping of points can be performed -with v.select. +with v.select.

    EXAMPLES

    diff --git a/scripts/v.db.dropcolumn/v.db.dropcolumn.py b/scripts/v.db.dropcolumn/v.db.dropcolumn.py index 298a29133b3..fd34f36893f 100755 --- a/scripts/v.db.dropcolumn/v.db.dropcolumn.py +++ b/scripts/v.db.dropcolumn/v.db.dropcolumn.py @@ -86,7 +86,7 @@ def main(): if driver == "sqlite": # echo "Using special trick for SQLite" - # http://www.sqlite.org/faq.html#q11 + # https://www.sqlite.org/faq.html#q11 colnames = [] coltypes = [] for f in gs.db_describe(table, database=database, driver=driver)["cols"]: diff --git a/scripts/v.db.join/v.db.join.html b/scripts/v.db.join/v.db.join.html index e44705c55b5..436c86a7d43 100644 --- a/scripts/v.db.join/v.db.join.html +++ b/scripts/v.db.join/v.db.join.html @@ -16,8 +16,8 @@

    EXAMPLES

    Exercise to join North Carolina geological classes from a CSV table to the "geology" map of the North Carolina sample dataset (requires download -of legend CSV file nc_geology.csv -from External data for NC sample dataset): +of legend CSV file nc_geology.csv +from External data for NC sample dataset):
     # check original map attributes
    @@ -49,7 +49,7 @@ 

    EXAMPLES

    Soil map table join

    Joining the soil type explanations from table soils_legend -into the Spearfish soils map (download legend): +into the Spearfish soils map (download legend):
     g.copy vect=soils,mysoils
    diff --git a/scripts/v.db.reconnect.all/v.db.reconnect.all.py b/scripts/v.db.reconnect.all/v.db.reconnect.all.py
    index b42b8006673..7a422f47f7f 100755
    --- a/scripts/v.db.reconnect.all/v.db.reconnect.all.py
    +++ b/scripts/v.db.reconnect.all/v.db.reconnect.all.py
    @@ -19,6 +19,8 @@
     # % keyword: vector
     # % keyword: attribute table
     # % keyword: database
    +# % keyword: DBF
    +# % keyword: SQLite
     # %end
     # %flag
     # % key: c
    @@ -255,10 +257,7 @@ def main():
                     schema = ""
                     table = schema_table
     
    -            if new_schema:
    -                new_schema_table = "%s.%s" % (new_schema, table)
    -            else:
    -                new_schema_table = table
    +            new_schema_table = "%s.%s" % (new_schema, table) if new_schema else table
     
                 gs.debug(
                     "DATABASE = '%s' SCHEMA = '%s' TABLE = '%s' ->\n"
    diff --git a/scripts/v.db.univar/v.db.univar.html b/scripts/v.db.univar/v.db.univar.html
    index 4329051c2a9..4c09a9714a0 100644
    --- a/scripts/v.db.univar/v.db.univar.html
    +++ b/scripts/v.db.univar/v.db.univar.html
    @@ -12,10 +12,10 @@ 

    DESCRIPTION

    is read from each line in the attribute table, whether there are no, one or several features with the category value referenced by that line, or whether any features have more than one category value. For feature-based, instead of -attribute table-based, univariate statistics on attributes see v.univar. +attribute table-based, univariate statistics on attributes see +v.univar. -NOTES +

    NOTES

    A database connection must be defined for the selected vector layer. diff --git a/scripts/v.dissolve/tests/conftest.py b/scripts/v.dissolve/tests/conftest.py index 9b069330488..e5e9a38818d 100644 --- a/scripts/v.dissolve/tests/conftest.py +++ b/scripts/v.dissolve/tests/conftest.py @@ -13,10 +13,7 @@ def updates_as_transaction(table, cat_column, column, column_quote, cats, values): """Create SQL statement for categories and values for a given column""" sql = ["BEGIN TRANSACTION"] - if column_quote: - quote = "'" - else: - quote = "" + quote = "'" if column_quote else "" for cat, value in zip(cats, values): sql.append( f"UPDATE {table} SET {column} = {quote}{value}{quote} " diff --git a/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py b/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py index 68ca178b864..90dc3de075e 100644 --- a/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py +++ b/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py @@ -101,10 +101,7 @@ def test_aggregate_column_result(dataset, backend): for stats_column in stats_columns: assert stats_column in columns column_info = columns[stats_column] - if stats_column.endswith("_n"): - correct_type = "integer" - else: - correct_type = "double precision" + correct_type = "integer" if stats_column.endswith("_n") else "double precision" assert ( columns[stats_column]["type"].lower() == correct_type ), f"{stats_column} has a wrong type" @@ -221,10 +218,7 @@ def test_sqlite_agg_accepted(dataset): for method, stats_column in zip(stats, expected_stats_columns): assert stats_column in columns column_info = columns[stats_column] - if method == "count": - correct_type = "integer" - else: - correct_type = "double precision" + correct_type = "integer" if method == "count" else "double precision" assert ( columns[stats_column]["type"].lower() == correct_type ), f"{stats_column} has a wrong type" diff --git a/scripts/v.dissolve/tests/v_dissolve_layers_test.py b/scripts/v.dissolve/tests/v_dissolve_layers_test.py index 702aa8f8496..f6986d35917 100644 --- a/scripts/v.dissolve/tests/v_dissolve_layers_test.py +++ b/scripts/v.dissolve/tests/v_dissolve_layers_test.py @@ -50,10 +50,7 @@ def test_layer_2(dataset_layer_2): for method, stats_column in zip(stats, expected_stats_columns): assert stats_column in columns column_info = columns[stats_column] - if method == "count": - correct_type = "integer" - else: - correct_type = "double precision" + correct_type = "integer" if method == "count" else "double precision" assert ( columns[stats_column]["type"].lower() == correct_type ), f"{stats_column} has a wrong type" diff --git a/scripts/v.dissolve/v.dissolve.html b/scripts/v.dissolve/v.dissolve.html index 54044a1bcf4..f2547babeda 100644 --- a/scripts/v.dissolve/v.dissolve.html +++ b/scripts/v.dissolve/v.dissolve.html @@ -57,13 +57,13 @@

    Aggregation using sql backend

    When the sql backend is used, the methods depend on the SQL database backend used for the attribute table of the input vector. For -SQLite, there are at least the following built-in aggregate +SQLite, there are at least the following +built-in aggregate functions: count, min, max, avg, sum, and total. -For PostgreSQL, the list of aggregate +For PostgreSQL, the list of +aggregate functions is much longer and includes, e.g., count, min, max, avg, sum, stddev, and variance. @@ -276,8 +276,8 @@

    Aggregating multiple attributes

     v.dissolve input=boundary_municp column=DOTURBAN_N output=municipalities_4 \
    -	aggregate_columns=ACRES,NEW_PERC_G aggregate_methods=sum,avg \
    -	result_columns=acres,new_perc_g
    +    aggregate_columns=ACRES,NEW_PERC_G aggregate_methods=sum,avg \
    +    result_columns=acres,new_perc_g
     

    @@ -336,9 +336,9 @@

    Aggregating using SQL syntax

    used with group_concat:
    -    v.dissolve input=boundary_municp column=DOTURBAN_N output=municipalities_7 \
    -        aggregate_columns="group_concat(MB_NAME, ';')" \
    -        result_columns="names TEXT"
    +v.dissolve input=boundary_municp column=DOTURBAN_N output=municipalities_7 \
    +    aggregate_columns="group_concat(MB_NAME, ';')" \
    +    result_columns="names TEXT"
     

    diff --git a/scripts/v.dissolve/v.dissolve.py b/scripts/v.dissolve/v.dissolve.py index 7336833060a..cb03ae3591e 100755 --- a/scripts/v.dissolve/v.dissolve.py +++ b/scripts/v.dissolve/v.dissolve.py @@ -16,7 +16,7 @@ ############################################################################# # %module -# % description: Dissolves adjacent or overlaping features sharing a common category number or attribute. +# % description: Dissolves adjacent or overlapping features sharing a common category number or attribute. # % keyword: vector # % keyword: dissolve # % keyword: area diff --git a/scripts/v.dissolve/v_dissolve.ipynb b/scripts/v.dissolve/v_dissolve.ipynb index f90907a704d..085b23828d8 100644 --- a/scripts/v.dissolve/v_dissolve.ipynb +++ b/scripts/v.dissolve/v_dissolve.ipynb @@ -19,7 +19,6 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "import json\n", "import subprocess\n", "import sys\n", diff --git a/scripts/v.import/testsuite/test_v_import.py b/scripts/v.import/testsuite/test_v_import.py index d8dd6b85887..90934bbb3e6 100755 --- a/scripts/v.import/testsuite/test_v_import.py +++ b/scripts/v.import/testsuite/test_v_import.py @@ -18,9 +18,9 @@ class TestVImport(TestCase): imported = "test_v_import_imported" - def tearDown(cls): + def tearDown(self): """Remove imported map after each test method""" - cls.runModule("g.remove", flags="f", type="vector", name=cls.imported) + self.runModule("g.remove", flags="f", type="vector", name=self.imported) def test_import_same_proj_gpkg(self): """Import GPKG in same proj, default params""" diff --git a/scripts/v.import/v.import.html b/scripts/v.import/v.import.html index a530f5f3662..281136939e2 100644 --- a/scripts/v.import/v.import.html +++ b/scripts/v.import/v.import.html @@ -1,7 +1,7 @@

    DESCRIPTION

    v.import imports vector data from files and database connections -supported by the OGR library into the +supported by the OGR library into the current project (previously called location) and mapset. If the coordinate reference system (CRS) of the input does not match the CRS of the project, the input is reprojected @@ -11,13 +11,13 @@

    DESCRIPTION

    Supported Vector Formats

    v.import uses the OGR library which supports various vector data -formats including ESRI -Shapefile, Mapinfo +formats including ESRI +Shapefile, Mapinfo File, UK .NTF, SDTS, TIGER, IHO S-57 (ENC), DGN, GML, GPX, AVCBin, REC, Memory, OGDI, and PostgreSQL, depending on the local OGR installation. For details see the OGR web site. The OGR (Simple Features Library) is part of the -GDAL library, hence GDAL needs to be +GDAL library, hence GDAL needs to be installed to use v.import.

    diff --git a/scripts/v.in.e00/v.in.e00.html b/scripts/v.in.e00/v.in.e00.html index ef027c192e2..931bec50cf6 100644 --- a/scripts/v.in.e00/v.in.e00.html +++ b/scripts/v.in.e00/v.in.e00.html @@ -12,7 +12,7 @@

    NOTES

    REFERENCES

    AVCE00 library (providing 'avcimport' and 'e00conv')
    -OGR vector library +OGR vector library

    SEE ALSO

    diff --git a/scripts/v.in.e00/v.in.e00.py b/scripts/v.in.e00/v.in.e00.py index 4d63636199f..4258fa3181a 100755 --- a/scripts/v.in.e00/v.in.e00.py +++ b/scripts/v.in.e00/v.in.e00.py @@ -86,10 +86,7 @@ def main(): ) merging = True - if vect: - name = vect - else: - name = e00name + name = vect or e00name # do import diff --git a/scripts/v.in.geonames/v.in.geonames.html b/scripts/v.in.geonames/v.in.geonames.html index f2657c878c3..a38aa770cc5 100644 --- a/scripts/v.in.geonames/v.in.geonames.html +++ b/scripts/v.in.geonames/v.in.geonames.html @@ -78,4 +78,4 @@

    SEE ALSO

    AUTHOR

    -Markus Neteler +Markus Neteler diff --git a/scripts/v.in.lines/v.in.lines.py b/scripts/v.in.lines/v.in.lines.py index 44112b297a3..35991988f6b 100755 --- a/scripts/v.in.lines/v.in.lines.py +++ b/scripts/v.in.lines/v.in.lines.py @@ -50,12 +50,7 @@ def main(): fs = separator(options["separator"]) threeD = flags["z"] - - if threeD: - do3D = "z" - else: - do3D = "" - + do3D = "z" if threeD else "" tmp = grass.tempfile() # set up input file diff --git a/scripts/v.in.mapgen/v.in.mapgen.py b/scripts/v.in.mapgen/v.in.mapgen.py index 404fb7ec6b2..efe7af1075d 100755 --- a/scripts/v.in.mapgen/v.in.mapgen.py +++ b/scripts/v.in.mapgen/v.in.mapgen.py @@ -73,18 +73,12 @@ def main(): if not os.path.isfile(infile): grass.fatal(_("Input file <%s> not found") % infile) - if output: - name = output - else: - name = "" + name = output or "" if threeD: matlab = True - if threeD: - do3D = "z" - else: - do3D = "" + do3D = "z" if threeD else "" tmp = grass.tempfile() diff --git a/scripts/v.in.wfs/v.in.wfs.py b/scripts/v.in.wfs/v.in.wfs.py index 9f53840edcf..2949949ad50 100755 --- a/scripts/v.in.wfs/v.in.wfs.py +++ b/scripts/v.in.wfs/v.in.wfs.py @@ -154,12 +154,10 @@ def main(): if flags["l"]: wfs_url = options["url"] + "REQUEST=GetCapabilities&SERVICE=WFS" - print(wfs_url) - tmp = grass.tempfile() tmpxml = tmp + ".xml" - grass.debug(wfs_url) + grass.debug("The request URL: {wfs_url}") # Set user and password if given if options["username"] and options["password"]: diff --git a/scripts/v.pack/v.pack.py b/scripts/v.pack/v.pack.py index 4468c888bcb..e39d52dbafe 100755 --- a/scripts/v.pack/v.pack.py +++ b/scripts/v.pack/v.pack.py @@ -73,10 +73,7 @@ def main(): infile = infile.split("@")[0] # output name - if options["output"]: - outfile = options["output"] - else: - outfile = infile + ".pack" + outfile = options["output"] or infile + ".pack" # check if exists the output file if os.path.exists(outfile): diff --git a/scripts/v.rast.stats/testsuite/test_v_rast_stats.py b/scripts/v.rast.stats/testsuite/test_v_rast_stats.py index 56acbce5964..01ae6d4a7d2 100644 --- a/scripts/v.rast.stats/testsuite/test_v_rast_stats.py +++ b/scripts/v.rast.stats/testsuite/test_v_rast_stats.py @@ -24,11 +24,12 @@ def tearDownClass(cls): cls.del_temp_region() def tearDown(self): - self.runModule("g.remove", flags="f", type="raster", name="map_a") - self.runModule("g.remove", flags="f", type="raster", name="map_b") - self.runModule("g.remove", flags="f", type="raster", name="zone_map") - self.runModule("g.remove", flags="f", type="raster", name="row_map") - self.runModule("g.remove", flags="f", type="raster", name="test_line") + self.runModule( + "g.remove", + flags="f", + type="raster", + name="map_a,map_b,zone_map,row_map,test_line", + ) def setUp(self): """Create input data""" diff --git a/scripts/v.rast.stats/v.rast.stats.py b/scripts/v.rast.stats/v.rast.stats.py index 803fc8691ad..4096aa49caf 100644 --- a/scripts/v.rast.stats/v.rast.stats.py +++ b/scripts/v.rast.stats/v.rast.stats.py @@ -116,10 +116,7 @@ def main(): # Get mapset of the vector vs = vector.split("@") - if len(vs) > 1: - vect_mapset = vs[1] - else: - vect_mapset = mapset + vect_mapset = vs[1] if len(vs) > 1 else mapset # does map exist in CURRENT mapset? if vect_mapset != mapset or not gs.find_file(vector, "vector", mapset)["file"]: @@ -373,10 +370,7 @@ def set_up_columns(vector, layer, percentile, colprefix, basecols, dbfdriver, c) perc = b if perc: # namespace is limited in DBF but the % value is important - if dbfdriver: - perccol = "per" + percentile - else: - perccol = "percentile_" + percentile + perccol = "per" + percentile if dbfdriver else "percentile_" + percentile percindex = basecols.index(perc) basecols[percindex] = perccol @@ -424,10 +418,7 @@ def set_up_columns(vector, layer, percentile, colprefix, basecols, dbfdriver, c) + _("Use -c flag to update values in this column.") ) else: - if i == "n": - coltype = "INTEGER" - else: - coltype = "DOUBLE PRECISION" + coltype = "INTEGER" if i == "n" else "DOUBLE PRECISION" addcols.append(currcolumn + " " + coltype) if addcols: diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index cec84582155..80e9e8a1189 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -91,10 +91,7 @@ def main(): isConnection = False colnames = ["cat"] - if option == "coor": - extracolnames = ["x", "y", "z"] - else: - extracolnames = [option] + extracolnames = ["x", "y", "z"] if option == "coor" else [option] if units == "percent": unitsp = "meters" @@ -227,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 87cc65b7608..147fb323e22 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -93,10 +93,7 @@ def main(): return 0 # set the output name - if options["output"]: - map_name = options["output"] - else: - map_name = data_name + map_name = options["output"] or data_name # grass env gisenv = grass.gisenv() @@ -233,19 +230,13 @@ def main(): # for each old connection for t in dbnlist: # it split the line of each connection, to found layer number and key - if len(t.split("|")) != 1: - values = t.split("|") - else: - values = t.split(" ") + values = t.split("|") if len(t.split("|")) != 1 else t.split(" ") from_table = values[1] layer = values[0].split("/")[0] # we need to take care about the table name in case of several layer if options["output"]: - if len(dbnlist) > 1: - to_table = "%s_%s" % (map_name, layer) - else: - to_table = map_name + to_table = "%s_%s" % (map_name, layer) if len(dbnlist) > 1 else map_name else: to_table = from_table diff --git a/scripts/v.what.strds/v.what.strds.py b/scripts/v.what.strds/v.what.strds.py index 8be00f3536d..2c819fd0e44 100644 --- a/scripts/v.what.strds/v.what.strds.py +++ b/scripts/v.what.strds/v.what.strds.py @@ -202,8 +202,7 @@ def main(): if name is None: isvalid = False break - else: - mapname_list.append(name) + mapname_list.append(name) if isvalid: entry = mapmatrizes[0][i] 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.info/t.info.py b/temporal/t.info/t.info.py index 575446030a1..c04fe0c0a5f 100755 --- a/temporal/t.info/t.info.py +++ b/temporal/t.info/t.info.py @@ -103,11 +103,7 @@ def main(): if not system and not name: gs.fatal(_("Please specify %s=") % ("name")) - if name.find("@") >= 0: - id_ = name - else: - id_ = name + "@" + gs.gisenv()["MAPSET"] - + id_ = name if name.find("@") >= 0 else name + "@" + gs.gisenv()["MAPSET"] dataset = tgis.dataset_factory(type_, id_) if not dataset.is_in_db(dbif): diff --git a/temporal/t.list/t.list.html b/temporal/t.list/t.list.html index 7d88ecb8fdd..38e11b2d3e7 100644 --- a/temporal/t.list/t.list.html +++ b/temporal/t.list/t.list.html @@ -50,8 +50,8 @@

    EXAMPLES

    The where option can also be used to list the stds with a -certain pattern in their name, i.e. as the pattern option in g.list. +certain pattern in their name, i.e. as the pattern option in +g.list.
     # strds whose name start with "precip"
    diff --git a/temporal/t.list/t.list.py b/temporal/t.list/t.list.py
    index 52285d04b83..c41bcae4e22 100755
    --- a/temporal/t.list/t.list.py
    +++ b/temporal/t.list/t.list.py
    @@ -123,10 +123,7 @@ def main():
             outfile = open(outpath, "w")
     
         for ttype in temporal_type.split(","):
    -        if ttype == "absolute":
    -            time = "absolute time"
    -        else:
    -            time = "relative time"
    +        time = "absolute time" if ttype == "absolute" else "relative time"
     
             stds_list = tgis.get_dataset_list(type, ttype, columns, where, order, dbif=dbif)
     
    diff --git a/temporal/t.rast.accdetect/t.rast.accdetect.py b/temporal/t.rast.accdetect/t.rast.accdetect.py
    index 1588b44d4b9..17433e06f3f 100644
    --- a/temporal/t.rast.accdetect/t.rast.accdetect.py
    +++ b/temporal/t.rast.accdetect/t.rast.accdetect.py
    @@ -173,11 +173,7 @@ def main():
     
         mapset = tgis.get_current_mapset()
     
    -    if input.find("@") >= 0:
    -        id = input
    -    else:
    -        id = input + "@" + mapset
    -
    +    id = input if input.find("@") >= 0 else input + "@" + mapset
         input_strds = tgis.SpaceTimeRasterDataset(id)
     
         if not input_strds.is_in_db():
    @@ -261,10 +257,7 @@ def main():
         # The minimum threshold space time raster dataset
         minimum_strds = None
         if minimum:
    -        if minimum.find("@") >= 0:
    -            minimum_id = minimum
    -        else:
    -            minimum_id = minimum + "@" + mapset
    +        minimum_id = minimum if minimum.find("@") >= 0 else minimum + "@" + mapset
     
             minimum_strds = tgis.SpaceTimeRasterDataset(minimum_id)
             if not minimum_strds.is_in_db():
    @@ -282,10 +275,7 @@ def main():
         # The maximum threshold space time raster dataset
         maximum_strds = None
         if maximum:
    -        if maximum.find("@") >= 0:
    -            maximum_id = maximum
    -        else:
    -            maximum_id = maximum + "@" + mapset
    +        maximum_id = maximum if maximum.find("@") >= 0 else maximum + "@" + mapset
     
             maximum_strds = tgis.SpaceTimeRasterDataset(maximum_id)
             if not maximum_strds.is_in_db():
    @@ -304,16 +294,10 @@ def main():
     
         if input_strds.is_time_absolute():
             start = tgis.string_to_datetime(start)
    -        if stop:
    -            stop = tgis.string_to_datetime(stop)
    -        else:
    -            stop = input_strds_end
    +        stop = tgis.string_to_datetime(stop) if stop else input_strds_end
         else:
             start = int(start)
    -        if stop:
    -            stop = int(stop)
    -        else:
    -            stop = input_strds_end
    +        stop = int(stop) if stop else input_strds_end
     
         if input_strds.is_time_absolute():
             end = tgis.increment_datetime_by_string(start, cycle)
    @@ -365,10 +349,7 @@ def main():
             if indicator:
                 num_maps = len(input_maps)
                 for i in range(num_maps):
    -                if reverse:
    -                    map = input_maps[num_maps - i - 1]
    -                else:
    -                    map = input_maps[i]
    +                map = input_maps[num_maps - i - 1] if reverse else input_maps[i]
     
                     if (
                         input_strds.get_temporal_type() == "absolute"
    @@ -637,19 +618,13 @@ def compute_occurrence(
         # Aggregate
         num_maps = len(input_maps)
         for i in range(num_maps):
    -        if reverse:
    -            map = input_maps[num_maps - i - 1]
    -        else:
    -            map = input_maps[i]
    +        map = input_maps[num_maps - i - 1] if reverse else input_maps[i]
     
             # Compute the days since start
             input_start, input_end = map.get_temporal_extent_as_tuple()
     
             td = input_start - start
    -        if map.is_time_absolute():
    -            days = tgis.time_delta_to_relative_time(td)
    -        else:
    -            days = td
    +        days = tgis.time_delta_to_relative_time(td) if map.is_time_absolute() else td
     
             if input_strds.get_temporal_type() == "absolute" and tsuffix == "gran":
                 suffix = tgis.create_suffix_from_datetime(
    diff --git a/temporal/t.rast.accdetect/testsuite/test_simple.py b/temporal/t.rast.accdetect/testsuite/test_simple.py
    index 522c13f93e4..d67537487d5 100644
    --- a/temporal/t.rast.accdetect/testsuite/test_simple.py
    +++ b/temporal/t.rast.accdetect/testsuite/test_simple.py
    @@ -62,8 +62,7 @@ def tearDownClass(cls):
     
         def tearDown(self):
             """Remove generated data"""
    -        self.runModule("t.remove", flags="df", type="strds", inputs="B")
    -        self.runModule("t.remove", flags="df", type="strds", inputs="C")
    +        self.runModule("t.remove", flags="df", type="strds", inputs="B,C")
     
         def test_simple(self):
             self.assertModule(
    diff --git a/temporal/t.rast.accumulate/t.rast.accumulate.html b/temporal/t.rast.accumulate/t.rast.accumulate.html
    index e36d6a79c57..52c37b5e9f0 100644
    --- a/temporal/t.rast.accumulate/t.rast.accumulate.html
    +++ b/temporal/t.rast.accumulate/t.rast.accumulate.html
    @@ -70,7 +70,7 @@ 

    EXAMPLE

    # Import the temperature data t.rast.import input=temperature_mean_1990_2000_daily_celsius.tar.gz \ - output=temperature_mean_1990_2000_daily_celsius directory=/tmp + output=temperature_mean_1990_2000_daily_celsius directory=/tmp # We need to set the region correctly g.region -p raster=`t.rast.list input=temperature_mean_1990_2000_daily_celsius column=name | tail -1` @@ -93,9 +93,9 @@

    EXAMPLE

    # a granularity of one day. Base temperature is 10°C, upper limit is 30°C. # Hence the accumulation starts at 10°C and does not accumulate values above 30°C. t.rast.accumulate input="temperature_mean_1990_2000_daily_celsius" \ - output="temperature_mean_1990_2000_daily_celsius_accumulated_10_30" \ - limits="10,30" start="1990-01-01" stop="2000-01-01" cycle="12 months" \ - basename="temp_acc_daily_10_30" method="bedd" + output="temperature_mean_1990_2000_daily_celsius_accumulated_10_30" \ + limits="10,30" start="1990-01-01" stop="2000-01-01" cycle="12 months" \ + basename="temp_acc_daily_10_30" method="bedd" ############################################################################# #### ACCUMULATION PATTERN DETECTION ######################################### @@ -104,18 +104,18 @@

    EXAMPLE

    # First cycle at 325°C - 427°C GDD t.rast.accdetect input=temperature_mean_1990_2000_daily_celsius_accumulated_10_30@PERMANENT \ - occ=leafhopper_occurrence_c1_1990_2000 start="1990-01-01" stop="2000-01-01" \ - cycle="12 months" range=325,427 basename=lh_c1 indicator=leafhopper_indicator_c1_1990_2000 + occ=leafhopper_occurrence_c1_1990_2000 start="1990-01-01" stop="2000-01-01" \ + cycle="12 months" range=325,427 basename=lh_c1 indicator=leafhopper_indicator_c1_1990_2000 # Second cycle at 685°C - 813°C GDD t.rast.accdetect input=temperature_mean_1990_2000_daily_celsius_accumulated_10_30@PERMANENT \ - occ=leafhopper_occurrence_c2_1990_2000 start="1990-01-01" stop="2000-01-01" \ - cycle="12 months" range=685,813 basename=lh_c2 indicator=leafhopper_indicator_c2_1990_2000 + occ=leafhopper_occurrence_c2_1990_2000 start="1990-01-01" stop="2000-01-01" \ + cycle="12 months" range=685,813 basename=lh_c2 indicator=leafhopper_indicator_c2_1990_2000 # Third cycle at 1047°C - 1179°C GDD t.rast.accdetect input=temperature_mean_1990_2000_daily_celsius_accumulated_10_30@PERMANENT \ - occ=leafhopper_occurrence_c3_1990_2000 start="1990-01-01" stop="2000-01-01" \ - cycle="12 months" range=1047,1179 basename=lh_c3 indicator=leafhopper_indicator_c3_1990_2000 + occ=leafhopper_occurrence_c3_1990_2000 start="1990-01-01" stop="2000-01-01" \ + cycle="12 months" range=1047,1179 basename=lh_c3 indicator=leafhopper_indicator_c3_1990_2000 ############################################################################# @@ -124,36 +124,36 @@

    EXAMPLE

    # Extract the areas that have full cycles t.rast.aggregate input=leafhopper_indicator_c1_1990_2000 gran="1 year" \ - output=leafhopper_cycle_1_1990_2000_yearly method=maximum basename=li_c1 + output=leafhopper_cycle_1_1990_2000_yearly method=maximum basename=li_c1 t.rast.mapcalc input=leafhopper_cycle_1_1990_2000_yearly basename=lh_clean_c1 \ - output=leafhopper_cycle_1_1990_2000_yearly_clean \ - expression="if(leafhopper_cycle_1_1990_2000_yearly == 3, 1, null())" + output=leafhopper_cycle_1_1990_2000_yearly_clean \ + expression="if(leafhopper_cycle_1_1990_2000_yearly == 3, 1, null())" t.rast.aggregate input=leafhopper_indicator_c2_1990_2000 gran="1 year" \ - output=leafhopper_cycle_2_1990_2000_yearly method=maximum basename=li_c2 + output=leafhopper_cycle_2_1990_2000_yearly method=maximum basename=li_c2 t.rast.mapcalc input=leafhopper_cycle_2_1990_2000_yearly basename=lh_clean_c2 \ - output=leafhopper_cycle_2_1990_2000_yearly_clean \ - expression="if(leafhopper_cycle_2_1990_2000_yearly == 3, 2, null())" + output=leafhopper_cycle_2_1990_2000_yearly_clean \ + expression="if(leafhopper_cycle_2_1990_2000_yearly == 3, 2, null())" t.rast.aggregate input=leafhopper_indicator_c3_1990_2000 gran="1 year" \ - output=leafhopper_cycle_3_1990_2000_yearly method=maximum basename=li_c3 + output=leafhopper_cycle_3_1990_2000_yearly method=maximum basename=li_c3 t.rast.mapcalc input=leafhopper_cycle_3_1990_2000_yearly basename=lh_clean_c3 \ - output=leafhopper_cycle_3_1990_2000_yearly_clean \ - expression="if(leafhopper_cycle_3_1990_2000_yearly == 3, 3, null())" + output=leafhopper_cycle_3_1990_2000_yearly_clean \ + expression="if(leafhopper_cycle_3_1990_2000_yearly == 3, 3, null())" t.rast.mapcalc input=leafhopper_cycle_1_1990_2000_yearly_clean,leafhopper_cycle_2_1990_2000_yearly_clean,leafhopper_cycle_3_1990_2000_yearly_clean \ - basename=lh_cleann_all_cycles \ - output=leafhopper_all_cycles_1990_2000_yearly_clean \ - expression="if(isnull(leafhopper_cycle_3_1990_2000_yearly_clean), \ - if(isnull(leafhopper_cycle_2_1990_2000_yearly_clean), \ - if(isnull(leafhopper_cycle_1_1990_2000_yearly_clean), \ - null() ,1),2),3)" - -cat > color.table << EOF + basename=lh_cleann_all_cycles \ + output=leafhopper_all_cycles_1990_2000_yearly_clean \ + expression="if(isnull(leafhopper_cycle_3_1990_2000_yearly_clean), \ + if(isnull(leafhopper_cycle_2_1990_2000_yearly_clean), \ + if(isnull(leafhopper_cycle_1_1990_2000_yearly_clean), \ + null() ,1),2),3)" + +cat > color.table << EOF 3 yellow 2 blue 1 red @@ -170,35 +170,35 @@

    EXAMPLE

    # Extract the duration in days of the first cycle t.rast.aggregate input=leafhopper_occurrence_c1_1990_2000 gran="1 year" \ - output=leafhopper_min_day_c1_1990_2000 method=minimum basename=occ_min_day_c1 + output=leafhopper_min_day_c1_1990_2000 method=minimum basename=occ_min_day_c1 t.rast.aggregate input=leafhopper_occurrence_c1_1990_2000 gran="1 year" \ - output=leafhopper_max_day_c1_1990_2000 method=maximum basename=occ_max_day_c1 + output=leafhopper_max_day_c1_1990_2000 method=maximum basename=occ_max_day_c1 t.rast.mapcalc input=leafhopper_min_day_c1_1990_2000,leafhopper_max_day_c1_1990_2000 \ - basename=occ_duration_c1 \ - output=leafhopper_duration_c1_1990_2000 \ - expression="leafhopper_max_day_c1_1990_2000 - leafhopper_min_day_c1_1990_2000" + basename=occ_duration_c1 \ + output=leafhopper_duration_c1_1990_2000 \ + expression="leafhopper_max_day_c1_1990_2000 - leafhopper_min_day_c1_1990_2000" # Extract the duration in days of the second cycle t.rast.aggregate input=leafhopper_occurrence_c2_1990_2000 gran="1 year" \ - output=leafhopper_min_day_c2_1990_2000 method=minimum basename=occ_min_day_c2 + output=leafhopper_min_day_c2_1990_2000 method=minimum basename=occ_min_day_c2 t.rast.aggregate input=leafhopper_occurrence_c2_1990_2000 gran="1 year" \ - output=leafhopper_max_day_c2_1990_2000 method=maximum basename=occ_max_day_c2 + output=leafhopper_max_day_c2_1990_2000 method=maximum basename=occ_max_day_c2 t.rast.mapcalc input=leafhopper_min_day_c2_1990_2000,leafhopper_max_day_c2_1990_2000 \ - basename=occ_duration_c2 \ - output=leafhopper_duration_c2_1990_2000 \ - expression="leafhopper_max_day_c2_1990_2000 - leafhopper_min_day_c2_1990_2000" + basename=occ_duration_c2 \ + output=leafhopper_duration_c2_1990_2000 \ + expression="leafhopper_max_day_c2_1990_2000 - leafhopper_min_day_c2_1990_2000" # Extract the duration in days of the third cycle t.rast.aggregate input=leafhopper_occurrence_c3_1990_2000 gran="1 year" \ - output=leafhopper_min_day_c3_1990_2000 method=minimum basename=occ_min_day_c3 + output=leafhopper_min_day_c3_1990_2000 method=minimum basename=occ_min_day_c3 t.rast.aggregate input=leafhopper_occurrence_c3_1990_2000 gran="1 year" \ - output=leafhopper_max_day_c3_1990_2000 method=maximum basename=occ_max_day_c3 + output=leafhopper_max_day_c3_1990_2000 method=maximum basename=occ_max_day_c3 t.rast.mapcalc input=leafhopper_min_day_c3_1990_2000,leafhopper_max_day_c3_1990_2000 \ - basename=occ_duration_c3 \ - output=leafhopper_duration_c3_1990_2000 \ - expression="leafhopper_max_day_c3_1990_2000 - leafhopper_min_day_c3_1990_2000" + basename=occ_duration_c3 \ + output=leafhopper_duration_c3_1990_2000 \ + expression="leafhopper_max_day_c3_1990_2000 - leafhopper_min_day_c3_1990_2000" t.rast.colors input=leafhopper_duration_c1_1990_2000 color=rainbow t.rast.colors input=leafhopper_duration_c2_1990_2000 color=rainbow @@ -212,35 +212,35 @@

    EXAMPLE

    # First cycle t.rast.aggregate input=leafhopper_indicator_c1_1990_2000 gran="1 month" \ - output=leafhopper_indi_min_month_c1_1990_2000 method=minimum basename=occ_indi_min_month_c1 + output=leafhopper_indi_min_month_c1_1990_2000 method=minimum basename=occ_indi_min_month_c1 t.rast.aggregate input=leafhopper_indicator_c1_1990_2000 gran="1 month" \ - output=leafhopper_indi_max_month_c1_1990_2000 method=maximum basename=occ_indi_max_month_c1 + output=leafhopper_indi_max_month_c1_1990_2000 method=maximum basename=occ_indi_max_month_c1 t.rast.mapcalc input=leafhopper_indi_min_month_c1_1990_2000,leafhopper_indi_max_month_c1_1990_2000 \ - basename=indicator_monthly_c1 \ - output=leafhopper_monthly_indicator_c1_1990_2000 \ - expression="if(leafhopper_indi_min_month_c1_1990_2000 == 1, 1, if(leafhopper_indi_max_month_c1_1990_2000 == 3, 3, 2))" + basename=indicator_monthly_c1 \ + output=leafhopper_monthly_indicator_c1_1990_2000 \ + expression="if(leafhopper_indi_min_month_c1_1990_2000 == 1, 1, if(leafhopper_indi_max_month_c1_1990_2000 == 3, 3, 2))" # Second cycle t.rast.aggregate input=leafhopper_indicator_c2_1990_2000 gran="1 month" \ - output=leafhopper_indi_min_month_c2_1990_2000 method=minimum basename=occ_indi_min_month_c2 + output=leafhopper_indi_min_month_c2_1990_2000 method=minimum basename=occ_indi_min_month_c2 t.rast.aggregate input=leafhopper_indicator_c2_1990_2000 gran="1 month" \ - output=leafhopper_indi_max_month_c2_1990_2000 method=maximum basename=occ_indi_max_month_c2 + output=leafhopper_indi_max_month_c2_1990_2000 method=maximum basename=occ_indi_max_month_c2 t.rast.mapcalc input=leafhopper_indi_min_month_c2_1990_2000,leafhopper_indi_max_month_c2_1990_2000 \ - basename=indicator_monthly_c2 \ - output=leafhopper_monthly_indicator_c2_1990_2000 \ - expression="if(leafhopper_indi_min_month_c2_1990_2000 == 1, 1, if(leafhopper_indi_max_month_c2_1990_2000 == 3, 3, 2))" + basename=indicator_monthly_c2 \ + output=leafhopper_monthly_indicator_c2_1990_2000 \ + expression="if(leafhopper_indi_min_month_c2_1990_2000 == 1, 1, if(leafhopper_indi_max_month_c2_1990_2000 == 3, 3, 2))" # Third cycle t.rast.aggregate input=leafhopper_indicator_c3_1990_2000 gran="1 month" \ - output=leafhopper_indi_min_month_c3_1990_2000 method=minimum basename=occ_indi_min_month_c3 + output=leafhopper_indi_min_month_c3_1990_2000 method=minimum basename=occ_indi_min_month_c3 t.rast.aggregate input=leafhopper_indicator_c3_1990_2000 gran="1 month" \ - output=leafhopper_indi_max_month_c3_1990_2000 method=maximum basename=occ_indi_max_month_c3 + output=leafhopper_indi_max_month_c3_1990_2000 method=maximum basename=occ_indi_max_month_c3 t.rast.mapcalc input=leafhopper_indi_min_month_c3_1990_2000,leafhopper_indi_max_month_c3_1990_2000 \ - basename=indicator_monthly_c3 \ - output=leafhopper_monthly_indicator_c3_1990_2000 \ - expression="if(leafhopper_indi_min_month_c3_1990_2000 == 1, 1, if(leafhopper_indi_max_month_c3_1990_2000 == 3, 3, 2))" + basename=indicator_monthly_c3 \ + output=leafhopper_monthly_indicator_c3_1990_2000 \ + expression="if(leafhopper_indi_min_month_c3_1990_2000 == 1, 1, if(leafhopper_indi_max_month_c3_1990_2000 == 3, 3, 2))" -cat > color.table << EOF +cat > color.table << EOF 3 red 2 yellow 1 green diff --git a/temporal/t.rast.accumulate/t.rast.accumulate.py b/temporal/t.rast.accumulate/t.rast.accumulate.py index 6fe067e02bc..d254d21c110 100644 --- a/temporal/t.rast.accumulate/t.rast.accumulate.py +++ b/temporal/t.rast.accumulate/t.rast.accumulate.py @@ -192,11 +192,7 @@ def main(): mapset = tgis.get_current_mapset() - if input.find("@") >= 0: - id = input - else: - id = input + "@" + mapset - + id = input if input.find("@") >= 0 else input + "@" + mapset input_strds = tgis.SpaceTimeRasterDataset(id) if not input_strds.is_in_db(): @@ -205,10 +201,7 @@ def main(): input_strds.select(dbif) - if output.find("@") >= 0: - out_id = output - else: - out_id = output + "@" + mapset + out_id = output if output.find("@") >= 0 else output + "@" + mapset # The output space time raster dataset output_strds = tgis.SpaceTimeRasterDataset(out_id) @@ -244,11 +237,7 @@ def main(): # The lower threshold space time raster dataset if lower: - - if lower.find("@") >= 0: - lower_id = lower - else: - lower_id = lower + "@" + mapset + lower_id = lower if lower.find("@") >= 0 else lower + "@" + mapset lower_strds = tgis.SpaceTimeRasterDataset(lower_id) if not lower_strds.is_in_db(): @@ -271,11 +260,7 @@ def main(): _("The upper option works only in conjunction with the lower option") ) - if upper.find("@") >= 0: - upper_id = upper - else: - upper_id = upper + "@" + mapset - + upper_id = upper if upper.find("@") >= 0 else upper + "@" + mapset upper_strds = tgis.SpaceTimeRasterDataset(upper_id) if not upper_strds.is_in_db(): dbif.close() @@ -293,17 +278,11 @@ def main(): if input_strds.is_time_absolute(): start = tgis.string_to_datetime(start) - if stop: - stop = tgis.string_to_datetime(stop) - else: - stop = input_strds_end + stop = tgis.string_to_datetime(stop) if stop else input_strds_end start = tgis.adjust_datetime_to_granularity(start, granularity) else: start = int(start) - if stop: - stop = int(stop) - else: - stop = input_strds_end + stop = int(stop) if stop else input_strds_end if input_strds.is_time_absolute(): end = tgis.increment_datetime_by_string(start, cycle) @@ -371,10 +350,7 @@ def main(): num_maps = len(gran_list) for i in range(num_maps): - if reverse: - map = gran_list[num_maps - i - 1] - else: - map = gran_list[i] + map = gran_list[num_maps - i - 1] if reverse else gran_list[i] # Select input maps based on temporal topology relations input_maps = [] if map.get_equal(): diff --git a/temporal/t.rast.accumulate/testsuite/test_accumulation.py b/temporal/t.rast.accumulate/testsuite/test_accumulation.py index f5bf6dcf5d7..6c277c320cf 100644 --- a/temporal/t.rast.accumulate/testsuite/test_accumulation.py +++ b/temporal/t.rast.accumulate/testsuite/test_accumulation.py @@ -12,7 +12,6 @@ import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestAccumulate(TestCase): @@ -95,9 +94,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): """Remove the temporary region""" - cls.runModule("t.remove", flags="df", type="strds", inputs="A") - cls.runModule("t.remove", flags="df", type="strds", inputs="Lower") - cls.runModule("t.remove", flags="df", type="strds", inputs="Upper") + cls.runModule("t.remove", flags="df", type="strds", inputs="A,Lower,Upper") cls.del_temp_region() def tearDown(self): diff --git a/temporal/t.rast.aggregate.ds/t.rast.aggregate.ds.html b/temporal/t.rast.aggregate.ds/t.rast.aggregate.ds.html index d7efc4a5bf0..b76274c76d3 100644 --- a/temporal/t.rast.aggregate.ds/t.rast.aggregate.ds.html +++ b/temporal/t.rast.aggregate.ds/t.rast.aggregate.ds.html @@ -42,7 +42,7 @@

    Precipitation aggregation

    for map in ${MAPS} ; do r.mapcalc expression="${map} = 1" - echo ${map} >> map_list.txt + echo ${map} >> map_list.txt done t.create type=strds temporaltype=absolute \ @@ -262,7 +262,7 @@

    MODIS satellite sensor daily data aggregation to 8 days

    # to a YYYY-MM-DD date for start and end, and create a file with # mapnames, start date and end date -g.list type=raster pattern=8day_20??_* > names_list +g.list type=raster pattern=8day_20??_* > names_list for NAME in `cat names_list` ; do @@ -277,10 +277,10 @@

    MODIS satellite sensor daily data aggregation to 8 days

    if [ $DOY -le "353" ] ; then doy_end=$(( $DOY + 8 )) elif [ $DOY -eq "361" ] ; then - if [ $[$YEAR % 4] -eq 0 ] && [ $[$YEAR % 100] -ne 0 ] || [ $[$YEAR % 400] -eq 0 ] ; then + if [ $[$YEAR % 4] -eq 0 ] && [ $[$YEAR % 100] -ne 0 ] || [ $[$YEAR % 400] -eq 0 ] ; then doy_end=$(( $DOY + 6 )) else - doy_end=$(( $DOY + 5 )) + doy_end=$(( $DOY + 5 )) fi fi @@ -288,7 +288,7 @@

    MODIS satellite sensor daily data aggregation to 8 days

    DATE_END=`date -d "${YEAR}-01-01 +$(( ${doy_end} -1 ))days" +%Y-%m-%d` # text file with mapnames, start date and end date - echo "$NAME|$DATE_START|$DATE_END" >> list_map_start_end_time.txt + echo "$NAME|$DATE_START|$DATE_END" >> list_map_start_end_time.txt done diff --git a/temporal/t.rast.aggregate/t.rast.aggregate.py b/temporal/t.rast.aggregate/t.rast.aggregate.py index 609d6d19d38..0675407794a 100755 --- a/temporal/t.rast.aggregate/t.rast.aggregate.py +++ b/temporal/t.rast.aggregate/t.rast.aggregate.py @@ -218,10 +218,7 @@ def main(): dbif, gs.overwrite(), ) - if register_null: - register_null = False - else: - register_null = True + register_null = not register_null tgis.register_map_object_list( "rast", diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py index 924e3950ca8..e7702ba23b5 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py index 2b56dd30615..5ad25e2e32c 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py @@ -11,7 +11,6 @@ import os from datetime import datetime -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py index 244b0d519d5..dc1da4c1cc3 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.algebra/t.rast.algebra.html b/temporal/t.rast.algebra/t.rast.algebra.html index 126ed5df9c2..1944d63baa3 100644 --- a/temporal/t.rast.algebra/t.rast.algebra.html +++ b/temporal/t.rast.algebra/t.rast.algebra.html @@ -230,11 +230,11 @@

    Logical operators

    == equal != not equal - > greater than - >= greater than or equal - < less than - <= less than or equal - && and + > greater than + >= greater than or equal + < less than + <= less than or equal + && and || or
    @@ -291,26 +291,26 @@

    Comparison operator

    aggregation operator: {"comparison operator", "topological relations", aggregation operator, "temporal operator"}
    -This aggregation operator (| or &) defines the behaviour when a map is +This aggregation operator (| or &) defines the behaviour when a map is related to more than one map, e.g. for the topological relation 'contains'. -Should all (&) conditions for the related maps be true or is it sufficient +Should all (&) conditions for the related maps be true or is it sufficient to have any (|) condition that is true. The resulting boolean value is -then compared to the first condition by the comparison operator (|| or &&). +then compared to the first condition by the comparison operator (|| or &&). By default, the aggregation operator is related to the comparison operator:
    -comparison operator -> aggregation operator: +comparison operator -> aggregation operator:
    -|| -> | and && -> &
    +|| -> | and && -> &
     
    Examples:
     Condition 1 {||, equal, r} Condition 2
    -Condition 1 {&&, equal|during, l} Condition 2
    -Condition 1 {&&, equal|contains, |, l} Condition 2
    -Condition 1 {&&, equal|during, l} Condition 2 && Condition 3
    -Condition 1 {&&, equal|during, l} Condition 2 {&&,contains, |, r} Condition 3
    +Condition 1 {&&, equal|during, l} Condition 2
    +Condition 1 {&&, equal|contains, |, l} Condition 2
    +Condition 1 {&&, equal|during, l} Condition 2 && Condition 3
    +Condition 1 {&&, equal|during, l} Condition 2 {&&,contains, |, r} Condition 3
     

    Hash operator

    @@ -328,7 +328,7 @@

    Hash operator

    maps from B will be returned.
    -C = if({equal}, A {#, contains} B > 2, A {:, contains} B)
    +C = if({equal}, A {#, contains} B > 2, A {:, contains} B)
     
    This expression selects all maps from A that temporally contain at least 2 @@ -434,13 +434,13 @@

    Combinations of temporal, raster and select operators

    a1 of A:
    - C = A {+, contains} B --> c1 = a1 + b1 + b2 + b3
    + C = A {+, contains} B --> c1 = a1 + b1 + b2 + b3
     

    Important: the aggregation behaviour is not symmetric

    - C = B {+, during} A --> c1 = b1 + a1
    + C = B {+, during} A --> c1 = b1 + a1
                              c2 = b2 + a1
                              c3 = b3 + a1
     
    @@ -497,7 +497,7 @@

    Sum of space-time raster datasets

    Sum maps from STRDS A with maps from STRDS B which have equal time stamps and are temporally before Jan. 1. 2005 and store them in STRDS D:
    -D = if(start_date(A) < "2005-01-01", A + B)
    +D = if(start_date(A) < "2005-01-01", A + B)
     
    Create the sum of all maps from STRDS A and B that have equal time stamps @@ -520,7 +520,7 @@

    Selection of raster cells

    the cells of A are in the range [100.0, 1600] of time intervals that have more than 30 days (Jan, Mar, May, Jul, Aug, Oct, Dec):
    -C = if(A > 100 && A < 1600 && td(A) > 30, B)
    +C = if(A > 100 && A < 1600 && td(A) > 30, B)
     

    Selection of raster cells with temporal topology relation

    @@ -528,7 +528,7 @@

    Selection of raster cells with temporal topology relation

    Same expression with explicit definition of the temporal topology relation and temporal operators:
    -C = if({equal}, A > 100 && A < 1600 {&&,equal} td(A) > 30, B)
    +C = if({equal}, A > 100 && A < 1600 {&&,equal} td(A) > 30, B)
     

    Conditional computation

    @@ -539,7 +539,7 @@

    Conditional computation

    equal time stamps. The number of days or fraction of days per interval is computed using the td() function that has as argument the STRDS "Prec":
    -C = if(Temp > 10.0, Prec / 3600.0 / 24.0 / td(Prec))
    +C = if(Temp > 10.0, Prec / 3600.0 / 24.0 / td(Prec))
     

    Conditional computation with temporal topology relation

    @@ -547,7 +547,7 @@

    Conditional computation with temporal topology relation

    Same expression with explicit definition of the temporal topology relation and temporal operators:
    -C = if({equal}, Temp > 10.0, Prec / 3600.0 / 24.0 {/,equal,l} td(Prec))
    +C = if({equal}, Temp > 10.0, Prec / 3600.0 / 24.0 {/,equal,l} td(Prec))
     

    Computation with time intervals

    @@ -555,7 +555,7 @@

    Computation with time intervals

    intervals of STRDS B if more than one map of A is contained in an interval of B, use A otherwise. The resulting time intervals are either from B or A:
    -C = if(B {#,contain} A > 1, (B {+,contain,l} A - B) / (B {#,contain} A), A)
    +C = if(B {#,contain} A > 1, (B {+,contain,l} A - B) / (B {#,contain} A), A)
     

    Computation with time intervals with temporal topology relation

    @@ -563,14 +563,14 @@

    Computation with time intervals with temporal topology relation

    Same expression with explicit definition of the temporal topology relation and temporal operators:
    -C = if({equal}, B {#,contain} A > 1, (B {+,contain,l} A {-,equal,l} B) {equal,=/} (B {#,contain} A), A)
    +C = if({equal}, B {#,contain} A > 1, (B {+,contain,l} A {-,equal,l} B) {equal,=/} (B {#,contain} A), A)
     

    Compute DOY for spatio-temporal conditions

    Compute the DOY for all maps from STRDS A where conditions are met at three -consecutive time intervals (e.g. temperature > 0): +consecutive time intervals (e.g. temperature > 0):
    -B = if(A > 0.0 && A[-1] > 0.0 && A[-2] > 0.0, start_doy(A, -1), 0)"
    +B = if(A > 0.0 && A[-1] > 0.0 && A[-2] > 0.0, start_doy(A, -1), 0)"
     
    @@ -608,10 +608,10 @@

    REFERENCES

    Related publications:
    • Gebbert, S., Pebesma, E. 2014. TGRASS: A temporal GIS for field based environmental modeling. - Environmental Modelling & Software 53, 1-12 (DOI) + Environmental Modelling & Software 53, 1-12 (DOI) - preprint PDF
    • Gebbert, S., Pebesma, E. 2017. The GRASS GIS temporal framework. International Journal of - Geographical Information Science 31, 1273-1292 (DOI)
    • + Geographical Information Science 31, 1273-1292 (DOI)
    • Gebbert, S., Leppelt, T., Pebesma, E., 2019. A topology based spatio-temporal map algebra for big data analysis. Data 4, 86. (DOI)
    diff --git a/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py b/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py index cf3d12a1aae..f07fabc9106 100644 --- a/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py +++ b/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py @@ -12,7 +12,6 @@ import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule from grass.gunittest.main import test diff --git a/temporal/t.rast.export/t.rast.export.py b/temporal/t.rast.export/t.rast.export.py index fdf19541ee4..48e0960ae25 100755 --- a/temporal/t.rast.export/t.rast.export.py +++ b/temporal/t.rast.export/t.rast.export.py @@ -115,13 +115,13 @@ def main(): import grass.temporal as tgis # Get the options - _input = options["input"] + input_ = options["input"] output = options["output"] compression = options["compression"] directory = options["directory"] where = options["where"] - _format = options["format"] - _type = options["type"] + format_ = options["format"] + type_ = options["type"] kws = { key: options[key] for key in ("createopt", "metaopt", "nodata") if options[key] } @@ -132,7 +132,7 @@ def main(): if not os.access(directory, os.W_OK): gs.fatal(_("Directory {} is not writable").format(directory)) - if _type and _format in {"pack", "AAIGrid"}: + if type_ and format_ in {"pack", "AAIGrid"}: gs.warning( _("Type options is not working with pack format, it will be skipped") ) @@ -148,7 +148,7 @@ def main(): tgis.init() # Export the space time raster dataset tgis.export_stds( - _input, output, compression, directory, where, _format, "strds", _type, **kws + input_, output, compression, directory, where, format_, "strds", type_, **kws ) diff --git a/temporal/t.rast.extract/t.rast.extract.html b/temporal/t.rast.extract/t.rast.extract.html index bc3b0b30f7c..1a3b6d84e5e 100644 --- a/temporal/t.rast.extract/t.rast.extract.html +++ b/temporal/t.rast.extract/t.rast.extract.html @@ -27,16 +27,13 @@

    NOTES

    -t.rast.extract input=tempmean_monthly where="start_time > '2010-01-05'" \
    -               output=selected_tempmean_monthly basename=new_tmean_month \
    -               expression="if(tempmean_monthly < 0, null(), tempmean_monthly)"
    -
    +t.rast.extract input=tempmean_monthly where="start_time > '2010-01-05'" output=selected_tempmean_monthly basename=new_tmean_month expression="if(tempmean_monthly < 0, null(), tempmean_monthly)" +

    EXAMPLE

    -t.rast.extract input=tempmean_monthly output=tempmean_monthly_later_2012 \
    -               where="start_time >= '2012-01-01'"
    +t.rast.extract input=tempmean_monthly output=tempmean_monthly_later_2012 where="start_time >= '2012-01-01'"
     
     t.rast.list tempmean_monthly_later_2012
     name|mapset|start_time|end_time
    diff --git a/temporal/t.rast.extract/testsuite/test_t_rast_extract.py b/temporal/t.rast.extract/testsuite/test_t_rast_extract.py
    index ca3c1a4c1db..b9fff4753c2 100644
    --- a/temporal/t.rast.extract/testsuite/test_t_rast_extract.py
    +++ b/temporal/t.rast.extract/testsuite/test_t_rast_extract.py
    @@ -8,9 +8,6 @@
     @author Soeren Gebbert
     """
     
    -import subprocess
    -
    -import grass.pygrass.modules as pymod
     from grass.gunittest.case import TestCase
     from grass.gunittest.gmodules import SimpleModule
     
    diff --git a/temporal/t.rast.gapfill/t.rast.gapfill.py b/temporal/t.rast.gapfill/t.rast.gapfill.py
    index 84395da6295..a4d3b3a8c95 100755
    --- a/temporal/t.rast.gapfill/t.rast.gapfill.py
    +++ b/temporal/t.rast.gapfill/t.rast.gapfill.py
    @@ -119,17 +119,17 @@ def main():
     
         # Identify all gaps and create new names
         count = 0
    -    for _map in maps:
    -        if _map.get_id() is None:
    +    for map_ in maps:
    +        if map_.get_id() is None:
                 count += 1
                 if sp.get_temporal_type() == "absolute" and tsuffix in {"gran", "time"}:
    -                _id = "{ba}@{ma}".format(ba=base, ma=mapset)
    +                id_ = "{ba}@{ma}".format(ba=base, ma=mapset)
                 else:
                     map_name = tgis.create_numeric_suffix(base, num + count, tsuffix)
    -                _id = "{name}@{ma}".format(name=map_name, ma=mapset)
    -            _map.set_id(_id)
    +                id_ = "{name}@{ma}".format(name=map_name, ma=mapset)
    +            map_.set_id(id_)
     
    -            gap_list.append(_map)
    +            gap_list.append(map_)
     
         if len(gap_list) == 0:
             gs.message(_("No gaps found"))
    @@ -140,16 +140,16 @@ def main():
         tb.build(maps)
     
         # Do some checks before computation
    -    for _map in gap_list:
    -        if not _map.get_precedes() or not _map.get_follows():
    +    for map_ in gap_list:
    +        if not map_.get_precedes() or not map_.get_follows():
                 gs.fatal(_("Unable to determine successor and predecessor of a gap."))
     
    -        if len(_map.get_precedes()) > 1:
    +        if len(map_.get_precedes()) > 1:
                 gs.warning(
                     _("More than one successor of the gap found. Using the first found.")
                 )
     
    -        if len(_map.get_follows()) > 1:
    +        if len(map_.get_follows()) > 1:
                 gs.warning(
                     _(
                         "More than one predecessor of the gap found. "
    @@ -160,9 +160,9 @@ def main():
         # Interpolate the maps using parallel processing
         result_list = []
     
    -    for _map in gap_list:
    -        predecessor = _map.get_follows()[0]
    -        successor = _map.get_precedes()[0]
    +    for map_ in gap_list:
    +        predecessor = map_.get_follows()[0]
    +        successor = map_.get_precedes()[0]
     
             gran = sp.get_granularity()
             tmpval, start = predecessor.get_temporal_extent_as_tuple()
    @@ -170,7 +170,7 @@ def main():
     
             # Now resample the gap
             map_matrix = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity(
    -            (_map,), start, end, gran
    +            (map_,), start, end, gran
             )
     
             map_names = []
    @@ -210,7 +210,7 @@ def main():
                                 "Map with name <%s> already exists. "
                                 "Please use another base name."
                             )
    -                        % (_id)
    +                        % (id_)
                         )
                     elif new_map.is_in_db(dbif):
                         overwrite_flags[new_id] = True
    @@ -235,24 +235,24 @@ def main():
         process_queue.wait()
     
         # Insert new interpolated maps in temporal database and dataset
    -    for _map in result_list:
    -        id = _map.get_id()
    +    for map_ in result_list:
    +        id = map_.get_id()
             if overwrite_flags[id]:
    -            if _map.is_time_absolute():
    -                start, end = _map.get_absolute_time()
    -                if _map.is_in_db():
    -                    _map.delete(dbif)
    -                _map = sp.get_new_map_instance(id)
    -                _map.set_absolute_time(start, end)
    +            if map_.is_time_absolute():
    +                start, end = map_.get_absolute_time()
    +                if map_.is_in_db():
    +                    map_.delete(dbif)
    +                map_ = sp.get_new_map_instance(id)
    +                map_.set_absolute_time(start, end)
                 else:
    -                start, end, unit = _map.get_relative_time()
    -                if _map.is_in_db():
    -                    _map.delete(dbif)
    -                _map = sp.get_new_map_instance(id)
    -                _map.set_relative_time(start, end, unit)
    -        _map.load()
    -        _map.insert(dbif)
    -        sp.register_map(_map, dbif)
    +                start, end, unit = map_.get_relative_time()
    +                if map_.is_in_db():
    +                    map_.delete(dbif)
    +                map_ = sp.get_new_map_instance(id)
    +                map_.set_relative_time(start, end, unit)
    +        map_.load()
    +        map_.insert(dbif)
    +        sp.register_map(map_, dbif)
     
         sp.update_from_registered_maps(dbif)
         sp.update_command_string(dbif=dbif)
    diff --git a/temporal/t.rast.gapfill/testsuite/test_gapfill.py b/temporal/t.rast.gapfill/testsuite/test_gapfill.py
    index 7b083617d08..bfc8f48f581 100644
    --- a/temporal/t.rast.gapfill/testsuite/test_gapfill.py
    +++ b/temporal/t.rast.gapfill/testsuite/test_gapfill.py
    @@ -8,8 +8,6 @@
     @author Soeren Gebbert
     """
     
    -import subprocess
    -
     from grass.gunittest.case import TestCase
     from grass.gunittest.gmodules import SimpleModule
     from grass.gunittest.utils import xfail_windows
    diff --git a/temporal/t.rast.mapcalc/t.rast.mapcalc.html b/temporal/t.rast.mapcalc/t.rast.mapcalc.html
    index c26f2e9c95a..afbe1d04422 100644
    --- a/temporal/t.rast.mapcalc/t.rast.mapcalc.html
    +++ b/temporal/t.rast.mapcalc/t.rast.mapcalc.html
    @@ -136,7 +136,7 @@ 

    EXAMPLES

     t.rast.mapcalc input=tempmean_monthly output=january_under_0 basename=january_under_0 \
    -    expression="if(start_month() == 1 && tempmean_monthly > 0, null(), tempmean_monthly)"
    +    expression="if(start_month() == 1 && tempmean_monthly > 0, null(), tempmean_monthly)"
     
     # print minimum and maximum only for January in the new strds
     t.rast.list january_under_0 columns=name,start_time,min,max | grep 01-01
    diff --git a/temporal/t.rast.neighbors/testsuite/test_neighbors.py b/temporal/t.rast.neighbors/testsuite/test_neighbors.py
    index 414b009fb1d..b48df4df169 100644
    --- a/temporal/t.rast.neighbors/testsuite/test_neighbors.py
    +++ b/temporal/t.rast.neighbors/testsuite/test_neighbors.py
    @@ -5,6 +5,7 @@
     """
     
     import os
    +
     import grass.temporal as tgis
     from grass.gunittest.case import TestCase
     from grass.gunittest.gmodules import SimpleModule
    diff --git a/temporal/t.rast.series/t.rast.series.html b/temporal/t.rast.series/t.rast.series.html
    index 494605cb294..9a1a09db512 100644
    --- a/temporal/t.rast.series/t.rast.series.html
    +++ b/temporal/t.rast.series/t.rast.series.html
    @@ -20,8 +20,7 @@ 

    NOTES

    will slow down processing, the user can set a higher limit with the file_limit parameter. Note that file_limit limit should not exceed the user-specific limit on open files set by your operating system. See the -Wiki +Wiki for more information.

    Performance

    @@ -49,7 +48,7 @@

    Estimate the average temperature for a subset of the time series

     t.rast.series input=tempmean_daily output=tempmean_season method=average \
    -  where="start_time >= '2012-06' and start_time <= '2012-08'"
    +  where="start_time >= '2012-06' and start_time <= '2012-08'"
     

    Climatology: single month in a multi-annual time series

    diff --git a/temporal/t.rast.series/testsuite/test_series.py b/temporal/t.rast.series/testsuite/test_series.py index 99fe69d4352..97df7c048fc 100644 --- a/temporal/t.rast.series/testsuite/test_series.py +++ b/temporal/t.rast.series/testsuite/test_series.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule @@ -61,11 +60,15 @@ def tearDownClass(cls): type="raster", maps="series_average,series_maximum,series_minimum,series_minimum_2", ) - cls.runModule("g.remove", flags="f", type="raster", name="series_average") - cls.runModule("g.remove", flags="f", type="raster", name="series_maximum") - cls.runModule("g.remove", flags="f", type="raster", name="series_minimum") - cls.runModule("g.remove", flags="f", type="raster", name="series_minimum_2") - cls.runModule("g.remove", flags="f", type="raster", name="series_quantile") + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=( + "series_average,series_maximum" + + ",series_minimum,series_minimum_2,series_quantile" + ), + ) def test_time_stamp(self): self.assertModule( @@ -206,10 +209,12 @@ def tearDownClass(cls): type="raster", maps="series_average,series_maximum,series_minimum,series_minimum_2", ) - cls.runModule("g.remove", flags="f", type="raster", name="series_average") - cls.runModule("g.remove", flags="f", type="raster", name="series_maximum") - cls.runModule("g.remove", flags="f", type="raster", name="series_minimum") - cls.runModule("g.remove", flags="f", type="raster", name="series_minimum_2") + cls.runModule( + "g.remove", + flags="f", + type="raster", + name="series_average,series_maximum,series_minimum,series_minimum_2", + ) def test_average(self): self.assertModule( diff --git a/temporal/t.rast.to.rast3/t.rast.to.rast3.html b/temporal/t.rast.to.rast3/t.rast.to.rast3.html index 778e4869c68..3ece18d6ef2 100644 --- a/temporal/t.rast.to.rast3/t.rast.to.rast3.html +++ b/temporal/t.rast.to.rast3/t.rast.to.rast3.html @@ -54,7 +54,7 @@

    EXAMPLE

     # create the subset for 2012 data
     t.rast.extract input=tempmean_monthly output=tempmean_monthly_later_2012 \
    -               where="start_time >= '2012-01-01'"
    +               where="start_time >= '2012-01-01'"
     
     # set the right 3D region
     g.region -p3 res3=500
    diff --git a/temporal/t.rast.to.rast3/t.rast.to.rast3.py b/temporal/t.rast.to.rast3/t.rast.to.rast3.py
    index 7776d7426ee..118e19549c6 100755
    --- a/temporal/t.rast.to.rast3/t.rast.to.rast3.py
    +++ b/temporal/t.rast.to.rast3/t.rast.to.rast3.py
    @@ -183,10 +183,7 @@ def main():
             gs.warning(_("%s failed to set units.") % "r3.support")
     
         # Register the space time voxel cube in the temporal GIS
    -    if output.find("@") >= 0:
    -        id = output
    -    else:
    -        id = output + "@" + mapset
    +    id = output if output.find("@") >= 0 else output + "@" + mapset
     
         start, end = sp.get_temporal_extent_as_tuple()
         r3ds = tgis.Raster3DDataset(id)
    diff --git a/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py b/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py
    index 3a6eb7d45cc..28853ecbff1 100644
    --- a/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py
    +++ b/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py
    @@ -8,11 +8,7 @@
     @author Soeren Gebbert
     """
     
    -import subprocess
    -
    -import grass.pygrass.modules as pymod
     from grass.gunittest.case import TestCase
    -from grass.gunittest.gmodules import SimpleModule
     
     
     class TestSTRDSToRast3(TestCase):
    diff --git a/temporal/t.rast.to.vect/testsuite/test_to_vect.py b/temporal/t.rast.to.vect/testsuite/test_to_vect.py
    index 2217b46a909..b429d8bf0dc 100644
    --- a/temporal/t.rast.to.vect/testsuite/test_to_vect.py
    +++ b/temporal/t.rast.to.vect/testsuite/test_to_vect.py
    @@ -8,8 +8,6 @@
     @author Soeren Gebbert
     """
     
    -import subprocess
    -
     from grass.gunittest.case import TestCase
     from grass.gunittest.gmodules import SimpleModule
     
    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 dca870d6a98..7bdfe9f7f6a 100644
    --- a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py
    +++ b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py
    @@ -9,6 +9,7 @@
     """
     
     from pathlib import Path
    +
     from grass.gunittest.case import TestCase
     from grass.gunittest.gmodules import SimpleModule
     from grass.gunittest.utils import xfail_windows
    @@ -147,8 +148,7 @@ def setUpClass(cls):
         @classmethod
         def tearDownClass(cls):
             """Remove the temporary region"""
    -        cls.runModule("t.remove", flags="df", type="strds", inputs="A")
    -        cls.runModule("t.remove", flags="df", type="strds", inputs="B")
    +        cls.runModule("t.remove", flags="df", type="strds", inputs="A,B")
             cls.runModule("g.remove", flags="f", type="raster", name="zones")
     
             cls.del_temp_region()
    @@ -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/temporal/t.rast.what/t.rast.what.html b/temporal/t.rast.what/t.rast.what.html
    index a6c112ebbb0..3bd5a6ebd8e 100644
    --- a/temporal/t.rast.what/t.rast.what.html
    +++ b/temporal/t.rast.what/t.rast.what.html
    @@ -109,7 +109,7 @@ 

    Example 2

    # using the where statement to select a subset of the STRDS # and stdout as output t.rast.what strds=A points=points \ - where="start_time >= '1990-03-01'" layout=timerow -n + where="start_time >= '1990-03-01'" layout=timerow -n x|y|1990-03-01 00:00:00;1990-04-01 00:00:00|1990-04-01 00:00:00;1990-05-01 00:00:00 115.004358627375|36.3593955782903|3|4 diff --git a/temporal/t.rast.what/t.rast.what.py b/temporal/t.rast.what/t.rast.what.py index b3cec73a538..24190a6a716 100755 --- a/temporal/t.rast.what/t.rast.what.py +++ b/temporal/t.rast.what/t.rast.what.py @@ -98,22 +98,6 @@ # % description: Use stdin as input and ignore coordinates and point option # %end -## Temporary disabled the r.what flags due to test issues -##%flag -##% key: f -##% description: Show the category labels of the grid cell(s) -##%end - -##%flag -##% key: r -##% description: Output color values as RRR:GGG:BBB -##%end - -##%flag -##% key: i -##% description: Output integer category values, not cell values -##%end - # %flag # % key: v # % description: Show the category for vector points map @@ -410,10 +394,7 @@ def one_point_per_row_output( for i in range(len(values)): start, end = map_list[i].get_temporal_extent_as_tuple() - if vcat: - cat_str = "{ca}{sep}".format(ca=cat, sep=separator) - else: - cat_str = "" + cat_str = "{ca}{sep}".format(ca=cat, sep=separator) if vcat else "" if site_input: coor_string = ( "%(x)10.10f%(sep)s%(y)10.10f%(sep)s%(site_name)s%(sep)s" @@ -480,10 +461,7 @@ def one_point_per_col_output( out_str = "start%(sep)send" % ({"sep": separator}) # Define different separator for coordinates and sites - if separator == ",": - coor_sep = ";" - else: - coor_sep = "," + coor_sep = ";" if separator == "," else "," for row in matrix: if vcat: @@ -517,10 +495,7 @@ def one_point_per_col_output( first = False - if vcat: - ncol = 4 - else: - ncol = 3 + ncol = 4 if vcat else 3 for col in range(num_cols - ncol): start, end = output_time_list[count][col].get_temporal_extent_as_tuple() time_string = "%(start)s%(sep)s%(end)s" % ( @@ -567,10 +542,7 @@ def one_point_per_timerow_output( if write_header: if first is True: - if vcat: - header = "cat{sep}".format(sep=separator) - else: - header = "" + header = "cat{sep}".format(sep=separator) if vcat else "" if site_input: header += "x%(sep)sy%(sep)ssite" % ({"sep": separator}) else: diff --git a/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py b/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py index 4f0d476e0e8..3ae010e8423 100644 --- a/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py +++ b/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py @@ -8,9 +8,6 @@ :authors: Soeren Gebbert """ -import subprocess - -import grass.pygrass.modules as pymod from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py index 4ca64e88442..21980921168 100644 --- a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py +++ b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py @@ -9,6 +9,7 @@ """ from pathlib import Path + from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule from grass.gunittest.utils import xfail_windows diff --git a/temporal/t.rename/t.rename.py b/temporal/t.rename/t.rename.py index a6aee79b790..a1f1a164fee 100755 --- a/temporal/t.rename/t.rename.py +++ b/temporal/t.rename/t.rename.py @@ -59,15 +59,8 @@ def main(): # Get the current mapset to create the id of the space time dataset mapset = gs.gisenv()["MAPSET"] - if input.find("@") >= 0: - old_id = input - else: - old_id = input + "@" + mapset - - if output.find("@") >= 0: - new_id = output - else: - new_id = output + "@" + mapset + old_id = input if input.find("@") >= 0 else input + "@" + mapset + new_id = output if output.find("@") >= 0 else output + "@" + mapset # Do not overwrite yourself if new_id == old_id: diff --git a/temporal/t.sample/t.sample.html b/temporal/t.sample/t.sample.html index 58cac201de9..14003800c15 100644 --- a/temporal/t.sample/t.sample.html +++ b/temporal/t.sample/t.sample.html @@ -57,7 +57,7 @@

    EXAMPLE

    n1=`g.tempfile pid=1 -d` n2=`g.tempfile pid=2 -d` -cat > "${n1}" << EOF +cat > "${n1}" << EOF a1 a2 a3 @@ -66,7 +66,7 @@

    EXAMPLE

    a6 EOF -cat > "${n2}" << EOF +cat > "${n2}" << EOF pnts1|2001-01-01|2001-03-01 pnts2|2001-05-01|2001-07-01 EOF diff --git a/temporal/t.select/t.select.html b/temporal/t.select/t.select.html index 0d64ce40a6e..04b74ff2b72 100644 --- a/temporal/t.select/t.select.html +++ b/temporal/t.select/t.select.html @@ -218,11 +218,11 @@

    Logical operators

    == equal != not equal - > greater than - >= greater than or equal - < less than - <= less than or equal - && and + > greater than + >= greater than or equal + < less than + <= less than or equal + && and || or
    @@ -272,23 +272,23 @@

    Comparison operator

    The structure is similar to the select operator with the extension of an aggregation operator: {"comparison operator", "topological relations", aggregation operator, "temporal operator"}
    -This aggregation operator (| or &) define the behaviour if a map is related the more +This aggregation operator (| or &) define the behaviour if a map is related the more than one map, e.g for the topological relations 'contains'. -Should all (&) conditions for the related maps be true or is it sufficient to +Should all (&) conditions for the related maps be true or is it sufficient to have any (|) condition that is true. The resulting boolean value is then compared -to the first condition by the comparison operator (|| or &&). +to the first condition by the comparison operator (|| or &&). As default the aggregation operator is related to the comparison operator:
    -Comparison operator -> aggregation operator: +Comparison operator -> aggregation operator:
    -|| -> | and && -> &
    +|| -> | and && -> &
     
    Examples:
     Condition 1 {||, equal, r} Condition 2
    -Condition 1 {&&, equal|during, l} Condition 2
    -Condition 1 {&&, equal|contains, |, l} Condition 2
    -Condition 1 {&&, equal|during, l} Condition 2 && Condition 3
    -Condition 1 {&&, equal|during, l} Condition 2 {&&,contains, |, r} Condition 3
    +Condition 1 {&&, equal|during, l} Condition 2
    +Condition 1 {&&, equal|contains, |, l} Condition 2
    +Condition 1 {&&, equal|during, l} Condition 2 && Condition 3
    +Condition 1 {&&, equal|during, l} Condition 2 {&&,contains, |, r} Condition 3
     

    Hash operator

    @@ -303,7 +303,7 @@

    Hash operator

    A list of integers (scalars) corresponding to the maps of A that contain maps from B will be returned.

    -C = if({equal}, A {#, contains} B > 2, A {:, contains} B)
    +C = if({equal}, A {#, contains} B > 2, A {:, contains} B)
     
    This expression selects all maps from A that temporally contains at least 2 maps from B and stores them in space time dataset C. The leading equal statement @@ -340,14 +340,14 @@

    EXAMPLES

    with space time dataset B and C and are earlier that Jan. 1. 2005 and store them in space time dataset D.
    -D = if(start_date(A) < "2005-01-01", A : B : C)
    +D = if(start_date(A) < "2005-01-01", A : B : C)
     
    Select all maps from space time dataset A which contains more than three maps of space time dataset B, else select maps from C with time stamps that are not equal to A and store them in space time dataset D.
    -D = if(A {#, contains} B > 3, A {:, contains} B, C)
    +D = if(A {#, contains} B > 3, A {:, contains} B, C)
     
    Select all maps from space time dataset B which are during the temporal diff --git a/temporal/t.shift/testsuite/test_shift.py b/temporal/t.shift/testsuite/test_shift.py index ea28e165995..3d55b059b4c 100644 --- a/temporal/t.shift/testsuite/test_shift.py +++ b/temporal/t.shift/testsuite/test_shift.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestShiftAbsoluteSTRDS(TestCase): diff --git a/temporal/t.snap/testsuite/test_snap.py b/temporal/t.snap/testsuite/test_snap.py index 36a71c420bf..e46e25c454d 100644 --- a/temporal/t.snap/testsuite/test_snap.py +++ b/temporal/t.snap/testsuite/test_snap.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSnapAbsoluteSTRDS(TestCase): diff --git a/temporal/t.support/testsuite/test_support_str3ds.py b/temporal/t.support/testsuite/test_support_str3ds.py index 928826dbd72..533a9649692 100644 --- a/temporal/t.support/testsuite/test_support_str3ds.py +++ b/temporal/t.support/testsuite/test_support_str3ds.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSupportAbsoluteSTR3DS(TestCase): diff --git a/temporal/t.support/testsuite/test_support_strds.py b/temporal/t.support/testsuite/test_support_strds.py index f5e9ac3aa29..397a4a5e88d 100644 --- a/temporal/t.support/testsuite/test_support_strds.py +++ b/temporal/t.support/testsuite/test_support_strds.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSupportAbsoluteSTRDS(TestCase): diff --git a/temporal/t.support/testsuite/test_support_stvds.py b/temporal/t.support/testsuite/test_support_stvds.py index 2b6e347dead..b7ecc1aee01 100644 --- a/temporal/t.support/testsuite/test_support_stvds.py +++ b/temporal/t.support/testsuite/test_support_stvds.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSupportAbsoluteSTVDS(TestCase): diff --git a/temporal/t.topology/t.topology.py b/temporal/t.topology/t.topology.py index 4356596f319..e9da9b369a7 100755 --- a/temporal/t.topology/t.topology.py +++ b/temporal/t.topology/t.topology.py @@ -74,10 +74,7 @@ def main(): spatial = None if spatio_temporal_relations: - if sp.get_type() == "strds": - spatial = "2D" - else: - spatial = "3D" + spatial = "2D" if sp.get_type() == "strds" else "3D" if temporal_relations or spatio_temporal_relations: sp.print_spatio_temporal_relationships(maps=maps, spatial=spatial) diff --git a/temporal/t.topology/test.t.topology.reltime.sh b/temporal/t.topology/test.t.topology.reltime.sh index 847289c4b2f..60e49355e9a 100755 --- a/temporal/t.topology/test.t.topology.reltime.sh +++ b/temporal/t.topology/test.t.topology.reltime.sh @@ -96,6 +96,5 @@ cat "${n5}" t.topology input=precip_rel_y t.topology -m input=precip_rel_y -t.remove type=strds input=precip_rel_d -t.remove type=strds input=precip_rel_y +t.remove type=strds input=precip_rel_d,precip_rel_y t.unregister type=raster file="${n1}" diff --git a/temporal/t.unregister/t.unregister.py b/temporal/t.unregister/t.unregister.py index b39b7b9819f..cacfe579a7b 100755 --- a/temporal/t.unregister/t.unregister.py +++ b/temporal/t.unregister/t.unregister.py @@ -93,12 +93,7 @@ def main(): # Map names as comma separated string if maps is not None and maps != "": - if maps.find(",") == -1: - maplist = [ - maps, - ] - else: - maplist = maps.split(",") + maplist = [maps] if maps.find(",") == -1 else maps.split(",") # Build the maplist for count in range(len(maplist)): diff --git a/temporal/t.unregister/testsuite/test_unregister.py b/temporal/t.unregister/testsuite/test_unregister.py index a32d33c1f32..b0102095e3d 100644 --- a/temporal/t.unregister/testsuite/test_unregister.py +++ b/temporal/t.unregister/testsuite/test_unregister.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.vect.algebra/t.vect.algebra.html b/temporal/t.vect.algebra/t.vect.algebra.html index 48931efa302..89453068a61 100644 --- a/temporal/t.vect.algebra/t.vect.algebra.html +++ b/temporal/t.vect.algebra/t.vect.algebra.html @@ -221,11 +221,11 @@

    Logical operators

    == equal != not equal - > greater than - >= greater than or equal - < less than - <= less than or equal - && and + > greater than + >= greater than or equal + < less than + <= less than or equal + && and || or
    @@ -280,27 +280,27 @@

    Comparison operator


    -This aggregation operator (| or &) define the behaviour if a map is related the more +This aggregation operator (| or &) define the behaviour if a map is related the more than one map, e.g for the topological relations 'contains'. -Should all (&) conditions for the related maps be true or is it sufficient to +Should all (&) conditions for the related maps be true or is it sufficient to have any (|) condition that is true. The resulting boolean value is then compared -to the first condition by the comparison operator (|| or &&). +to the first condition by the comparison operator (|| or &&). As default the aggregation operator is related to the comparison operator:
    Comparison operator -> aggregation operator:
    -|| -> | and && -> &
    +|| -> | and && -> &
     
    Examples:
     Condition 1 {||, equal, r} Condition 2
    -Condition 1 {&&, equal|during, l} Condition 2
    -Condition 1 {&&, equal|contains, |, l} Condition 2
    -Condition 1 {&&, equal|during, l} Condition 2 && Condition 3
    -Condition 1 {&&, equal|during, l} Condition 2 {&&,contains, |, r} Condition 3
    +Condition 1 {&&, equal|during, l} Condition 2
    +Condition 1 {&&, equal|contains, |, l} Condition 2
    +Condition 1 {&&, equal|during, l} Condition 2 && Condition 3
    +Condition 1 {&&, equal|during, l} Condition 2 {&&,contains, |, r} Condition 3
     

    Hash operator

    @@ -320,7 +320,7 @@

    Hash operator

    -C = if({equal}, A {#, contains} B > 2, A {:, contains} B)
    +C = if({equal}, A {#, contains} B > 2, A {:, contains} B)
     
    This expression selects all maps from A that temporally contains at least 2 @@ -365,7 +365,7 @@

    Spatial vector operators

      Boolean Name   Operator Meaning         Precedence   Correspondent function
     ----------------------------------------------------------------------------------
    - AND            &        Intersection          1      (v.overlay operator=and)
    + AND            &        Intersection          1      (v.overlay operator=and)
      OR             |        Union                 1      (v.overlay operator=or)
      DISJOINT OR    +        Disjoint union        1      (v.patch)
      XOR            ^        Symmetric difference  1      (v.overlay operator=xor)
    @@ -402,15 +402,15 @@ 

    Combinations of temporal, vector and select operators

    a1 of A:
    -C = A {&, contains} B --> c1 = a1 & b1 & b2 & b3
    +C = A {&, contains} B --> c1 = a1 & b1 & b2 & b3
     
    Keep attention that the aggregation behaviour is not symmetric:
    -C = B {&, during} A --> c1 = b1 & a1
    -                        c2 = b2 & a1
    -                        c3 = b3 & a1
    +C = B {&, during} A --> c1 = b1 & a1
    +                        c2 = b2 & a1
    +                        c3 = b3 & a1
     

    Examples:

    @@ -420,7 +420,7 @@

    Examples:

    temporary before Jan. 1. 2005 and store them in space time dataset D.
    -D = if(start_date(A) < "2005-01-01", A & B)
    +D = if(start_date(A) < "2005-01-01", A & B)
     
    Buffer all vector points from space time vector dataset A and B with a @@ -429,7 +429,7 @@

    Examples:

    vector dataset D with intersected time stamps.
    -D = buff_p(A, 1) {&,overlaps|overlapped|equal|during|contains,i} buff_p(B, 1)
    +D = buff_p(A, 1) {&,overlaps|overlapped|equal|during|contains,i} buff_p(B, 1)
     
    Select all maps from space time dataset B which are during the temporal diff --git a/temporal/t.vect.db.select/t.vect.db.select.html b/temporal/t.vect.db.select/t.vect.db.select.html index 939c0d49c41..17b12b861e7 100644 --- a/temporal/t.vect.db.select/t.vect.db.select.html +++ b/temporal/t.vect.db.select/t.vect.db.select.html @@ -26,7 +26,7 @@

    EXAMPLE

    before 1900-01-01.
    -t.vect.db.select input=shoreline column=DATE,SOURCE t_where="start_time < 1900"
    +t.vect.db.select input=shoreline column=DATE,SOURCE t_where="start_time < 1900"
     start_time|end_time|DATE|SOURCE
     1849|1873|01/01/1858|NOAA/USGS
     1849|1873|01/01/1857|NOAA/USGS
    diff --git a/temporal/t.vect.export/t.vect.export.py b/temporal/t.vect.export/t.vect.export.py
    index d440f41d184..72004125af6 100755
    --- a/temporal/t.vect.export/t.vect.export.py
    +++ b/temporal/t.vect.export/t.vect.export.py
    @@ -75,17 +75,17 @@ def main():
         import grass.temporal as tgis
     
         # Get the options
    -    _input = options["input"]
    +    input_ = options["input"]
         output = options["output"]
         compression = options["compression"]
         directory = options["directory"]
         where = options["where"]
    -    _format = options["format"]
    +    format_ = options["format"]
     
         # Make sure the temporal database exists
         tgis.init()
         # Export the space time vector dataset
    -    tgis.export_stds(_input, output, compression, directory, where, _format, "stvds")
    +    tgis.export_stds(input_, output, compression, directory, where, format_, "stvds")
     
     
     ############################################################################
    diff --git a/temporal/t.vect.extract/t.vect.extract.html b/temporal/t.vect.extract/t.vect.extract.html
    index 6de3552d67d..c6b7716cf02 100644
    --- a/temporal/t.vect.extract/t.vect.extract.html
    +++ b/temporal/t.vect.extract/t.vect.extract.html
    @@ -10,7 +10,7 @@ 

    EXAMPLE

    with all the data later than 2000:
    -t.vect.extract input=shoreline where="start_time > 2000" \
    +t.vect.extract input=shoreline where="start_time > 2000" \
                    output=shoreline_later_2000 basename=new_shoreline
     
     t.info shoreline_later_2000@shoreline type=stvds
    @@ -61,7 +61,7 @@ 

    EXAMPLE

    | Command history: | # 2014-11-29 08:43:50 | t.vect.extract input="shoreline" - | where="start_time > 2000" output="shoreline_later_2000" + | where="start_time > 2000" output="shoreline_later_2000" | basename="new_shoreline" | # 2014-11-29 08:44:14 | t.support type="stvds" diff --git a/temporal/t.vect.extract/test.t.vect.extract.sh b/temporal/t.vect.extract/test.t.vect.extract.sh index b5cd6882e94..8b176dcc8ed 100755 --- a/temporal/t.vect.extract/test.t.vect.extract.sh +++ b/temporal/t.vect.extract/test.t.vect.extract.sh @@ -44,5 +44,4 @@ t.vect.list input=soil_abs3 columns=name,start_time,end_time,primitives # @postprocess t.unregister type=vector maps=soil_1,soil_2,soil_3,soil_4,soil_5,soil_6,soil_7,soil_8 t.remove type=stvds input=soil_abs1,soil_abs2,soil_abs3 -g.remove -f type=vector name=soil_1,soil_2,soil_3,soil_4,soil_5,soil_6,soil_7,soil_8 -g.remove -f type=vector name=new_vect_1,new_vect_2,new_vect_3,new_vect_4,new_vect_5,new_vect_6 +g.remove -f type=vector name=soil_1,soil_2,soil_3,soil_4,soil_5,soil_6,soil_7,soil_8,new_vect_1,new_vect_2,new_vect_3,new_vect_4,new_vect_5,new_vect_6 diff --git a/temporal/t.vect.observe.strds/t.vect.observe.strds.py b/temporal/t.vect.observe.strds/t.vect.observe.strds.py index 9c60a3d026c..7e9ac225890 100755 --- a/temporal/t.vect.observe.strds/t.vect.observe.strds.py +++ b/temporal/t.vect.observe.strds/t.vect.observe.strds.py @@ -185,8 +185,7 @@ def main(): if name is None: isvalid = False break - else: - mapname_list.append(name) + mapname_list.append(name) if isvalid: entry = mapmatrizes[0][i] @@ -202,11 +201,8 @@ def main(): vector_db = gs.vector.vector_db(input) # We copy the vector table and create the new layers - if vector_db: - # Use the first layer to copy the categories from - layers = "1," - else: - layers = "" + # If vector_db, use the first layer to copy the categories from + layers = "1," if vector_db else "" first = True for layer in range(num_samples): layer += 1 diff --git a/temporal/t.vect.univar/t.vect.univar.html b/temporal/t.vect.univar/t.vect.univar.html index 2e747567b0a..36015d9396c 100644 --- a/temporal/t.vect.univar/t.vect.univar.html +++ b/temporal/t.vect.univar/t.vect.univar.html @@ -5,7 +5,7 @@

    DESCRIPTION

    EXAMPLE

    -The example is based on the t.vect.observe.strds +The example is based on the t.vect.observe.strds example; so create the precip_stations space time vector dataset and after run the following command: diff --git a/temporal/t.vect.what.strds/t.vect.what.strds.py b/temporal/t.vect.what.strds/t.vect.what.strds.py index 6ea36e79579..b1f2c17a9c6 100755 --- a/temporal/t.vect.what.strds/t.vect.what.strds.py +++ b/temporal/t.vect.what.strds/t.vect.what.strds.py @@ -158,12 +158,9 @@ def main(): raster_maps = (new_map.get_id(),) for rastermap in raster_maps: - if column: - col_name = column - else: - # Create a new column with the SQL compliant - # name of the sampled raster map - col_name = rastermap.split("@")[0].replace(".", "_") + # Create a new column with the SQL compliant + # name of the sampled raster map if not column + col_name = column or rastermap.split("@")[0].replace(".", "_") coltype = "DOUBLE PRECISION" # Get raster type diff --git a/temporal/temporalintro.html b/temporal/temporalintro.html index c5eca6ead2c..c52b4e2057e 100644 --- a/temporal/temporalintro.html +++ b/temporal/temporalintro.html @@ -6,13 +6,13 @@
    • Space time raster datasets (strds) are designed to manage raster map time series. Modules that process strds have the - naming prefix t.rast. + naming prefix t.rast.
    • Space time 3D raster datasets (str3ds) are designed to manage 3D raster map time series. Modules that process str3ds have - the naming prefix t.rast3d. + the naming prefix t.rast3d.
    • Space time vector datasets (stvds) are designed to manage vector map time series. Modules that process stvds have the - naming prefix t.vect. + naming prefix t.vect.
    These new data types can be managed, analyzed and processed with @@ -35,9 +35,9 @@

    Temporal data management in general

    map. This is critical if:
    • The user has no write access to the maps from other mapsets - he/she wants to register
    • + he/she wants to register
    • If registered maps are removed from other mapsets, the temporal - database will not be updated and will contain ghost maps
    • + database will not be updated and will contain ghost maps
    SQLite3 or PostgreSQL are supported as temporal database backends. @@ -262,22 +262,32 @@

    See also

    + + diff --git a/utils/Makefile b/utils/Makefile index fdff52b8e3d..8137e1b7e63 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -5,13 +5,19 @@ SUBDIRS = timer g.html2man include $(MODULE_TOPDIR)/include/Make/Dir.make include $(MODULE_TOPDIR)/include/Make/Compile.make -default: parsubdirs $(UTILSDIR)/mkhtml.py \ +default: parsubdirs $(UTILSDIR)/mkdocs.py $(UTILSDIR)/mkhtml.py $(UTILSDIR)/mkmarkdown.py \ $(UTILSDIR)/generate_last_commit_file.py \ $(UTILSDIR)/g.echo$(EXE) +$(UTILSDIR)/mkdocs.py: mkdocs.py + $(INSTALL) $< $@ + $(UTILSDIR)/mkhtml.py: mkhtml.py $(INSTALL) $< $@ +$(UTILSDIR)/mkmarkdown.py: mkmarkdown.py + $(INSTALL) $< $@ + $(UTILSDIR)/generate_last_commit_file.py: generate_last_commit_file.py $(INSTALL) $< $@ diff --git a/utils/dep_tree2sql.sh b/utils/dep_tree2sql.sh index 176924fc382..99f061f86f4 100755 --- a/utils/dep_tree2sql.sh +++ b/utils/dep_tree2sql.sh @@ -36,28 +36,28 @@ # # You can then use simple queries such as: # -# grass=> SELECT object FROM obj_imp WHERE symbol = 'I_get_target' ; -# object -# -------------------------------------------------------------------- -# imagery/i.ortho.photo/photo.2image/OBJ.i686-pc-linux-gnu/target.o -# imagery/i.ortho.photo/photo.2target/OBJ.i686-pc-linux-gnu/target.o -# imagery/i.ortho.photo/photo.elev/OBJ.i686-pc-linux-gnu/main.o -# imagery/i.ortho.photo/photo.rectify/OBJ.i686-pc-linux-gnu/target.o -# imagery/i.ortho.photo/photo.target/OBJ.i686-pc-linux-gnu/main.o -# imagery/i.rectify/OBJ.i686-pc-linux-gnu/target.o +# grass=> SELECT object FROM obj_imp WHERE symbol = 'I_get_target' ; +# object +# -------------------------------------------------------------------- +# imagery/i.ortho.photo/photo.2image/OBJ.i686-pc-linux-gnu/target.o +# imagery/i.ortho.photo/photo.2target/OBJ.i686-pc-linux-gnu/target.o +# imagery/i.ortho.photo/photo.elev/OBJ.i686-pc-linux-gnu/main.o +# imagery/i.ortho.photo/photo.rectify/OBJ.i686-pc-linux-gnu/target.o +# imagery/i.ortho.photo/photo.target/OBJ.i686-pc-linux-gnu/main.o +# imagery/i.rectify/OBJ.i686-pc-linux-gnu/target.o # # to discover which files import a given symbol, or more complex queries # such as: # -# grass=> SELECT DISTINCT b.object FROM lib_exp a, obj_imp b -# grass-> WHERE a.library = 'libgrass_form.6.1.cvs.so' AND a.symbol = b.symbol ; -# object -# ----------------------------------------------------------- -# vector/v.digit/OBJ.i686-pc-linux-gnu/attr.o -# vector/v.digit/OBJ.i686-pc-linux-gnu/line.o -# vector/v.what/OBJ.i686-pc-linux-gnu/what.o -# visualization/nviz/src/OBJ.i686-pc-linux-gnu/query_vect.o -# (5 rows) +# grass=> SELECT DISTINCT b.object FROM lib_exp a, obj_imp b +# grass-> WHERE a.library = 'libgrass_form.6.1.cvs.so' AND a.symbol = b.symbol ; +# object +# ----------------------------------------------------------- +# vector/v.digit/OBJ.i686-pc-linux-gnu/attr.o +# vector/v.digit/OBJ.i686-pc-linux-gnu/line.o +# vector/v.what/OBJ.i686-pc-linux-gnu/what.o +# visualization/nviz/src/OBJ.i686-pc-linux-gnu/query_vect.o +# (5 rows) # # to discover which files import any symbol defined in a specific # library. And so on. @@ -71,111 +71,112 @@ # easiest way to figure out what is in a given table (apart from looking # at the name) is to just sample it, e.g.: # -# grass=> SELECT * FROM stlib_exp LIMIT 5 ; -# library | object | symbol -# -------------------+------------+--------------- -# libgrass_manage.a | add_elem.o | add_element -# libgrass_manage.a | ask.o | ask_in_mapset -# libgrass_manage.a | ask.o | ask_new -# libgrass_manage.a | ask.o | ask_old -# libgrass_manage.a | copyfile.o | copyfile -# (5 rows) +# grass=> SELECT * FROM stlib_exp LIMIT 5 ; +# library | object | symbol +# -------------------+------------+--------------- +# libgrass_manage.a | add_elem.o | add_element +# libgrass_manage.a | ask.o | ask_in_mapset +# libgrass_manage.a | ask.o | ask_new +# libgrass_manage.a | ask.o | ask_old +# libgrass_manage.a | copyfile.o | copyfile +# (5 rows) # tmpdir=/tmp/sql-grass dbname=grass if [ -n "$1" ]; then - builddir="$1" + builddir="$1" else - echo "Usage: del_tree2sql.sh " >&2 - exit 1 + echo "Usage: del_tree2sql.sh " >&2 + exit 1 fi rm -rf "$tmpdir" mkdir -m 711 "$tmpdir" || exit 1 -cd $builddir +cd "$builddir" || exit 1 -( cd dist.* +( + cd dist.* || exit 1 -#LD_LIBRARY_PATH=`pwd`/lib -#export LD_LIBRARY_PATH + #LD_LIBRARY_PATH=`pwd`/lib + #export LD_LIBRARY_PATH -find . -type f -perm +111 \! -name '*.so.*' \ - | while read file ; do ldd $file | sed 's!^!'$file'!' ; done 2>/dev/null \ - | sed -e 's/^\.\///' -e 's/ (0x.*)$//' -e 's/ => \(.*\)$/ \1/' -e 's/ => .*$//' \ - | fgrep -v 'not a dynamic executable' \ - | awk -vOFS='\t' '{print $1,$2,$3 ? $3 : $2}' \ - > "$tmpdir/ldd.lst" + find . -type f -perm /a+x \! -name '*.so.*' \ + | while read -r file; do ldd "$file" | sed 's!^!'"$file"'!'; done 2> /dev/null \ + | sed -e 's/^\.\///' -e 's/ (0x.*)$//' -e 's/ => \(.*\)$/ \1/' -e 's/ => .*$//' \ + | grep -F -v 'not a dynamic executable' \ + | awk -vOFS='\t' '{print $1,$2,$3 ? $3 : $2}' \ + > "$tmpdir/ldd.lst" -find . -type f -perm +111 \! -name '*.so' \ - | xargs nm -AD 2>/dev/null \ - | egrep ': {8}{1,2} U ' \ - | sed -e 's/:/ /g' -e 's/\.\///' \ - | awk -vOFS='\t' '{print $1,$3}' \ - > "$tmpdir/prog_imp.lst" + find . -type f -perm /a+x \! -name '*.so' -print0 \ + | xargs -0 nm -AD 2> /dev/null \ + | grep -E ': {8}{1,2} U ' \ + | sed -e 's/:/ /g' -e 's/\.\///' \ + | awk -vOFS='\t' '{print $1,$3}' \ + > "$tmpdir/prog_imp.lst" -find . -type f -perm +111 \! -name '*.so' \ - | xargs nm -AD 2>/dev/null \ - | egrep ':[0-9a-f]{8}{1,2} [BCDGRSTW] ' \ - | sed -e 's/:/ /g' -e 's/\.\///' \ - | awk -vOFS='\t' '{print $1,$4}' \ - > "$tmpdir/prog_exp.lst" + find . -type f -perm /a+x \! -name '*.so' -print0 \ + | xargs -0 nm -AD 2> /dev/null \ + | grep -E ':[0-9a-f]{8}{1,2} [BCDGRSTW] ' \ + | sed -e 's/:/ /g' -e 's/\.\///' \ + | awk -vOFS='\t' '{print $1,$4}' \ + > "$tmpdir/prog_exp.lst" ) -find * -type f -name 'lib?*.a' \ - | xargs nm -A \ - | egrep ':[0-9a-f]{8}{1,2} [BCDGRSTW] ' \ - | sed 's/:/ /g' \ - | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$2,$5}' \ - > "$tmpdir/stlib_exp.lst" - -find * -type f -name 'lib?*.so' \ - | xargs nm -AD \ - | egrep ':[0-9a-f]{8}{1,2} [BCDGRSTW] ' \ - | sed 's/:/ /g' \ - | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$4}' \ - > "$tmpdir/shlib_exp.lst" - -find * -type f -name '*.o' \ - | xargs nm -A \ - | egrep ':[0-9a-f]{8}{1,2} [BCDGRSTW] ' \ - | sed 's/:/ /g' \ - | awk -vOFS='\t' '{print $1,$4}' \ - > "$tmpdir/obj_exp.lst" - -find * -type f -name 'lib?*.a' \ - | xargs nm -A \ - | egrep ': {8}{1,2} U ' \ - | sed 's/:/ /g' \ - | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$2,$4}' \ - > "$tmpdir/stlib_imp.lst" - -find * -type f -name 'lib?*.so' \ - | xargs nm -AD \ - | egrep ': {8}{1,2} U ' \ - | sed 's/:/ /g' \ - | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$3}' \ - > "$tmpdir/shlib_imp.lst" - -find * -type f -name '*.o' \ - | xargs nm -A \ - | egrep ': {8}{1,2} U ' \ - | sed 's/:/ /g' \ - | awk -vOFS='\t' '{print $1,$3}' \ - > "$tmpdir/obj_imp.lst" - -libs=`awk '{print $3}' "$tmpdir/ldd.lst" | uniq | sort | uniq` - -nm -AD $libs \ - | egrep ':[0-9a-f]{8}{1,2} [TWDRC] ' \ - | sed 's/:/ /g' \ - | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$4}' \ - > "$tmpdir/libs.lst" - -cat > "$tmpdir/ansi.lst" < "$tmpdir/stlib_exp.lst" + +find ./* -type f -name 'lib?*.so' -print0 \ + | xargs -0 nm -AD \ + | grep -E ':[0-9a-f]{8}{1,2} [BCDGRSTW] ' \ + | sed 's/:/ /g' \ + | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$4}' \ + > "$tmpdir/shlib_exp.lst" + +find ./* -type f -name '*.o' -print0 \ + | xargs -0 nm -A \ + | grep -E ':[0-9a-f]{8}{1,2} [BCDGRSTW] ' \ + | sed 's/:/ /g' \ + | awk -vOFS='\t' '{print $1,$4}' \ + > "$tmpdir/obj_exp.lst" + +find ./* -type f -name 'lib?*.a' -print0 \ + | xargs -0 nm -A \ + | grep -E ': {8}{1,2} U ' \ + | sed 's/:/ /g' \ + | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$2,$4}' \ + > "$tmpdir/stlib_imp.lst" + +find ./* -type f -name 'lib?*.so' -print0 \ + | xargs -0 nm -AD \ + | grep -E ': {8}{1,2} U ' \ + | sed 's/:/ /g' \ + | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$3}' \ + > "$tmpdir/shlib_imp.lst" + +find ./* -type f -name '*.o' -print0 \ + | xargs -0 nm -A \ + | grep -E ': {8}{1,2} U ' \ + | sed 's/:/ /g' \ + | awk -vOFS='\t' '{print $1,$3}' \ + > "$tmpdir/obj_imp.lst" + +mapfile -t libs < <(awk '{print $3}' "$tmpdir/ldd.lst" | uniq | sort | uniq) + +nm -AD "${libs[@]}" \ + | grep -E ':[0-9a-f]{8}{1,2} [TWDRC] ' \ + | sed 's/:/ /g' \ + | awk -vOFS='\t' '{print gensub("^[^ ]*/","",1,$1),$4}' \ + > "$tmpdir/libs.lst" + +cat > "$tmpdir/ansi.lst" << EOF abort asctime atexit @@ -278,199 +279,199 @@ fsetpos64 tmpfile64 EOF -dropdb "$dbname" +dropdb --if-exists "$dbname" createdb "$dbname" -psql -n -q -d "$dbname" < 1 ; + SELECT DISTINCT symbol + FROM lib_exp + GROUP BY symbol + HAVING COUNT(*) > 1 ; CREATE TABLE duplicates2 AS - SELECT * - FROM lib_exp - WHERE symbol IN ( - SELECT symbol - FROM duplicates - ) ; + SELECT * + FROM lib_exp + WHERE symbol IN ( + SELECT symbol + FROM duplicates + ) ; SELECT DISTINCT library, symbol - INTO TABLE lib_imp - FROM stlib_imp + INTO TABLE lib_imp + FROM stlib_imp UNION SELECT DISTINCT library, symbol - FROM shlib_imp ; + FROM shlib_imp ; CREATE TABLE imports AS - SELECT a.library, a.symbol - FROM lib_imp a - WHERE NOT EXISTS ( - SELECT b.library, b.symbol - FROM lib_exp b - WHERE b.symbol = a.symbol - AND b.library = a.library - ) ; + SELECT a.library, a.symbol + FROM lib_imp a + WHERE NOT EXISTS ( + SELECT b.library, b.symbol + FROM lib_exp b + WHERE b.symbol = a.symbol + AND b.library = a.library + ) ; CREATE TABLE defined AS - SELECT DISTINCT symbol - FROM lib_exp ; + SELECT DISTINCT symbol + FROM lib_exp ; CREATE TABLE used AS - SELECT DISTINCT symbol - FROM imports ; + SELECT DISTINCT symbol + FROM imports ; CREATE TABLE undefined AS - SELECT symbol - FROM used u - WHERE NOT EXISTS ( - SELECT * - FROM defined d - WHERE d.symbol = u.symbol - ) ; + SELECT symbol + FROM used u + WHERE NOT EXISTS ( + SELECT * + FROM defined d + WHERE d.symbol = u.symbol + ) ; SELECT symbol INTO TABLE undefined_1 - FROM undefined + FROM undefined EXCEPT SELECT b.symbol - FROM undefined a, libs b - WHERE a.symbol = b.symbol ; + FROM undefined a, libs b + WHERE a.symbol = b.symbol ; CREATE TABLE undefined_2 AS - SELECT i.symbol, i.object, i.library - FROM stlib_imp i, undefined_1 u - WHERE i.symbol = u.symbol ; + SELECT i.symbol, i.object, i.library + FROM stlib_imp i, undefined_1 u + WHERE i.symbol = u.symbol ; CREATE TABLE depends AS - SELECT i.library AS im_lib, - i.symbol AS symbol, - e.library AS ex_lib - FROM imports i, lib_exp e - WHERE i.symbol = e.symbol ; + SELECT i.library AS im_lib, + i.symbol AS symbol, + e.library AS ex_lib + FROM imports i, lib_exp e + WHERE i.symbol = e.symbol ; CREATE TABLE lib_deps AS - SELECT DISTINCT im_lib, ex_lib - FROM depends - WHERE im_lib <> ex_lib ; + SELECT DISTINCT im_lib, ex_lib + FROM depends + WHERE im_lib <> ex_lib ; CREATE TABLE lib_deps_1 AS - SELECT a.im_lib, - a.ex_lib AS in_lib, - b.ex_lib - FROM lib_deps a, lib_deps b - WHERE a.ex_lib = b.im_lib ; + SELECT a.im_lib, + a.ex_lib AS in_lib, + b.ex_lib + FROM lib_deps a, lib_deps b + WHERE a.ex_lib = b.im_lib ; CREATE TABLE lib_deps_2 AS - SELECT a.im_lib, - a.in_lib AS in1_lib, - a.ex_lib AS in2_lib, - b.ex_lib - FROM lib_deps_1 a, lib_deps b - WHERE a.ex_lib = b.im_lib - AND a.im_lib <> a.ex_lib ; + SELECT a.im_lib, + a.in_lib AS in1_lib, + a.ex_lib AS in2_lib, + b.ex_lib + FROM lib_deps_1 a, lib_deps b + WHERE a.ex_lib = b.im_lib + AND a.im_lib <> a.ex_lib ; SELECT im_lib, ex_lib INTO TABLE lib_deps_trans - FROM lib_deps + FROM lib_deps UNION SELECT im_lib, ex_lib - FROM lib_deps_1 + FROM lib_deps_1 UNION SELECT im_lib, ex_lib - FROM lib_deps_2 ; + FROM lib_deps_2 ; CREATE TABLE prog_libs AS SELECT DISTINCT a.program, b.library @@ -479,92 +480,92 @@ WHERE a.symbol = b.symbol ; SELECT DISTINCT a.symbol INTO TABLE libc - FROM prog_imp a, libs b - WHERE a.symbol = b.symbol - AND b.library = 'libc.so.6' + FROM prog_imp a, libs b + WHERE a.symbol = b.symbol + AND b.library = 'libc.so.6' UNION - SELECT DISTINCT a.symbol - FROM imports a, libs b - WHERE a.symbol = b.symbol - AND b.library = 'libc.so.6' ; + SELECT DISTINCT a.symbol + FROM imports a, libs b + WHERE a.symbol = b.symbol + AND b.library = 'libc.so.6' ; SELECT symbol INTO nonansi - FROM libc - WHERE symbol !~ '_.*' + FROM libc + WHERE symbol !~ '_.*' EXCEPT SELECT symbol - FROM ansi ; + FROM ansi ; CREATE TABLE nonansi_progs AS - SELECT a.program, a.symbol - FROM prog_imp a, nonansi b - WHERE a.symbol = b.symbol ; + SELECT a.program, a.symbol + FROM prog_imp a, nonansi b + WHERE a.symbol = b.symbol ; CREATE TABLE nonansi_libs AS - SELECT a.library, a.symbol - FROM imports a, nonansi b - WHERE a.symbol = b.symbol ; + SELECT a.library, a.symbol + FROM imports a, nonansi b + WHERE a.symbol = b.symbol ; CREATE TABLE nonansi_prog_counts AS - SELECT symbol, COUNT(*) - FROM nonansi_progs - GROUP BY symbol ; + SELECT symbol, COUNT(*) + FROM nonansi_progs + GROUP BY symbol ; CREATE TABLE nonansi_lib_counts AS - SELECT symbol, COUNT(*) - FROM nonansi_libs - GROUP BY symbol ; + SELECT symbol, COUNT(*) + FROM nonansi_libs + GROUP BY symbol ; SELECT symbol INTO TABLE nonansi_counts - FROM nonansi_prog_counts + FROM nonansi_prog_counts UNION SELECT symbol - FROM nonansi_lib_counts ; + FROM nonansi_lib_counts ; ALTER TABLE nonansi_counts - ADD COLUMN progs INTEGER ; + ADD COLUMN progs INTEGER ; ALTER TABLE nonansi_counts - ADD COLUMN libs INTEGER ; + ADD COLUMN libs INTEGER ; UPDATE nonansi_counts - SET progs = 0, libs = 0 ; + SET progs = 0, libs = 0 ; UPDATE nonansi_counts - SET progs = b.count - FROM nonansi_prog_counts b - WHERE nonansi_counts.symbol = b.symbol ; + SET progs = b.count + FROM nonansi_prog_counts b + WHERE nonansi_counts.symbol = b.symbol ; UPDATE nonansi_counts - SET libs = c.count - FROM nonansi_lib_counts c - WHERE nonansi_counts.symbol = c.symbol; + SET libs = c.count + FROM nonansi_lib_counts c + WHERE nonansi_counts.symbol = c.symbol; -- SELECT a.symbol, a.program --- FROM prog_imp a, nonansi_prog_counts b --- WHERE a.symbol = b.symbol --- AND a.program NOT LIKE 'bin/%' --- ORDER BY b.count DESC, b.symbol ; +-- FROM prog_imp a, nonansi_prog_counts b +-- WHERE a.symbol = b.symbol +-- AND a.program NOT LIKE 'bin/%' +-- ORDER BY b.count DESC, b.symbol ; -- SELECT symbol, library --- FROM duplicates2 --- ORDER BY symbol ; +-- FROM duplicates2 +-- ORDER BY symbol ; -- SELECT a.im_lib, a.ex_lib --- FROM lib_deps a, lib_deps b --- WHERE a.ex_lib = b.im_lib --- AND b.ex_lib = a.im_lib ; +-- FROM lib_deps a, lib_deps b +-- WHERE a.ex_lib = b.im_lib +-- AND b.ex_lib = a.im_lib ; -- SELECT * FROM lib_deps_2 --- WHERE im_lib = ex_lib ; +-- WHERE im_lib = ex_lib ; -- SELECT * FROM lib_deps_1 --- WHERE im_lib = ex_lib ; +-- WHERE im_lib = ex_lib ; -- SELECT im_lib FROM lib_deps_trans --- WHERE im_lib = ex_lib ; +-- WHERE im_lib = ex_lib ; -- SELECT a.program, a.library -- FROM ldd a @@ -578,3 +579,5 @@ UPDATE nonansi_counts -- ---------------------------------------------------------------------- EOF + +rm -rf "$tmpdir" diff --git a/utils/g.html2man/g.html2man.py b/utils/g.html2man/g.html2man.py index 58ffb2f7bca..46a749ae5d3 100755 --- a/utils/g.html2man/g.html2man.py +++ b/utils/g.html2man/g.html2man.py @@ -47,7 +47,7 @@ def main(): sf.close() # strip excess whitespace - blank_re = re.compile("[ \t\n]*\n([ \t]*\n)*") + blank_re = re.compile(r"[ \t\n]*\n([ \t]*\n)*") s = blank_re.sub("\n", s) s = s.lstrip() diff --git a/utils/g.html2man/ggroff.py b/utils/g.html2man/ggroff.py index e62c5ec2b1c..c96fec4eab7 100644 --- a/utils/g.html2man/ggroff.py +++ b/utils/g.html2man/ggroff.py @@ -69,7 +69,7 @@ def __init__(self, filename, stream=sys.stdout): "index": [], } self.stack = [] - self.strip_re = re.compile("^[ \t]+") + self.strip_re = re.compile(r"^[ \t]+") self.filename = filename self.at_bol = True @@ -119,10 +119,7 @@ def fmt(self, format, content, var=None): self.show(pre) if sep != "": if var: - if var == "index": - val = self.get("index") + [0] - else: - val = True + val = self.get("index") + [0] if var == "index" else True self.pp_with(content, var, val) else: self.pp(content) diff --git a/utils/gitlog2changelog.py b/utils/gitlog2changelog.py index 7a98f17e1ab..1c6b41848da 100755 --- a/utils/gitlog2changelog.py +++ b/utils/gitlog2changelog.py @@ -61,7 +61,7 @@ # Match the author line and extract the part we want # (Don't use startswith to allow Author override inside commit message.) elif "Author:" in line: - authorList = re.split(": ", line, 1) + authorList = re.split(r": ", line, 1) try: author = authorList[1] author = author[0 : len(author) - 1] @@ -71,7 +71,7 @@ # Match the date line elif line.startswith("Date:"): - dateList = re.split(": ", line, 1) + dateList = re.split(r": ", line, 1) try: date = dateList[1] date = date[0 : len(date) - 1] @@ -100,7 +100,7 @@ else: message = message + " " + line.strip() # If this line is hit all of the files have been stored for this commit - elif re.search("files? changed", line): + elif re.search(r"files? changed", line): filesFound = True continue # Collect the files for this commit. FIXME: Still need to add +/- to files diff --git a/utils/mkdocs.py b/utils/mkdocs.py new file mode 100644 index 00000000000..1323fe06229 --- /dev/null +++ b/utils/mkdocs.py @@ -0,0 +1,435 @@ +# common functions used by mkmarkdown.py and mkhtml.py + +import sys +import os +import json +import subprocess +import re +import urllib.parse as urlparse +from http import HTTPStatus +from pathlib import Path +from datetime import datetime +from urllib import request as urlrequest +from urllib.error import HTTPError, URLError + +try: + import grass.script as gs +except ImportError: + # During compilation GRASS GIS + gs = None + +from generate_last_commit_file import COMMIT_DATE_FORMAT + +HEADERS = { + "User-Agent": "Mozilla/5.0", +} +HTTP_STATUS_CODES = list(HTTPStatus) + +top_dir = os.path.abspath(os.getenv("MODULE_TOPDIR")) + + +def read_file(name): + try: + return Path(name).read_text() + except OSError: + return "" + + +def get_version_branch(major_version, addons_git_repo_url): + """Check if version branch for the current GRASS version exists, + if not, take branch for the previous version + For the official repo we assume that at least one version branch is present + + :param major_version int: GRASS GIS major version + :param addons_git_repo_url str: Addons Git ropository URL + + :return version_branch str: version branch + """ + version_branch = f"grass{major_version}" + if gs: + branch = gs.Popen( + [ + "git", + "ls-remote", + "--heads", + addons_git_repo_url, + f"refs/heads/{version_branch}", + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + branch, stderr = branch.communicate() + if stderr: + gs.fatal( + _( + "Failed to get branch from the Git repository" + " <{repo_path}>.\n{error}" + ).format( + repo_path=addons_git_repo_url, + error=gs.decode(stderr), + ) + ) + if version_branch not in gs.decode(branch): + version_branch = "grass{}".format(int(major_version) - 1) + return version_branch + + +def has_src_code_git(src_dir): + """Has core module or addon source code Git + + :param str src_dir: core module or addon root directory + + :return subprocess.CompletedProcess or None: subprocess.CompletedProcess + if core module or addon + source code has Git + """ + actual_dir = Path.cwd() + os.chdir(src_dir) + try: + process_result = subprocess.run( + [ + "git", + "log", + "-1", + f"--format=%H,{COMMIT_DATE_FORMAT}", + src_dir, + ], + capture_output=True, + ) # --format=%H,COMMIT_DATE_FORMAT commit hash,author date + os.chdir(actual_dir) + return process_result if process_result.returncode == 0 else None + except FileNotFoundError: + os.chdir(actual_dir) + return None + + +def get_last_git_commit(src_dir, top_dir, pgm, addon_path, major_version): + """Get last module/addon git commit + :param str src_dir: module/addon source dir + :param str top_dir: top source dir + :param str pgm: program name + :param str addon_path: addon path + :param str major_version: major GRASS version + + :return dict git_log: dict with key commit and date, if not + possible download commit from GitHub REST API + server values of keys have "unknown" string + """ + process_result = has_src_code_git(src_dir=src_dir) + if process_result: + return parse_git_commit( + commit=process_result.stdout.decode(), + src_dir=src_dir, + ) + if gs: + # Addons installation + return get_git_commit_from_rest_api_for_addon_repo( + addon_path=addon_path, src_dir=src_dir, pgm=pgm, major_version=major_version + ) + # During GRASS GIS compilation from source code without Git + return get_git_commit_from_file(src_dir=src_dir, pgm=pgm) + + +def parse_git_commit( + commit, + src_dir, + git_log=None, +): + """Parse Git commit + + :param str commit: commit message + :param str src_dir: addon source dir + :param dict git_log: dict which store last commit and commnit + date + + :return dict git_log: dict which store last commit and commnit date + """ + if not git_log: + git_log = get_default_git_log(src_dir=src_dir) + if commit: + git_log["commit"], commit_date = commit.strip().split(",") + git_log["date"] = format_git_commit_date_from_local_git( + commit_datetime=commit_date, + ) + return git_log + + +def get_default_git_log(src_dir, datetime_format="%A %b %d %H:%M:%S %Y"): + """Get default Git commit and commit date, when getting commit from + local Git, local JSON file and remote GitHub REST API server wasn't + successful. + + :param str src_dir: addon source dir + :param str datetime_format: output commit datetime format + e.g. Sunday Jan 16 23:09:35 2022 + + :return dict: dict which store last commit and commnit date + """ + return { + "commit": "unknown", + "date": datetime.fromtimestamp(os.path.getmtime(src_dir)).strftime( + datetime_format + ), + } + + +def format_git_commit_date_from_local_git( + commit_datetime, datetime_format="%A %b %d %H:%M:%S %Y" +): + """Format datetime from local Git or JSON file + + :param str commit_datetime: commit datetime + :param str datetime_format: output commit datetime format + e.g. Sunday Jan 16 23:09:35 2022 + + :return str: output formatted commit datetime + """ + try: + date = datetime.fromisoformat( + commit_datetime, + ) + except ValueError: + if commit_datetime.endswith("Z"): + # Python 3.10 and older does not support Z in time, while recent versions + # of Git (2.45.1) use it. Try to help the parsing if Z is in the string. + date = datetime.fromisoformat(commit_datetime[:-1] + "+00:00") + else: + raise + return date.strftime(datetime_format) + + +def get_git_commit_from_rest_api_for_addon_repo( + addon_path, + src_dir, + pgm, + major_version, + git_log=None, +): + """Get Git commit from remote GitHub REST API for addon repository + + :param str addon_path: addon path + :param str src_dir: addon source dir + :param str pgm: program name + :param major_version int: GRASS GIS major version + :param dict git_log: dict which store last commit and commnit date + + :return dict git_log: dict which store last commit and commnit date + """ + # Accessed date time if getting commit from GitHub REST API wasn't successful + if not git_log: + git_log = get_default_git_log(src_dir=src_dir) + if addon_path is not None: + grass_addons_url = ( + "https://api.github.com/repos/osgeo/grass-addons/commits?" + "path={path}&page=1&per_page=1&sha=grass{major}".format( + path=addon_path, + major=major_version, + ) + ) # sha=git_branch_name + + response = download_git_commit( + url=grass_addons_url, + pgm=pgm, + response_format="application/json", + ) + if response: + commit = json.loads(response.read()) + if commit: + git_log["commit"] = commit[0]["sha"] + git_log["date"] = format_git_commit_date_from_rest_api( + commit_datetime=commit[0]["commit"]["author"]["date"], + ) + return git_log + + +def get_git_commit_from_file( + src_dir, + pgm, + git_log=None, +): + """Get Git commit from JSON file + + :param str src_dir: addon source dir + :param str pgm: program name + :param dict git_log: dict which store last commit and commnit date + + :return dict git_log: dict which store last commit and commnit date + """ + # Accessed date time if getting commit from JSON file wasn't successful + if not git_log: + git_log = get_default_git_log(src_dir=src_dir) + json_file_path = os.path.join( + top_dir, + "core_modules_with_last_commit.json", + ) + if os.path.exists(json_file_path): + with open(json_file_path) as f: + core_modules_with_last_commit = json.load(f) + if pgm in core_modules_with_last_commit: + core_module = core_modules_with_last_commit[pgm] + git_log["commit"] = core_module["commit"] + git_log["date"] = format_git_commit_date_from_local_git( + commit_datetime=core_module["date"], + ) + return git_log + + +def download_git_commit(url, pgm, response_format, *args, **kwargs): + """Download module/addon last commit from GitHub API + + :param str url: url address + :param str pgm: program name + :param str response_format: content type + + :return urllib.request.urlopen or None response: response object or + None + """ + try: + response = urlopen(url, *args, **kwargs) + if response.code != 200: + index = HTTP_STATUS_CODES.index(response.code) + desc = HTTP_STATUS_CODES[index].description + gs.fatal( + _( + "Download commit from <{url}>, return status code {code}, {desc}" + ).format( + url=url, + code=response.code, + desc=desc, + ), + ) + if response_format not in response.getheader("Content-Type"): + gs.fatal( + _( + "Wrong downloaded commit file format. " + "Check url <{url}>. Allowed file format is " + "{response_format}." + ).format( + url=url, + response_format=response_format, + ), + ) + return response + except HTTPError as err: + gs.warning( + _( + "The download of the commit from the GitHub API " + "server wasn't successful, <{}>. Commit and commit " + "date will not be included in the <{}> addon html manual " + "page." + ).format(err.msg, pgm), + ) + except URLError: + gs.warning( + _( + "Download file from <{url}>, failed. Check internet " + "connection. Commit and commit date will not be included " + "in the <{pgm}> addon manual page." + ).format(url=url, pgm=pgm), + ) + + +def format_git_commit_date_from_rest_api( + commit_datetime, datetime_format="%A %b %d %H:%M:%S %Y" +): + """Format datetime from remote GitHub REST API + + :param str commit_datetime: commit datetime + :param str datetime_format: output commit datetime format + e.g. Sunday Jan 16 23:09:35 2022 + + :return str: output formatted commit datetime + """ + return datetime.strptime( + commit_datetime, + "%Y-%m-%dT%H:%M:%SZ", # ISO 8601 YYYY-MM-DDTHH:MM:SSZ + ).strftime(datetime_format) + + +def urlopen(url, *args, **kwargs): + """Wrapper around urlopen. Same function as 'urlopen', but with the + ability to define headers. + """ + request = urlrequest.Request(url, headers=HEADERS) + return urlrequest.urlopen(request, *args, **kwargs) + + +def get_addon_path(base_url, pgm, major_version): + """Check if pgm is in the addons list and get addon path + + Make or update list of the official addons source + code paths g.extension prefix parameter plus /grass-addons directory + using Git repository + + :param str base_url: base URL + :param str pgm: program name + :param str major_version: GRASS major version + + :return str|None: pgm path if pgm is addon else None + """ + addons_base_dir = os.getenv("GRASS_ADDON_BASE") + if addons_base_dir and major_version: + grass_addons_dir = Path(addons_base_dir) / "grass-addons" + if gs: + call = gs.call + popen = gs.Popen + fatal = gs.fatal + else: + call = subprocess.call + popen = subprocess.Popen + fatal = sys.stderr.write + addons_branch = get_version_branch( + major_version=major_version, + addons_git_repo_url=urlparse.urljoin(base_url, "grass-addons/"), + ) + if not Path(addons_base_dir).exists(): + Path(addons_base_dir).mkdir(parents=True, exist_ok=True) + if not grass_addons_dir.exists(): + call( + [ + "git", + "clone", + "-q", + "--no-checkout", + f"--branch={addons_branch}", + "--filter=blob:none", + urlparse.urljoin(base_url, "grass-addons/"), + ], + cwd=addons_base_dir, + ) + addons_file_list = popen( + ["git", "ls-tree", "--name-only", "-r", addons_branch], + cwd=grass_addons_dir, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + addons_file_list, stderr = addons_file_list.communicate() + if stderr: + message = ( + "Failed to get addons files list from the" + " Git repository <{repo_path}>.\n{error}" + ) + if gs: + fatal( + _( + message, + ).format( + repo_path=grass_addons_dir, + error=gs.decode(stderr), + ) + ) + else: + message += "\n" + fatal( + message.format( + repo_path=grass_addons_dir, + error=stderr.decode(), + ) + ) + addon_paths = re.findall( + rf".*{pgm}*.", + gs.decode(addons_file_list) if gs else addons_file_list.decode(), + ) + for addon_path in addon_paths: + if pgm == Path(addon_path).name: + return addon_path diff --git a/utils/mkhtml.py b/utils/mkhtml.py index 39a5e6e26eb..c01ab0534cb 100644 --- a/utils/mkhtml.py +++ b/utils/mkhtml.py @@ -16,22 +16,16 @@ # ############################################################################# -import http import sys import os import string import re from datetime import datetime import locale -import json -import pathlib -import subprocess -from pathlib import Path from html.parser import HTMLParser from urllib import request as urlrequest -from urllib.error import HTTPError, URLError import urllib.parse as urlparse try: @@ -40,52 +34,13 @@ # During compilation GRASS GIS gs = None -from generate_last_commit_file import COMMIT_DATE_FORMAT - -HEADERS = { - "User-Agent": "Mozilla/5.0", -} -HTTP_STATUS_CODES = list(http.HTTPStatus) - - -def get_version_branch(major_version, addons_git_repo_url): - """Check if version branch for the current GRASS version exists, - if not, take branch for the previous version - For the official repo we assume that at least one version branch is present - - :param major_version int: GRASS GIS major version - :param addons_git_repo_url str: Addons Git ropository URL - - :return version_branch str: version branch - """ - version_branch = f"grass{major_version}" - if gs: - branch = gs.Popen( - [ - "git", - "ls-remote", - "--heads", - addons_git_repo_url, - f"refs/heads/{version_branch}", - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - branch, stderr = branch.communicate() - if stderr: - gs.fatal( - _( - "Failed to get branch from the Git repository" - " <{repo_path}>.\n{error}" - ).format( - repo_path=addons_git_repo_url, - error=gs.decode(stderr), - ) - ) - if version_branch not in gs.decode(branch): - version_branch = "grass{}".format(int(major_version) - 1) - return version_branch - +from mkdocs import ( + read_file, + get_version_branch, + get_last_git_commit, + top_dir as topdir, + get_addon_path, +) grass_version = os.getenv("VERSION_NUMBER", "unknown") trunk_url = "" @@ -125,14 +80,6 @@ def _get_encoding(): return encoding -def urlopen(url, *args, **kwargs): - """Wrapper around urlopen. Same function as 'urlopen', but with the - ability to define headers. - """ - request = urlrequest.Request(url, headers=HEADERS) - return urlrequest.urlopen(request, *args, **kwargs) - - def set_proxy(): """Set proxy""" proxy = os.getenv("GRASS_PROXY") @@ -148,274 +95,6 @@ def set_proxy(): set_proxy() -def download_git_commit(url, response_format, *args, **kwargs): - """Download module/addon last commit from GitHub API - - :param str url: url address - :param str response_format: content type - - :return urllib.request.urlopen or None response: response object or - None - """ - try: - response = urlopen(url, *args, **kwargs) - if response.code != 200: - index = HTTP_STATUS_CODES.index(response.code) - desc = HTTP_STATUS_CODES[index].description - gs.fatal( - _( - "Download commit from <{url}>, return status code {code}, {desc}" - ).format( - url=url, - code=response.code, - desc=desc, - ), - ) - if response_format not in response.getheader("Content-Type"): - gs.fatal( - _( - "Wrong downloaded commit file format. " - "Check url <{url}>. Allowed file format is " - "{response_format}." - ).format( - url=url, - response_format=response_format, - ), - ) - return response - except HTTPError as err: - gs.warning( - _( - "The download of the commit from the GitHub API " - "server wasn't successful, <{}>. Commit and commit " - "date will not be included in the <{}> addon html manual " - "page." - ).format(err.msg, pgm), - ) - except URLError: - gs.warning( - _( - "Download file from <{url}>, failed. Check internet " - "connection. Commit and commit date will not be included " - "in the <{pgm}> addon manual page." - ).format(url=url, pgm=pgm), - ) - - -def get_default_git_log(src_dir, datetime_format="%A %b %d %H:%M:%S %Y"): - """Get default Git commit and commit date, when getting commit from - local Git, local JSON file and remote GitHub REST API server wasn't - successful. - - :param str src_dir: addon source dir - :param str datetime_format: output commit datetime format - e.g. Sunday Jan 16 23:09:35 2022 - - :return dict: dict which store last commit and commnit date - """ - return { - "commit": "unknown", - "date": datetime.fromtimestamp(os.path.getmtime(src_dir)).strftime( - datetime_format - ), - } - - -def parse_git_commit( - commit, - src_dir, - git_log=None, -): - """Parse Git commit - - :param str commit: commit message - :param str src_dir: addon source dir - :param dict git_log: dict which store last commit and commnit - date - - :return dict git_log: dict which store last commit and commnit date - """ - if not git_log: - git_log = get_default_git_log(src_dir=src_dir) - if commit: - git_log["commit"], commit_date = commit.strip().split(",") - git_log["date"] = format_git_commit_date_from_local_git( - commit_datetime=commit_date, - ) - return git_log - - -def get_git_commit_from_file( - src_dir, - git_log=None, -): - """Get Git commit from JSON file - - :param str src_dir: addon source dir - :param dict git_log: dict which store last commit and commnit date - - :return dict git_log: dict which store last commit and commnit date - """ - # Accessed date time if getting commit from JSON file wasn't successful - if not git_log: - git_log = get_default_git_log(src_dir=src_dir) - json_file_path = os.path.join( - topdir, - "core_modules_with_last_commit.json", - ) - if os.path.exists(json_file_path): - with open(json_file_path) as f: - core_modules_with_last_commit = json.load(f) - if pgm in core_modules_with_last_commit: - core_module = core_modules_with_last_commit[pgm] - git_log["commit"] = core_module["commit"] - git_log["date"] = format_git_commit_date_from_local_git( - commit_datetime=core_module["date"], - ) - return git_log - - -def get_git_commit_from_rest_api_for_addon_repo( - addon_path, - src_dir, - git_log=None, -): - """Get Git commit from remote GitHub REST API for addon repository - - :param str addon_path: addon path - :param str src_dir: addon source dir - :param dict git_log: dict which store last commit and commnit date - - :return dict git_log: dict which store last commit and commnit date - """ - # Accessed date time if getting commit from GitHub REST API wasn't successful - if not git_log: - git_log = get_default_git_log(src_dir=src_dir) - if addon_path is not None: - grass_addons_url = ( - "https://api.github.com/repos/osgeo/grass-addons/commits?" - "path={path}&page=1&per_page=1&sha=grass{major}".format( - path=addon_path, - major=major, - ) - ) # sha=git_branch_name - - response = download_git_commit( - url=grass_addons_url, - response_format="application/json", - ) - if response: - commit = json.loads(response.read()) - if commit: - git_log["commit"] = commit[0]["sha"] - git_log["date"] = format_git_commit_date_from_rest_api( - commit_datetime=commit[0]["commit"]["author"]["date"], - ) - return git_log - - -def format_git_commit_date_from_rest_api( - commit_datetime, datetime_format="%A %b %d %H:%M:%S %Y" -): - """Format datetime from remote GitHub REST API - - :param str commit_datetime: commit datetime - :param str datetime_format: output commit datetime format - e.g. Sunday Jan 16 23:09:35 2022 - - :return str: output formatted commit datetime - """ - return datetime.strptime( - commit_datetime, - "%Y-%m-%dT%H:%M:%SZ", # ISO 8601 YYYY-MM-DDTHH:MM:SSZ - ).strftime(datetime_format) - - -def format_git_commit_date_from_local_git( - commit_datetime, datetime_format="%A %b %d %H:%M:%S %Y" -): - """Format datetime from local Git or JSON file - - :param str commit_datetime: commit datetime - :param str datetime_format: output commit datetime format - e.g. Sunday Jan 16 23:09:35 2022 - - :return str: output formatted commit datetime - """ - try: - date = datetime.fromisoformat( - commit_datetime, - ) - except ValueError: - if commit_datetime.endswith("Z"): - # Python 3.10 and older does not support Z in time, while recent versions - # of Git (2.45.1) use it. Try to help the parsing if Z is in the string. - date = datetime.fromisoformat(commit_datetime[:-1] + "+00:00") - else: - raise - return date.strftime(datetime_format) - - -def has_src_code_git(src_dir, is_addon): - """Has core module or addon source code Git - - :param str src_dir: core module or addon root directory - :param bool is_addon: True if it is addon - - :return subprocess.CompletedProcess or None: subprocess.CompletedProcess - if core module or addon - source code has Git - """ - actual_dir = Path.cwd() - if is_addon: - os.chdir(src_dir) - else: - os.chdir(topdir) - try: - process_result = subprocess.run( - [ - "git", - "log", - "-1", - f"--format=%H,{COMMIT_DATE_FORMAT}", - src_dir, - ], - capture_output=True, - ) # --format=%H,COMMIT_DATE_FORMAT commit hash,author date - os.chdir(actual_dir) - return process_result if process_result.returncode == 0 else None - except FileNotFoundError: - os.chdir(actual_dir) - return None - - -def get_last_git_commit(src_dir, addon_path, is_addon): - """Get last module/addon git commit - - :param str src_dir: module/addon source dir - :param str addon_path: addon path - :param bool is_addon: True if it is addon - - :return dict git_log: dict with key commit and date, if not - possible download commit from GitHub REST API - server values of keys have "unknown" string - """ - process_result = has_src_code_git(src_dir=src_dir, is_addon=is_addon) - if process_result: - return parse_git_commit( - commit=process_result.stdout.decode(), - src_dir=src_dir, - ) - if gs: - # Addons installation - return get_git_commit_from_rest_api_for_addon_repo( - addon_path=addon_path, - src_dir=src_dir, - ) - # During GRASS GIS compilation from source code without Git - return get_git_commit_from_file(src_dir=src_dir) - - html_page_footer_pages_path = os.getenv("HTML_PAGE_FOOTER_PAGES_PATH") or "" pgm = sys.argv[1] @@ -509,13 +188,6 @@ def get_last_git_commit(src_dir, addon_path, is_addon): ) -def read_file(name): - try: - return Path(name).read_text() - except OSError: - return "" - - def create_toc(src_data): class MyHTMLParser(HTMLParser): def __init__(self): @@ -562,7 +234,7 @@ def handle_data(self, data): def escape_href(label): # remove html tags - label = re.sub("<[^<]+?>", "", label) + label = re.sub(r"<[^<]+?>", "", label) # fix   label = label.replace(" ", "") # fix " @@ -677,95 +349,18 @@ def update_toc(data): return "\n".join(ret_data) -def get_addon_path(): - """Check if pgm is in the addons list and get addon path - - Make or update list of the official addons source - code paths g.extension prefix parameter plus /grass-addons directory - using Git repository - - :return str|None: pgm path if pgm is addon else None - """ - addons_base_dir = os.getenv("GRASS_ADDON_BASE") - if addons_base_dir and major: - grass_addons_dir = pathlib.Path(addons_base_dir) / "grass-addons" - if gs: - call = gs.call - popen = gs.Popen - fatal = gs.fatal - else: - call = subprocess.call - popen = subprocess.Popen - fatal = sys.stderr.write - addons_branch = get_version_branch( - major_version=major, - addons_git_repo_url=urlparse.urljoin(base_url, "grass-addons/"), - ) - if not pathlib.Path(addons_base_dir).exists(): - pathlib.Path(addons_base_dir).mkdir(parents=True, exist_ok=True) - if not grass_addons_dir.exists(): - call( - [ - "git", - "clone", - "-q", - "--no-checkout", - f"--branch={addons_branch}", - "--filter=blob:none", - urlparse.urljoin(base_url, "grass-addons/"), - ], - cwd=addons_base_dir, - ) - addons_file_list = popen( - ["git", "ls-tree", "--name-only", "-r", addons_branch], - cwd=grass_addons_dir, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - addons_file_list, stderr = addons_file_list.communicate() - if stderr: - message = ( - "Failed to get addons files list from the" - " Git repository <{repo_path}>.\n{error}" - ) - if gs: - fatal( - _( - message, - ).format( - repo_path=grass_addons_dir, - error=gs.decode(stderr), - ) - ) - else: - message += "\n" - fatal( - message.format( - repo_path=grass_addons_dir, - error=stderr.decode(), - ) - ) - addon_paths = re.findall( - rf".*{pgm}*.", - gs.decode(addons_file_list) if gs else addons_file_list.decode(), - ) - for addon_path in addon_paths: - if pgm == pathlib.Path(addon_path).name: - return addon_path - - # process header src_data = read_file(src_file) -name = re.search("()", src_data, re.IGNORECASE) +name = re.search(r"()", src_data, re.IGNORECASE) pgm_desc = "GRASS GIS Reference Manual" if name: pgm = name.group(2).strip().split("-", 1)[0].strip() name_desc = re.search( - "()", src_data, re.IGNORECASE + r"()", src_data, re.IGNORECASE ) if name_desc: pgm_desc = name_desc.group(2).strip() -desc = re.search("()", src_data, re.IGNORECASE) +desc = re.search(r"()", src_data, re.IGNORECASE) if desc: pgm = desc.group(2).strip() header_tmpl = string.Template(header_base + header_nopgm) @@ -774,7 +369,7 @@ def get_addon_path(): else: header_tmpl = string.Template(header_base + header_pgm_desc) -if not re.search("", src_data, re.IGNORECASE): +if not re.search(r"", src_data, re.IGNORECASE): tmp_data = read_file(tmp_file) """ Adjusting keywords html pages paths if add-on html man page @@ -800,7 +395,7 @@ def get_addon_path(): orig_keywords_paths.group(1), ",".join(new_keywords_paths), ) - if not re.search("", tmp_data, re.IGNORECASE): + if not re.search(r"", tmp_data, re.IGNORECASE): sys.stdout.write(header_tmpl.substitute(PGM=pgm, PGM_DESC=pgm_desc)) if tmp_data: @@ -808,7 +403,7 @@ def get_addon_path(): for line in tmp_data.splitlines(True): # The cleanup happens on Makefile level too. if not re.search( - "||
    ", line, re.IGNORECASE + r"||
    ", line, re.IGNORECASE ): if header_logo_img_el in line: sys.stdout.write(line) @@ -825,7 +420,7 @@ def get_addon_path(): # if is found, suppose a complete html is provided. # otherwise, generate module class reference: -if re.search("", src_data, re.IGNORECASE): +if re.search(r"", src_data, re.IGNORECASE): sys.exit() index_names = { @@ -858,7 +453,7 @@ def to_title(name): index_titles[key] = to_title(name) # process footer -index = re.search("()", src_data, re.IGNORECASE) +index = re.search(r"()", src_data, re.IGNORECASE) if index: index_name = index.group(2).strip() if "|" in index_name: @@ -875,7 +470,6 @@ def to_title(name): year = str(datetime.now().year) # check the names of scripts to assign the right folder -topdir = os.path.abspath(os.getenv("MODULE_TOPDIR")) curdir = os.path.abspath(os.path.curdir) if curdir.startswith(topdir + os.path.sep): source_url = trunk_url @@ -887,7 +481,7 @@ def to_title(name): url_source = "" addon_path = None if os.getenv("SOURCE_URL", ""): - addon_path = get_addon_path() + addon_path = get_addon_path(base_url=base_url, pgm=pgm, major_version=major) if addon_path: # Addon is installed from the local dir if os.path.exists(os.getenv("SOURCE_URL")): @@ -918,8 +512,10 @@ def to_title(name): git_commit = get_last_git_commit( src_dir=curdir, + top_dir=topdir, + pgm=pgm, addon_path=addon_path or None, - is_addon=bool(addon_path), + major_version=major, ) if git_commit["commit"] == "unknown": date_tag = "Accessed: {date}".format(date=git_commit["date"]) diff --git a/utils/mkmarkdown.py b/utils/mkmarkdown.py new file mode 100644 index 00000000000..b7f595fc3c4 --- /dev/null +++ b/utils/mkmarkdown.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 + +############################################################################ +# +# MODULE: Builds manual pages (Markdown) +# AUTHOR(S): Markus Neteler +# Glynn Clements +# Martin Landa +# PURPOSE: Create Markdown manual page snippets +# Inspired by mkhtml.py +# COPYRIGHT: (C) 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. +# +############################################################################# + +import os +import sys +import string +import urllib.parse as urlparse + +try: + import grass.script as gs +except ImportError: + # During compilation GRASS GIS + gs = None + +from mkdocs import ( + read_file, + get_version_branch, + get_last_git_commit, + top_dir, + get_addon_path, +) + + +def parse_source(pgm): + """Parse source code to get source code and log message URLs, + and date time of the last modification. + + :param str pgm: program name + + :return url_source, url_log, date_time + """ + grass_version = os.getenv("VERSION_NUMBER", "unknown") + main_url = "" + addons_url = "" + grass_git_branch = "main" + major, minor, patch = None, None, None + if grass_version != "unknown": + major, minor, patch = grass_version.split(".") + base_url = "https://github.com/OSGeo/" + main_url = urlparse.urljoin( + base_url, + urlparse.urljoin( + "grass/tree/", + grass_git_branch + "/", + ), + ) + addons_url = urlparse.urljoin( + base_url, + urlparse.urljoin( + "grass-addons/tree/", + get_version_branch( + major, + urlparse.urljoin(base_url, "grass-addons/"), + ), + ), + ) + + cur_dir = os.path.abspath(os.path.curdir) + if cur_dir.startswith(top_dir + os.path.sep): + source_url = main_url + pgmdir = cur_dir.replace(top_dir, "").lstrip(os.path.sep) + else: + # addons + source_url = addons_url + pgmdir = os.path.sep.join(cur_dir.split(os.path.sep)[-3:]) + + url_source = "" + addon_path = None + if os.getenv("SOURCE_URL", ""): + addon_path = get_addon_path(base_url=base_url, pgm=pgm, major_version=major) + if addon_path: + # Addon is installed from the local dir + if os.path.exists(os.getenv("SOURCE_URL")): + url_source = urlparse.urljoin( + addons_url, + addon_path, + ) + else: + url_source = urlparse.urljoin( + os.environ["SOURCE_URL"].split("src")[0], + addon_path, + ) + else: + url_source = urlparse.urljoin(source_url, pgmdir) + if sys.platform == "win32": + url_source = url_source.replace(os.path.sep, "/") + + # Process Source code section + branches = "branches" + tree = "tree" + commits = "commits" + + if branches in url_source: + url_log = url_source.replace(branches, commits) + url_source = url_source.replace(branches, tree) + else: + url_log = url_source.replace(tree, commits) + + git_commit = get_last_git_commit( + src_dir=cur_dir, + top_dir=top_dir, + pgm=pgm, + addon_path=addon_path or None, + major_version=major, + ) + if git_commit["commit"] == "unknown": + date_tag = "Accessed: {date}".format(date=git_commit["date"]) + else: + commit = git_commit["commit"] + date_tag = ( + "Latest change: {date} in commit: " + "[{commit_short}](https://github.com/OSGeo/grass/commit/{commit})".format( + date=git_commit["date"], commit=commit, commit_short=commit[:7] + ) + ) + + return url_source, url_log, date_tag + + +if __name__ == "__main__": + pgm = sys.argv[1] + + src_file = f"{pgm}.md" + tmp_file = f"{pgm}.tmp.md" + + sourcecode = string.Template( + """ +## SOURCE CODE + +Available at: [${PGM} source code](${URL_SOURCE}) +([history](${URL_LOG}))${MD_NEWLINE} +${DATE_TAG} +""" + ) + + # process header/usage generated by --md-description + sys.stdout.write(read_file(tmp_file)) + sys.stdout.write("\n") + # process body + sys.stdout.write(read_file(src_file)) + + # process footer + url_source, url_log, date_tag = parse_source(pgm) + sys.stdout.write( + sourcecode.substitute( + URL_SOURCE=url_source, + PGM=pgm, + URL_LOG=url_log, + DATE_TAG=date_tag, + MD_NEWLINE=" ", + ) + ) diff --git a/utils/mkrest.py b/utils/mkrest.py index 24481bc3374..6270b78c6b2 100755 --- a/utils/mkrest.py +++ b/utils/mkrest.py @@ -21,10 +21,7 @@ from datetime import datetime pgm = sys.argv[1] -if len(sys.argv) > 1: - year = sys.argv[2] -else: - year = str(datetime.now().year) +year = sys.argv[2] if len(sys.argv) > 1 else str(datetime.now().year) src_file = "%s.html" % pgm tmp_file = "%s.tmp.txt" % pgm @@ -69,7 +66,7 @@ def read_file(name): src_data = read_file(src_file) -title = re.search("()", src_data, re.IGNORECASE) +title = re.search(r"()", src_data, re.IGNORECASE) if title: title_name = title.group(2).strip() @@ -111,7 +108,7 @@ def read_file(name): "v": "vector", } -index = re.search("()", src_data, re.IGNORECASE) +index = re.search(r"()", src_data, re.IGNORECASE) if index: index_name = index.group(2).strip() diff --git a/utils/ppmrotate.py b/utils/ppmrotate.py index ec041e0f253..cef32eba0f4 100755 --- a/utils/ppmrotate.py +++ b/utils/ppmrotate.py @@ -110,11 +110,8 @@ def convert_and_rotate(src, dst, flip=False): to_png = False if dst.lower().endswith(".png"): to_png = True - if to_png: - tmp_img = gs.tempfile() + ".ppm" - # TODO: clean up the file - else: - tmp_img = dst + # TODO: clean up the file + tmp_img = gs.tempfile() + ".ppm" if to_png else dst write_ppm(tmp_img, ppm) if to_png: ppmtopng(dst, tmp_img) 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/thumbnails.py b/utils/thumbnails.py index ee9bd5e17ab..181a16aa666 100755 --- a/utils/thumbnails.py +++ b/utils/thumbnails.py @@ -23,13 +23,14 @@ def cleanup(): + names = [] if tmp_grad_rel: - gs.run_command( - "g.remove", flags="f", type="raster", name=tmp_grad_rel, quiet=True - ) + names.append(tmp_grad_rel) if tmp_grad_abs: + names.append(tmp_grad_abs) + if len(names) > 0: gs.run_command( - "g.remove", flags="f", type="raster", name=tmp_grad_abs, quiet=True + "g.remove", flags="f", type="raster", name=",".join(names), quiet=True ) diff --git a/utils/update_version.py b/utils/update_version.py index c66a34a62cd..947e68a1648 100755 --- a/utils/update_version.py +++ b/utils/update_version.py @@ -226,10 +226,7 @@ def status(args): version_info = read_version_file() today = datetime.date.today().isoformat() version = construct_version(version_info) - if not version_info.micro.endswith("dev"): - tag = version - else: - tag = None + tag = version if not version_info.micro.endswith("dev") else None if args.bash: status_as_bash(version_info=version_info, today=today, version=version, tag=tag) else: 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.buffer/v.buffer.html b/vector/v.buffer/v.buffer.html index 8c835331630..8870cd335c5 100644 --- a/vector/v.buffer/v.buffer.html +++ b/vector/v.buffer/v.buffer.html @@ -10,12 +10,13 @@

    NOTES

    Internal buffers for areas can be generated with negative distance values ("inward buffer" or "negative buffer" or "shrinking"). +

    v.buffer fusions the geometries of buffers by default. Categories and attribute table will not be transferred (this would not make sense as one buffer geometry can be the result of many different input geometries). To transfer the categories and -attributes the user can set the t flag. This will result in +attributes the user can set the -t flag. This will result in buffers being cut up where buffers of individual input geometries overlap. Each part that is the result of overlapping buffers of multiple geometries will have multiple categories corresponding to @@ -29,11 +30,11 @@

    NOTES

    the GEOS library.

    -For advanced users: built-in buffer algorithm no longer -desired, we use GEOS: If GRASS is not compiled with GEOS support -or environmental +For advanced users: the built-in buffer algorithm is no longer +used, as we use GEOS instead. If GRASS was not compiled with GEOS support +or the environmental variable GRASS_VECTOR_BUFFER is defined, then GRASS -generates buffers using built-in buffering algorithm (which is still +generates buffers using the built-in buffering algorithm (which is still buggy for some input data).

    @@ -56,8 +57,8 @@

    Corner settings

    -Straight corners with caps are created by -s flag (red color on -the figure below), while -c flag doesn't make caps at the ends of +Straight corners with caps are created using the -s flag (red color on +the figure below), while the -c flag doesn't make caps at the ends of polylines (green color on the figure below):
    @@ -65,8 +66,8 @@

    Corner settings

    -Using -s with a point vector map as input data, square buffers are -created instead of round buffers. +With a point vector map as input data, square buffers are created instead +of round buffers by using the -s flag.
    @@ -154,7 +155,7 @@

    Buffer inside input areas

    REFERENCES

    SEE ALSO

    diff --git a/vector/v.build.polylines/walk.c b/vector/v.build.polylines/walk.c index 9507c587319..2d168fb6662 100644 --- a/vector/v.build.polylines/walk.c +++ b/vector/v.build.polylines/walk.c @@ -166,6 +166,8 @@ int walk_forward_and_pick_up_coords(struct Map_info *map, int start_line, next_node = n2; /* continue at end node */ } else { + if (cats_tmp) + Vect_destroy_cats_struct(cats_tmp); return 1; /* no other line */ } } diff --git a/vector/v.build/v.build.html b/vector/v.build/v.build.html index 9f51afdb22b..c66da69110a 100644 --- a/vector/v.build/v.build.html +++ b/vector/v.build/v.build.html @@ -27,7 +27,7 @@

    NOTES

    If error vector map is specified, v.build checks:
      -
    • isolated bondaries (which are not forming any areas),
    • +
    • isolated boundaries (which are not forming any areas),
    • centroids outside of area,
    • duplicated centroids.
    @@ -38,7 +38,7 @@

    NOTES

    • lines or boundaries of zero length,
    • -
    • intersecting boundaries, ie. overlapping areas,
    • +
    • intersecting boundaries, i.e. overlapping areas,
    • areas without centroids that are not isles.
    @@ -46,7 +46,7 @@

    EXAMPLES

    Build topology

    -Note that option=build recreates also spatial and category +Note that option=build also recreates spatial and category indices, not only topology. For linked OGR layers (see v.external) also feature index is created. @@ -61,7 +61,7 @@

    Build topology

    Dump topology or indices

    Dump options print topology, spatial, category or feature index to -standard output. Such information can be printed also for vector maps +standard output. Such information can also be printed for vector maps from other mapsets. A description of the vector topology is available in the GRASS GIS 8 Programmer's Manual, section "Vector library topology management". diff --git a/vector/v.class/v.class.html b/vector/v.class/v.class.html index 026f81c7e73..a530ca39e8e 100644 --- a/vector/v.class/v.class.html +++ b/vector/v.class/v.class.html @@ -35,19 +35,20 @@

    NOTES

    are those of the number of breaks asked for.

    The discont algorithm systematically searches discontinuities -in the slope of the cumulated frequencies curve, by approximating this +in the slope of the cumulative frequencies curve, by approximating this curve through straight line segments whose vertices define the class breaks. The first approximation is a straight line which links the two end nodes of the curve. This line is then replaced by a two-segmented polyline whose central node is the point on the curve which is farthest from the preceding straight line. The point on the curve furthest from this new polyline is then chosen as a new node to create break up one of -the two preceding segments, and so forth. The problem of the difference -in terms of units between the two axes is solved by rescaling both -amplitudes to an interval between 0 and 1. In the original algorithm, -the process is stopped when the difference between the slopes of the two -new segments is no longer significant (alpha = 0.05). As the slope is -the ratio between the frequency and the amplitude of the corresponding +the two preceding segments, and so forth. + +

    The problem of the difference in terms of units between the two axes +is solved by rescaling both amplitudes to an interval between 0 and 1. +In the original algorithm, the process is stopped when the difference between +the slopes of the two new segments is no longer significant (alpha = 0.05). As +the slope is the ratio between the frequency and the amplitude of the corresponding interval, i.e. its density, this effectively tests whether the frequencies of the two newly proposed classes are different from those obtained by simply distributing the sum of their frequencies amongst them in proportion diff --git a/vector/v.clean/v.clean.html b/vector/v.clean/v.clean.html index 6da10283703..fcaa9d212c4 100644 --- a/vector/v.clean/v.clean.html +++ b/vector/v.clean/v.clean.html @@ -184,10 +184,10 @@

    Remove small angles between lines at nodes

    run with several tools.

    -
    - +
    -tool=rmsa +
    +tool=rmsa

    diff --git a/vector/v.cluster/v.cluster.html b/vector/v.cluster/v.cluster.html index 0e92f266eb9..235e9491b1e 100644 --- a/vector/v.cluster/v.cluster.html +++ b/vector/v.cluster/v.cluster.html @@ -21,7 +21,7 @@

    DESCRIPTION

    separately for each observed density (distance to the farthest neighbor).

    dbscan

    -The Density-Based Spatial +The Density-Based Spatial Clustering of Applications with Noise is a commonly used clustering algorithm. A new cluster is started for a point with at least min - 1 neighbors within the maximum distance. These neighbors @@ -45,8 +45,8 @@

    density

    densities and can create nested clusters.

    optics

    -This method is Ordering Points to +This method is +Ordering Points to Identify the Clustering Structure. It is controlled by the number of neighbor points (option min - 1). The core distance of a point is the distance to the farthest neighbor. The reachability of a diff --git a/vector/v.db.select/v.db.select.html b/vector/v.db.select/v.db.select.html index e75beb5336b..13bbbbb1b78 100644 --- a/vector/v.db.select/v.db.select.html +++ b/vector/v.db.select/v.db.select.html @@ -107,7 +107,7 @@

    JSON

    The JSON also contains information about columns stored under key info. Column names and types are under key columns. -Each colum has SQL data type under sql_type in all caps. +Each column has SQL data type under sql_type in all caps. A boolean is_number specifies whether the value is a number, i.e., integer or floating point number. The is_number value is aded for convenience and it is recommended to rely on the types derived diff --git a/vector/v.decimate/v.decimate.html b/vector/v.decimate/v.decimate.html index ceaae540ff1..e1bad03acbf 100644 --- a/vector/v.decimate/v.decimate.html +++ b/vector/v.decimate/v.decimate.html @@ -8,16 +8,16 @@

    DESCRIPTION

    Two main decimation techniques are:
    • count-based decimation (skip, preserve, offset - and limit options) -
    • grid-based decimation (-g flag) + and limit options)
    • +
    • grid-based decimation (-g flag)

    The grid-based decimation will remove points based on:

      -
    • similar z coordinates (-z flag and zdiff option) -
    • same categories (-c flag) -
    • count of points (-f flag and cell_limit option) +
    • similar z coordinates (-z flag and zdiff option)
    • +
    • same categories (-c flag)
    • +
    • count of points (-f flag and cell_limit option)

    @@ -49,8 +49,8 @@

    DESCRIPTION

    Besides decimation, point count can be reduced by applying different selections or filters, these are:
      -
    • selection by category (cats option) -
    • selection by z values (zrange option) +
    • selection by category (cats option)
    • +
    • selection by z values (zrange option)

    NOTES

    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.edit/v.edit.html b/vector/v.edit/v.edit.html index 081deadf29c..3768e65ad4d 100644 --- a/vector/v.edit/v.edit.html +++ b/vector/v.edit/v.edit.html @@ -46,8 +46,8 @@

    Feature selection

    box, size defined by threshold)
  • bbox - using bounding box
  • polygon - using polygon (at least 3 coordinate pairs have to be set)
  • -
  • where - using where statement (attribute data) -
  • query - special query (e.g. minimal vector line length) +
  • where - using where statement (attribute data)
  • +
  • query - special query (e.g. minimal vector line length)
  • Additional parameters for vector feature specification are: @@ -165,7 +165,7 @@

    Tool description

    and zbulk parameter. Also input vector map must be 3D.
  • select - Print comma separated list of selected line - id's. No editing is done. + id's. No editing is done.
  • EXAMPLES

    @@ -181,7 +181,7 @@

    Create new vector map

    Create new vector map and read data from file 'roads.txt':
    -v.out.ascii in=roads format=standard > roads.txt;
    +v.out.ascii in=roads format=standard > roads.txt;
     v.edit tool=create map=vectmap input=roads.txt
     
    diff --git a/vector/v.external.out/link.c b/vector/v.external.out/link.c index 58e01b035f5..da5ab52a56b 100644 --- a/vector/v.external.out/link.c +++ b/vector/v.external.out/link.c @@ -100,6 +100,7 @@ void make_link(const char *dsn_opt, const char *format, char *option_str, G_verbose_message(_("Switched to PostGIS format")); G_free_key_value(key_val); + G_free(dsn); } int parse_option_pg(const char *option, char **key, char **value) diff --git a/vector/v.external.out/v.external.out.html b/vector/v.external.out/v.external.out.html index 1d82620f17c..f9c3575aa88 100644 --- a/vector/v.external.out/v.external.out.html +++ b/vector/v.external.out/v.external.out.html @@ -2,9 +2,9 @@

    DESCRIPTION

    v.external.out instructs GRASS to write vector maps in external data format (e.g. ESRI Shapefile, Mapinfo, and others) -using OGR library. PostGIS data can +using OGR library. PostGIS data can be also written by -built-in GRASS-PostGIS +built-in GRASS-PostGIS data provider.

    NOTES

    @@ -26,9 +26,9 @@

    NOTES

    by format option. See the list of valid creation options at OGR formats specification page, example -for ESRI +for ESRI Shapefile -or PostgreSQL/PostGIS +or PostgreSQL/PostGIS format (section "Layer Creation Options"). Options are comma-separated pairs (key=value), the options are case-insensitive, @@ -180,10 +180,10 @@

    Restore settings

    REFERENCES

    SEE ALSO

    diff --git a/vector/v.external/dsn.c b/vector/v.external/dsn.c index 1a0d6bc2a57..c56009a64e2 100644 --- a/vector/v.external/dsn.c +++ b/vector/v.external/dsn.c @@ -31,7 +31,7 @@ char *get_datasource_name(const char *opt_dsn, int use_ogr) /* add db.login settings (user, password, host, port) */ if (DB_OK == - db_get_login2("pg", database, &user, &passwd, &host, &port)) { + db_get_login("pg", database, &user, &passwd, &host, &port)) { if (user) { if (!G_strcasestr(opt_dsn, "user=")) { strcat(connect_str, " user="); diff --git a/vector/v.external/v.external.html b/vector/v.external/v.external.html index fb1512f8942..200d3726363 100644 --- a/vector/v.external/v.external.html +++ b/vector/v.external/v.external.html @@ -3,7 +3,7 @@

    DESCRIPTION

    v.external creates new vector map as a link to external OGR layer or PostGIS feature table. OGR (Simple Features Library) is part of the -GDAL library, so you need to install +GDAL library, so you need to install GDAL to use v.external for external OGR layers. Note that a PostGIS feature table can be linked also using built-in GRASS-PostGIS data driver (requires GRASS to be built with PostgreSQL support). @@ -140,7 +140,7 @@

    SEE ALSO

    -GDAL Library +GDAL Library
    PostGIS diff --git a/vector/v.extract/testsuite/test_v_extract.py b/vector/v.extract/testsuite/test_v_extract.py index d266e8ad649..c46505a5527 100644 --- a/vector/v.extract/testsuite/test_v_extract.py +++ b/vector/v.extract/testsuite/test_v_extract.py @@ -5,13 +5,12 @@ Author: Sunveer Singh, Google Code-in 2017 Copyright: (C) 2017 by Sunveer Singh and the GRASS Development Team Licence: This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. + License (>=v2). Read the file COPYING that comes with GRASS + for details. """ import os from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule from grass.script.core import read_command TABLE_1 = """cat|MAJORRDS_|ROAD_NAME|MULTILANE|PROPYEAR|OBJECTID|SHAPE_LEN @@ -54,8 +53,8 @@ def setUpClass(cls): def tearDownClass(cls): cls.del_temp_region() - def tearDown(cls): - cls.runModule("g.remove", flags="f", type="vector", name=cls.output) + def tearDown(self): + self.runModule("g.remove", flags="f", type="vector", name=self.output) def test_flagd(self): """Testing flag d""" diff --git a/vector/v.fill.holes/examples.ipynb b/vector/v.fill.holes/examples.ipynb index fcc006501e4..a6b3ea746ce 100644 --- a/vector/v.fill.holes/examples.ipynb +++ b/vector/v.fill.holes/examples.ipynb @@ -15,12 +15,10 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "import sys\n", "\n", "from IPython.display import Image\n", "\n", - "import grass.script as gs\n", "import grass.jupyter as gj" ] }, diff --git a/vector/v.hull/chull.c b/vector/v.hull/chull.c index 93dfd15742e..cd8dcf52153 100644 --- a/vector/v.hull/chull.c +++ b/vector/v.hull/chull.c @@ -687,6 +687,8 @@ void CleanEdges(void) e = edges; DELETE(edges, e); } + if (!edges) + return; e = edges->next; do { if (e->delete) { @@ -711,6 +713,8 @@ void CleanFaces(void) f = faces; DELETE(faces, f); } + if (!faces) + return; f = faces->next; do { if (f->visible) { @@ -746,6 +750,8 @@ void CleanVertices(void) v = vertices; DELETE(vertices, v); } + if (!vertices) + return; v = vertices->next; do { if (v->mark && !v->onhull) { diff --git a/vector/v.hull/v.hull.html b/vector/v.hull/v.hull.html index e77a028e905..68a85a8ab15 100644 --- a/vector/v.hull/v.hull.html +++ b/vector/v.hull/v.hull.html @@ -54,9 +54,9 @@

    REFERENCES

    • M. de Berg, M. van Kreveld, M. Overmars, O. Schwarzkopf, - (2000). Computational geometry, chapter 1.1, 2-8. + (2000). Computational geometry, chapter 1.1, 2-8.
    • J. O'Rourke, (1998). Computational Geometry in C (Second - Edition), chapter 4. + Edition), chapter 4.

    SEE ALSO

    diff --git a/vector/v.in.ascii/points.c b/vector/v.in.ascii/points.c index 0fd1899c2e2..ab1720f78d7 100644 --- a/vector/v.in.ascii/points.c +++ b/vector/v.in.ascii/points.c @@ -494,6 +494,9 @@ int points_to_bin(FILE *ascii, int rowlen, struct Map_info *Map, G_free_tokens(tokens); } G_percent(nrows, nrows, 2); + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(Cats); + G_free(buf); return 0; } diff --git a/vector/v.in.db/v.in.db.html b/vector/v.in.db/v.in.db.html index a51fd936f93..00a81365acc 100644 --- a/vector/v.in.db/v.in.db.html +++ b/vector/v.in.db/v.in.db.html @@ -114,7 +114,7 @@

    Creating a point map from DBF table for selected records only

     v.in.db driver=dbf  database=/home/user/tables/ table=pointsfile x=x y=y z=z \
    -        key=idcol out=dtmpoints where="x NOT NULL and z > 100"
    +        key=idcol out=dtmpoints where="x NOT NULL and z > 100"
     

    Creating a map from SQLite table

    diff --git a/vector/v.in.dxf/v.in.dxf.html b/vector/v.in.dxf/v.in.dxf.html index 85d05623344..a08d2fbb5ee 100644 --- a/vector/v.in.dxf/v.in.dxf.html +++ b/vector/v.in.dxf/v.in.dxf.html @@ -45,7 +45,7 @@

    DESCRIPTION

    REFERENCES

    -AutoCad DXF (from Wikipedia, the free encyclopedia)
    +AutoCad DXF (from Wikipedia, the free encyclopedia)
    DXF References (Autodesk-supplied documentation)

    SEE ALSO

    diff --git a/vector/v.in.ogr/dsn.c b/vector/v.in.ogr/dsn.c index 2fecff7e9fb..7e483e71050 100644 --- a/vector/v.in.ogr/dsn.c +++ b/vector/v.in.ogr/dsn.c @@ -38,7 +38,7 @@ char *get_datasource_name(const char *opt_dsn, int use_ogr) /* add db.login settings (user, password, host, port) */ if (DB_OK == - db_get_login2("pg", database, &user, &passwd, &host, &port)) { + db_get_login("pg", database, &user, &passwd, &host, &port)) { if (user) { if (!G_strcasestr(opt_dsn, "user=")) { strcat(connect_str, " user="); diff --git a/vector/v.in.ogr/testsuite/test_v_in_ogr.py b/vector/v.in.ogr/testsuite/test_v_in_ogr.py index 167cd8747e8..31d2ef7ef3b 100644 --- a/vector/v.in.ogr/testsuite/test_v_in_ogr.py +++ b/vector/v.in.ogr/testsuite/test_v_in_ogr.py @@ -4,7 +4,6 @@ """ from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestOgrImport(TestCase): diff --git a/vector/v.in.ogr/v.in.ogr.html b/vector/v.in.ogr/v.in.ogr.html index 3a461969663..2ab3ca938a6 100644 --- a/vector/v.in.ogr/v.in.ogr.html +++ b/vector/v.in.ogr/v.in.ogr.html @@ -306,22 +306,22 @@

    OpenStreetMap (OSM)

    is recommended because file sizes are smaller. The OSM driver will categorize features into 5 layers :
      -
    • points: "node" features that have significant tags attached. -
    • lines: "way" features that are recognized as non-area. +
    • points: "node" features that have significant tags attached.
    • +
    • lines: "way" features that are recognized as non-area.
    • multilinestrings: "relation" features that form a -multilinestring(type = 'multilinestring' or type = 'route'). +multilinestring(type = 'multilinestring' or type = 'route').
    • multipolygons: "relation" features that form a multipolygon (type = 'multipolygon' or type = 'boundary'), and "way" features that are -recognized as area. +recognized as area.
    • other_relations: "relation" features that do -not belong to any of the above layers. +not belong to any of the above layers.
    It is recommended to import one layer at a time, and to select features with the where option, e.g. to import roads, use
    -v.in.ogr where="highway <> ''"
    +v.in.ogr where="highway >< ''"
     
    i.e. the OSM tag highway must be set. diff --git a/vector/v.in.pdal/v.in.pdal.html b/vector/v.in.pdal/v.in.pdal.html index 51fc849a184..1042f8415bf 100644 --- a/vector/v.in.pdal/v.in.pdal.html +++ b/vector/v.in.pdal/v.in.pdal.html @@ -5,10 +5,10 @@

    DESCRIPTION

    v.in.pdal supports the following filters:
      -
    • 2D region filter -
    • Z coordinates filter -
    • return filter -
    • class filter +
    • 2D region filter
    • +
    • Z coordinates filter
    • +
    • return filter
    • +
    • class filter

    EXAMPLES

    @@ -28,7 +28,7 @@

    REFERENCES

    Processing UAV and lidar point clouds in GRASS GIS. XXIII ISPRS Congress 2016 [ISPRS Archives, - ResearchGate] + ResearchGate]

    SEE ALSO

    @@ -36,8 +36,8 @@

    SEE ALSO

    r.in.pdal, g.region, -v.vect.stats -v.in.ogr, +v.vect.stats, +v.in.ogr

    AUTHOR

    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.info/v.info.html b/vector/v.info/v.info.html index 05e7903ac2d..19549d2744b 100644 --- a/vector/v.info/v.info.html +++ b/vector/v.info/v.info.html @@ -77,7 +77,7 @@

    Attribute columns for given layer

     v.info -c map=geology
     
    -Displaying column types/names for database connection of layer <1>:
    +Displaying column types/names for database connection of layer <1>:
     INTEGER|cat
     DOUBLE PRECISION|onemap_pro
     DOUBLE PRECISION|PERIMETER
    diff --git a/vector/v.kcv/v.kcv.html b/vector/v.kcv/v.kcv.html
    index 3e5b1b8a663..b82ae2d5bb7 100644
    --- a/vector/v.kcv/v.kcv.html
    +++ b/vector/v.kcv/v.kcv.html
    @@ -47,8 +47,8 @@ 

    EXAMPLES

    SEE ALSO

    -v.random, -g.region +v.random, +g.region

    AUTHORS

    diff --git a/vector/v.kernel/v.kernel.html b/vector/v.kernel/v.kernel.html index c2bd14c87b5..9ef78fb20bd 100644 --- a/vector/v.kernel/v.kernel.html +++ b/vector/v.kernel/v.kernel.html @@ -1,11 +1,10 @@

    DESCRIPTION

    v.kernel generates a raster density map from vector points -data using a moving -kernel. Available kernel +data using a moving kernel. Available kernel density functions are uniform, triangular, epanechnikov, -quartic, triweight, gaussian, cosine, default -is gaussian. +quartic, triweight, gaussian, cosine. The default function is gaussian. +

    The module can also generate a vector density map on a vector network. Conventional kernel functions produce biased estimates by overestimating the densities around network nodes, whereas the equal split method of @@ -20,7 +19,7 @@

    NOTES

    (integer). The density result stored as category may be multiplied by this number.

    For the gaussian kernel, standard deviation for the -gaussian function +gaussian function is set to 1/4 of the radius.

    With the -o flag (experimental) the command tries to calculate an @@ -38,7 +37,7 @@

    EXAMPLES

    -Density of schools
    +Density of schools
    School density
    @@ -54,7 +53,7 @@

    REFERENCES

    method for networks, its computational method and a GIS-based tool. International Journal of Geographical Information Science, Vol 23(1), pp. 7-32.
    -DOI: 10.1080/13658810802475491 +DOI: 10.1080/13658810802475491

    SEE ALSO

    diff --git a/vector/v.label.sa/v.label.sa.html b/vector/v.label.sa/v.label.sa.html index 65864c78a2e..2376c70771c 100644 --- a/vector/v.label.sa/v.label.sa.html +++ b/vector/v.label.sa/v.label.sa.html @@ -41,7 +41,7 @@

    SEE ALSO

    d.label
    d.labels
    ps.map -Wikipedia article on simulated annealing +Wikipedia article on simulated annealing

    AUTHOR

    diff --git a/vector/v.label/v.label.html b/vector/v.label/v.label.html index 1f05cf845ff..0331e6ff8a9 100644 --- a/vector/v.label/v.label.html +++ b/vector/v.label/v.label.html @@ -56,15 +56,15 @@

    Caution: The following information may be incomplete, out of date, and wrong may be specified as:
    -	lower left	(lower left corner of the text)
    -	lower right	(lower right corner of the text)
    -	lower center	(bottom center of the text)
    +    lower left    (lower left corner of the text)
    +    lower right    (lower right corner of the text)
    +    lower center    (bottom center of the text)
     
    -	upper left	(upper left corner of the text)
    -	upper right	(upper right corner of the text)
    -	upper center	(top center of the text)
    +    upper left    (upper left corner of the text)
    +    upper right    (upper right corner of the text)
    +    upper center    (top center of the text)
     
    -	center	(center of the text)
    +    center    (center of the text)
     
     
    @@ -97,21 +97,19 @@

    Caution: The following information may be incomplete, out of date, and wrong Alternatively fontsize can set the font size in normal font points. -
    TEXT COLOR: +
    TEXT COLOR:
    This selects the text color. If unspecified, the label's text is drawn in black, by default. The text color can be specified in one of several ways:
      -
    1. By color name: - -
      +
    2. By color name:
      aqua black blue brown cyan gray green grey indigo -magenta orange purple red violet white yellow +magenta orange purple red violet white yellow
    3. As red, green, blue component values. (0-255)
      -for example: 128:100:200 +for example: 128:100:200
    4. -
    5. Specify "none" to suppress the lettering. +
    6. Specify "none" to suppress the lettering.
    @@ -203,7 +201,7 @@

    EXAMPLE

     cd $MAPSET/paint/labels/
    -cat file1 file2 file3 file4 > file_all
    +cat file1 file2 file3 file4 > file_all
     

    SEE ALSO

    diff --git a/vector/v.lrs/lrs.html b/vector/v.lrs/lrs.html index 027f72d44ce..edc517788cd 100644 --- a/vector/v.lrs/lrs.html +++ b/vector/v.lrs/lrs.html @@ -70,8 +70,8 @@

    Double referenced system

    must be entered to the system and it is done by optional MP attributes:
      -
    • end_mp - end MP -
    • end_off - end offset +
    • end_mp - end MP
    • +
    • end_off - end offset
    In this case original MP on km 4 will have these attributes:
    @@ -100,7 +100,7 @@ 

    Double referenced system

    LRS table structure

    - +
    @@ -116,12 +116,12 @@

    LRS table structure

    Available commands

      -
    • v.lrs.create to create a linear referencing system, -
    • v.lrs.label to create stationing on the LRS, +
    • v.lrs.create to create a linear referencing system,
    • +
    • v.lrs.label to create stationing on the LRS,
    • v.lrs.segment to create points/segments on LRS, - and + and
    • v.lrs.where to find line id and real km+offset -for given points in vector map using linear referencing system. +for given points in vector map using linear referencing system.

    Input lines for v.lrs.segment and v.lrs.label

    @@ -157,12 +157,12 @@

    NOTES

    Explanations of selected options:
    • llayer: vector layer in line map (usually 1; see vectorintro - for "layer" concept) + for "layer" concept)
    • player: vector layer in point map (usually 1; see vectorintro - for "layer" concept) -
    • rsdriver: Driver name for LRS table - DBMI SQL driver (dbf, pg, mysql, sqlite, etc) -
    • rsdatabase: Database name for LRS table - DBMI SQL database name (e.g., "lrsdb") -
    • rstable: Name of the LRS table - DBMI SQL table name (e.g., "streamslrs") + for "layer" concept)
    • +
    • rsdriver: Driver name for LRS table - DBMI SQL driver (dbf, pg, mysql, sqlite, etc)
    • +
    • rsdatabase: Database name for LRS table - DBMI SQL database name (e.g., "lrsdb")
    • +
    • rstable: Name of the LRS table - DBMI SQL table name (e.g., "streamslrs")

    SEE ALSO

    diff --git a/vector/v.mkgrid/v.mkgrid.html b/vector/v.mkgrid/v.mkgrid.html index 8d5a6900fff..a1e7d87a6df 100644 --- a/vector/v.mkgrid/v.mkgrid.html +++ b/vector/v.mkgrid/v.mkgrid.html @@ -66,8 +66,8 @@

    Creating a positioned grid in a latitude-longitude

    at 167deg 52min east, 47deg 6min south. For use with e.g. QGIS you can then pull this grid into a project with projected coordinate reference system (CRS) using v.proj before -exporting as a Shapefile with v.out.ogr (within GRASS GIS you could -just use d.grid -w from the projec with projected CRS for the same effect): +exporting as a vector file with v.out.ogr (within GRASS GIS you could +just use d.grid -w from the project with projected CRS for the same effect):
     v.mkgrid map=p2min_grid grid=10,12 position=coor coordinates=167:52E,47:06S box=0:02,0:02
    @@ -153,7 +153,7 @@ 

    Using hexagons for point density

    v.vect.stats points=points_of_interest areas=hexagons count_column=count
    -User should note that some of the points may be outside the grid +Users should note that some of the points may be outside the grid since the hexagons cannot cover all the area around the edges (the computational region extent needs to be enlarged if all points should be considered). @@ -164,11 +164,6 @@

    Using hexagons for point density

    v.colors map=hexagons use=attr column=count color=viridis - -

    Point density in a hexagonal grid diff --git a/vector/v.net.alloc/v.net.alloc.html b/vector/v.net.alloc/v.net.alloc.html index 2a1f0efd1cb..81dcd45a9d4 100644 --- a/vector/v.net.alloc/v.net.alloc.html +++ b/vector/v.net.alloc/v.net.alloc.html @@ -190,8 +190,8 @@

    EXAMPLES

    v.db.update map=streets_hospitals column=FT_COST value=-1 where="ONE_WAY = 'TF'" # add costs to newly created lines -v.db.update map=streets_hospitals column=TF_COST value=0 where="cat > 49746" -v.db.update map=streets_hospitals column=FT_COST value=0 where="cat > 49746" +v.db.update map=streets_hospitals column=TF_COST value=0 where="cat > 49746" +v.db.update map=streets_hospitals column=FT_COST value=0 where="cat > 49746" # from centers v.net.alloc in=streets_hospitals out=streets_hospitals_alloc_from center_cats=1-10000 arc_column=FT_COST arc_backward_column=TF_COST diff --git a/vector/v.net.allpairs/v.net.allpairs.html b/vector/v.net.allpairs/v.net.allpairs.html index 8f65be7a356..5bd5bc45d85 100644 --- a/vector/v.net.allpairs/v.net.allpairs.html +++ b/vector/v.net.allpairs/v.net.allpairs.html @@ -50,8 +50,8 @@

    EXAMPLE

    SEE ALSO

    -v.net.path, -v.net.distance +v.net.path, +v.net.distance

    AUTHORS

    diff --git a/vector/v.net.bridge/v.net.bridge.html b/vector/v.net.bridge/v.net.bridge.html index fedb0559d6c..7f871ae8a1a 100644 --- a/vector/v.net.bridge/v.net.bridge.html +++ b/vector/v.net.bridge/v.net.bridge.html @@ -8,8 +8,8 @@

    NOTES

    the (sub-)network. A node is an articulation point if its removal would disconnect the (sub-)network. For more information and formal definitions check the wikipedia entries: -bridge -and articulation +bridge +and articulation point.

    The output of the module contains the selected @@ -26,12 +26,6 @@

    NOTES

    An articulation point in graph theory is an articulation node in GRASS terminology. -

    EXAMPLES

    - -
    -	TBD
    -
    -

    SEE ALSO

    diff --git a/vector/v.net.centrality/v.net.centrality.html b/vector/v.net.centrality/v.net.centrality.html index bd122149d34..28871b660e3 100644 --- a/vector/v.net.centrality/v.net.centrality.html +++ b/vector/v.net.centrality/v.net.centrality.html @@ -9,7 +9,7 @@

    NOTES

    stores them in the given columns of an attribute table, which is created and linked to the output map. For the description of these, please check the following -wikipedia article. +wikipedia article. If the column name is not given for a measure then that measure is not computed. If -a flag is set then points are added on nodes without points. Also, the points for which the output is computed diff --git a/vector/v.net.flow/v.net.flow.html b/vector/v.net.flow/v.net.flow.html index 66a617cb0e6..9a15c95301e 100644 --- a/vector/v.net.flow/v.net.flow.html +++ b/vector/v.net.flow/v.net.flow.html @@ -23,7 +23,7 @@

    NOTES

    flowing in the backward direction. Cut map contains the edges in the minimum cut.
    -A famous result +A famous result says that the total amount of water flowing is equal to the minimum cut. diff --git a/vector/v.net.iso/v.net.iso.html b/vector/v.net.iso/v.net.iso.html index 28c92571cbb..edc3450e173 100644 --- a/vector/v.net.iso/v.net.iso.html +++ b/vector/v.net.iso/v.net.iso.html @@ -89,7 +89,7 @@

    Subdivision of a network using distance:

    #1 0 - < 1000 #2 1000 - < 2000 #3 2000 - < 5000 -#4 >= 5000 +#4 >= 5000 To display the result, run for example: @@ -162,7 +162,7 @@

    Subdivision of a network using traveling time:

    v.db.update map=myroads_net_iso_time layer=1 column=trav_time value="0 - 1" where="cat = 1" v.db.update map=myroads_net_iso_time layer=1 column=trav_time value="1 - 2" where="cat = 2" v.db.update map=myroads_net_iso_time layer=1 column=trav_time value="2 - 5" where="cat = 3" -v.db.update map=myroads_net_iso_time layer=1 column=trav_time value="> 5" where="cat = 4" +v.db.update map=myroads_net_iso_time layer=1 column=trav_time value="> 5" where="cat = 4" # colors # cats=1: blue v.db.update map=myroads_net_iso_time layer=1 column=GRASSRGB value="000:000:255" where="cat = 1" diff --git a/vector/v.net.path/v.net.path.html b/vector/v.net.path/v.net.path.html index 9af5842495a..60b26f3a591 100644 --- a/vector/v.net.path/v.net.path.html +++ b/vector/v.net.path/v.net.path.html @@ -24,8 +24,8 @@

    DESCRIPTION

    attached attribute table.

    Nodes can be

      -
    • piped into the program from file or from stdin, or -
    • defined in the graphical user interface ("enter values interactively"). +
    • piped into the program from file or from stdin, or
    • +
    • defined in the graphical user interface ("enter values interactively").
    The syntax is as follows: @@ -61,7 +61,7 @@

    DESCRIPTION

  • 0 - OK, path found
  • 1 - node is not reachable
  • 2 - point of given category does not exist
  • - +
  • cost - travelling costs (on the network, not to/from network)
  • fdist - the distance from first point to the network
  • tdist - the distance from the network to second point
  • diff --git a/vector/v.net.salesman/v.net.salesman.html b/vector/v.net.salesman/v.net.salesman.html index 0f29c69e857..00153281daf 100644 --- a/vector/v.net.salesman/v.net.salesman.html +++ b/vector/v.net.salesman/v.net.salesman.html @@ -3,7 +3,7 @@

    DESCRIPTION

    v.net.salesman calculates the optimal route to visit nodes on a vector network. -

    Costs may be either line lengths, or attributes saved in a database +

    Costs may be either line lengths or attributes saved in a database table. These attribute values are taken as costs of whole segments, not as costs to traverse a length unit (e.g. meter) of the segment. For example, if the speed limit is 100 km / h, the cost to traverse a @@ -14,16 +14,16 @@

    DESCRIPTION

    Supported are cost assignments for arcs, and also different costs for both directions of a vector line. For areas, costs will be calculated along boundary lines. +

    The input vector needs to be prepared with v.net operation=connect in order to connect points representing center nodes to the network.

    Points specified by category must be exactly on network nodes, and the input vector map needs to be prepared with v.net operation=connect. -

    Application of flag -t enables a turntable support. -This flag requires additional parameters turn_layer and turn_cat_layer -that are otherwise ignored. - The turntable allows +

    The flag -t enables turntable support. +This flag requires additional parameters, turn_layer and turn_cat_layer, +that are otherwise ignored. The turntable allows to model e.g. traffic code, where some turns may be prohibited. This means that the input layer is expanded by turntable with costs of every possible turn on any possible node @@ -161,7 +161,7 @@

    AUTHORS

    TURNS SUPPORT

    -The turns support was implemnented as part of GRASS GIS turns cost project +The turns support was implemented as part of GRASS GIS turns cost project at Czech Technical University in Prague, Czech Republic.
    Eliska Kyzlikova, Stepan Turek, Lukas Bocan and Viera Bejdova participated in the project. diff --git a/vector/v.net.timetable/v.net.timetable.html b/vector/v.net.timetable/v.net.timetable.html index e990ca5d8f1..3540f93e08f 100644 --- a/vector/v.net.timetable/v.net.timetable.html +++ b/vector/v.net.timetable/v.net.timetable.html @@ -9,7 +9,7 @@

    DESCRIPTION

    PATH_ID FROM_X FROM_Y TO_X TO_Y START_TIME MIN_CHANGE MAX_CHANGES WALK_CHANGE PATH_ID FROM_STOP TO_STOP START_TIME MIN_CHANGE MAX_CHANGES WALK_CHANGE -where PATH_ID is the identificator of a query that is used in the +where PATH_ID is the identifier of a query that is used in the output map to differentiate between queries. Search begins at START_TIME. MIN_CHANGE gives the minimum number of time (inclusively) for a change from one route to another. MAX_CHANGES @@ -42,7 +42,7 @@

    DESCRIPTION

    3|47|300|3|24|24 where CAT is the category of a point in the map, PATH_ID is the path -identificator, STOP_ID is the identificator of the stop as used in +identifier, STOP_ID is the identifier of the stop as used in the input map, INDEX is the index of the stop on the path (i.e, index=1 is the first stop visited, ...) and ARR_TIME and DEP_TIME denote the arrival time and departure time respectively. Arrival @@ -51,14 +51,14 @@

    DESCRIPTION

    time.
    The table linked to the second layer corresponds to subroutes taken -between stops. The following table is obtainedd for the above query: +between stops. The following table is obtained for the above query:
     cat|path_id|from_id|to_id|route_id|index|from_time|to_time
     1|47|130|250|15|1|15|22
     2|47|250|300|-1|2|22|24
     
    where CAT is the category of lines of subroute between stops FROM_ID -to TO_ID, ROUTE_ID is the identificator of the route taken or -1 if +to TO_ID, ROUTE_ID is the identifier of the route taken or -1 if walking, INDEX and PATH_ID are as above and FROM_TIME and TO_TIME denote the times between which the route is taken.
    @@ -67,7 +67,7 @@

    DESCRIPTION

    is added between two corresponding points. Finally, instead of straight line segment, the actual paths of routes can be given in paths layer. If this parameter is used then each line in the -input map must contain identificators as category numbers of all +input map must contain identifiers as category numbers of all routes passing through the line. The module then finds the path between two stops and writes this path instead. In case of walking from one stop to another, straight line between the stops is used. @@ -83,7 +83,7 @@

    NOTES

    still needs to be a separate route for every time. For each stop (given by the category number of the point) the table storing information about the routes must contain the list of all routes -stopping at the stop(given by route identificators) together with +stopping at the stop(given by route identifiers) together with arrival times. That is, the table must contain three columns: stop - which is the key of the table, route_id and stop_time where each triple corresponds to a route arriving to a stop and a @@ -122,7 +122,7 @@

    NOTES

    EXAMPLES

    -To find a path from stop with identificator 130 to stop with +To find a path from stop with identifier 130 to stop with category 300, starting at time 0, with one time unit for change, maximum of 5 changes and with walking not considered a change of route, we use the following command: diff --git a/vector/v.net/arcs.c b/vector/v.net/arcs.c index 6d18f760bfd..20554fc19f9 100644 --- a/vector/v.net/arcs.c +++ b/vector/v.net/arcs.c @@ -68,6 +68,7 @@ int create_arcs(FILE *file, struct Map_info *Pnts, struct Map_info *Out, Vect_destroy_line_struct(points); Vect_destroy_cats_struct(cats); + Vect_destroy_line_struct(points2); return narcs; } diff --git a/vector/v.net/report.c b/vector/v.net/report.c index 952acd5dfff..bce9baa3c5a 100644 --- a/vector/v.net/report.c +++ b/vector/v.net/report.c @@ -128,6 +128,9 @@ int report(struct Map_info *In, int afield, int nfield, int action) } } } + Vect_destroy_cats_struct(Cats); + Vect_destroy_cats_struct(Cats2); + Vect_destroy_line_struct(Points); return 0; } diff --git a/vector/v.net/testsuite/test_v_net.py b/vector/v.net/testsuite/test_v_net.py index 469ac127f47..50bb047628f 100644 --- a/vector/v.net/testsuite/test_v_net.py +++ b/vector/v.net/testsuite/test_v_net.py @@ -6,10 +6,10 @@ class TestVNet(TestCase): network = "test_vnet" - def tearDown(cls): + def tearDown(self): """Remove viewshed map after each test method""" # TODO: eventually, removing maps should be handled through testing framework functions - cls.runModule("g.remove", flags="f", type="vector", name=cls.network) + self.runModule("g.remove", flags="f", type="vector", name=self.network) def test_nodes(self): """Test""" diff --git a/vector/v.net/v.net.html b/vector/v.net/v.net.html index ab112155589..baef25e5484 100644 --- a/vector/v.net/v.net.html +++ b/vector/v.net/v.net.html @@ -154,7 +154,7 @@

    NOTES

    EXAMPLES

    -The examples are North Carolina dataset based. +The examples are North Carolina dataset based.

    Create nodes globally for all line ends and intersections

    diff --git a/vector/v.normal/v.normal.html b/vector/v.normal/v.normal.html index 327fcdcd5d1..2f40d6171e6 100644 --- a/vector/v.normal/v.normal.html +++ b/vector/v.normal/v.normal.html @@ -9,22 +9,22 @@

    NOTES

    giving an index, ranges of indices, or multiple thereof.
      -
    1. Sample skewness and kurtosis -
    2. Geary's a-statistic and an approximate normal transformation -
    3. Extreme normal deviates -
    4. D'Agostino's D-statistic -
    5. Modified Kuiper V-statistic -
    6. Modified Watson U^2-statistic -
    7. Durbin's Exact Test (modified Kolmogorov) -
    8. Modified Anderson-Darling statistic -
    9. Modified Cramer-Von Mises W^2-statistic -
    10. Kolmogorov-Smirnov D-statistic (modified for normality testing) +
    11. Sample skewness and kurtosis
    12. +
    13. Geary's a-statistic and an approximate normal transformation
    14. +
    15. Extreme normal deviates
    16. +
    17. D'Agostino's D-statistic
    18. +
    19. Modified Kuiper V-statistic
    20. +
    21. Modified Watson U^2-statistic
    22. +
    23. Durbin's Exact Test (modified Kolmogorov)
    24. +
    25. Modified Anderson-Darling statistic
    26. +
    27. Modified Cramer-Von Mises W^2-statistic
    28. +
    29. Kolmogorov-Smirnov D-statistic (modified for normality testing)
    30. Chi-Square test statistic (equal probability classes) and - the number of degrees of freedom -
    31. Shapiro-Wilk W Test -
    32. Weisberg-Binghams W'' (similar to Shapiro-Francia's W') -
    33. Royston's extension of W for large samples -
    34. Kotz Separate-Families Test for Lognormality vs. Normality + the number of degrees of freedom
    35. +
    36. Shapiro-Wilk W Test
    37. +
    38. Weisberg-Binghams W'' (similar to Shapiro-Francia's W')
    39. +
    40. Royston's extension of W for large samples
    41. +
    42. Kotz Separate-Families Test for Lognormality vs. Normality

    EXAMPLE

    diff --git a/vector/v.out.ascii/v.out.ascii.html b/vector/v.out.ascii/v.out.ascii.html index 2eff87a01fa..964df04b084 100644 --- a/vector/v.out.ascii/v.out.ascii.html +++ b/vector/v.out.ascii/v.out.ascii.html @@ -90,7 +90,7 @@

    Point mode

    Print also selected attributes:
    -v.out.ascii input=geodetic_pts format=point where="cat > 5 and cat <= 8" columns=GEOD_NAME
    +v.out.ascii input=geodetic_pts format=point where="cat > 5 and cat <= 8" columns=GEOD_NAME
     
     573638.06289275|271623.25042595|6|27 WC 6
     574416.81289275|274116.65542595|7|27 WC 7
    @@ -100,7 +100,7 @@ 

    Point mode

    To print all attributes type columns=*:
    -v.out.ascii input=geodetic_pts format=point where="cat > 5 and cat <= 8" columns=*
    +v.out.ascii input=geodetic_pts format=point where="cat > 5 and cat <= 8" columns=*
     573638.06289275|271623.25042595|6|6|0.00000000|0.00000000|6|6|27 WC 6|573638.09200000|271623.24100000|0.00|0|1.00000000|1.00000000
     574416.81289275|274116.65542595|7|7|0.00000000|0.00000000|7|7|27 WC 7|574416.84100000|274116.64900000|0.00|0|1.00000000|1.00000000
     575301.31189275|275303.81342595|8|8|0.00000000|0.00000000|8|8|27 WC 8|575301.30600000|275303.82600000|0.00|0|1.00000000|1.00000000
    @@ -109,7 +109,7 @@ 

    Point mode

    WKT mode

    WKT is abbreviation -for Well-known +for Well-known text.
    diff --git a/vector/v.out.dxf/main.c b/vector/v.out.dxf/main.c
    index d00a15e1378..2e30172dd10 100644
    --- a/vector/v.out.dxf/main.c
    +++ b/vector/v.out.dxf/main.c
    @@ -195,6 +195,8 @@ int add_plines(struct Map_info *Map, int field, double textsize)
             }
             nlines_dxf++;
         }
    +    Vect_destroy_line_struct(Points);
    +    Vect_destroy_cats_struct(Cats);
     
         return nlines_dxf;
     }
    diff --git a/vector/v.out.dxf/v.out.dxf.html b/vector/v.out.dxf/v.out.dxf.html
    index 853e19472bd..95057f05f22 100644
    --- a/vector/v.out.dxf/v.out.dxf.html
    +++ b/vector/v.out.dxf/v.out.dxf.html
    @@ -12,7 +12,7 @@ 

    NOTES

    REFERENCES

    -AutoCad DXF (from Wikipedia, the free encyclopedia) +AutoCad DXF (from Wikipedia, the free encyclopedia)

    SEE ALSO

    diff --git a/vector/v.out.ogr/args.c b/vector/v.out.ogr/args.c index 18841837e24..8310c302c50 100644 --- a/vector/v.out.ogr/args.c +++ b/vector/v.out.ogr/args.c @@ -77,6 +77,19 @@ void parse_args(int argc, char **argv, struct Options *options, _("OGR layer creation option (format specific, NAME=VALUE)"); options->lco->guisection = _("Creation"); + options->method = G_define_option(); + options->method->key = "method"; + options->method->type = TYPE_STRING; + options->method->required = NO; + options->method->options = "fast,slow"; + options->method->answer = "fast"; + options->method->label = _("Method to use for export, " + "default is fast export, " + "use slow export in case of problems with " + "the fast method"); + G_asprintf((char **)&options->method->descriptions, "fast;%s;slow;%s", + _("new, faster method"), _("old, slower method")); + flags->update = G_define_flag(); flags->update->key = 'u'; flags->update->description = diff --git a/vector/v.out.ogr/attrb_fast.c b/vector/v.out.ogr/attrb_fast.c new file mode 100644 index 00000000000..45ee832f076 --- /dev/null +++ b/vector/v.out.ogr/attrb_fast.c @@ -0,0 +1,155 @@ +#include + +#include "local_proto.h" + +int mk_att_fast(int cat, struct field_info *Fi, int ncol, int *colctype, + const char **colname, int doatt, int nocat, + OGRFeatureH Ogr_feature, int *noatt, dbCursor *cursor, + int *more, int *db_cat, int key_col_index) +{ + int j, ogrfieldnum; + dbTable *Table; + static int first = 1; + static dbString dbstring; + dbColumn *Column; + dbValue *Value; + + G_debug(2, "mk_att() cat = %d, doatt = %d", cat, doatt); + + /* init constants */ + if (first) { + db_init_string(&dbstring); + first = 0; + } + + /* Attributes */ + /* Reset */ + if (!doatt) { + ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, GV_KEY_COLUMN); + if (ogrfieldnum > -1) + OGR_F_UnsetField(Ogr_feature, ogrfieldnum); + /* doatt reset moved into have cat loop as the table needs to be + open to know the OGR field ID. Hopefully this has no ill consequences + */ + } + + /* Read & set attributes */ + if (cat >= 0) { /* Line with category */ + if (doatt) { + /* get current entries from cursor, + * check cat value in attributes */ + + Table = db_get_cursor_table(cursor); + while (*more && cat > *db_cat) { + Column = db_get_table_column(Table, key_col_index); + Value = db_get_column_value(Column); + + /* yes, the key column is sometimes of type double */ + switch (colctype[key_col_index]) { + case DB_C_TYPE_INT: + *db_cat = db_get_value_int(Value); + break; + case DB_C_TYPE_DOUBLE: + *db_cat = (int)db_get_value_double(Value); + break; + } + + G_debug(2, "found db_cat %d for cat %d in column %s", *db_cat, + cat, db_get_column_name(Column)); + + if (cat > *db_cat) { + if (db_fetch(cursor, DB_NEXT, more) != DB_OK) { + G_fatal_error(_("Unable to fetch data from table")); + } + } + } + + if (!(*more) || cat != *db_cat) { + G_debug(1, "No database record for cat = %d", cat); + /* Set at least key column to category */ + if (!nocat) { + ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, Fi->key); + OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum, cat); + (*noatt)++; + } + else { + G_fatal_error(_("No database record for cat = %d and " + "export of 'cat' disabled"), + cat); + } + } + else { + for (j = 0; j < ncol; j++) { + Column = db_get_table_column(Table, j); + Value = db_get_column_value(Column); + db_convert_column_value_to_string( + Column, &dbstring); /* for debug only */ + G_debug(2, "col %d : val = %s", j, + db_get_string(&dbstring)); + + G_debug(2, " colctype = %d", colctype[j]); + + if (nocat && strcmp(Fi->key, colname[j]) == 0) + continue; + + ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname[j]); + G_debug(2, " column = %s -> fieldnum = %d", colname[j], + ogrfieldnum); + + if (ogrfieldnum < 0) { + G_debug(4, + "Could not get OGR field number for column %s", + colname[j]); + continue; + } + + /* Reset */ + if ((nocat && strcmp(Fi->key, colname[j]) == 0) == 0) { + /* if this is 'cat', then execute the following only if + * the '-s' flag was NOT given */ + OGR_F_SetFieldNull(Ogr_feature, ogrfieldnum); + } + + /* prevent writing NULL values */ + if (!db_test_value_isnull(Value)) { + if ((nocat && strcmp(Fi->key, colname[j]) == 0) == 0) { + /* if this is 'cat', then execute the following only + * if the '-s' flag was NOT given */ + + switch (colctype[j]) { + case DB_C_TYPE_INT: + OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum, + db_get_value_int(Value)); + break; + case DB_C_TYPE_DOUBLE: + OGR_F_SetFieldDouble( + Ogr_feature, ogrfieldnum, + db_get_value_double(Value)); + break; + case DB_C_TYPE_STRING: + OGR_F_SetFieldString( + Ogr_feature, ogrfieldnum, + db_get_value_string(Value)); + break; + case DB_C_TYPE_DATETIME: + db_convert_column_value_to_string(Column, + &dbstring); + OGR_F_SetFieldString(Ogr_feature, ogrfieldnum, + db_get_string(&dbstring)); + break; + } + } + } + else + OGR_F_SetFieldNull(Ogr_feature, ogrfieldnum); + } + } + } + else { /* Use cat only */ + ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, GV_KEY_COLUMN); + OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum, cat); + } + } + + return 1; +} diff --git a/vector/v.out.ogr/dsn.c b/vector/v.out.ogr/dsn.c index 31d258c05c7..bd7ce101ed2 100644 --- a/vector/v.out.ogr/dsn.c +++ b/vector/v.out.ogr/dsn.c @@ -37,7 +37,7 @@ char *get_datasource_name(const char *opt_dsn, int use_ogr) /* add db.login settings (user, password, host, port) */ if (DB_OK == - db_get_login2("pg", database, &user, &passwd, &host, &port)) { + db_get_login("pg", database, &user, &passwd, &host, &port)) { if (user) { if (!G_strcasestr(opt_dsn, "user=")) { strcat(connect_str, " user="); diff --git a/vector/v.out.ogr/export_areas.c b/vector/v.out.ogr/export_areas.c index acab7164a8d..5cbc78c408d 100644 --- a/vector/v.out.ogr/export_areas.c +++ b/vector/v.out.ogr/export_areas.c @@ -13,8 +13,9 @@ static int export_areas_multi(struct Map_info *, int, int, OGRFeatureDefnH, static OGRGeometryH create_polygon(struct Map_info *, int, struct line_pnts *, int); +#if 0 /* maybe useful */ -void reverse_points(struct line_pnts *Points) +static void reverse_points(struct line_pnts *Points) { int i, j, nhalf; double tmp; @@ -35,6 +36,7 @@ void reverse_points(struct line_pnts *Points) Points->z[j] = tmp; } } +#endif /* export areas as single/multi-polygons */ int export_areas(struct Map_info *In, int field, int multi, int donocat, diff --git a/vector/v.out.ogr/export_areas_fast.c b/vector/v.out.ogr/export_areas_fast.c new file mode 100644 index 00000000000..cad77b2279a --- /dev/null +++ b/vector/v.out.ogr/export_areas_fast.c @@ -0,0 +1,539 @@ +#include + +#include "local_proto.h" + +static int export_areas_single(struct Map_info *, int, int, OGRFeatureDefnH, + OGRLayerH, struct field_info *, dbDriver *, int, + int *, const char **, int, int, int *, int *, + int); +static int export_areas_multi(struct Map_info *, int, int, OGRFeatureDefnH, + OGRLayerH, struct field_info *, dbDriver *, int, + int *, const char **, int, int, int *, int *, + int); +static OGRGeometryH create_polygon(struct Map_info *, int, struct line_pnts *, + int); + +#if 0 +/* maybe useful */ +static void reverse_points(struct line_pnts *Points) +{ + int i, j, nhalf; + double tmp; + + nhalf = Points->n_points / 2; + + for (i = 0, j = Points->n_points - 1; i < nhalf; i++, j--) { + tmp = Points->x[i]; + Points->x[i] = Points->x[j]; + Points->x[j] = tmp; + + tmp = Points->y[i]; + Points->y[i] = Points->y[j]; + Points->y[j] = tmp; + + tmp = Points->z[i]; + Points->z[i] = Points->z[j]; + Points->z[j] = tmp; + } +} +#endif + +/* export areas as single/multi-polygons */ +int export_areas_fast(struct Map_info *In, int field, int multi, int donocat, + OGRFeatureDefnH Ogr_featuredefn, OGRLayerH Ogr_layer, + struct field_info *Fi, dbDriver *driver, int ncol, + int *colctype, const char **colname, int doatt, int nocat, + int *noatt, int *fout, int outer_ring_ccw) +{ + if (multi) + /* export as multi-polygons */ + return export_areas_multi( + In, field, donocat, Ogr_featuredefn, Ogr_layer, Fi, driver, ncol, + colctype, colname, doatt, nocat, noatt, fout, outer_ring_ccw); + + /* export as polygons */ + return export_areas_single(In, field, donocat, Ogr_featuredefn, Ogr_layer, + Fi, driver, ncol, colctype, colname, doatt, + nocat, noatt, fout, outer_ring_ccw); +} + +int export_areas_single(struct Map_info *In, int field, int donocat, + OGRFeatureDefnH Ogr_featuredefn, OGRLayerH Ogr_layer, + struct field_info *Fi, dbDriver *driver, int ncol, + int *colctype, const char **colname, int doatt, + int nocat, int *n_noatt, int *n_nocat, + int outer_ring_ccw) +{ + int i; + int cat, last_cat, db_cat, centroid, area; + int n_exported; + + struct line_pnts *Points; + struct line_cats *Cats; + + int findex; + struct Cat_index *ci; + int cat_index, n_cats; + + dbString dbstring; + char buf[SQL_BUFFER_SIZE]; + dbCursor cursor; + int more; + int key_col_index; + + OGRGeometryH Ogr_geometry; + OGRFeatureH Ogr_feature; + + Points = Vect_new_line_struct(); + Cats = Vect_new_cats_struct(); + + n_exported = 0; + + /* get category index for given field */ + findex = Vect_cidx_get_field_index(In, field); + if (findex == -1) { + G_fatal_error(_("Unable to export multi-features. No category index " + "for layer %d."), + field); + } + + ci = &(In->plus.cidx[findex]); + n_cats = ci->n_cats; + + if (donocat) + G_message(_("Exporting features with category...")); + + /* select attributes ordered by category value */ + db_init_string(&dbstring); + sprintf(buf, "SELECT * FROM %s ORDER BY %s ASC", Fi->table, Fi->key); + G_debug(2, "SQL: %s", buf); + db_set_string(&dbstring, buf); + if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != + DB_OK) { + G_fatal_error(_("Cannot select attributes sorted by %s"), Fi->key); + } + + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + + /* get index of key column */ + key_col_index = -1; + for (i = 0; i < ncol; i++) { + if (strcmp(Fi->key, colname[i]) == 0) { + key_col_index = i; + break; + } + } + + last_cat = -1; + db_cat = -1; + for (cat_index = 0; cat_index < n_cats; cat_index++) { + + G_percent(cat_index, n_cats, 5); + + /* get area's category */ + if (!(ci->cat[cat_index][1] & GV_CENTROID)) + continue; + + cat = ci->cat[cat_index][0]; + /* make sure the cidx is ordered by cat */ + if (cat < last_cat) + G_fatal_error(_("Category index is not sorted ascending by cat!")); + last_cat = cat; + + centroid = ci->cat[cat_index][2]; + + area = Vect_get_centroid_area(In, centroid); + + if (area < 1) { + /* centroid not in area or duplicate centroid */ + continue; + } + + /* create polygon from area */ + Ogr_geometry = create_polygon(In, area, Points, outer_ring_ccw); + + /* add feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + /* get attributes */ + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, Ogr_feature, + n_noatt, &cursor, &more, &db_cat, key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + OGR_G_DestroyGeometry(Ogr_geometry); + } + + if (donocat) + G_message(_("Exporting features without category...")); + + if (doatt) { + db_close_cursor(&cursor); + if (donocat) { + cat = -1; + if (db_open_select_cursor(driver, &dbstring, &cursor, + DB_SEQUENTIAL) != DB_OK) { + G_fatal_error(_("Cannot select attributes for cat = %d"), cat); + } + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + } + } + + for (area = 1; area <= Vect_get_num_areas(In); area++) { + centroid = Vect_get_area_centroid(In, area); + /* skip areas without centroid */ + if (centroid == 0) + continue; + + /* get areas's category */ + Vect_get_area_cats(In, area, Cats); + Vect_cat_get(Cats, field, &cat); + /* skip areas with category */ + if (cat >= 0) + continue; + /* skip areas without category, do not export not labeled */ + if (cat < 0 && !donocat) { + (*n_nocat)++; + continue; + } + + (*n_nocat)++; + + /* create polygon from area */ + Ogr_geometry = create_polygon(In, area, Points, outer_ring_ccw); + + /* add feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + /* no attributes for features without category */ + cat = -1; + db_cat = -2; + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, Ogr_feature, + n_noatt, &cursor, &more, &db_cat, key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + OGR_G_DestroyGeometry(Ogr_geometry); + } + + if (donocat && doatt) + db_close_cursor(&cursor); + + Vect_destroy_line_struct(Points); + + return n_exported; +} + +int export_areas_multi(struct Map_info *In, int field, int donocat, + OGRFeatureDefnH Ogr_featuredefn, OGRLayerH Ogr_layer, + struct field_info *Fi, dbDriver *driver, int ncol, + int *colctype, const char **colname, int doatt, + int nocat, int *n_noatt, int *n_nocat, + int outer_ring_ccw) +{ + int i, n_exported, area, centroid; + int cat, last_cat, db_cat, line, findex, ipart; + + struct line_pnts *Points; + struct line_cats *Cats; + struct ilist *line_list, *lcats; + + struct Cat_index *ci; + int cat_index, n_cats; + + dbString dbstring; + char buf[SQL_BUFFER_SIZE]; + dbCursor cursor; + int more; + int key_col_index; + + OGRGeometryH Ogr_geometry, Ogr_geometry_part; + OGRFeatureH Ogr_feature; + OGRwkbGeometryType wkbtype, wkbtype_part; + + Points = Vect_new_line_struct(); + Cats = Vect_new_cats_struct(); + line_list = Vect_new_list(); + lcats = Vect_new_list(); + + n_exported = 0; + + /* check if category index is available for given field */ + findex = Vect_cidx_get_field_index(In, field); + if (findex == -1) { + G_fatal_error(_("Unable to export multi-features. No category index " + "for layer %d."), + field); + } + + ci = &(In->plus.cidx[findex]); + n_cats = ci->n_cats; + + /* determine type */ + wkbtype_part = wkbPolygon; + wkbtype = get_multi_wkbtype(wkbtype_part); + + if (donocat) + G_message(_("Exporting features with category...")); + + key_col_index = -1; + more = 1; + if (doatt) { + /* select attributes ordered by category value */ + db_init_string(&dbstring); + sprintf(buf, "SELECT * FROM %s ORDER BY %s ASC", Fi->table, Fi->key); + G_debug(2, "SQL: %s", buf); + db_set_string(&dbstring, buf); + if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != + DB_OK) { + G_fatal_error(_("Cannot select attributes sorted by %s"), Fi->key); + } + + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + + /* get index of key column */ + key_col_index = -1; + for (i = 0; i < ncol; i++) { + if (strcmp(Fi->key, colname[i]) == 0) { + key_col_index = i; + break; + } + } + } + + last_cat = -1; + db_cat = -1; + cat_index = 0; + while (cat_index < n_cats) { + + G_percent(cat_index, n_cats, 5); + + cat = ci->cat[cat_index][0]; + + /* make sure the cidx is ordered by cat */ + if (cat < last_cat) + G_fatal_error(_("Category index is not sorted ascending by cat!")); + last_cat = cat; + + /* collect all features with current cat */ + Vect_reset_list(line_list); + while (cat_index < n_cats && ci->cat[cat_index][0] == cat) { + if (ci->cat[cat_index][1] & GV_CENTROID) { + Vect_list_append(line_list, ci->cat[cat_index][2]); + } + cat_index++; + } + + /* create multi-feature */ + Ogr_geometry = OGR_G_CreateGeometry(wkbtype); + + /* build simple features geometry, go through all parts */ + for (ipart = 0; ipart < line_list->n_values; ipart++) { + line = line_list->value[ipart]; + G_debug(3, "cat=%d, line=%d -> part=%d", cat, line, ipart); + + /* get centroid's category */ + Vect_read_line(In, NULL, Cats, line); + /* check for category consistency */ + Vect_field_cat_get(Cats, field, lcats); + if (!Vect_val_in_list(lcats, cat)) + G_fatal_error(_("Unable to create multi-feature. " + "Category %d not found in line %d, field %d"), + cat, line, field); + + /* find corresponding area */ + area = Vect_get_centroid_area(In, line); + if (area <= 0) + continue; + + /* create polygon from area */ + Ogr_geometry_part = + create_polygon(In, area, Points, outer_ring_ccw); + + /* add part */ + OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part); + } + + if (!OGR_G_IsEmpty(Ogr_geometry)) { + /* write multi-feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + /* get attributes */ + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, + Ogr_feature, n_noatt, &cursor, &more, &db_cat, + key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + } + else { + /* skip empty features */ + G_debug(3, "multi-feature is empty -> skipped"); + } + + OGR_G_DestroyGeometry(Ogr_geometry); + } + + if (donocat) + G_message(_("Exporting features without category...")); + + /* check areas without category, if -c flag is given write them as + * one multi-feature */ + Ogr_geometry = OGR_G_CreateGeometry(wkbtype); + + if (doatt) { + db_close_cursor(&cursor); + if (donocat) { + cat = -1; + if (db_open_select_cursor(driver, &dbstring, &cursor, + DB_SEQUENTIAL) != DB_OK) { + G_fatal_error(_("Cannot select attributes for cat = %d"), cat); + } + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + } + } + + for (area = 1; area <= Vect_get_num_areas(In); area++) { + centroid = Vect_get_area_centroid(In, area); + /* skip areas without centroid */ + if (centroid == 0) + continue; + + /* get areas's category */ + Vect_get_area_cats(In, area, Cats); + Vect_cat_get(Cats, field, &cat); + /* skip areas with category */ + if (cat >= 0) + continue; + /* skip areas without category, do not export not labeled */ + if (cat < 0 && !donocat) { + (*n_nocat)++; + continue; + } + + /* create polygon from area */ + Ogr_geometry_part = create_polygon(In, area, Points, outer_ring_ccw); + + /* add part */ + OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part); + + (*n_nocat)++; + } + + if (!OGR_G_IsEmpty(Ogr_geometry)) { + /* write multi-feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + /* no attributes for features without category */ + cat = -1; + db_cat = -2; + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, Ogr_feature, + n_noatt, &cursor, &more, &db_cat, key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + } + else { + /* skip empty features */ + G_debug(3, "multi-feature is empty -> skipped"); + } + + OGR_G_DestroyGeometry(Ogr_geometry); + + if (donocat && doatt) + db_close_cursor(&cursor); + + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(Cats); + Vect_destroy_list(line_list); + Vect_destroy_list(lcats); + + return n_exported; +} + +OGRGeometryH create_polygon(struct Map_info *In, int area, + struct line_pnts *Points, int outer_ring_ccw) +{ + int j, k; + OGRGeometryH Ogr_geometry, ring; + + Vect_get_area_points(In, area, Points); + + Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon); + ring = OGR_G_CreateGeometry(wkbLinearRing); + + /* Area */ + if (Vect_is_3d(In)) { + if (outer_ring_ccw) { + for (j = Points->n_points - 1; j >= 0; j--) + OGR_G_AddPoint(ring, Points->x[j], Points->y[j], Points->z[j]); + } + else { + for (j = 0; j < Points->n_points; j++) + OGR_G_AddPoint(ring, Points->x[j], Points->y[j], Points->z[j]); + } + } + else { + if (outer_ring_ccw) { + for (j = Points->n_points - 1; j >= 0; j--) + OGR_G_AddPoint_2D(ring, Points->x[j], Points->y[j]); + } + else { + for (j = 0; j < Points->n_points; j++) + OGR_G_AddPoint_2D(ring, Points->x[j], Points->y[j]); + } + } + + OGR_G_AddGeometryDirectly(Ogr_geometry, ring); + + /* Isles */ + for (k = 0; k < Vect_get_area_num_isles(In, area); k++) { + Vect_get_isle_points(In, Vect_get_area_isle(In, area, k), Points); + ring = OGR_G_CreateGeometry(wkbLinearRing); + if (Vect_is_3d(In)) { + if (outer_ring_ccw) { + for (j = Points->n_points - 1; j >= 0; j--) + OGR_G_AddPoint(ring, Points->x[j], Points->y[j], + Points->z[j]); + } + else { + for (j = 0; j < Points->n_points; j++) + OGR_G_AddPoint(ring, Points->x[j], Points->y[j], + Points->z[j]); + } + } + else { + if (outer_ring_ccw) { + for (j = Points->n_points - 1; j >= 0; j--) + OGR_G_AddPoint_2D(ring, Points->x[j], Points->y[j]); + } + else { + for (j = 0; j < Points->n_points; j++) + OGR_G_AddPoint_2D(ring, Points->x[j], Points->y[j]); + } + } + OGR_G_AddGeometryDirectly(Ogr_geometry, ring); + } + + return Ogr_geometry; +} diff --git a/vector/v.out.ogr/export_lines_fast.c b/vector/v.out.ogr/export_lines_fast.c new file mode 100644 index 00000000000..e9509c8d972 --- /dev/null +++ b/vector/v.out.ogr/export_lines_fast.c @@ -0,0 +1,546 @@ +#include + +#include "local_proto.h" + +static int export_lines_single(struct Map_info *, int, int, int, int, + OGRFeatureDefnH, OGRLayerH, struct field_info *, + dbDriver *, int, int *, const char **, int, int, + int *, int *); +static int export_lines_multi(struct Map_info *, int, int, int, int, + OGRFeatureDefnH, OGRLayerH, struct field_info *, + dbDriver *, int, int *, const char **, int, int, + int *, int *); + +static void line_to_polygon(OGRGeometryH, const struct line_pnts *); + +static void add_part(OGRGeometryH, OGRwkbGeometryType, int, struct line_pnts *); + +static OGRGeometryH build_geometry(struct Map_info *, struct line_pnts *, int, + int, int); + +/* export primitives as single/multi-features */ +int export_lines_fast(struct Map_info *In, int field, int otype, int multi, + int donocat, int force_poly, + OGRFeatureDefnH Ogr_featuredefn, OGRLayerH Ogr_layer, + struct field_info *Fi, dbDriver *driver, int ncol, + int *colctype, const char **colname, int doatt, int nocat, + int *n_noatt, int *n_nocat) +{ + if (multi) + /* export as multi-features */ + return export_lines_multi(In, field, otype, donocat, force_poly, + Ogr_featuredefn, Ogr_layer, Fi, driver, ncol, + colctype, colname, doatt, nocat, n_noatt, + n_nocat); + + /* export as single features */ + return export_lines_single( + In, field, otype, donocat, force_poly, Ogr_featuredefn, Ogr_layer, Fi, + driver, ncol, colctype, colname, doatt, nocat, n_noatt, n_nocat); +} + +/* export line as single feature */ +int export_lines_single(struct Map_info *In, int field, int otype, int donocat, + int force_poly, OGRFeatureDefnH Ogr_featuredefn, + OGRLayerH Ogr_layer, struct field_info *Fi, + dbDriver *driver, int ncol, int *colctype, + const char **colname, int doatt, int nocat, + int *n_noatt, int *n_nocat) +{ + int i, n_exported; + int cat, last_cat, db_cat, type; + + struct line_pnts *Points; + struct line_cats *Cats; + + int findex; + struct Cat_index *ci; + int cat_index, n_cats; + + dbString dbstring; + char buf[SQL_BUFFER_SIZE]; + dbCursor cursor; + int more; + int key_col_index; + + OGRGeometryH Ogr_geometry; + OGRFeatureH Ogr_feature; + + Points = Vect_new_line_struct(); + Cats = Vect_new_cats_struct(); + + n_exported = 0; + + /* get category index for given field */ + findex = Vect_cidx_get_field_index(In, field); + if (findex == -1) { + G_fatal_error(_("Unable to export multi-features. No category index " + "for layer %d."), + field); + } + + ci = &(In->plus.cidx[findex]); + n_cats = ci->n_cats; + + if (donocat) + G_message(_("Exporting features with category...")); + + key_col_index = -1; + more = 1; + if (doatt) { + /* select attributes ordered by category value */ + db_init_string(&dbstring); + sprintf(buf, "SELECT * FROM %s ORDER BY %s ASC", Fi->table, Fi->key); + G_debug(2, "SQL: %s", buf); + db_set_string(&dbstring, buf); + if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != + DB_OK) { + G_fatal_error(_("Cannot select attributes sorted by %s"), Fi->key); + } + + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + + /* get index of key column */ + for (i = 0; i < ncol; i++) { + if (strcmp(Fi->key, colname[i]) == 0) { + key_col_index = i; + break; + } + } + } + + last_cat = -1; + db_cat = -1; + for (cat_index = 0; cat_index < n_cats; cat_index++) { + + G_percent(cat_index, n_cats, 5); + + if (!(ci->cat[cat_index][1] & otype)) + continue; + + cat = ci->cat[cat_index][0]; + /* make sure the cidx is ordered by cat */ + if (cat < last_cat) + G_fatal_error(_("Category index is not sorted ascending by cat!")); + last_cat = cat; + + i = ci->cat[cat_index][2]; + + /* read line */ + type = Vect_read_line(In, Points, Cats, i); + G_debug(2, "line = %d type = %d", i, type); + if (!(otype & type)) { + /* skip lines with different type */ + G_debug(2, "type %d not specified -> skipping", type); + continue; + } + + Ogr_geometry = build_geometry(In, Points, type, otype, force_poly); + + /* add feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + /* get attributes */ + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, Ogr_feature, + n_noatt, &cursor, &more, &db_cat, key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + OGR_G_DestroyGeometry(Ogr_geometry); + } + + if (donocat) + G_message(_("Exporting features without category...")); + + if (doatt) { + db_close_cursor(&cursor); + if (donocat) { + cat = -1; + if (db_open_select_cursor(driver, &dbstring, &cursor, + DB_SEQUENTIAL) != DB_OK) { + G_fatal_error(_("Cannot select attributes for cat = %d"), cat); + } + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + } + } + + /* this loop is needed to count features without category in the layer + * to be exported */ + Vect_rewind(In); + while (TRUE) { + type = Vect_read_next_line(In, Points, Cats); + if (type < 0) + break; + + Vect_cat_get(Cats, field, &cat); + if (cat >= 0) + continue; /* skip features with category */ + if (cat < 0 && !donocat) { + (*n_nocat)++; + continue; /* skip lines without category, do not export + * not labeled */ + } + + (*n_nocat)++; + + db_cat = -2; + cat = -1; + + /* code duplicated from above --> */ + Ogr_geometry = build_geometry(In, Points, type, otype, force_poly); + + /* add feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + /* no attributes for features without category */ + cat = -1; + db_cat = -2; + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, Ogr_feature, + n_noatt, &cursor, &more, &db_cat, key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + OGR_G_DestroyGeometry(Ogr_geometry); + /* <-- code duplicated from above */ + } + if (doatt && donocat) + db_close_cursor(&cursor); + + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(Cats); + + return n_exported; +} + +/* export line as multi-feature */ +int export_lines_multi(struct Map_info *In, int field, int otype, int donocat, + int force_poly, OGRFeatureDefnH Ogr_featuredefn, + OGRLayerH Ogr_layer, struct field_info *Fi, + dbDriver *driver, int ncol, int *colctype, + const char **colname, int doatt, int nocat, int *n_noatt, + int *n_nocat) +{ + int i, n_exported; + int cat, last_cat, db_cat, type; + int line, findex, ipart; + + struct line_pnts *Points; + struct line_cats *Cats; + struct ilist *line_list, *lcats; + + struct Cat_index *ci; + int cat_index, n_cats; + + dbString dbstring; + char buf[SQL_BUFFER_SIZE]; + dbCursor cursor; + int more; + int key_col_index; + + OGRGeometryH Ogr_geometry; + OGRFeatureH Ogr_feature; + OGRwkbGeometryType wkbtype, wkbtype_part; + + Points = Vect_new_line_struct(); + Cats = Vect_new_cats_struct(); + line_list = Vect_new_list(); + lcats = Vect_new_list(); + + n_exported = 0; + + /* check if category index is available for given field */ + findex = Vect_cidx_get_field_index(In, field); + if (findex == -1) { + G_fatal_error(_("Unable to export multi-features. No category index " + "for layer %d."), + field); + } + + ci = &(In->plus.cidx[findex]); + n_cats = ci->n_cats; + + if (donocat) + G_message(_("Exporting features with category...")); + + /* determine type */ + type = -1; /* unknown -> GeometryCollection */ + if (Vect_cidx_get_num_types_by_index(In, findex) == 1) + Vect_cidx_get_type_count_by_index(In, findex, 0, &type, NULL); + if (force_poly) + wkbtype_part = wkbPolygon; + else + wkbtype_part = get_wkbtype(type, otype); + wkbtype = get_multi_wkbtype(wkbtype_part); + + key_col_index = -1; + more = 1; + if (doatt) { + /* select attributes ordered by category value */ + db_init_string(&dbstring); + sprintf(buf, "SELECT * FROM %s ORDER BY %s ASC", Fi->table, Fi->key); + G_debug(2, "SQL: %s", buf); + db_set_string(&dbstring, buf); + if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != + DB_OK) { + G_fatal_error(_("Cannot select attributes sorted by %s"), Fi->key); + } + + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + + /* get index of key column */ + key_col_index = -1; + for (i = 0; i < ncol; i++) { + if (strcmp(Fi->key, colname[i]) == 0) { + key_col_index = i; + break; + } + } + } + + last_cat = -1; + db_cat = -1; + cat_index = 0; + while (cat_index < n_cats) { + + G_percent(cat_index, n_cats, 5); + + cat = ci->cat[cat_index][0]; + /* make sure the cidx is ordered by cat */ + if (cat < last_cat) + G_fatal_error(_("Category index is not sorted ascending by cat!")); + last_cat = cat; + + /* collect all features with current cat */ + Vect_reset_list(line_list); + while (cat_index < n_cats && ci->cat[cat_index][0] == cat) { + if (ci->cat[cat_index][1] & otype) { + Vect_list_append(line_list, ci->cat[cat_index][2]); + } + cat_index++; + } + + /* create multi-feature */ + Ogr_geometry = OGR_G_CreateGeometry(wkbtype); + + /* build simple features geometry, go through all parts */ + for (ipart = 0; ipart < line_list->n_values; ipart++) { + line = line_list->value[ipart]; + G_debug(3, "cat=%d, line=%d -> part=%d", cat, line, ipart); + + /* read line */ + type = Vect_read_line(In, Points, Cats, line); + + /* check for category consistency */ + Vect_field_cat_get(Cats, field, lcats); + if (!Vect_val_in_list(lcats, cat)) + G_fatal_error(_("Unable to create multi-feature. " + "Category %d not found in line %d, field %d"), + cat, line, field); + + /* add part */ + add_part(Ogr_geometry, wkbtype_part, type == GV_LINE && force_poly, + Points); + } + + if (!OGR_G_IsEmpty(Ogr_geometry)) { + /* write multi-feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + /* get attributes */ + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, + Ogr_feature, n_noatt, &cursor, &more, &db_cat, + key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + } + else { + /* skip empty features */ + G_debug(3, "multi-feature is empty -> skipped"); + } + + OGR_G_DestroyGeometry(Ogr_geometry); + } + + if (donocat) + G_message(_("Exporting features without category...")); + + /* check lines without category, if -c flag is given write them as + * one multi-feature */ + Ogr_geometry = OGR_G_CreateGeometry(wkbtype); + + if (doatt) { + db_close_cursor(&cursor); + if (donocat) { + cat = -1; + if (db_open_select_cursor(driver, &dbstring, &cursor, + DB_SEQUENTIAL) != DB_OK) { + G_fatal_error(_("Cannot select attributes for cat = %d"), cat); + } + if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) + G_fatal_error(_("Unable to fetch data from table")); + } + } + + /* this loop is needed to count features without category in the layer + * to be exported */ + Vect_rewind(In); + while (TRUE) { + type = Vect_read_next_line(In, Points, Cats); + if (type < 0) + break; + + Vect_cat_get(Cats, field, &cat); + if (cat >= 0) + continue; /* skip features with category */ + if (cat < 0 && !donocat) { + (*n_nocat)++; + continue; /* skip lines without category, do not export + * not labeled */ + } + + (*n_nocat)++; + + /* add part */ + add_part(Ogr_geometry, wkbtype_part, type == GV_LINE && force_poly, + Points); + } + + if (!OGR_G_IsEmpty(Ogr_geometry)) { + /* write multi-feature */ + Ogr_feature = OGR_F_Create(Ogr_featuredefn); + OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); + + /* no attributes for features without category */ + cat = -1; + db_cat = -2; + mk_att_fast(cat, Fi, ncol, colctype, colname, doatt, nocat, Ogr_feature, + n_noatt, &cursor, &more, &db_cat, key_col_index); + if (OGR_L_CreateFeature(Ogr_layer, Ogr_feature) != OGRERR_NONE) { + G_fatal_error(_("Failed to create OGR feature")); + } + else + n_exported++; + + OGR_F_Destroy(Ogr_feature); + } + else { + /* skip empty features */ + G_debug(3, "multi-feature is empty -> skipped"); + } + + OGR_G_DestroyGeometry(Ogr_geometry); + + if (donocat && doatt) + db_close_cursor(&cursor); + + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(Cats); + Vect_destroy_list(line_list); + Vect_destroy_list(lcats); + + return n_exported; +} + +/* build polygon for closed line */ +void line_to_polygon(OGRGeometryH Ogr_geometry, const struct line_pnts *Points) +{ + int j; + OGRGeometryH ring; + + ring = OGR_G_CreateGeometry(wkbLinearRing); + + /* create a ring */ + for (j = 0; j < Points->n_points; j++) { + OGR_G_AddPoint(ring, Points->x[j], Points->y[j], Points->z[j]); + } + + /* close ring */ + if (Points->x[Points->n_points - 1] != Points->x[0] || + Points->y[Points->n_points - 1] != Points->y[0] || + Points->z[Points->n_points - 1] != Points->z[0]) { + OGR_G_AddPoint(ring, Points->x[0], Points->y[0], Points->z[0]); + } + + OGR_G_AddGeometryDirectly(Ogr_geometry, ring); +} + +void add_part(OGRGeometryH Ogr_geometry, OGRwkbGeometryType wkbtype_part, + int force_poly, struct line_pnts *Points) +{ + int j; + OGRGeometryH Ogr_geometry_part; + + Ogr_geometry_part = OGR_G_CreateGeometry(wkbtype_part); + if (force_poly) { + line_to_polygon(Ogr_geometry_part, Points); + } + else { + if (OGR_G_GetGeometryType(Ogr_geometry_part) == wkbPoint) { + /* GV_POINTS -> wkbPoint */ + OGR_G_AddPoint(Ogr_geometry_part, Points->x[0], Points->y[0], + Points->z[0]); + } + else { /* GV_LINES -> wkbLinestring */ + for (j = 0; j < Points->n_points; j++) { + OGR_G_AddPoint(Ogr_geometry_part, Points->x[j], Points->y[j], + Points->z[j]); + } + } + } + OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part); +} + +static OGRGeometryH build_geometry(struct Map_info *In, + struct line_pnts *Points, int type, + int otype, int force_poly) +{ + OGRGeometryH Ogr_geometry; + + /* build simple features geometry */ + if ((type == GV_LINE && force_poly) || type == GV_FACE) { + /* lines to polygons + faces to 2.5D polygons */ + Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon); + line_to_polygon(Ogr_geometry, Points); + } + else { + Ogr_geometry = OGR_G_CreateGeometry(get_wkbtype(type, otype)); + if (OGR_G_GetGeometryType(Ogr_geometry) == wkbPoint) { + /* GV_POINTS -> wkbPoint */ + if (Vect_is_3d(In)) + OGR_G_AddPoint(Ogr_geometry, Points->x[0], Points->y[0], + Points->z[0]); + else + OGR_G_AddPoint_2D(Ogr_geometry, Points->x[0], Points->y[0]); + } + else { + /* GV_LINES -> wkbLinestring */ + int j; + for (j = 0; j < Points->n_points; j++) { + if (Vect_is_3d(In)) + OGR_G_AddPoint(Ogr_geometry, Points->x[j], Points->y[j], + Points->z[j]); + else + OGR_G_AddPoint_2D(Ogr_geometry, Points->x[j], Points->y[j]); + } + } + } + + return Ogr_geometry; +} diff --git a/vector/v.out.ogr/local_proto.h b/vector/v.out.ogr/local_proto.h index a0406a350a1..07921ece8f3 100644 --- a/vector/v.out.ogr/local_proto.h +++ b/vector/v.out.ogr/local_proto.h @@ -12,7 +12,7 @@ struct Options { struct Option *input, *dsn, *layer, *type, *format, *field, *dsco, *lco, - *otype; + *otype, *method; }; struct Flags { @@ -23,10 +23,14 @@ struct Flags { /* args.c */ void parse_args(int, char **, struct Options *, struct Flags *); -/* attributes.c */ +/* attrb.c */ int mk_att(int, struct field_info *, dbDriver *, int, int *, const char **, int, int, OGRFeatureH, int *); +/* attrb_fast.c */ +int mk_att_fast(int, struct field_info *, int, int *, const char **, int, int, + OGRFeatureH, int *, dbCursor *, int *, int *, int); + /* dsn.c */ char *get_datasource_name(const char *, int); @@ -46,7 +50,18 @@ int export_lines(struct Map_info *, int, int, int, int, int, OGRFeatureDefnH, OGRLayerH, struct field_info *, dbDriver *, int, int *, const char **, int, int, int *, int *); +/* export_lines_fast.c */ +int export_lines_fast(struct Map_info *, int, int, int, int, int, + OGRFeatureDefnH, OGRLayerH, struct field_info *, + dbDriver *, int, int *, const char **, int, int, int *, + int *); + /* export_areas.c */ int export_areas(struct Map_info *, int, int, int, OGRFeatureDefnH, OGRLayerH, struct field_info *, dbDriver *, int, int *, const char **, int, int, int *, int *, int); + +/* export_areas_fast.c */ +int export_areas_fast(struct Map_info *, int, int, int, OGRFeatureDefnH, + OGRLayerH, struct field_info *, dbDriver *, int, int *, + const char **, int, int, int *, int *, int); diff --git a/vector/v.out.ogr/main.c b/vector/v.out.ogr/main.c index 788d27a3665..b0c2b34419d 100644 --- a/vector/v.out.ogr/main.c +++ b/vector/v.out.ogr/main.c @@ -820,11 +820,20 @@ int main(int argc, char *argv[]) Vect_get_num_primitives(&In, otype)), Vect_get_num_primitives(&In, otype)); - n_feat += export_lines( - &In, field, otype, flags.multi->answer ? TRUE : FALSE, donocat, - ftype == GV_BOUNDARY ? TRUE : FALSE, Ogr_featuredefn, Ogr_layer, Fi, - Driver, ncol, colctype, colname, doatt, - flags.nocat->answer ? TRUE : FALSE, &n_noatt, &n_nocat); + if (strcmp(options.method->answer, "slow") == 0) { + n_feat += export_lines( + &In, field, otype, flags.multi->answer ? TRUE : FALSE, donocat, + ftype == GV_BOUNDARY ? TRUE : FALSE, Ogr_featuredefn, Ogr_layer, + Fi, Driver, ncol, colctype, colname, doatt, + flags.nocat->answer ? TRUE : FALSE, &n_noatt, &n_nocat); + } + else { + n_feat += export_lines_fast( + &In, field, otype, flags.multi->answer ? TRUE : FALSE, donocat, + ftype == GV_BOUNDARY ? TRUE : FALSE, Ogr_featuredefn, Ogr_layer, + Fi, Driver, ncol, colctype, colname, doatt, + flags.nocat->answer ? TRUE : FALSE, &n_noatt, &n_nocat); + } } /* Areas (run always to count features of different type) */ @@ -834,11 +843,20 @@ int main(int argc, char *argv[]) Vect_get_num_areas(&In)), Vect_get_num_areas(&In)); - n_feat += export_areas(&In, field, flags.multi->answer ? TRUE : FALSE, - donocat, Ogr_featuredefn, Ogr_layer, Fi, Driver, - ncol, colctype, colname, doatt, - flags.nocat->answer ? TRUE : FALSE, &n_noatt, - &n_nocat, outer_ring_ccw); + if (strcmp(options.method->answer, "slow") == 0) { + n_feat += export_areas( + &In, field, flags.multi->answer ? TRUE : FALSE, donocat, + Ogr_featuredefn, Ogr_layer, Fi, Driver, ncol, colctype, colname, + doatt, flags.nocat->answer ? TRUE : FALSE, &n_noatt, &n_nocat, + outer_ring_ccw); + } + else { + n_feat += export_areas_fast( + &In, field, flags.multi->answer ? TRUE : FALSE, donocat, + Ogr_featuredefn, Ogr_layer, Fi, Driver, ncol, colctype, colname, + doatt, flags.nocat->answer ? TRUE : FALSE, &n_noatt, &n_nocat, + outer_ring_ccw); + } } /* diff --git a/vector/v.out.ogr/v.out.ogr.html b/vector/v.out.ogr/v.out.ogr.html index d9a2c84049b..664a5c35a1a 100644 --- a/vector/v.out.ogr/v.out.ogr.html +++ b/vector/v.out.ogr/v.out.ogr.html @@ -1,27 +1,27 @@

    DESCRIPTION

    v.out.ogr converts GRASS vector map layer to any of the -supported OGR vector formats +supported OGR vector formats (including OGC GeoPackage, ESRI Shapefile, SpatiaLite or GML).

    OGR (Simple Features Library) is part of the -GDAL library, so you need to +GDAL library, so you need to install this library to use v.out.ogr.

    The OGR library supports many various formats including:

    @@ -193,7 +193,7 @@

    Export to KML (Google Earth)

    REFERENCES

    diff --git a/vector/v.out.postgis/v.out.postgis.html b/vector/v.out.postgis/v.out.postgis.html index 104a9ad2dae..2307ce6a394 100644 --- a/vector/v.out.postgis/v.out.postgis.html +++ b/vector/v.out.postgis/v.out.postgis.html @@ -39,7 +39,7 @@

    DESCRIPTION

  • TOPO_TOLERANCE=<value> - tolerance for PostGIS Topology schema, see CreateTopology - function for defails, default: 0
  • + function for details, default: 0
  • TOPO_GEO_ONLY=YES|NO - store in PostGIS Topology schema only data relevant to Topo-Geo data model, default: NO
  • @@ -65,8 +65,8 @@

    NOTES

    "geom". Name of the geometry column can be changed by options=GEOMETRY_NAME=<column>. Note that for exporting vector features as simple features can be alternatively -used PostgreSQL driver -from OGR library +used PostgreSQL driver +from OGR library through v.out.ogr module.

    @@ -90,7 +90,7 @@

    NOTES

    Multigeometries are not currently supported. Features with the same -category are exported as multiple singe features. +category are exported as multiple single features.

    v.out.postgis also allows exporting vector features as @@ -154,7 +154,7 @@

    Export Simple Features

    OGR library, namely using PostgreSQL driver. Contrary to the v.out.ogr module, v.out.postgis is using directly PostGIS data provider -which is part of GRASS vector engine. Beside +which is part of GRASS vector engine. Besides that, v.out.postgis is optimized for PostGIS export including topological access to the data. @@ -258,7 +258,7 @@

    TODO

    REQUIREMENTS

      -
    • PostGIS 2.x or later for topological export (flag -l) +
    • PostGIS 2.x or later for topological export (flag -l)

    REFERENCES

    diff --git a/vector/v.out.vtk/v.out.vtk.html b/vector/v.out.vtk/v.out.vtk.html index 47bae357546..97d8c82c0e7 100644 --- a/vector/v.out.vtk/v.out.vtk.html +++ b/vector/v.out.vtk/v.out.vtk.html @@ -9,12 +9,12 @@

    NOTES

    The following vector types can be exported together in one VTK ascii file:
      -
    • point
    • -
    • line
    • -
    • centroid
    • -
    • boundary
    • -
    • area
    • -
    • face
    • +
    • point
    • +
    • line
    • +
    • centroid
    • +
    • boundary
    • +
    • area
    • +
    • face
    Category data (cat) for the selected vector type and layer will be written as scalar diff --git a/vector/v.outlier/v.outlier.html b/vector/v.outlier/v.outlier.html index 3cd3ee46a5a..7e615364916 100644 --- a/vector/v.outlier/v.outlier.html +++ b/vector/v.outlier/v.outlier.html @@ -13,12 +13,12 @@

    DESCRIPTION

    (default), or only positive or only negative outliers. Filtering out only positive outliers can be useful to filter out vegetation returns (e.g. from forest canopies) from LIDAR point clouds, in order to -extract Digital Terrain Models. Filtering out only negative outliers +extract digital terrain models (DTMs). Filtering out only negative outliers can be useful to estimate vegetation height.

    -There is a flag to create a vector that can be visualizated by -qgis. That means that topology is build and the z coordinate is +There is a flag to create a vector that can be visualized in +QGIS. That means that topology is built and the z coordinate is considered as a category.

    EXAMPLES

    diff --git a/vector/v.overlay/v.overlay.html b/vector/v.overlay/v.overlay.html index 0077f2915f5..7069ad58b23 100644 --- a/vector/v.overlay/v.overlay.html +++ b/vector/v.overlay/v.overlay.html @@ -164,13 +164,13 @@

    Overlay operations: AND, OR, NOT, XOR

    -GRASS v.overlay: input polygons (1 and 2) +GRASS v.overlay: input polygons (1 and 2)
    Figure: v.overlay operations: original input polygons

    -GRASS v.overlay results: AND, OR, NOT, XOR operations +GRASS v.overlay results: AND, OR, NOT, XOR operations
    Figure: v.overlay results of AND, OR, NOT, XOR operations
    @@ -219,9 +219,9 @@

    Polygons overlaid with polygons

    -GRASS v.overlay: polygon to polygon union (input 1) -GRASS v.overlay: polygon to polygon union (input 2) -GRASS v.overlay: polygon to polygon union (result) +GRASS v.overlay: polygon to polygon union (input 1) +GRASS v.overlay: polygon to polygon union (input 2) +GRASS v.overlay: polygon to polygon union (result)
    Figure: v.overlay: Polygon union (right) of urban area (left) and Census 2000 (middle) areas (North Carolina dataset)
    @@ -247,7 +247,7 @@

    Lines overlaid with polygons

    GRASS v.overlay: Line to polygon clipping
    -
    AttributeTypeDescription
    rsid integer reference segment ID, unique in the table
    lcat integer category of the line in the LRS map
    +
    diff --git a/vector/v.patch/v.patch.html b/vector/v.patch/v.patch.html index 6e49b5509f4..7d648ecc473 100644 --- a/vector/v.patch/v.patch.html +++ b/vector/v.patch/v.patch.html @@ -13,8 +13,8 @@

    NOTES

    editing can be done automatically using v.clean.

    -Lines may need to be snapped with v.clean tool=snap,break,rmdupl. +Lines may need to be snapped with +v.clean tool=snap,break,rmdupl.

    Boundaries may need to be cleaned with v.clean tool=break,rmdupl,rmsa diff --git a/vector/v.proj/v.proj.html b/vector/v.proj/v.proj.html index 62d32bbd958..9910b7258b4 100644 --- a/vector/v.proj/v.proj.html +++ b/vector/v.proj/v.proj.html @@ -66,9 +66,9 @@

    REFERENCES

  • Evenden, G.I. (1990) Cartographic projection procedures for the UNIX environment - a user's manual. USGS Open-File Report 90-284 (OF90-284.pdf) - See also there: Interim Report and 2nd Interim Report on Release 4, Evenden 1994). + See also there: Interim Report and 2nd Interim Report on Release 4, Evenden 1994).
  • Richards, John A. (1993), Remote Sensing Digital Image Analysis, - Springer-Verlag, Berlin, 2nd edition. + Springer-Verlag, Berlin, 2nd edition.
  • PROJ: Projection/datum support library. @@ -76,12 +76,12 @@

    REFERENCES

    Further reading

    SEE ALSO

    diff --git a/vector/v.random/testsuite/test_v_random.py b/vector/v.random/testsuite/test_v_random.py index e5cc95a93db..7b68434f46b 100644 --- a/vector/v.random/testsuite/test_v_random.py +++ b/vector/v.random/testsuite/test_v_random.py @@ -30,9 +30,10 @@ def setUpClass(cls): def tearDownClass(cls): cls.del_temp_region() - def tearDown(cls): - cls.runModule("g.remove", type="vector", flags="f", name=cls.output) - cls.runModule("g.remove", type="vector", flags="f", name=cls.output2) + def tearDown(self): + self.runModule( + "g.remove", type="vector", flags="f", name=(self.output, self.output2) + ) def test_num_points(self): """Checking if number of points equals 100""" diff --git a/vector/v.random/v.random.html b/vector/v.random/v.random.html index f663a924cfe..5a9ce903d40 100644 --- a/vector/v.random/v.random.html +++ b/vector/v.random/v.random.html @@ -29,13 +29,13 @@

    Restriction to vector areas

    Attributes attached to restrict vector map are also transferred -if the layer parameter is defined > 0, +if the layer parameter is defined > 0, see example below.

    NOTES

    -Importantly, attributes will only be transferred if layer > 0 +Importantly, attributes will only be transferred if layer > 0 (e.g., layer=1).

    EXAMPLES

    @@ -110,7 +110,7 @@

    Generating random points in 3D

    -
    +
    Random points with different X, Y, and Z coordinates
    @@ -153,7 +153,7 @@

    Generating random adjacent areas

    -
    +
    Random adjacent areas from random points (here: used as centroids)
    @@ -227,7 +227,7 @@

    Stratified random sampling: Random sampling from vector map by attribute

    -
    +
    Random points only sampled in forested areas (stratified random sampling)
    @@ -250,7 +250,7 @@

    Stratified random sampling: Random sampling from vector map with spatial con -->

    -
    +
    Two random points sampled in each individual water body (stratified random sampling)
    diff --git a/vector/v.reclass/v.reclass.html b/vector/v.reclass/v.reclass.html index 4b206db4065..4fc3e1b81cd 100644 --- a/vector/v.reclass/v.reclass.html +++ b/vector/v.reclass/v.reclass.html @@ -10,9 +10,9 @@

    DESCRIPTION

    keyword value (separated by space) or comment beginning with '#' (hash). -Definition of new category begins with keyword cat followed +Definition of new category begins with keyword cat followed by the new category value. -Keyword where specifies SQL where condition. +Keyword where specifies SQL where condition.

    NOTES

    diff --git a/vector/v.rectify/v.rectify.html b/vector/v.rectify/v.rectify.html index 6bfb8e628bf..e2cd9d936bf 100644 --- a/vector/v.rectify/v.rectify.html +++ b/vector/v.rectify/v.rectify.html @@ -46,25 +46,26 @@

    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)

    -
    x' = a1 + b1 * x + c1 * y -
    y' = a2 + b2 * x + c2 * y +
    x' = a1 + b1 * x + c1 * y +
    y' = a2 + b2 * x + c2 * y

    3D linear affine transformation (1st order transformation)

    -
    x' = a1 + b1 * x + c1 * y + d1 * z -
    y' = a2 + b2 * x + c2 * y + d2 * z -
    z' = a3 + b3 * x + c3 * y + d3 * z +
    x' = a1 + b1 * x + c1 * y + d1 * z +
    y' = a2 + b2 * x + c2 * y + d2 * z +
    z' = a3 + b3 * x + c3 * y + d3 * z
    The a,b,c,d coefficients are determined by least squares regression @@ -110,7 +111,7 @@

    SEE ALSO

    m.transform, r.proj, v.proj, -v.transform, +v.transform

    diff --git a/vector/v.select/testsuite/test_v_select.py b/vector/v.select/testsuite/test_v_select.py index b8564505a6a..c72aac8c4cc 100644 --- a/vector/v.select/testsuite/test_v_select.py +++ b/vector/v.select/testsuite/test_v_select.py @@ -17,8 +17,8 @@ class TestRasterReport(TestCase): ainput = "geology" output = "testvselect" - def tearDown(cls): - cls.runModule("g.remove", type="vector", flags="f", name=cls.output) + def tearDown(self): + self.runModule("g.remove", type="vector", flags="f", name=self.output) def test_opo(self): """Testing operator overlap""" diff --git a/vector/v.select/v.select.html b/vector/v.select/v.select.html index 5d32e2fe2e4..cf799cfe21e 100644 --- a/vector/v.select/v.select.html +++ b/vector/v.select/v.select.html @@ -5,7 +5,7 @@

    DESCRIPTION

    Supported operators (without GEOS; using GRASS' own algorithm):

      -
    • overlap - features partially or completely overlap (GEOS equivalent: intersects) +
    • overlap - features partially or completely overlap (GEOS equivalent: intersects)
    Supported operators (internally using diff --git a/vector/v.support/v.support.html b/vector/v.support/v.support.html index 706a04a12a7..1c81680e1ef 100644 --- a/vector/v.support/v.support.html +++ b/vector/v.support/v.support.html @@ -16,8 +16,8 @@

    EXAMPLE

    SEE ALSO

    - v.build, - v.info +v.build, +v.info

    AUTHOR

    diff --git a/vector/v.surf.bspline/v.surf.bspline.html b/vector/v.surf.bspline/v.surf.bspline.html index 1d6199d189e..ea101c9beb7 100644 --- a/vector/v.surf.bspline/v.surf.bspline.html +++ b/vector/v.surf.bspline/v.surf.bspline.html @@ -2,79 +2,78 @@

    DESCRIPTION

    v.surf.bspline performs a bilinear/bicubic spline interpolation with Tykhonov regularization. The input is a 2D -or 3D vector points map. Values to interpolate can be the z +or 3D vector point layer. Values to interpolate can be the z values of 3D points or the values in a user-specified attribute column -in a 2D or 3D vector map. Output can be a raster -(raster_output) or vector (output) map. Optionally, a -"sparse point" vector map can be input which indicates the location +in a 2D or 3D vector layer. Output can be a raster +(raster_output) or vector (output) layer. Optionally, a +"sparse point" vector layer can be input which indicates the location of output vector points.

    NOTES

    From a theoretical perspective, the interpolating procedure takes place in two parts: the first is an estimate of the linear coefficients -of a spline function is derived from the observation points using a -least squares regression; the second is the computation of the -interpolated surface (or interpolated vector points). As used here, the +of a spline function, which is derived from the observation points using a +least squares regression. The second is the computation of the +interpolated surface or interpolated vector points. As used here, the splines are 2D piece-wise non-zero polynomial functions calculated -within a limited, 2D area. The length (in mapping units) of each spline +within a limited, 2D area. The length, in mapping units, of each spline step is defined by ew_step for the east-west direction and ns_step for the north-south direction. For optimal performance, the length of spline step should be no less than the distance between observation points. Each vector point observation is modeled as a linear function of the non-zero splines in the area around the observation. The least squares regression predicts the the coefficients -of these linear functions. Regularization, avoids the need to have one +of these linear functions. Regularization avoids the need to have one observation and one coefficient for each spline (in order to avoid instability).

    With regularly distributed data points, a spline step corresponding to the maximum distance between two points in both the east and north -directions is sufficient. But often data points are not regularly -distributed and require statistial regularization or estimation. In +directions is sufficient. However, data points are often not regularly +distributed and require statistical regularization or estimation. In such cases, v.surf.bspline will attempt to minimize the gradient of bilinear splines or the curvature of bicubic splines in areas lacking -point observations. As a general rule, spline step length should be +point observations. As a general rule, the spline step length should be greater than the mean distance between observation points (twice the distance between points is a good starting point). Separate east-west and north-south spline step length arguments allows the user to account for some degree of anisotropy in the distribution of -observation points. Short spline step lengths - especially spline step -lengths that are less than the distance between observation points - +observation points. Short spline step lengths, especially spline step +lengths that are less than the distance between observation points, can greatly increase the processing time. -

    Moreover, the maximum number of splines for each direction at each +

    The maximum number of splines for each direction at each time is fixed, regardless of the spline step length. As the total -number of splines used increases (i.e., with small spline step +number of splines increases (i.e., with small spline step lengths), the region is automatically split into subregions for interpolation. Each subregion can contain no more than 150x150 splines. To avoid subregion boundary problems, subregions are created to partially overlap each other. A weighted mean of observations, based on point locations, is calculated within each subregion. -

    The Tykhonov regularization parameter (lambda_i) acts to +

    The Tykhonov regularization parameter, lambda_i, acts to smooth the interpolation. With a small lambda_i, the interpolated surface closely follows observation points; a larger value will produce a smoother interpolation. -

    The input can be a 2D or 3D vector points map. If input is 3D +

    The input can be a 2D or 3D point vector layer. If input is 3D and column is not given than z-coordinates are used for interpolation. Parameter column is required when input is 2D -vector map. - -

    v.surf.bspline can produce a raster_output OR -a output (but NOT simultaneously). Note that topology is not -build for output vector point map. The topology can be built if -required by v.build. - -

    If output is a vector points map and a sparse vector points -map is not specified, the output vector map will contain points at the -same locations as observation points in the input map, but the values -of the output points are interpolated values. If instead -a sparse vector points map is specified, the output vector map -will contain points at the same locations as the sparse vector map -points, and values will be those of the interpolated raster surface at -those points. +vector layer. + +

    v.surf.bspline can produce raster (raster_output) OR +vector output but NOT simultaneously. Note that topology is not +built for output point vector layer. If required, the topology can be built +using v.build. + +

    If output is a point vector layer and sparse is not specified, +the output vector layer will contain points at the +same locations as observation points in the input layer but the values +of the output points will be interpolated values. If a sparse +point vector layer is specified, the output vector layer will contain points +at the same locations as the sparse vector layer points. The values will be +those of the interpolated raster surface at those points.

    A cross validation "leave-one-out" analysis is available to help to determine the optimal lambda_i value that produces an @@ -96,7 +95,7 @@

    Basic interpolation

    v.surf.bspline input=point_vector output=interpolate_surface method=bicubic -A bicubic spline interpolation will be done and a vector points map +A bicubic spline interpolation will be done and a point vector layer with estimated (i.e., interpolated) values will be created.

    Basic interpolation and raster output with a longer spline step

    @@ -106,7 +105,7 @@

    Basic interpolation and raster output with a longer spline step

    A bilinear spline interpolation will be done with a spline step length -of 25 map units. An interpolated raster map will be created at the +of 25 map units. An interpolated raster layer will be created at the current region resolution.

    Estimation of lambda_i parameter with a cross validation process

    @@ -121,8 +120,8 @@

    Estimation on sparse points

    v.surf.bspline input=point_vector sparse=sparse_points output=interpolate_surface -An output map of vector points will be created, corresponding to the -sparse vector map, with interpolated values. +An output layer of vector points will be created, corresponding to the +sparse vector layer, with interpolated values.

    Using attribute values instead z-coordinates

    @@ -144,13 +143,11 @@

    North Carolina dataset example using z-coordinates for interpolation

    KNOWN ISSUES

    -Known issues: -

    In order to avoid RAM memory problems, an auxiliary table is needed for recording some intermediate calculations. This requires -the GROUP BY SQL function is used, which is not supported by -the DBF driver. For this reason, vector map output +the GROUP BY SQL function is used. This function is not +supported by the DBF driver. For this reason, vector output (output) is not permitted with the DBF driver. There are no problems with the raster map output from the DBF driver. diff --git a/vector/v.surf.rst/benchmark/benchmark_v_surf_rst.py b/vector/v.surf.rst/benchmark/benchmark_v_surf_rst.py index 91fd784e0b3..ac69b441010 100644 --- a/vector/v.surf.rst/benchmark/benchmark_v_surf_rst.py +++ b/vector/v.surf.rst/benchmark/benchmark_v_surf_rst.py @@ -36,8 +36,7 @@ def benchmark(size, label, results): ) results.append(bm.benchmark_nprocs(module, label=label, max_nprocs=8, repeat=3)) - Module("g.remove", quiet=True, flags="f", type="raster", name=reference) - Module("g.remove", quiet=True, flags="f", type="raster", name=output) + Module("g.remove", quiet=True, flags="f", type="raster", name=(reference, output)) def generate_map(npoints, rows, cols, fname): diff --git a/vector/v.surf.rst/benchmark/benchmark_v_surf_rst_cv.py b/vector/v.surf.rst/benchmark/benchmark_v_surf_rst_cv.py index 21a3c7459eb..f140ee67b8a 100644 --- a/vector/v.surf.rst/benchmark/benchmark_v_surf_rst_cv.py +++ b/vector/v.surf.rst/benchmark/benchmark_v_surf_rst_cv.py @@ -37,8 +37,7 @@ def benchmark(size, label, results): ) results.append(bm.benchmark_nprocs(module, label=label, max_nprocs=8, repeat=3)) - Module("g.remove", quiet=True, flags="f", type="raster", name=reference) - Module("g.remove", quiet=True, flags="f", type="raster", name=output) + Module("g.remove", quiet=True, flags="f", type="raster", name=(reference, output)) def generate_map(npoints, rows, cols, fname): diff --git a/vector/v.surf.rst/v.surf.rst.html b/vector/v.surf.rst/v.surf.rst.html index 66a39ebc6f8..8194aef36d9 100644 --- a/vector/v.surf.rst/v.surf.rst.html +++ b/vector/v.surf.rst/v.surf.rst.html @@ -305,14 +305,14 @@

    Performance

    benchmark for v.surf.rst
    Figure 1: Benchmark shows execution time for different - number of cells (1M, 2M, 4M, and 8M). + number of cells (1M, 2M, 4M, and 8M).
    benchmark for cross-validation of
      v.surf.rst
    Figure 2: Benchmark shows execution time for running cross-validation on - different number of cells (100k, 200k, 400k, and 800k). + different number of cells (100k, 200k, 400k, and 800k).

    EXAMPLE

    @@ -355,10 +355,10 @@

    Usage of the where parameter

    v.db.univar -e elevrand column=value # interpolation based on subset of points (only those over 1st quartile) -v.surf.rst input=elevrand zcolumn=value elevation=elev_partial npmin=100 where="value > 94.9" +v.surf.rst input=elevrand zcolumn=value elevation=elev_partial npmin=100 where="value > 94.9" r.colors map=elev_partial raster=elevation d.rast elev_partial -d.vect elevrand where="value > 94.9" +d.vect elevrand where="value > 94.9"

    REFERENCES

    @@ -389,7 +389,7 @@

    REFERENCES

  • Mitas, L., and Mitasova H., 1988, General variational approach to the approximation problem, Computers and Mathematics with Applications, v.16, p. 983-992.
  • -
  • +
  • Neteler, M. and Mitasova, H., 2008, Open Source GIS: A GRASS GIS Approach, 3rd Edition, Springer, New York, 406 pages.
  • Talmi, A. and Gilat, G., 1977 : Method for Smooth Approximation of Data, diff --git a/vector/v.to.3d/testsuite/test_vto3d.py b/vector/v.to.3d/testsuite/test_vto3d.py index bfa982ddd87..2297ec3a174 100644 --- a/vector/v.to.3d/testsuite/test_vto3d.py +++ b/vector/v.to.3d/testsuite/test_vto3d.py @@ -15,10 +15,13 @@ def setUpClass(cls): def tearDownClass(cls): cls.del_temp_region() - def tearDown(cls): + def tearDown(self): """Remove contours map after each test method""" - cls.runModule( - "g.remove", flags="f", type="vector", name=[cls.contours2d, cls.contours3d] + self.runModule( + "g.remove", + flags="f", + type="vector", + name=[self.contours2d, self.contours3d], ) def test_contours(self): diff --git a/vector/v.to.3d/v.to.3d.html b/vector/v.to.3d/v.to.3d.html index 6053b746a88..1c02859e7b6 100644 --- a/vector/v.to.3d/v.to.3d.html +++ b/vector/v.to.3d/v.to.3d.html @@ -6,17 +6,19 @@

    DESCRIPTION

    parameter.

    -Flag -r enables to perform reverse transformation, i.e., -transform 3D vector to 2D by omitting z-coordinate. Height of input 3D +The flag -r enables to perform reverse transformation, i.e., +transform 3D vector to 2D by omitting z-coordinate. The height of input 3D features can be optionally stored in column.

    NOTES

    +

    When transforming 2D vector features to 3D based on attribute, all NULL values are silently converted to height 0.0. +

    -Reverse transformation is possible for points and lines. -In case of lines, the reverse transformation should be used +The reverse transformation, 2D to 3D, is possible for points and lines. +In the case of lines, the reverse transformation should be used only when all vertices of a line have the same z-coordinate (for example contours). diff --git a/vector/v.to.db/query.c b/vector/v.to.db/query.c index 51856321d31..aecd934aded 100644 --- a/vector/v.to.db/query.c +++ b/vector/v.to.db/query.c @@ -191,6 +191,9 @@ int query(struct Map_info *Map) } db_close_database_shutdown_driver(driver); + Vect_destroy_line_struct(Points); + Vect_destroy_cats_struct(Cats); + Vect_destroy_field_info(Fi); return 0; } diff --git a/vector/v.to.db/v.to.db.html b/vector/v.to.db/v.to.db.html index 99c2d5b3dbc..f0ba460d450 100644 --- a/vector/v.to.db/v.to.db.html +++ b/vector/v.to.db/v.to.db.html @@ -25,7 +25,7 @@

    NOTES

    all features of same category taken together.

    Line azimuth is calculated as angle from the North direction to the line endnode direction at the line statnode. By default it's reported in decimal degrees (0-360, CW) but -it also may be repored in radians with unit=radians. Azimuth value +it also may be reported in radians with unit=radians. Azimuth value -1 is used to report closed line with it's startnode and endnode being in same place. Azimuth values make sense only if every vector line has only one entry in database (unique CAT value). @@ -165,4 +165,4 @@

    SEE ALSO

    AUTHORS

    Radim Blazek, ITC-irst, Trento, Italy
    -Line sinuousity implemented by Wolf Bergenheim +Line sinuosity implemented by Wolf Bergenheim diff --git a/vector/v.to.rast/v.to.rast.html b/vector/v.to.rast/v.to.rast.html index c5c4e7a54d2..4ebe8bf4922 100644 --- a/vector/v.to.rast/v.to.rast.html +++ b/vector/v.to.rast/v.to.rast.html @@ -27,15 +27,15 @@

    NOTES

    use options are:

    • -attr - read values from attribute table (default) +attr - read values from attribute table (default)
    • -cat - read values from category +cat - read values from category
    • -value - use value specified by value option +value - use value specified by value option
    • -z - use z coordinate (points or contours only) +z - use z coordinate (points or contours only)
    • -dir - line direction in degrees counterclockwise from east (lines only) +dir - line direction in degrees counterclockwise from east (lines only)

    The column parameter uses an existing column from the vector map database table as the category value in the output raster map. Existing table @@ -49,13 +49,13 @@

    NOTES

    Labeled areas and/or centroids will produce filled raster coverages with edges that straddle the original area boundary as long as the boundary is NOT labeled. -
    (Use v.category option=del type=boundary to remove.) +
    (Use v.category option=del type=boundary to remove.)
  • Labeled lines and boundaries will produce lines of raster cells which touch the -original vector line. This tends to be more aggressive than area-only conversions. +original vector line. This tends to be more aggressive than area-only conversions.
  • Points and orphaned centroids will be converted into single cells on the -resultant raster map. +resultant raster map.
  • Line directions are given in degrees counterclockwise from east.

    Raster category labels are supported for all of use= except use=z. @@ -106,7 +106,7 @@

    Calculate slope along path

    -Slope along path
    +Slope along path
    Slope in degrees along bus route
    @@ -153,7 +153,7 @@

    Convert vector points to raster with raster cell binning

    -Number of schools per raster cell
    +Number of schools per raster cell
    Number of schools per raster cell
    diff --git a/vector/v.univar/main.c b/vector/v.univar/main.c index f84bf118fab..5bfa2b672f8 100644 --- a/vector/v.univar/main.c +++ b/vector/v.univar/main.c @@ -19,7 +19,7 @@ /* TODO * - add flag to weigh by line/boundary length and area size * Roger Bivand on GRASS devel ml on July 2 2004 - * http://lists.osgeo.org/pipermail/grass-dev/2004-July/014976.html + * https://lists.osgeo.org/pipermail/grass-dev/2004-July/014976.html * "[...] calculating weighted means, weighting by line length * or area surface size [does not make sense]. I think it would be * better to treat each line or area as a discrete, unweighted, unit @@ -358,6 +358,8 @@ void select_from_geometry(void) G_debug(3, "i=%d j=%d sum = %f val=%f", i, j, sum, val); } } + Vect_destroy_line_struct(jPoints); + Vect_destroy_line_struct(iPoints); } void select_from_database(void) diff --git a/vector/v.univar/v.univar.html b/vector/v.univar/v.univar.html index ee9c6f77582..3d886864421 100644 --- a/vector/v.univar/v.univar.html +++ b/vector/v.univar/v.univar.html @@ -27,8 +27,8 @@

    NOTES

  • type=point: point distances are considered;
  • type=line: line to line distances are considered;
  • type=area: not supported, use type=centroid instead (and see - v.distance for calculating distances - between areas)
  • + v.distance for calculating distances + between areas)

    EXAMPLES

    diff --git a/vector/v.vect.stats/testsuite/test_vect_stats.py b/vector/v.vect.stats/testsuite/test_vect_stats.py index fe982ceff33..e8a1c30c966 100644 --- a/vector/v.vect.stats/testsuite/test_vect_stats.py +++ b/vector/v.vect.stats/testsuite/test_vect_stats.py @@ -5,8 +5,8 @@ Author: Sunveer Singh, Google Code-in 2017 Copyright: (C) 2017 by Sunveer Singh and the GRASS Development Team Licence: This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. + License (>=v2). Read the file COPYING that comes with GRASS + for details. """ from grass.gunittest.case import TestCase diff --git a/vector/v.vect.stats/v.vect.stats.html b/vector/v.vect.stats/v.vect.stats.html index adc8ee54f77..109519154c5 100644 --- a/vector/v.vect.stats/v.vect.stats.html +++ b/vector/v.vect.stats/v.vect.stats.html @@ -213,17 +213,17 @@

    Point statistics in a hexagonal grid

    d.frame frame=f2 at=50,100,50,100 -c v.colors map=hexagons use=attr column=count color=viridis -d.vect map=hexagons where="count > 0" +d.vect map=hexagons where="count > 0" d.text text="count" at=60,5 size=10 color=black d.frame frame=f3 at=0,50,0,50 -c v.colors map=hexagons use=attr column=average color=viridis -d.vect map=hexagons where="count > 0" +d.vect map=hexagons where="count > 0" d.text text="average" at=60,5 size=10 color=black d.frame frame=f4 at=0,50,50,100 -c v.colors map=hexagons use=attr column=stddev color=viridis -d.vect map=hexagons where="count > 0" +d.vect map=hexagons where="count > 0" d.text text="stddev" at=60,5 size=10 color=black d.mon stop=cairo diff --git a/vector/v.vol.rst/v.vol.rst.html b/vector/v.vol.rst/v.vol.rst.html index 06fc55e5118..34699390602 100644 --- a/vector/v.vol.rst/v.vol.rst.html +++ b/vector/v.vol.rst/v.vol.rst.html @@ -68,7 +68,7 @@

    SQL support

     # preparation as in above example
    -v.vol.rst elevrand_3d wcol=soilrange elevation=soilrange zscale=100 where="soilrange > 3"
    +v.vol.rst elevrand_3d wcol=soilrange elevation=soilrange zscale=100 where="soilrange > 3"
     

    Cross validation procedure

    @@ -85,7 +85,7 @@

    Cross validation procedure

    representing the whole dataset.

    Example - (based on Slovakia3d dataset): + (based on Slovakia3d dataset):

     v.info -c precip3d
     g.region n=5530000 s=5275000 w=4186000 e=4631000 res=500 -p
    diff --git a/vector/v.voronoi/v.voronoi.html b/vector/v.voronoi/v.voronoi.html
    index 0b2c9e4cd40..c058a0587fd 100644
    --- a/vector/v.voronoi/v.voronoi.html
    +++ b/vector/v.voronoi/v.voronoi.html
    @@ -10,7 +10,7 @@ 

    DESCRIPTION

    The -s flag can be used to extract the center line of areas or -skeletons of areas with thin >= 0. Smaller values for the +skeletons of areas with thin >= 0. Smaller values for the thin option will preserve more detail, while negative values will extract only the center line. @@ -82,7 +82,7 @@

    REFERENCES

    Steve J. Fortune, (1987). A Sweepline Algorithm for Voronoi Diagrams, Algorithmica 2, 153-174 - (DOI). + (DOI).

    SEE ALSO

    diff --git a/vector/vectorintro.html b/vector/vectorintro.html index db85a0afd37..814526ec8b1 100644 --- a/vector/vectorintro.html +++ b/vector/vectorintro.html @@ -268,8 +268,8 @@

    Geometry operations

    Based on the control points, v.rectify rectifies a vector map by computing a coordinate transformation for each vector object. -Triangulation and point-to-polygon conversions can be done with v.delaunay, v.hull, +Triangulation and point-to-polygon conversions can be done with +v.delaunay, v.hull, and v.voronoi. The v.random command generated random points. @@ -310,8 +310,8 @@

    Vector queries

    Vector-Raster queries

    Raster values can be transferred to vector maps with - v.what.rast and -v.rast.stats. +v.what.rast and +v.rast.stats.

    Vector network analysis

    @@ -322,7 +322,7 @@

    Vector network analysis

  • Network preparation and maintenance: v.net
  • Shortest path: d.path and v.net.path
  • -
  • Shortest path between all pairs of nodes v.net.allpairs +
  • Shortest path between all pairs of nodes v.net.allpairs
  • Allocation of sources (create subnetworks, e.g. police station zones): v.net.alloc
  • Iso-distances (from centers): v.net.iso
  • @@ -394,4 +394,5 @@

    See also

  • Introduction into temporal data processing
  • Introduction to database management
  • Projections and spatial transformations
  • +
  • Graphical User Interface
  • Figure: v.overlay: Line to polygon clipping