├── processing_provider
├── __init__.py
├── provider.py
├── rvt_slrm.py
├── rvt_slope.py
├── rvt_hillshade.py
├── rvt_multi_hillshade.py
├── rvt_msrm.py
├── rvt_svf.py
├── rvt_local_dom.py
├── rvt_opns.py
├── rvt_asvf.py
├── rvt_sky_illum.py
├── rvt_fill_no_data.py
├── rvt_blender.py
└── rvt_mstp.py
├── test
├── tenbytenraster.keywords
├── __init__.py
├── tenbytenraster.prj
├── tenbytenraster.asc
├── tenbytenraster.asc.aux.xml
├── tenbytenraster.lic
├── test_resources.py
├── tenbytenraster.qml
├── test_qrvt_dialog.py
├── test_translations.py
├── utilities.py
├── test_init.py
├── test_qgis_environment.py
└── qgis_interface.py
├── icon.png
├── loading.gif
├── resources.qrc
├── remove_before_zip.bat
├── resources_bat.bat
├── scripts
├── compile-strings.sh
├── run-env-linux.sh
└── update-strings.sh
├── i18n
└── af.ts
├── rvt
└── __init__.py
├── RELEASE_README.md
├── settings
├── blender_VAT.json
├── blender_file_example.json
├── default_terrains_settings.json
└── default_blender_combinations.json
├── __init__.py
├── qrvt_dialog.py
├── README.md
├── metadata.txt
├── .gitignore
├── pb_tool.cfg
├── plugin_upload.py
├── resources.py
├── Makefile
├── pylintrc
├── LICENSE
└── qrvt_dialog_about.py
/processing_provider/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/tenbytenraster.keywords:
--------------------------------------------------------------------------------
1 | title: Tenbytenraster
2 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EarthObservation/rvt-qgis/HEAD/icon.png
--------------------------------------------------------------------------------
/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EarthObservation/rvt-qgis/HEAD/loading.gif
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
1 | # import qgis libs so that ve set the correct sip api version
2 | import qgis # pylint: disable=W0611 # NOQA
--------------------------------------------------------------------------------
/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | icon.png
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/tenbytenraster.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/remove_before_zip.bat:
--------------------------------------------------------------------------------
1 | rmdir /s /q .\__pycache__\ 2>nul
2 |
3 | rmdir /s /q .\processing_provider\__pycache__\ 2>nul
4 |
5 | rmdir /s /q .\rvt\__pycache__\ 2>nul
6 |
7 | del ".\settings\plugin_size.json" >nul 2>&1
8 | pause
--------------------------------------------------------------------------------
/resources_bat.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call "C:\Program Files\QGIS 3.0\bin\o4w_env.bat"
3 | call "C:\Program Files\QGIS 3.0\bin\qt5_env.bat"
4 | call "C:\Program Files\QGIS 3.0\bin\py3_env.bat"
5 |
6 | @echo on
7 | pyrcc5 -o resources.py resources.qrc
--------------------------------------------------------------------------------
/scripts/compile-strings.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | LRELEASE=$1
3 | LOCALES=$2
4 |
5 |
6 | for LOCALE in ${LOCALES}
7 | do
8 | echo "Processing: ${LOCALE}.ts"
9 | # Note we don't use pylupdate with qt .pro file approach as it is flakey
10 | # about what is made available.
11 | $LRELEASE i18n/${LOCALE}.ts
12 | done
13 |
--------------------------------------------------------------------------------
/i18n/af.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @default
5 |
6 |
7 | Good morning
8 | Goeie more
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/test/tenbytenraster.asc:
--------------------------------------------------------------------------------
1 | NCOLS 10
2 | NROWS 10
3 | XLLCENTER 1535380.000000
4 | YLLCENTER 5083260.000000
5 | DX 10
6 | DY 10
7 | NODATA_VALUE -9999
8 | 0 1 2 3 4 5 6 7 8 9
9 | 0 1 2 3 4 5 6 7 8 9
10 | 0 1 2 3 4 5 6 7 8 9
11 | 0 1 2 3 4 5 6 7 8 9
12 | 0 1 2 3 4 5 6 7 8 9
13 | 0 1 2 3 4 5 6 7 8 9
14 | 0 1 2 3 4 5 6 7 8 9
15 | 0 1 2 3 4 5 6 7 8 9
16 | 0 1 2 3 4 5 6 7 8 9
17 | 0 1 2 3 4 5 6 7 8 9
18 | CRS
19 | NOTES
20 |
--------------------------------------------------------------------------------
/test/tenbytenraster.asc.aux.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Point
4 |
5 |
6 |
7 | 9
8 | 4.5
9 | 0
10 | 2.872281323269
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/rvt/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Relief Visualization Toolbox – python library
3 |
4 | Contains functions for computing the visualizations.
5 |
6 | Credits:
7 | Žiga Kokalj (ziga.kokalj@zrc-sazu.si)
8 | Krištof Oštir (kristof.ostir@fgg.uni-lj.si)
9 | Klemen Zakšek
10 | Klemen Čotar
11 | Maja Somrak
12 | Žiga Maroh
13 | Nejc Čož
14 |
15 | Copyright:
16 | 2010-2020 Research Centre of the Slovenian Academy of Sciences and Arts
17 | 2016-2020 University of Ljubljana, Faculty of Civil and Geodetic Engineering
18 | """
19 |
--------------------------------------------------------------------------------
/test/tenbytenraster.lic:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tim Sutton, Linfiniti Consulting CC
5 |
6 |
7 |
8 | tenbytenraster.asc
9 | 2700044251
10 | Yes
11 | Tim Sutton
12 | Tim Sutton (QGIS Source Tree)
13 | Tim Sutton
14 | This data is publicly available from QGIS Source Tree. The original
15 | file was created and contributed to QGIS by Tim Sutton.
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/scripts/run-env-linux.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | QGIS_PREFIX_PATH=/usr/local/qgis-2.0
4 | if [ -n "$1" ]; then
5 | QGIS_PREFIX_PATH=$1
6 | fi
7 |
8 | echo ${QGIS_PREFIX_PATH}
9 |
10 |
11 | export QGIS_PREFIX_PATH=${QGIS_PREFIX_PATH}
12 | export QGIS_PATH=${QGIS_PREFIX_PATH}
13 | export LD_LIBRARY_PATH=${QGIS_PREFIX_PATH}/lib
14 | export PYTHONPATH=${QGIS_PREFIX_PATH}/share/qgis/python:${QGIS_PREFIX_PATH}/share/qgis/python/plugins:${PYTHONPATH}
15 |
16 | echo "QGIS PATH: $QGIS_PREFIX_PATH"
17 | export QGIS_DEBUG=0
18 | export QGIS_LOG_FILE=/tmp/inasafe/realtime/logs/qgis.log
19 |
20 | export PATH=${QGIS_PREFIX_PATH}/bin:$PATH
21 |
22 | echo "This script is intended to be sourced to set up your shell to"
23 | echo "use a QGIS 2.0 built in $QGIS_PREFIX_PATH"
24 | echo
25 | echo "To use it do:"
26 | echo "source $BASH_SOURCE /your/optional/install/path"
27 | echo
28 | echo "Then use the make file supplied here e.g. make guitest"
29 |
--------------------------------------------------------------------------------
/RELEASE_README.md:
--------------------------------------------------------------------------------
1 | # Release of QGIS Plugin for Relief Visualization Toolbox
2 |
3 | Here is a guide how to upload (release) new version of the RVT QGIS plugin to the QGIS plugin repository.
4 |
5 | Required is pb_tool python library (pip install pb_tool) and
6 | Qt Creator software to change version in about dialogue (can also be done with txt editor).
7 |
8 | To release/upload changes (new version):
9 | * Change version in `metadata.txt`.
10 | * Open file `qrvt_dialog_about.ui` (about dialogue) with Qt Creator and change version.
11 | * Run `remove_before_zip.bat` to remove all pycache files.
12 | * Create new zip release file with pb_tool plugin: run `pbt zip` in root project directory (`rvt-qgis`).
13 | Newly created zip file `rvt-qgis.zip` will be created/overwritten in `zip_build` subdirectory.
14 | * Login to QGIS plugin repository (https://plugins.qgis.org/plugins/) then click `Upload a plugin`
15 | and upload newly created `rvt-qgis.zip` file.
16 | * Add changes to plugin changelog in `RVT_py` repository, file `qgis_releases.rst`.
--------------------------------------------------------------------------------
/test/test_resources.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Resources test.
3 |
4 | .. note:: This program is free software; you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation; either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | """
10 |
11 | __author__ = 'ziga.kokalj@zrc-sazu.si'
12 | __date__ = '2020-10-12'
13 | __copyright__ = 'Copyright 2020, Research Centre of the Slovenian Academy of Sciences and Arts'
14 |
15 | import unittest
16 |
17 | from qgis.PyQt.QtGui import QIcon
18 |
19 |
20 |
21 | class QRVTDialogTest(unittest.TestCase):
22 | """Test rerources work."""
23 |
24 | def setUp(self):
25 | """Runs before each test."""
26 | pass
27 |
28 | def tearDown(self):
29 | """Runs after each test."""
30 | pass
31 |
32 | def test_icon_png(self):
33 | """Test we can click OK."""
34 | path = ':/plugins/QRVT/icon.png'
35 | icon = QIcon(path)
36 | self.assertFalse(icon.isNull())
37 |
38 | if __name__ == "__main__":
39 | suite = unittest.makeSuite(QRVTResourcesTest)
40 | runner = unittest.TextTestRunner(verbosity=2)
41 | runner.run(suite)
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/settings/blender_VAT.json:
--------------------------------------------------------------------------------
1 | {
2 | "combination": {
3 | "name": "VAT - Archaeological",
4 | "layers": [
5 | {
6 | "layer": "1",
7 | "visualization_method": "Sky-View Factor",
8 | "norm": "Value",
9 | "min": 0.7,
10 | "max": 1.0,
11 | "blend_mode": "Multiply",
12 | "opacity": 25
13 | },
14 | {
15 | "layer": "2",
16 | "visualization_method": "Openness - Positive",
17 | "norm": "Value",
18 | "min": 68,
19 | "max": 93,
20 | "blend_mode": "Overlay",
21 | "opacity": 50
22 | },
23 | {
24 | "layer": "3",
25 | "visualization_method": "Slope gradient",
26 | "norm": "Value",
27 | "min": 0,
28 | "max": 50,
29 | "blend_mode": "Luminosity",
30 | "opacity": 50
31 | },
32 | {
33 | "layer": "4",
34 | "visualization_method": "Hillshade",
35 | "norm": "Value",
36 | "min": 0,
37 | "max": 1,
38 | "blend_mode": "Normal",
39 | "opacity": 100
40 | }
41 | ]
42 | }
43 | }
--------------------------------------------------------------------------------
/settings/blender_file_example.json:
--------------------------------------------------------------------------------
1 | {
2 | "combination": {
3 | "name": "VAT - Archaeological",
4 | "layers": [
5 | {
6 | "layer": "1",
7 | "visualization_method": "Sky-View Factor",
8 | "norm": "Value",
9 | "min": 0.7,
10 | "max": 1.0,
11 | "blend_mode": "Multiply",
12 | "opacity": 25
13 | },
14 | {
15 | "layer": "2",
16 | "visualization_method": "Openness - Positive",
17 | "norm": "Value",
18 | "min": 68,
19 | "max": 93,
20 | "blend_mode": "Overlay",
21 | "opacity": 50
22 | },
23 | {
24 | "layer": "3",
25 | "visualization_method": "Slope gradient",
26 | "norm": "Value",
27 | "min": 0,
28 | "max": 50,
29 | "blend_mode": "Luminosity",
30 | "opacity": 50
31 | },
32 | {
33 | "layer": "4",
34 | "visualization_method": "Hillshade",
35 | "norm": "Value",
36 | "min": 0,
37 | "max": 1,
38 | "blend_mode": "Normal",
39 | "opacity": 100
40 | },
41 | {
42 | "layer": "5",
43 | "visualization_method": "None"
44 | }
45 | ]
46 | }
47 | }
--------------------------------------------------------------------------------
/scripts/update-strings.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | LOCALES=$*
3 |
4 | # Get newest .py files so we don't update strings unnecessarily
5 |
6 | CHANGED_FILES=0
7 | PYTHON_FILES=`find . -regex ".*\(ui\|py\)$" -type f`
8 | for PYTHON_FILE in $PYTHON_FILES
9 | do
10 | CHANGED=$(stat -c %Y $PYTHON_FILE)
11 | if [ ${CHANGED} -gt ${CHANGED_FILES} ]
12 | then
13 | CHANGED_FILES=${CHANGED}
14 | fi
15 | done
16 |
17 | # Qt translation stuff
18 | # for .ts file
19 | UPDATE=false
20 | for LOCALE in ${LOCALES}
21 | do
22 | TRANSLATION_FILE="i18n/$LOCALE.ts"
23 | if [ ! -f ${TRANSLATION_FILE} ]
24 | then
25 | # Force translation string collection as we have a new language file
26 | touch ${TRANSLATION_FILE}
27 | UPDATE=true
28 | break
29 | fi
30 |
31 | MODIFICATION_TIME=$(stat -c %Y ${TRANSLATION_FILE})
32 | if [ ${CHANGED_FILES} -gt ${MODIFICATION_TIME} ]
33 | then
34 | # Force translation string collection as a .py file has been updated
35 | UPDATE=true
36 | break
37 | fi
38 | done
39 |
40 | if [ ${UPDATE} == true ]
41 | # retrieve all python files
42 | then
43 | echo ${PYTHON_FILES}
44 | # update .ts
45 | echo "Please provide translations by editing the translation files below:"
46 | for LOCALE in ${LOCALES}
47 | do
48 | echo "i18n/"${LOCALE}".ts"
49 | # Note we don't use pylupdate with qt .pro file approach as it is flakey
50 | # about what is made available.
51 | pylupdate4 -noobsolete ${PYTHON_FILES} -ts i18n/${LOCALE}.ts
52 | done
53 | else
54 | echo "No need to edit any translation files (.ts) because no python files"
55 | echo "has been updated since the last update translation. "
56 | fi
57 |
--------------------------------------------------------------------------------
/test/tenbytenraster.qml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 0
26 |
27 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | /***************************************************************************
4 | QRVT
5 | A QGIS plugin
6 | RVT plugin lets you compute different visualizations from raster DEM.
7 | Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
8 | -------------------
9 | begin : 2020-10-12
10 | copyright : (C) 2020 by Research Centre of the Slovenian Academy of Sciences and Arts
11 | email : ziga.kokalj@zrc-sazu.si
12 | git sha : $Format:%H$
13 | ***************************************************************************/
14 |
15 | /***************************************************************************
16 | * *
17 | * This program is free software; you can redistribute it and/or modify *
18 | * it under the terms of the GNU General Public License as published by *
19 | * the Free Software Foundation; either version 2 of the License, or *
20 | * (at your option) any later version. *
21 | * *
22 | ***************************************************************************/
23 | This script initializes the plugin, making it known to QGIS.
24 | """
25 |
26 |
27 | # noinspection PyPep8Naming
28 | def classFactory(iface): # pylint: disable=invalid-name
29 | """Load QRVT class from file QRVT.
30 |
31 | :param iface: A QGIS interface instance.
32 | :type iface: QgsInterface
33 | """
34 | #
35 | from .qrvt import QRVT
36 | return QRVT(iface)
37 |
--------------------------------------------------------------------------------
/test/test_qrvt_dialog.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Dialog test.
3 |
4 | .. note:: This program is free software; you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation; either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | """
10 |
11 | __author__ = 'ziga.kokalj@zrc-sazu.si'
12 | __date__ = '2020-10-12'
13 | __copyright__ = 'Copyright 2020, Research Centre of the Slovenian Academy of Sciences and Arts'
14 |
15 | import unittest
16 |
17 | from qgis.PyQt.QtGui import QDialogButtonBox, QDialog
18 |
19 | from qrvt_dialog import QRVTDialog
20 |
21 | from utilities import get_qgis_app
22 | QGIS_APP = get_qgis_app()
23 |
24 |
25 | class QRVTDialogTest(unittest.TestCase):
26 | """Test dialog works."""
27 |
28 | def setUp(self):
29 | """Runs before each test."""
30 | self.dialog = QRVTDialog(None)
31 |
32 | def tearDown(self):
33 | """Runs after each test."""
34 | self.dialog = None
35 |
36 | def test_dialog_ok(self):
37 | """Test we can click OK."""
38 |
39 | button = self.dialog.button_box.button(QDialogButtonBox.Ok)
40 | button.click()
41 | result = self.dialog.result()
42 | self.assertEqual(result, QDialog.Accepted)
43 |
44 | def test_dialog_cancel(self):
45 | """Test we can click cancel."""
46 | button = self.dialog.button_box.button(QDialogButtonBox.Cancel)
47 | button.click()
48 | result = self.dialog.result()
49 | self.assertEqual(result, QDialog.Rejected)
50 |
51 | if __name__ == "__main__":
52 | suite = unittest.makeSuite(QRVTDialogTest)
53 | runner = unittest.TextTestRunner(verbosity=2)
54 | runner.run(suite)
55 |
56 |
--------------------------------------------------------------------------------
/test/test_translations.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Safe Translations Test.
3 |
4 | .. note:: This program is free software; you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation; either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | """
10 | from .utilities import get_qgis_app
11 |
12 | __author__ = 'ismailsunni@yahoo.co.id'
13 | __date__ = '12/10/2011'
14 | __copyright__ = ('Copyright 2012, Australia Indonesia Facility for '
15 | 'Disaster Reduction')
16 | import unittest
17 | import os
18 |
19 | from qgis.PyQt.QtCore import QCoreApplication, QTranslator
20 |
21 | QGIS_APP = get_qgis_app()
22 |
23 |
24 | class SafeTranslationsTest(unittest.TestCase):
25 | """Test translations work."""
26 |
27 | def setUp(self):
28 | """Runs before each test."""
29 | if 'LANG' in iter(os.environ.keys()):
30 | os.environ.__delitem__('LANG')
31 |
32 | def tearDown(self):
33 | """Runs after each test."""
34 | if 'LANG' in iter(os.environ.keys()):
35 | os.environ.__delitem__('LANG')
36 |
37 | def test_qgis_translations(self):
38 | """Test that translations work."""
39 | parent_path = os.path.join(__file__, os.path.pardir, os.path.pardir)
40 | dir_path = os.path.abspath(parent_path)
41 | file_path = os.path.join(
42 | dir_path, 'i18n', 'af.qm')
43 | translator = QTranslator()
44 | translator.load(file_path)
45 | QCoreApplication.installTranslator(translator)
46 |
47 | expected_message = 'Goeie more'
48 | real_message = QCoreApplication.translate("@default", 'Good morning')
49 | self.assertEqual(real_message, expected_message)
50 |
51 |
52 | if __name__ == "__main__":
53 | suite = unittest.makeSuite(SafeTranslationsTest)
54 | runner = unittest.TextTestRunner(verbosity=2)
55 | runner.run(suite)
56 |
--------------------------------------------------------------------------------
/test/utilities.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Common functionality used by regression tests."""
3 |
4 | import sys
5 | import logging
6 |
7 |
8 | LOGGER = logging.getLogger('QGIS')
9 | QGIS_APP = None # Static variable used to hold hand to running QGIS app
10 | CANVAS = None
11 | PARENT = None
12 | IFACE = None
13 |
14 |
15 | def get_qgis_app():
16 | """ Start one QGIS application to test against.
17 |
18 | :returns: Handle to QGIS app, canvas, iface and parent. If there are any
19 | errors the tuple members will be returned as None.
20 | :rtype: (QgsApplication, CANVAS, IFACE, PARENT)
21 |
22 | If QGIS is already running the handle to that app will be returned.
23 | """
24 |
25 | try:
26 | from qgis.PyQt import QtGui, QtCore
27 | from qgis.core import QgsApplication
28 | from qgis.gui import QgsMapCanvas
29 | from .qgis_interface import QgisInterface
30 | except ImportError:
31 | return None, None, None, None
32 |
33 | global QGIS_APP # pylint: disable=W0603
34 |
35 | if QGIS_APP is None:
36 | gui_flag = True # All test will run qgis in gui mode
37 | #noinspection PyPep8Naming
38 | QGIS_APP = QgsApplication(sys.argv, gui_flag)
39 | # Make sure QGIS_PREFIX_PATH is set in your env if needed!
40 | QGIS_APP.initQgis()
41 | s = QGIS_APP.showSettings()
42 | LOGGER.debug(s)
43 |
44 | global PARENT # pylint: disable=W0603
45 | if PARENT is None:
46 | #noinspection PyPep8Naming
47 | PARENT = QtGui.QWidget()
48 |
49 | global CANVAS # pylint: disable=W0603
50 | if CANVAS is None:
51 | #noinspection PyPep8Naming
52 | CANVAS = QgsMapCanvas(PARENT)
53 | CANVAS.resize(QtCore.QSize(400, 400))
54 |
55 | global IFACE # pylint: disable=W0603
56 | if IFACE is None:
57 | # QgisInterface is a stub implementation of the QGIS plugin interface
58 | #noinspection PyPep8Naming
59 | IFACE = QgisInterface(CANVAS)
60 |
61 | return QGIS_APP, CANVAS, IFACE, PARENT
62 |
--------------------------------------------------------------------------------
/test/test_init.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Tests QGIS plugin init."""
3 |
4 | __author__ = 'Tim Sutton '
5 | __revision__ = '$Format:%H$'
6 | __date__ = '17/10/2010'
7 | __license__ = "GPL"
8 | __copyright__ = 'Copyright 2012, Australia Indonesia Facility for '
9 | __copyright__ += 'Disaster Reduction'
10 |
11 | import os
12 | import unittest
13 | import logging
14 | import configparser
15 |
16 | LOGGER = logging.getLogger('QGIS')
17 |
18 |
19 | class TestInit(unittest.TestCase):
20 | """Test that the plugin init is usable for QGIS.
21 |
22 | Based heavily on the validator class by Alessandro
23 | Passoti available here:
24 |
25 | http://github.com/qgis/qgis-django/blob/master/qgis-app/
26 | plugins/validator.py
27 |
28 | """
29 |
30 | def test_read_init(self):
31 | """Test that the plugin __init__ will validate on plugins.qgis.org."""
32 |
33 | # You should update this list according to the latest in
34 | # https://github.com/qgis/qgis-django/blob/master/qgis-app/
35 | # plugins/validator.py
36 |
37 | required_metadata = [
38 | 'name',
39 | 'description',
40 | 'version',
41 | 'qgisMinimumVersion',
42 | 'email',
43 | 'author']
44 |
45 | file_path = os.path.abspath(os.path.join(
46 | os.path.dirname(__file__), os.pardir,
47 | 'metadata.txt'))
48 | LOGGER.info(file_path)
49 | metadata = []
50 | parser = configparser.ConfigParser()
51 | parser.optionxform = str
52 | parser.read(file_path)
53 | message = 'Cannot find a section named "general" in %s' % file_path
54 | assert parser.has_section('general'), message
55 | metadata.extend(parser.items('general'))
56 |
57 | for expectation in required_metadata:
58 | message = ('Cannot find metadata "%s" in metadata source (%s).' % (
59 | expectation, file_path))
60 |
61 | self.assertIn(expectation, dict(metadata), message)
62 |
63 | if __name__ == '__main__':
64 | unittest.main()
65 |
--------------------------------------------------------------------------------
/test/test_qgis_environment.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Tests for QGIS functionality.
3 |
4 |
5 | .. note:: This program is free software; you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation; either version 2 of the License, or
8 | (at your option) any later version.
9 |
10 | """
11 | __author__ = 'tim@linfiniti.com'
12 | __date__ = '20/01/2011'
13 | __copyright__ = ('Copyright 2012, Australia Indonesia Facility for '
14 | 'Disaster Reduction')
15 |
16 | import os
17 | import unittest
18 | from qgis.core import (
19 | QgsProviderRegistry,
20 | QgsCoordinateReferenceSystem,
21 | QgsRasterLayer)
22 |
23 | from .utilities import get_qgis_app
24 | QGIS_APP = get_qgis_app()
25 |
26 |
27 | class QGISTest(unittest.TestCase):
28 | """Test the QGIS Environment"""
29 |
30 | def test_qgis_environment(self):
31 | """QGIS environment has the expected providers"""
32 |
33 | r = QgsProviderRegistry.instance()
34 | self.assertIn('gdal', r.providerList())
35 | self.assertIn('ogr', r.providerList())
36 | self.assertIn('postgres', r.providerList())
37 |
38 | def test_projection(self):
39 | """Test that QGIS properly parses a wkt string.
40 | """
41 | crs = QgsCoordinateReferenceSystem()
42 | wkt = (
43 | 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",'
44 | 'SPHEROID["WGS_1984",6378137.0,298.257223563]],'
45 | 'PRIMEM["Greenwich",0.0],UNIT["Degree",'
46 | '0.0174532925199433]]')
47 | crs.createFromWkt(wkt)
48 | auth_id = crs.authid()
49 | expected_auth_id = 'EPSG:4326'
50 | self.assertEqual(auth_id, expected_auth_id)
51 |
52 | # now test for a loaded layer
53 | path = os.path.join(os.path.dirname(__file__), 'tenbytenraster.asc')
54 | title = 'TestRaster'
55 | layer = QgsRasterLayer(path, title)
56 | auth_id = layer.crs().authid()
57 | self.assertEqual(auth_id, expected_auth_id)
58 |
59 | if __name__ == '__main__':
60 | unittest.main()
61 |
--------------------------------------------------------------------------------
/processing_provider/provider.py:
--------------------------------------------------------------------------------
1 | from qgis.core import QgsProcessingProvider
2 |
3 | from .rvt_hillshade import RVTHillshade
4 | from .rvt_multi_hillshade import RVTMultiHillshade
5 | from .rvt_slope import RVTSlope
6 | from .rvt_slrm import RVTSlrm
7 | from .rvt_svf import RVTSvf
8 | from .rvt_asvf import RVTASvf
9 | from .rvt_opns import RVTOpns
10 | from .rvt_sky_illum import RVTSim
11 | from .rvt_local_dom import RVTLocalDom
12 | from .rvt_blender import RVTBlender
13 | from .rvt_msrm import RVTMsrm
14 | from .rvt_mstp import RVTMstp
15 | from .rvt_fill_no_data import RVTFillNoData, RVTFillNoDataIDW
16 |
17 |
18 | class Provider(QgsProcessingProvider):
19 | def loadAlgorithms(self, *args, **kwargs):
20 | self.addAlgorithm(RVTHillshade())
21 | self.addAlgorithm(RVTMultiHillshade())
22 | self.addAlgorithm(RVTSlope())
23 | self.addAlgorithm(RVTSlrm())
24 | self.addAlgorithm(RVTSvf())
25 | self.addAlgorithm(RVTASvf())
26 | self.addAlgorithm(RVTOpns())
27 | # self.addAlgorithm(RVTSim())
28 | self.addAlgorithm(RVTLocalDom())
29 | self.addAlgorithm(RVTBlender())
30 | self.addAlgorithm(RVTMsrm())
31 | self.addAlgorithm(RVTMstp())
32 | self.addAlgorithm(RVTFillNoData())
33 | self.addAlgorithm(RVTFillNoDataIDW())
34 |
35 | def id(self, *args, **kwargs):
36 | """The ID of your plugin, used for identifying the provider.
37 |
38 | This string should be a unique, short, character only string,
39 | eg "qgis" or "gdal". This string should not be localised.
40 | """
41 | return 'rvt'
42 |
43 | def name(self, *args, **kwargs):
44 | """The human friendly name of your plugin in Processing.
45 |
46 | This string should be as short as possible (e.g. "Lastools", not
47 | "Lastools version 1.0.1 64-bit") and localised.
48 | """
49 | return self.tr('Relief visualization toolbox')
50 |
51 | def icon(self):
52 | """Should return a QIcon which is used for your provider inside
53 | the Processing toolbox.
54 | """
55 | return QgsProcessingProvider.icon(self)
56 |
--------------------------------------------------------------------------------
/qrvt_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | /***************************************************************************
4 | QRVTDialog
5 | A QGIS plugin
6 | RVT plugin lets you compute different visualizations from raster DEM.
7 | Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
8 | -------------------
9 | begin : 2020-10-12
10 | git sha : $Format:%H$
11 | copyright : (C) 2020 by Research Centre of the Slovenian Academy of Sciences and Arts
12 | email : ziga.kokalj@zrc-sazu.si
13 | ***************************************************************************/
14 |
15 | /***************************************************************************
16 | * *
17 | * This program is free software; you can redistribute it and/or modify *
18 | * it under the terms of the GNU General Public License as published by *
19 | * the Free Software Foundation; either version 2 of the License, or *
20 | * (at your option) any later version. *
21 | * *
22 | ***************************************************************************/
23 | """
24 |
25 | import os
26 |
27 | from qgis.PyQt import uic
28 | from qgis.PyQt import QtWidgets
29 |
30 | # This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
31 | FORM_CLASS, _ = uic.loadUiType(os.path.join(
32 | os.path.dirname(__file__), 'qrvt_dialog_base.ui'))
33 |
34 |
35 | class QRVTDialog(QtWidgets.QDialog, FORM_CLASS):
36 | def __init__(self, parent=None):
37 | """Constructor."""
38 | super(QRVTDialog, self).__init__(parent)
39 | # Set up the user interface from Designer through FORM_CLASS.
40 | # After self.setupUi() you can access any designer object by doing
41 | # self., and you can use autoconnect slots - see
42 | # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
43 | # #widgets-and-dialogs-with-auto-connect
44 | self.setupUi(self)
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Relief Visualization Toolbox QGIS Plugin
2 |
3 | 
4 |
5 | Relief Visualization Toolbox was produced to help scientist visualize raster elevation model datasets. We have narrowed down the selection to include techniques that have proven to be effective for identification of small scale features. Default settings therefore assume working with high resolution digital elevation models, derived from airborne laser scanning missions (lidar).
6 |
7 |
8 | ## Installation
9 | Plugin is uploaded to QGIS plugin repository [Relief visualization toolbox, QGIS plugin repository](https://plugins.qgis.org/plugins/rvt-qgis/).
10 |
11 | Detailed installation guide is available at [Relief visualization toolbox, QGIS Plugin installation](https://rvt-qgis.readthedocs.io/en/latest/install.html).
12 |
13 | To install plugin open QGIS and go to:
14 |
15 | ```
16 | Plugins > Manage and install plugins... > Search Relief Visualization Toolbox > Install
17 | ```
18 |
19 | The plugin has been tested under QGIS 3.12 and later.
20 |
21 | ## Documentation
22 |
23 | Documentation of the package and its usage is available at [Relief Visualization Toolbox in Python documentation](https://rvt-py.readthedocs.io/).
24 |
25 | ## References
26 |
27 | When using the tools, please cite:
28 |
29 | * Kokalj, Ž., Somrak, M. 2019. Why Not a Single Image? Combining Visualizations to Facilitate Fieldwork and On-Screen Mapping. Remote Sensing 11(7): 747.
30 | * Zakšek, K., Oštir, K., Kokalj, Ž. 2011. Sky-View Factor as a Relief Visualization Technique. Remote Sensing 3: 398-415.
31 |
32 | ## Contributing
33 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
34 |
35 | Please report any bugs and suggestions for improvements.
36 |
37 | ## Acknowledgment
38 |
39 | Development of RVT Python scripts was part financed by the Slovenian Research Agency core funding No. P2-0406 and by research projects No. J6-9395 and J2-9251. Development of RVT QGIS plugin was part financed by PTS Consultancy via the UK Government Culture Recovery Fund.
40 |
41 | ## License
42 | This project is licensed under the terms of the [Apache License](LICENSE).
43 |
44 | ## About
45 | RVT plugin for QGIS by Žiga Kokalj, Žiga Maroh, Nejc Čož and Krištof Oštir, 2022.
46 | It is developed in collaboration between ZRC SAZU and University of Ljubljana.
47 |
--------------------------------------------------------------------------------
/metadata.txt:
--------------------------------------------------------------------------------
1 | # This file contains metadata for your plugin.
2 |
3 | # This file should be included when you package your plugin.# Mandatory items:
4 |
5 | [general]
6 | name=Relief Visualization Toolbox
7 | qgisMinimumVersion=3.0
8 | description=Relief visualization toolbox (RVT) plugin helps scientists visualize raster elevation model datasets.
9 | version=0.10.0
10 | author=ZRC SAZU and University of Ljubljana (UL FGG), Žiga Maroh
11 | email=ziga.maroh@icloud.com
12 |
13 | about=Relief Visualization Toolbox was developed to help scientist visualize raster elevation model datasets. We narrowed down the selection to include techniques that have proven to be effective for identification of small scale features. Default settings therefore assume working with high resolution digital elevation models, derived from airborne laser scanning missions (lidar). Despite this, techniques are also used for different other purposes. Sky-view factor, for example, can be efficiently used in numerous studies where digital elevation model visualizations and automatic feature extraction techniques are indispensable, e.g. in geography, geomorphology, cartography, hydrology, glaciology, forestry and disaster management. It can be used even in engineering applications, such as, predicting the availability of the GPS signal in urban areas. Methods currently implemented are: -hillshading, -hillshading from multiple directions, -slope gradient, -simple local relief model, -sky-view factor (as developed by our team), -anisotropic sky-view factor, -positive and negative openness, -sky illumination, and -local dominance. © Copyright 2020 ZRC SAZU and University of Ljubljana
14 |
15 | tracker=https://github.com/EarthObservation/rvt-qgis/issues
16 | repository=https://github.com/EarthObservation/rvt-qgis
17 | # End of mandatory metadata
18 |
19 | # Recommended items:
20 |
21 | hasProcessingProvider=yes
22 | # Uncomment the following line and add your changelog:
23 | changelog=
24 | [0.10.0] - 2025.09.19:
25 | * Updated to RVT version 2.2.3
26 | * Added e4MSTP to Blender combinations
27 | * Fixed minor bugs
28 |
29 | # Tags are comma separated with spaces allowed
30 | tags=python,rvt,relief_visualization_toolbox,relief_visualization,raster_visualization,visualization,dem_visualization
31 |
32 | homepage=https://rvt-py.readthedocs.io/en/latest/rvtfor_qgis.html
33 | category=Plugins
34 | icon=icon.png
35 | # experimental flag
36 | experimental=False
37 |
38 | # deprecated flag (applies to the whole plugin, not just a single version)
39 | deprecated=False
40 |
41 | # Since QGIS 3.8, a comma separated list of plugins to be installed
42 | # (or upgraded) can be specified.
43 | # Check the documentation for more information.
44 | # plugin_dependencies=
45 |
46 | Category of the plugin: Raster, Vector, Database or Web
47 | # category=
48 |
49 | # If the plugin can run on QGIS Server.
50 | server=False
51 |
52 | # LICENSE
53 | license=Apache-2.0
54 | license_file=LICENSE
55 |
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Python template
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | *$py.class
7 |
8 | # C extensions
9 | *.so
10 |
11 | # Distribution / packaging
12 | .Python
13 | build/
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | .eggs/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | wheels/
25 | share/python-wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 | MANIFEST
30 |
31 | # PyInstaller
32 | # Usually these files are written by a python script from a template
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
34 | *.manifest
35 | *.spec
36 |
37 | # Installer logs
38 | pip-log.txt
39 | pip-delete-this-directory.txt
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .nox/
45 | .coverage
46 | .coverage.*
47 | .cache
48 | nosetests.xml
49 | coverage.xml
50 | *.cover
51 | *.py,cover
52 | .hypothesis/
53 | .pytest_cache/
54 | cover/
55 |
56 | # Translations
57 | *.mo
58 | *.pot
59 |
60 | # Django stuff:
61 | *.log
62 | local_settings.py
63 | db.sqlite3
64 | db.sqlite3-journal
65 |
66 | # Flask stuff:
67 | instance/
68 | .webassets-cache
69 |
70 | # Scrapy stuff:
71 | .scrapy
72 |
73 | # Sphinx documentation
74 | docs/_build/
75 |
76 | # PyBuilder
77 | .pybuilder/
78 | target/
79 |
80 | # Jupyter Notebook
81 | .ipynb_checkpoints
82 |
83 | # IPython
84 | profile_default/
85 | ipython_config.py
86 |
87 | # pyenv
88 | # For a library or package, you might want to ignore these files since the code is
89 | # intended to run in multiple environments; otherwise, check them in:
90 | # .python-version
91 |
92 | # pipenv
93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
96 | # install all needed dependencies.
97 | #Pipfile.lock
98 |
99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
100 | __pypackages__/
101 |
102 | # Celery stuff
103 | celerybeat-schedule
104 | celerybeat.pid
105 |
106 | # SageMath parsed files
107 | *.sage.py
108 |
109 | # Environments
110 | .env
111 | .venv
112 | env/
113 | venv/
114 | ENV/
115 | env.bak/
116 | venv.bak/
117 |
118 | # Spyder project settings
119 | .spyderproject
120 | .spyproject
121 |
122 | # Rope project settings
123 | .ropeproject
124 |
125 | # mkdocs documentation
126 | /site
127 |
128 | # mypy
129 | .mypy_cache/
130 | .dmypy.json
131 | dmypy.json
132 |
133 | # Pyre type checker
134 | .pyre/
135 |
136 | # pytype static type analyzer
137 | .pytype/
138 |
139 | # Cython debug symbols
140 | cython_debug/
141 |
142 | # VS Code
143 | .vscode/
144 |
145 | settings/plugin_size.json
146 | /zip_build
147 | /.idea
148 | .idea
149 | settings/default_settings.json
150 |
--------------------------------------------------------------------------------
/pb_tool.cfg:
--------------------------------------------------------------------------------
1 | #/***************************************************************************
2 | # QRVT
3 | #
4 | # Configuration file for plugin builder tool (pb_tool)
5 | # Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
6 | # -------------------
7 | # begin : 2020-10-12
8 | # copyright : © Copyright 2020 ZRC SAZU and University of Ljubljana
9 | # email : ziga.kokalj@zrc-sazu.si
10 | # ***************************************************************************/
11 | #
12 | #/***************************************************************************
13 | # * *
14 | # * This program is free software; you can redistribute it and/or modify *
15 | # * it under the terms of the GNU General Public License as published by *
16 | # * the Free Software Foundation; either version 2 of the License, or *
17 | # * (at your option) any later version. *
18 | # * *
19 | # ***************************************************************************/
20 | #
21 | #
22 | # You can install pb_tool using:
23 | # pip install http://geoapt.net/files/pb_tool.zip
24 | #
25 | # Consider doing your development (and install of pb_tool) in a virtualenv.
26 | #
27 | # For details on setting up and using pb_tool, see:
28 | # http://g-sherman.github.io/plugin_build_tool/
29 | #
30 | # Issues and pull requests here:
31 | # https://github.com/g-sherman/plugin_build_tool:
32 | #
33 | # Sane defaults for your plugin generated by the Plugin Builder are
34 | # already set below.
35 | #
36 | # As you add Python source files and UI files to your plugin, add
37 | # them to the appropriate [files] section below.
38 |
39 | [plugin]
40 | # Name of the plugin. This is the name of the directory that will
41 | # be created in .qgis2/python/plugins
42 | name: rvt-qgis
43 |
44 | # Full path to where you want your plugin directory copied. If empty,
45 | # the QGIS default path will be used. Don't include the plugin name in
46 | # the path.
47 | plugin_path:
48 |
49 | [files]
50 | # Python files that should be deployed with the plugin
51 | python_files: __init__.py qrvt.py qrvt_dialog.py
52 |
53 | # The main dialog file that is loaded (not compiled)
54 | main_dialog: qrvt_dialog_base.ui qrvt_dialog_about.ui
55 |
56 | # Other ui files for dialogs you create (these will be compiled)
57 | compiled_ui_files:
58 |
59 | # Resource file(s) that will be compiled
60 | resource_files: resources.qrc
61 |
62 | # Other files required for the plugin
63 | extras: metadata.txt LICENSE icon.png loading.gif Makefile
64 |
65 | # Other directories to be deployed with the plugin.
66 | # These must be subdirectories under the plugin directory
67 | extra_dirs: rvt processing_provider settings i18n
68 |
69 | # ISO code(s) for any locales (translations), separated by spaces.
70 | # Corresponding .ts files must exist in the i18n directory
71 | locales:
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/settings/default_terrains_settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "terrains_settings": [
3 | {
4 | "terrain_settings": {
5 | "name": "general",
6 | "Slope gradient": {
7 | "stretch": {"min": 0, "max": 50}
8 | },
9 | "Hillshade": {
10 | "stretch": {"min": 0, "max": 1},
11 | "hs_sun_el": {"value": 35}
12 | },
13 | "Multiple directions hillshade": {
14 | "stretch": {"min": 0, "max": 1},
15 | "mhs_sun_el": {"value": 35}
16 | },
17 | "Simple local relief model": {
18 | "stretch": {"min": -1, "max": 1},
19 | "slrm_rad_cell": {"value": 20}
20 | },
21 | "Sky-View Factor": {
22 | "stretch": {"min": 0.7, "max": 1},
23 | "svf_r_max": {"value": 10},
24 | "svf_noise": {"value": 0}
25 | },
26 | "Anisotropic Sky-View Factor": {
27 | "stretch": {"min": 0.65, "max": 1}
28 | },
29 | "Openness - Positive": {
30 | "stretch": {"min": 68, "max": 93}
31 | },
32 | "Openness - Negative": {
33 | "stretch": {"min": 60, "max": 95}
34 | },
35 | "Sky illumination": {
36 | "stretch": {"min": 0.25, "max": 0.3}
37 | },
38 | "Local dominance": {
39 | "stretch": {"min": 0.5, "max": 1.8},
40 | "ld_min_rad": {"value": 10},
41 | "ld_max_rad": {"value": 20},
42 | "ld_observer_h": {"value": 1.7}
43 | }
44 | }
45 |
46 | },
47 | {
48 | "terrain_settings": {
49 | "name": "flat",
50 | "Slope gradient": {
51 | "stretch": {"min": 0, "max": 15}
52 | },
53 | "Hillshade": {
54 | "hs_sun_el": {"value": 15}
55 | },
56 | "Multiple directions hillshade": {
57 | "mhs_sun_el": {"value": 15}
58 | },
59 | "Simple local relief model": {
60 | "slrm_rad_cell": {"value": 10}
61 | },
62 | "Sky-View Factor": {
63 | "stretch": {"min": 0.9, "max": 1},
64 | "svf_r_max": {"value": 20},
65 | "svf_noise": {"value": 3}
66 | },
67 | "Openness - Positive": {
68 | "stretch": {"min": 85, "max": 93}
69 | },
70 | "Openness - Negative": {
71 | "stretch": {"min": 75, "max": 95}
72 | },
73 | "Local dominance": {
74 | "stretch": {"min": 0.5, "max": 3},
75 | "ld_min_rad": {"value": 10},
76 | "ld_max_rad": {"value": 20},
77 | "ld_observer_h": {"value": 1.7}
78 | }
79 | }
80 | },
81 | {
82 | "terrain_settings": {
83 | "name": "steep",
84 | "Slope gradient": {
85 | "stretch": {"min": 0, "max": 60}
86 | },
87 | "Hillshade": {
88 | "hs_sun_el": {"value": 55}
89 | },
90 | "Multiple directions hillshade": {
91 | "mhs_sun_el": {"value": 55}
92 | },
93 | "Simple local relief model": {
94 | "slrm_rad_cell": {"value": 10}
95 | },
96 | "Sky-View Factor": {
97 | "stretch": {"min": 0.55, "max": 1},
98 | "svf_r_max": {"value": 10},
99 | "svf_noise": {"value": 0}
100 | },
101 | "Openness - Positive": {
102 | "stretch": {"min": 55, "max": 95}
103 | },
104 | "Openness - Negative": {
105 | "stretch": {"min": 45, "max": 95}
106 | },
107 | "Local dominance": {
108 | "stretch": {"min": 0.55, "max": 0.95},
109 | "ld_min_rad": {"value": 10},
110 | "ld_max_rad": {"value": 10},
111 | "ld_observer_h": {"value": 16}
112 | }
113 | }
114 |
115 | }
116 | ]
117 | }
--------------------------------------------------------------------------------
/plugin_upload.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 | """This script uploads a plugin package to the plugin repository.
4 | Authors: A. Pasotti, V. Picavet
5 | git sha : $TemplateVCSFormat
6 | """
7 |
8 | import sys
9 | import getpass
10 | import xmlrpc.client
11 | from optparse import OptionParser
12 |
13 | standard_library.install_aliases()
14 |
15 | # Configuration
16 | PROTOCOL = 'https'
17 | SERVER = 'plugins.qgis.org'
18 | PORT = '443'
19 | ENDPOINT = '/plugins/RPC2/'
20 | VERBOSE = False
21 |
22 |
23 | def main(parameters, arguments):
24 | """Main entry point.
25 |
26 | :param parameters: Command line parameters.
27 | :param arguments: Command line arguments.
28 | """
29 | address = "{protocol}://{username}:{password}@{server}:{port}{endpoint}".format(
30 | protocol=PROTOCOL,
31 | username=parameters.username,
32 | password=parameters.password,
33 | server=parameters.server,
34 | port=parameters.port,
35 | endpoint=ENDPOINT)
36 | print("Connecting to: %s" % hide_password(address))
37 |
38 | server = xmlrpc.client.ServerProxy(address, verbose=VERBOSE)
39 |
40 | try:
41 | with open(arguments[0], 'rb') as handle:
42 | plugin_id, version_id = server.plugin.upload(
43 | xmlrpc.client.Binary(handle.read()))
44 | print("Plugin ID: %s" % plugin_id)
45 | print("Version ID: %s" % version_id)
46 | except xmlrpc.client.ProtocolError as err:
47 | print("A protocol error occurred")
48 | print("URL: %s" % hide_password(err.url, 0))
49 | print("HTTP/HTTPS headers: %s" % err.headers)
50 | print("Error code: %d" % err.errcode)
51 | print("Error message: %s" % err.errmsg)
52 | except xmlrpc.client.Fault as err:
53 | print("A fault occurred")
54 | print("Fault code: %d" % err.faultCode)
55 | print("Fault string: %s" % err.faultString)
56 |
57 |
58 | def hide_password(url, start=6):
59 | """Returns the http url with password part replaced with '*'.
60 |
61 | :param url: URL to upload the plugin to.
62 | :type url: str
63 |
64 | :param start: Position of start of password.
65 | :type start: int
66 | """
67 | start_position = url.find(':', start) + 1
68 | end_position = url.find('@')
69 | return "%s%s%s" % (
70 | url[:start_position],
71 | '*' * (end_position - start_position),
72 | url[end_position:])
73 |
74 |
75 | if __name__ == "__main__":
76 | parser = OptionParser(usage="%prog [options] plugin.zip")
77 | parser.add_option(
78 | "-w", "--password", dest="password",
79 | help="Password for plugin site", metavar="******")
80 | parser.add_option(
81 | "-u", "--username", dest="username",
82 | help="Username of plugin site", metavar="user")
83 | parser.add_option(
84 | "-p", "--port", dest="port",
85 | help="Server port to connect to", metavar="80")
86 | parser.add_option(
87 | "-s", "--server", dest="server",
88 | help="Specify server name", metavar="plugins.qgis.org")
89 | options, args = parser.parse_args()
90 | if len(args) != 1:
91 | print("Please specify zip file.\n")
92 | parser.print_help()
93 | sys.exit(1)
94 | if not options.server:
95 | options.server = SERVER
96 | if not options.port:
97 | options.port = PORT
98 | if not options.username:
99 | # interactive mode
100 | username = getpass.getuser()
101 | print("Please enter user name [%s] :" % username, end=' ')
102 |
103 | res = input()
104 | if res != "":
105 | options.username = res
106 | else:
107 | options.username = username
108 | if not options.password:
109 | # interactive mode
110 | options.password = getpass.getpass()
111 | main(options, args)
112 |
--------------------------------------------------------------------------------
/settings/default_blender_combinations.json:
--------------------------------------------------------------------------------
1 | {
2 | "combinations": [
3 | {
4 | "combination": {
5 | "name": "Archaeological (VAT)",
6 | "layers": [
7 | {
8 | "layer": "1",
9 | "visualization_method": "Sky-View Factor",
10 | "norm": "Value",
11 | "min": 0.7,
12 | "max": 1.0,
13 | "blend_mode": "Multiply",
14 | "opacity": 25
15 | },
16 | {
17 | "layer": "2",
18 | "visualization_method": "Openness - Positive",
19 | "norm": "Value",
20 | "min": 68.0,
21 | "max": 93.0,
22 | "blend_mode": "Overlay",
23 | "opacity": 50
24 | },
25 | {
26 | "layer": "3",
27 | "visualization_method": "Slope gradient",
28 | "norm": "Value",
29 | "min": 0.0,
30 | "max": 50.0,
31 | "blend_mode": "Luminosity",
32 | "opacity": 50
33 | },
34 | {
35 | "layer": "4",
36 | "visualization_method": "Hillshade",
37 | "norm": "Value",
38 | "min": 0.0,
39 | "max": 1.0,
40 | "blend_mode": "Normal",
41 | "opacity": 100
42 | }
43 | ]
44 | }
45 | },
46 | {
47 | "combination": {
48 | "name": "Archaeological combined (VAT combined)",
49 | "layers": []
50 | }
51 | },
52 | {
53 | "combination": {
54 | "name": "enhanced Multi-Scale Topographic Position version 3",
55 | "layers": []
56 | }
57 | },
58 | {
59 | "combination": {
60 | "name": "e4MSTP",
61 | "layers": []
62 | }
63 | },
64 | {
65 | "combination": {
66 | "name": "Prismatic openness",
67 | "layers": [
68 | {
69 | "layer": "1",
70 | "visualization_method": "Openness - Positive",
71 | "norm": "Value",
72 | "min": 68.0,
73 | "max": 93.0,
74 | "blend_mode": "Overlay",
75 | "opacity": 50
76 | },
77 | {
78 | "layer": "2",
79 | "visualization_method": "Openness - Negative",
80 | "norm": "Value",
81 | "min": 68.0,
82 | "max": 93.0,
83 | "blend_mode": "Overlay",
84 | "opacity": 50
85 | },
86 | {
87 | "layer": "3",
88 | "visualization_method": "Multiple directions hillshade",
89 | "norm": "Value",
90 | "min": 0.0,
91 | "max": 1.0,
92 | "blend_mode": "Normal",
93 | "opacity": 100
94 | }
95 | ]
96 | }
97 | },
98 | {
99 | "combination": {
100 | "name": "City",
101 | "layers": [
102 | {
103 | "layer": "1",
104 | "visualization_method": "Shadow",
105 | "norm": "Value",
106 | "min": 0.0,
107 | "max": 1.0,
108 | "blend_mode": "Normal",
109 | "opacity": 70
110 | },
111 | {
112 | "layer": "2",
113 | "visualization_method": "Sky-View Factor",
114 | "norm": "Value",
115 | "min": 0.1,
116 | "max": 1.0,
117 | "blend_mode": "Normal",
118 | "opacity": 10
119 | },
120 | {
121 | "layer": "3",
122 | "visualization_method": "Sky illumination",
123 | "norm": "Perc",
124 | "min": 1.0,
125 | "max": 0.0,
126 | "blend_mode": "Normal",
127 | "opacity": 100
128 | }
129 | ]
130 | }
131 | }
132 | ]
133 | }
--------------------------------------------------------------------------------
/processing_provider/rvt_slrm.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTSlrm(QgsProcessingAlgorithm):
19 | """
20 | RVT Simple local relief model.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | RADIUS = "RADIUS"
26 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
27 | OUTPUT = 'OUTPUT'
28 |
29 | def tr(self, string):
30 | """
31 | Returns a translatable string with the self.tr() function.
32 | """
33 | return QCoreApplication.translate('Processing', string)
34 |
35 | def createInstance(self):
36 | return RVTSlrm()
37 |
38 | def name(self):
39 | """
40 | Returns the algorithm name, used for identifying the algorithm. This
41 | string should be fixed for the algorithm, and must not be localised.
42 | The name should be unique within each provider. Names should contain
43 | lowercase alphanumeric characters only and no spaces or other
44 | formatting characters.
45 | """
46 | return 'rvt_slrm'
47 |
48 | def displayName(self):
49 | """
50 | Returns the translated algorithm name, which should be used for any
51 | user-visible display of the algorithm name.
52 | """
53 | return self.tr('RVT Simplified local relief model')
54 |
55 | def shortHelpString(self):
56 | """
57 | Returns a localised short helper string for the algorithm. This string
58 | should provide a basic description about what the algorithm does and the
59 | parameters and outputs associated with it..
60 | """
61 | return self.tr("Relief visualization toolbox, Simplified local relief model. Calculates Simplified local"
62 | " relief model.")
63 |
64 | def initAlgorithm(self, config=None):
65 | """
66 | Here we define the inputs and output of the algorithm, along
67 | with some other properties.
68 | """
69 | self.addParameter(
70 | QgsProcessingParameterRasterLayer(
71 | self.INPUT,
72 | self.tr('Input DEM raster layer'),
73 | [QgsProcessing.TypeRaster]
74 | )
75 | )
76 | self.addParameter(
77 | QgsProcessingParameterNumber(
78 | name="VE_FACTOR",
79 | description="Vertical exaggeration factor",
80 | type=QgsProcessingParameterNumber.Double,
81 | defaultValue=1,
82 | minValue=-1000,
83 | maxValue=1000
84 | )
85 | )
86 | self.addParameter(
87 | QgsProcessingParameterNumber(
88 | name="RADIUS",
89 | description="Radius for trend assessment [pixels]",
90 | type=QgsProcessingParameterNumber.Integer,
91 | defaultValue=20,
92 | minValue=10,
93 | maxValue=50
94 | )
95 | )
96 | self.addParameter(
97 | QgsProcessingParameterBoolean(
98 | name="SAVE_AS_8BIT",
99 | description="Save as 8bit raster",
100 | defaultValue=False
101 | )
102 | )
103 | self.addParameter(
104 | QgsProcessingParameterRasterDestination(
105 | self.OUTPUT,
106 | self.tr('Output visualization raster layer')
107 | )
108 | )
109 |
110 | def processAlgorithm(self, parameters, context, feedback):
111 | """
112 | Here is where the processing itself takes place.
113 | """
114 | dem_layer = self.parameterAsRasterLayer(
115 | parameters,
116 | self.INPUT,
117 | context
118 | )
119 |
120 | ve_factor = float(self.parameterAsDouble(
121 | parameters,
122 | self.VE_FACTOR,
123 | context
124 | ))
125 | radius = int(self.parameterAsInt(
126 | parameters,
127 | self.RADIUS,
128 | context
129 | ))
130 | save_8bit = bool(self.parameterAsBool(
131 | parameters,
132 | self.SAVE_AS_8BIT,
133 | context
134 | ))
135 | visualization_path = (self.parameterAsOutputLayer(
136 | parameters,
137 | self.OUTPUT,
138 | context,
139 | ))
140 |
141 | dem_path = str(dem_layer.source())
142 |
143 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
144 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
145 | dem_arr = dict_arr_dem["array"]
146 | no_data = dict_arr_dem["no_data"]
147 |
148 | visualization_arr = rvt.vis.slrm(dem=dem_arr, radius_cell=radius, ve_factor=ve_factor, no_data=no_data)
149 | if not save_8bit:
150 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
151 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
152 | else:
153 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
154 | float_arr=visualization_arr, visualization=RVTVisualization.SIMPLE_LOCAL_RELIEF_MODEL
155 | )
156 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
157 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
158 |
159 | result = {self.OUTPUT: visualization_path}
160 | return result
161 |
--------------------------------------------------------------------------------
/processing_provider/rvt_slope.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTSlope(QgsProcessingAlgorithm):
19 | """
20 | RVT Slope gradient.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | UNIT = "UNIT"
26 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
27 | OUTPUT = 'OUTPUT'
28 |
29 | units_options = ["degree", "radian", "percent"]
30 |
31 | def tr(self, string):
32 | """
33 | Returns a translatable string with the self.tr() function.
34 | """
35 | return QCoreApplication.translate('Processing', string)
36 |
37 | def createInstance(self):
38 | return RVTSlope()
39 |
40 | def name(self):
41 | """
42 | Returns the algorithm name, used for identifying the algorithm. This
43 | string should be fixed for the algorithm, and must not be localised.
44 | The name should be unique within each provider. Names should contain
45 | lowercase alphanumeric characters only and no spaces or other
46 | formatting characters.
47 | """
48 | return 'rvt_slope'
49 |
50 | def displayName(self):
51 | """
52 | Returns the translated algorithm name, which should be used for any
53 | user-visible display of the algorithm name.
54 | """
55 | return self.tr('RVT Slope')
56 |
57 | def shortHelpString(self):
58 | """
59 | Returns a localised short helper string for the algorithm. This string
60 | should provide a basic description about what the algorithm does and the
61 | parameters and outputs associated with it..
62 | """
63 | return self.tr("Relief visualization toolbox, Slope. Calculates slope gradient.")
64 |
65 | def initAlgorithm(self, config=None):
66 | """
67 | Here we define the inputs and output of the algorithm, along
68 | with some other properties.
69 | """
70 | self.addParameter(
71 | QgsProcessingParameterRasterLayer(
72 | self.INPUT,
73 | self.tr('Input DEM raster layer'),
74 | [QgsProcessing.TypeRaster]
75 | )
76 | )
77 | self.addParameter(
78 | QgsProcessingParameterNumber(
79 | name="VE_FACTOR",
80 | description="Vertical exaggeration factor",
81 | type=QgsProcessingParameterNumber.Double,
82 | defaultValue=1,
83 | minValue=-1000,
84 | maxValue=1000
85 | )
86 | )
87 | self.addParameter(
88 | QgsProcessingParameterEnum(
89 | name="UNIT",
90 | description="Output units",
91 | options=self.units_options,
92 | defaultValue="degree"
93 | )
94 | )
95 | self.addParameter(
96 | QgsProcessingParameterBoolean(
97 | name="SAVE_AS_8BIT",
98 | description="Save as 8bit raster",
99 | defaultValue=False
100 | )
101 | )
102 | self.addParameter(
103 | QgsProcessingParameterRasterDestination(
104 | self.OUTPUT,
105 | self.tr('Output visualization raster layer')
106 | )
107 | )
108 |
109 | def processAlgorithm(self, parameters, context, feedback):
110 | """
111 | Here is where the processing itself takes place.
112 | """
113 | dem_layer = self.parameterAsRasterLayer(
114 | parameters,
115 | self.INPUT,
116 | context
117 | )
118 |
119 | ve_factor = float(self.parameterAsDouble(
120 | parameters,
121 | self.VE_FACTOR,
122 | context
123 | ))
124 | unit_enum = int(self.parameterAsEnum(
125 | parameters,
126 | self.UNIT,
127 | context
128 | ))
129 | unit = self.units_options[unit_enum]
130 | save_8bit = bool(self.parameterAsBool(
131 | parameters,
132 | self.SAVE_AS_8BIT,
133 | context
134 | ))
135 | visualization_path = (self.parameterAsOutputLayer(
136 | parameters,
137 | self.OUTPUT,
138 | context,
139 | ))
140 |
141 | dem_path = str(dem_layer.source())
142 |
143 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
144 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
145 | dem_arr = dict_arr_dem["array"]
146 | no_data = dict_arr_dem["no_data"]
147 |
148 | visualization_arr = rvt.vis.slope_aspect(dem=dem_arr, resolution_x=resolution[0], resolution_y=resolution[1],
149 | output_units=unit, ve_factor=ve_factor, no_data=no_data)["slope"]
150 | if not save_8bit:
151 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
152 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
153 | else:
154 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
155 | float_arr=visualization_arr, visualization=RVTVisualization.SLOPE
156 | )
157 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
158 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
159 |
160 | result = {self.OUTPUT: visualization_path}
161 | return result
162 |
--------------------------------------------------------------------------------
/resources.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Resource object code
4 | #
5 | # Created by: The Resource Compiler for PyQt5 (Qt v5.15.1)
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore
10 |
11 | qt_resource_data = b"\
12 | \x00\x00\x04\x0a\
13 | \x89\
14 | \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
15 | \x00\x00\x17\x00\x00\x00\x18\x08\x06\x00\x00\x00\x11\x7c\x66\x75\
16 | \x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
17 | \x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
18 | \x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\
19 | \x00\x9a\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd9\x02\x15\
20 | \x16\x11\x2c\x9d\x48\x83\xbb\x00\x00\x03\x8a\x49\x44\x41\x54\x48\
21 | \xc7\xad\x95\x4b\x68\x5c\x55\x18\xc7\x7f\xe7\xdc\x7b\x67\xe6\xce\
22 | \x4c\x66\x26\x49\xd3\x24\x26\xa6\xc6\xf8\x40\x21\xa5\x04\xb3\x28\
23 | \xda\x98\x20\xa5\x0b\xad\x55\xa8\x2b\xc5\x50\x1f\xa0\x6e\x34\x2b\
24 | \x45\x30\x14\x02\xba\x52\x69\x15\x17\x66\x63\x45\x97\x95\xa0\xad\
25 | \x0b\xfb\xc0\x06\x25\xb6\x71\x61\x12\x41\x50\xdb\x2a\x21\xd1\xe2\
26 | \x24\xf3\x9e\xc9\xcc\xbd\xe7\x1c\x17\x35\x43\x1e\x33\x21\xb6\xfd\
27 | \x56\x87\xf3\x9d\xfb\xfb\x1e\xf7\xff\x9d\x23\x8c\x31\x43\x95\xf4\
28 | \x85\x1e\x3f\x3b\x35\xac\xfd\xcc\x43\xdc\xa4\x49\x3b\xfe\x9d\x1d\
29 | \xdb\x7b\x22\x90\x78\xf8\xb2\x28\xa7\xbe\x7d\xc1\x4b\x9d\x79\xdf\
30 | \x18\x15\xe5\x16\x99\x10\x56\xde\x69\xdc\x3f\x22\xfd\xec\xd4\xf0\
31 | \xad\x04\x03\x18\xa3\xa2\x7e\x76\x6a\x58\xde\x68\x2b\xb4\x36\xf8\
32 | \xbe\xc6\x18\x53\xdb\xef\xe7\xfa\xec\xed\x67\x63\x10\x42\x00\xf0\
33 | \xfb\xd5\x65\x2a\x15\x45\xc7\x6d\x0d\x00\xc4\xa2\xc1\xaa\x6f\x0d\
34 | \x3e\x6c\xab\xc2\x1c\x56\xa4\x77\x4b\xb0\xf2\x35\x15\x5f\x21\x85\
35 | \xe0\xc8\x6b\x5f\x92\x2d\x37\x33\x39\xf9\x03\x27\x8e\x1f\xa2\xf7\
36 | \xbe\x9d\x04\x1c\x0b\x37\xe4\xac\xff\xa6\x30\x87\xbd\xba\x00\x6a\
37 | \x06\x79\xe5\xf5\xaf\x89\xd9\x92\xc5\xcc\x0a\xd9\x7c\x19\xcf\xe9\
38 | \xe2\xe4\xa9\x2f\x78\x7c\xff\x01\x72\x85\x0a\x2b\x65\x1f\xa5\x4c\
39 | \xb5\xb2\x55\x16\x80\xbd\x31\xda\xda\x20\x1f\x7d\x3e\xcd\xc2\xfd\
40 | \x59\xa6\x93\x39\x92\xd1\x22\xea\x9b\x16\xce\x9d\x3f\xce\xe0\x83\
41 | \x03\x24\x82\x59\x3a\xdb\x7b\x88\xc7\x82\x68\x63\x58\xc9\xcc\x62\
42 | \x8c\x21\x18\xb0\x6a\xc3\x37\x06\x49\x16\xff\x24\x6b\xa5\x49\xbb\
43 | \x25\xbc\xa2\xa6\x21\xbb\x40\x7f\xdf\x00\x83\xbd\x01\x8e\x3c\xd5\
44 | \x45\xd7\x8e\x6b\x9c\x9c\x98\x25\x1a\xb6\xe8\xbe\x3d\xc2\xdd\x77\
45 | \x44\x48\xc4\x1c\x22\xe1\xeb\x58\x59\xaf\xcf\xd3\x33\x29\x2e\x34\
46 | \x2d\x91\x93\x3e\xbe\x34\x78\x01\xc5\xe2\x61\xc5\xae\x72\x8e\x70\
47 | \xc8\xc2\x0d\x5a\xbc\xf5\xee\x2f\x9c\xfa\x3e\x86\x69\x7a\x8e\xcf\
48 | \x26\xe6\xf9\x63\xa1\x44\xa1\xa4\xd0\xda\x6c\x0d\x2f\x15\x7c\xb4\
49 | \x67\x28\x59\x0a\xcf\xd6\x54\xe2\x06\x13\x87\x2b\x6f\x68\xa6\x27\
50 | \xaf\x31\x32\x36\xc7\xb2\x7f\x17\xef\x7d\x7c\x8c\x33\x67\xcf\x12\
51 | \x70\x24\x4a\x69\xd6\x6a\x46\xd6\xd3\x70\x72\xa9\x82\x67\x34\x45\
52 | \xad\x28\xdb\x1a\x15\x34\x98\xff\x46\xed\xef\x37\x0d\x99\xbf\x4a\
53 | \x3c\x30\x38\xc0\xc8\x4b\xaf\x92\x5a\x9c\xe2\xe0\x23\x6d\x74\xb4\
54 | \xba\x84\x5d\x0b\x29\x45\x7d\xb8\x94\x82\x96\xb6\x10\xf3\xc5\x12\
55 | \x2a\xef\x53\x11\x1a\x63\xad\x3f\x93\x19\x85\xf1\xb1\x77\x58\x5a\
56 | \xf8\x99\x97\x9f\xe9\xa6\x75\x47\x90\xc6\xb8\x43\xd8\xb5\xb6\xce\
57 | \xfc\xfa\xfd\x00\xfb\x3e\xf4\xc8\x05\x35\xba\x5e\xeb\x46\x21\xf9\
58 | \xcf\x0a\xa9\x8c\x87\xe3\x48\xdc\x90\xb5\x6e\x98\x6a\xaa\x65\xf2\
59 | \x52\x92\x43\x2f\x5e\xc2\x8c\x02\x1a\x10\xf5\x07\xac\xc3\x75\x70\
60 | \x83\x92\x80\xb3\xf9\xd0\x26\xf8\x8f\xb3\x29\xc6\x3e\xb8\x8c\x19\
61 | \x35\x75\x6b\x7b\x7e\x3c\xca\x45\x0c\x7e\x49\x31\xf4\x58\x3b\xf7\
62 | \xf6\x34\x90\x88\x39\x04\x1c\x59\x1f\xfe\xdb\xd5\x3c\x5f\x9d\x4b\
63 | \x32\xfd\x44\xb2\xba\xd7\xfa\xb6\x60\xcf\xde\x16\xdc\x90\x45\x4c\
64 | \x4a\x2a\x9e\x62\xfe\x4e\xc5\xc8\xc1\x4e\xda\x76\x86\xe8\xe9\x0a\
65 | \xe3\xd8\x92\x58\xd4\xc6\xb2\x44\x6d\x78\x2a\x53\xe1\xca\x7c\x99\
66 | \x63\x5d\xbf\x56\x9d\xbd\x9f\x44\x18\x7a\xba\x95\x27\x0f\xb4\xd3\
67 | \xdc\x18\xc0\xf3\x0d\x52\x40\xd8\xb5\xb0\xa4\x20\x14\xb2\x70\x6c\
68 | \x81\x63\xcb\xaa\x42\xd6\xfd\xb7\xf4\xec\xa3\x06\xa0\x50\x52\xd8\
69 | \x4e\x1b\x7e\x4a\xd3\x31\xf9\x29\xcf\xfe\xd4\x49\x7f\x5f\x13\xfb\
70 | \xfa\x9b\x71\x43\x92\x58\xd4\x21\x18\x90\xac\xde\xb0\x42\x50\x13\
71 | \x58\x33\xf3\x88\x6b\xa1\xfd\x65\x96\xf2\x79\xc6\x43\x7b\xd8\x75\
72 | \x38\xcc\x3d\xdd\xd1\xaa\xcf\x71\xe4\xff\x7f\x91\x56\x33\xaf\xea\
73 | \x37\xe7\xa1\x94\x21\x16\xb5\xd1\x06\x2c\x29\x36\xf5\x72\x9b\x96\
74 | \x95\xc0\xc4\xda\x9d\x78\x83\x43\x53\x22\x80\x65\x09\x1c\xfb\x86\
75 | \xc1\x00\xe7\x25\x70\x14\x48\x6f\x1e\x22\x51\xe3\x75\xd9\xb6\xa5\
76 | \x81\xa3\x32\xb1\xfb\xf4\x0c\x30\xb8\xb1\x82\x9b\xb0\x09\x60\x30\
77 | \xb1\xfb\xf4\xcc\xbf\xa0\xe9\x6e\xae\x5a\xdf\x4b\x81\x00\x00\x00\
78 | \x00\x49\x45\x4e\x44\xae\x42\x60\x82\
79 | "
80 |
81 | qt_resource_name = b"\
82 | \x00\x07\
83 | \x07\x3b\xe0\xb3\
84 | \x00\x70\
85 | \x00\x6c\x00\x75\x00\x67\x00\x69\x00\x6e\x00\x73\
86 | \x00\x04\
87 | \x00\x07\x89\xd4\
88 | \x00\x71\
89 | \x00\x72\x00\x76\x00\x74\
90 | \x00\x08\
91 | \x0a\x61\x5a\xa7\
92 | \x00\x69\
93 | \x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
94 | "
95 |
96 | qt_resource_struct_v1 = b"\
97 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
98 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
99 | \x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
100 | \x00\x00\x00\x22\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
101 | "
102 |
103 | qt_resource_struct_v2 = b"\
104 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
105 | \x00\x00\x00\x00\x00\x00\x00\x00\
106 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
107 | \x00\x00\x00\x00\x00\x00\x00\x00\
108 | \x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
109 | \x00\x00\x00\x00\x00\x00\x00\x00\
110 | \x00\x00\x00\x22\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
111 | \x00\x00\x01\x75\xb6\xde\xf1\x32\
112 | "
113 |
114 | qt_version = [int(v) for v in QtCore.qVersion().split('.')]
115 | if qt_version < [5, 8, 0]:
116 | rcc_version = 1
117 | qt_resource_struct = qt_resource_struct_v1
118 | else:
119 | rcc_version = 2
120 | qt_resource_struct = qt_resource_struct_v2
121 |
122 | def qInitResources():
123 | QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
124 |
125 | def qCleanupResources():
126 | QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
127 |
128 | qInitResources()
129 |
--------------------------------------------------------------------------------
/processing_provider/rvt_hillshade.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTHillshade(QgsProcessingAlgorithm):
19 | """
20 | RVT Hillshade.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | SUN_AZIMUTH = 'SUN_AZIMUTH'
26 | SUN_ELEVATION = 'SUN_ELEVATION'
27 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
28 | OUTPUT = 'OUTPUT'
29 |
30 | def tr(self, string):
31 | """
32 | Returns a translatable string with the self.tr() function.
33 | """
34 | return QCoreApplication.translate('Processing', string)
35 |
36 | def createInstance(self):
37 | return RVTHillshade()
38 |
39 | def name(self):
40 | """
41 | Returns the algorithm name, used for identifying the algorithm. This
42 | string should be fixed for the algorithm, and must not be localised.
43 | The name should be unique within each provider. Names should contain
44 | lowercase alphanumeric characters only and no spaces or other
45 | formatting characters.
46 | """
47 | return 'rvt_hillshade'
48 |
49 | def displayName(self):
50 | """
51 | Returns the translated algorithm name, which should be used for any
52 | user-visible display of the algorithm name.
53 | """
54 | return self.tr('RVT Hillshade')
55 |
56 | def shortHelpString(self):
57 | """
58 | Returns a localised short helper string for the algorithm. This string
59 | should provide a basic description about what the algorithm does and the
60 | parameters and outputs associated with it..
61 | """
62 | return self.tr("Relief visualization toolbox, Hillshade. Calculates hillshade.")
63 |
64 | def initAlgorithm(self, config=None):
65 | """
66 | Here we define the inputs and output of the algorithm, along
67 | with some other properties.
68 | """
69 | self.addParameter(
70 | QgsProcessingParameterRasterLayer(
71 | self.INPUT,
72 | self.tr('Input DEM raster layer'),
73 | [QgsProcessing.TypeRaster]
74 | )
75 | )
76 | self.addParameter(
77 | QgsProcessingParameterNumber(
78 | name="VE_FACTOR",
79 | description="Vertical exaggeration factor",
80 | type=QgsProcessingParameterNumber.Double,
81 | defaultValue=1,
82 | minValue=-1000,
83 | maxValue=1000
84 | )
85 | )
86 | self.addParameter(
87 | QgsProcessingParameterNumber(
88 | name="SUN_AZIMUTH",
89 | description="Solar azimuth angle (clockwise from North) in degrees",
90 | type=QgsProcessingParameterNumber.Double,
91 | defaultValue=315,
92 | minValue=0,
93 | maxValue=360
94 | )
95 | )
96 | self.addParameter(
97 | QgsProcessingParameterNumber(
98 | name="SUN_ELEVATION",
99 | description="Solar vertical angle (above the horizon) in degrees",
100 | type=QgsProcessingParameterNumber.Double,
101 | defaultValue=35,
102 | minValue=0,
103 | maxValue=90
104 | )
105 | )
106 | self.addParameter(
107 | QgsProcessingParameterBoolean(
108 | name="SAVE_AS_8BIT",
109 | description="Save as 8bit raster",
110 | defaultValue=False
111 | )
112 | )
113 | self.addParameter(
114 | QgsProcessingParameterRasterDestination(
115 | self.OUTPUT,
116 | self.tr('Output visualization raster layer')
117 | )
118 | )
119 |
120 | def processAlgorithm(self, parameters, context, feedback):
121 | """
122 | Here is where the processing itself takes place.
123 | """
124 | dem_layer = self.parameterAsRasterLayer(
125 | parameters,
126 | self.INPUT,
127 | context
128 | )
129 |
130 | ve_factor = float(self.parameterAsDouble(
131 | parameters,
132 | self.VE_FACTOR,
133 | context
134 | ))
135 | sun_azimuth = float(self.parameterAsDouble(
136 | parameters,
137 | self.SUN_AZIMUTH,
138 | context
139 | ))
140 | sun_elevation = float(self.parameterAsDouble(
141 | parameters,
142 | self.SUN_ELEVATION,
143 | context
144 | ))
145 | save_8bit = bool(self.parameterAsBool(
146 | parameters,
147 | self.SAVE_AS_8BIT,
148 | context
149 | ))
150 | visualization_path = (self.parameterAsOutputLayer(
151 | parameters,
152 | self.OUTPUT,
153 | context,
154 | ))
155 |
156 | dem_path = str(dem_layer.source())
157 |
158 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
159 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
160 | dem_arr = dict_arr_dem["array"]
161 | no_data = dict_arr_dem["no_data"]
162 |
163 | visualization_arr = rvt.vis.hillshade(dem=dem_arr, resolution_x=resolution[0], resolution_y=resolution[1],
164 | sun_azimuth=sun_azimuth, sun_elevation=sun_elevation, ve_factor=ve_factor,
165 | no_data=no_data)
166 | if not save_8bit:
167 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
168 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
169 | else:
170 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
171 | float_arr=visualization_arr, visualization=RVTVisualization.HILLSHADE
172 | )
173 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
174 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
175 |
176 | result = {self.OUTPUT: visualization_path}
177 | return result
178 |
179 |
--------------------------------------------------------------------------------
/test/qgis_interface.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """QGIS plugin implementation.
3 |
4 | .. note:: This program is free software; you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation; either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | .. note:: This source code was copied from the 'postgis viewer' application
10 | with original authors:
11 | Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk
12 | Copyright (c) 2011 German Carrillo, geotux_tuxman@linuxmail.org
13 | Copyright (c) 2014 Tim Sutton, tim@linfiniti.com
14 |
15 | """
16 |
17 | __author__ = 'tim@linfiniti.com'
18 | __revision__ = '$Format:%H$'
19 | __date__ = '10/01/2011'
20 | __copyright__ = (
21 | 'Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk and '
22 | 'Copyright (c) 2011 German Carrillo, geotux_tuxman@linuxmail.org'
23 | 'Copyright (c) 2014 Tim Sutton, tim@linfiniti.com'
24 | )
25 |
26 | import logging
27 | from qgis.PyQt.QtCore import QObject, pyqtSlot, pyqtSignal
28 | from qgis.core import QgsMapLayerRegistry
29 | from qgis.gui import QgsMapCanvasLayer
30 | LOGGER = logging.getLogger('QGIS')
31 |
32 |
33 | #noinspection PyMethodMayBeStatic,PyPep8Naming
34 | class QgisInterface(QObject):
35 | """Class to expose QGIS objects and functions to plugins.
36 |
37 | This class is here for enabling us to run unit tests only,
38 | so most methods are simply stubs.
39 | """
40 | currentLayerChanged = pyqtSignal(QgsMapCanvasLayer)
41 |
42 | def __init__(self, canvas):
43 | """Constructor
44 | :param canvas:
45 | """
46 | QObject.__init__(self)
47 | self.canvas = canvas
48 | # Set up slots so we can mimic the behaviour of QGIS when layers
49 | # are added.
50 | LOGGER.debug('Initialising canvas...')
51 | # noinspection PyArgumentList
52 | QgsMapLayerRegistry.instance().layersAdded.connect(self.addLayers)
53 | # noinspection PyArgumentList
54 | QgsMapLayerRegistry.instance().layerWasAdded.connect(self.addLayer)
55 | # noinspection PyArgumentList
56 | QgsMapLayerRegistry.instance().removeAll.connect(self.removeAllLayers)
57 |
58 | # For processing module
59 | self.destCrs = None
60 |
61 | @pyqtSlot('QStringList')
62 | def addLayers(self, layers):
63 | """Handle layers being added to the registry so they show up in canvas.
64 |
65 | :param layers: list list of map layers that were added
66 |
67 | .. note:: The QgsInterface api does not include this method,
68 | it is added here as a helper to facilitate testing.
69 | """
70 | #LOGGER.debug('addLayers called on qgis_interface')
71 | #LOGGER.debug('Number of layers being added: %s' % len(layers))
72 | #LOGGER.debug('Layer Count Before: %s' % len(self.canvas.layers()))
73 | current_layers = self.canvas.layers()
74 | final_layers = []
75 | for layer in current_layers:
76 | final_layers.append(QgsMapCanvasLayer(layer))
77 | for layer in layers:
78 | final_layers.append(QgsMapCanvasLayer(layer))
79 |
80 | self.canvas.setLayerSet(final_layers)
81 | #LOGGER.debug('Layer Count After: %s' % len(self.canvas.layers()))
82 |
83 | @pyqtSlot('QgsMapLayer')
84 | def addLayer(self, layer):
85 | """Handle a layer being added to the registry so it shows up in canvas.
86 |
87 | :param layer: list list of map layers that were added
88 |
89 | .. note: The QgsInterface api does not include this method, it is added
90 | here as a helper to facilitate testing.
91 |
92 | .. note: The addLayer method was deprecated in QGIS 1.8 so you should
93 | not need this method much.
94 | """
95 | pass
96 |
97 | @pyqtSlot()
98 | def removeAllLayers(self):
99 | """Remove layers from the canvas before they get deleted."""
100 | self.canvas.setLayerSet([])
101 |
102 | def newProject(self):
103 | """Create new project."""
104 | # noinspection PyArgumentList
105 | QgsMapLayerRegistry.instance().removeAllMapLayers()
106 |
107 | # ---------------- API Mock for QgsInterface follows -------------------
108 |
109 | def zoomFull(self):
110 | """Zoom to the map full extent."""
111 | pass
112 |
113 | def zoomToPrevious(self):
114 | """Zoom to previous view extent."""
115 | pass
116 |
117 | def zoomToNext(self):
118 | """Zoom to next view extent."""
119 | pass
120 |
121 | def zoomToActiveLayer(self):
122 | """Zoom to extent of active layer."""
123 | pass
124 |
125 | def addVectorLayer(self, path, base_name, provider_key):
126 | """Add a vector layer.
127 |
128 | :param path: Path to layer.
129 | :type path: str
130 |
131 | :param base_name: Base name for layer.
132 | :type base_name: str
133 |
134 | :param provider_key: Provider key e.g. 'ogr'
135 | :type provider_key: str
136 | """
137 | pass
138 |
139 | def addRasterLayer(self, path, base_name):
140 | """Add a raster layer given a raster layer file name
141 |
142 | :param path: Path to layer.
143 | :type path: str
144 |
145 | :param base_name: Base name for layer.
146 | :type base_name: str
147 | """
148 | pass
149 |
150 | def activeLayer(self):
151 | """Get pointer to the active layer (layer selected in the legend)."""
152 | # noinspection PyArgumentList
153 | layers = QgsMapLayerRegistry.instance().mapLayers()
154 | for item in layers:
155 | return layers[item]
156 |
157 | def addToolBarIcon(self, action):
158 | """Add an icon to the plugins toolbar.
159 |
160 | :param action: Action to add to the toolbar.
161 | :type action: QAction
162 | """
163 | pass
164 |
165 | def removeToolBarIcon(self, action):
166 | """Remove an action (icon) from the plugin toolbar.
167 |
168 | :param action: Action to add to the toolbar.
169 | :type action: QAction
170 | """
171 | pass
172 |
173 | def addToolBar(self, name):
174 | """Add toolbar with specified name.
175 |
176 | :param name: Name for the toolbar.
177 | :type name: str
178 | """
179 | pass
180 |
181 | def mapCanvas(self):
182 | """Return a pointer to the map canvas."""
183 | return self.canvas
184 |
185 | def mainWindow(self):
186 | """Return a pointer to the main window.
187 |
188 | In case of QGIS it returns an instance of QgisApp.
189 | """
190 | pass
191 |
192 | def addDockWidget(self, area, dock_widget):
193 | """Add a dock widget to the main window.
194 |
195 | :param area: Where in the ui the dock should be placed.
196 | :type area:
197 |
198 | :param dock_widget: A dock widget to add to the UI.
199 | :type dock_widget: QDockWidget
200 | """
201 | pass
202 |
203 | def legendInterface(self):
204 | """Get the legend."""
205 | return self.canvas
206 |
--------------------------------------------------------------------------------
/processing_provider/rvt_multi_hillshade.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTMultiHillshade(QgsProcessingAlgorithm):
19 | """
20 | RVT Multiple directions hillshade.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | NUM_DIRECTIONS = 'NUM_DIRECTIONS'
26 | SUN_ELEVATION = 'SUN_ELEVATION'
27 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
28 | OUTPUT = 'OUTPUT'
29 |
30 | def tr(self, string):
31 | """
32 | Returns a translatable string with the self.tr() function.
33 | """
34 | return QCoreApplication.translate('Processing', string)
35 |
36 | def createInstance(self):
37 | return RVTMultiHillshade()
38 |
39 | def name(self):
40 | """
41 | Returns the algorithm name, used for identifying the algorithm. This
42 | string should be fixed for the algorithm, and must not be localised.
43 | The name should be unique within each provider. Names should contain
44 | lowercase alphanumeric characters only and no spaces or other
45 | formatting characters.
46 | """
47 | return 'rvt_multi_hillshade'
48 |
49 | def displayName(self):
50 | """
51 | Returns the translated algorithm name, which should be used for any
52 | user-visible display of the algorithm name.
53 | """
54 | return self.tr('RVT Multiple directions hillshade')
55 |
56 | def shortHelpString(self):
57 | """
58 | Returns a localised short helper string for the algorithm. This string
59 | should provide a basic description about what the algorithm does and the
60 | parameters and outputs associated with it..
61 | """
62 | return self.tr("Relief visualization toolbox, Multiple direction hillshade."
63 | " Calculates hillshade in multiple directions.")
64 |
65 | def initAlgorithm(self, config=None):
66 | """
67 | Here we define the inputs and output of the algorithm, along
68 | with some other properties.
69 | """
70 | self.addParameter(
71 | QgsProcessingParameterRasterLayer(
72 | self.INPUT,
73 | self.tr('Input DEM raster layer'),
74 | [QgsProcessing.TypeRaster]
75 | )
76 | )
77 | self.addParameter(
78 | QgsProcessingParameterNumber(
79 | name="VE_FACTOR",
80 | description="Vertical exaggeration factor",
81 | type=QgsProcessingParameterNumber.Double,
82 | defaultValue=1,
83 | minValue=-1000,
84 | maxValue=1000
85 | )
86 | )
87 | self.addParameter(
88 | QgsProcessingParameterNumber(
89 | name="NUM_DIRECTIONS",
90 | description="Number of solar azimuth angles (bands).",
91 | type=QgsProcessingParameterNumber.Integer,
92 | defaultValue=16,
93 | minValue=2,
94 | maxValue=64
95 | )
96 | )
97 | self.addParameter(
98 | QgsProcessingParameterNumber(
99 | name="SUN_ELEVATION",
100 | description="Solar vertical angle (above the horizon) in degrees.",
101 | type=QgsProcessingParameterNumber.Double,
102 | defaultValue=35,
103 | minValue=0,
104 | maxValue=90
105 | )
106 | )
107 | self.addParameter(
108 | QgsProcessingParameterBoolean(
109 | name="SAVE_AS_8BIT",
110 | description="Save as 8bit raster",
111 | defaultValue=False
112 | )
113 | )
114 | self.addParameter(
115 | QgsProcessingParameterRasterDestination(
116 | self.OUTPUT,
117 | self.tr('Output visualization raster layer')
118 | )
119 | )
120 |
121 | def processAlgorithm(self, parameters, context, feedback):
122 | """
123 | Here is where the processing itself takes place.
124 | """
125 | dem_layer = self.parameterAsRasterLayer(
126 | parameters,
127 | self.INPUT,
128 | context
129 | )
130 |
131 | ve_factor = float(self.parameterAsDouble(
132 | parameters,
133 | self.VE_FACTOR,
134 | context
135 | ))
136 | nr_dir = int(self.parameterAsInt(
137 | parameters,
138 | self.NUM_DIRECTIONS,
139 | context
140 | ))
141 | sun_elevation = float(self.parameterAsDouble(
142 | parameters,
143 | self.SUN_ELEVATION,
144 | context
145 | ))
146 | save_8bit = bool(self.parameterAsBool(
147 | parameters,
148 | self.SAVE_AS_8BIT,
149 | context
150 | ))
151 | visualization_path = (self.parameterAsOutputLayer(
152 | parameters,
153 | self.OUTPUT,
154 | context,
155 | ))
156 |
157 | dem_path = str(dem_layer.source())
158 |
159 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
160 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
161 | dem_arr = dict_arr_dem["array"]
162 | no_data = dict_arr_dem["no_data"]
163 |
164 | visualization_arr = rvt.vis.multi_hillshade(dem=dem_arr, resolution_x=resolution[0], resolution_y=resolution[1],
165 | nr_directions=nr_dir, sun_elevation=sun_elevation,
166 | ve_factor=ve_factor, no_data=no_data)
167 | if not save_8bit:
168 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
169 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
170 | else:
171 | default = rvt.default.DefaultValues() # we have to use this class to calculate 8bita
172 | visualization_8bit_arr = default.float_to_8bit(
173 | float_arr=dem_arr,
174 | visualization=RVTVisualization.MULTI_HILLSHADE,
175 | x_res=resolution[0],
176 | y_res=resolution[1],
177 | no_data=no_data
178 | )
179 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
180 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
181 |
182 | result = {self.OUTPUT: visualization_path}
183 | return result
184 |
--------------------------------------------------------------------------------
/processing_provider/rvt_msrm.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTMsrm(QgsProcessingAlgorithm):
19 | """
20 | RVT Multi-scale relief model.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | FEATURE_MIN = "FEATURE_MIN"
26 | FEATURE_MAX = "FEATURE_MAX"
27 | SCALING_FACTOR = "SCALING_FACTOR"
28 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
29 | OUTPUT = 'OUTPUT'
30 |
31 | def tr(self, string):
32 | """
33 | Returns a translatable string with the self.tr() function.
34 | """
35 | return QCoreApplication.translate('Processing', string)
36 |
37 | def createInstance(self):
38 | return RVTMsrm()
39 |
40 | def name(self):
41 | """
42 | Returns the algorithm name, used for identifying the algorithm. This
43 | string should be fixed for the algorithm, and must not be localised.
44 | The name should be unique within each provider. Names should contain
45 | lowercase alphanumeric characters only and no spaces or other
46 | formatting characters.
47 | """
48 | return 'rvt_msrm'
49 |
50 | def displayName(self):
51 | """
52 | Returns the translated algorithm name, which should be used for any
53 | user-visible display of the algorithm name.
54 | """
55 | return self.tr('RVT Multi-scale relief model')
56 |
57 | def shortHelpString(self):
58 | """
59 | Returns a localised short helper string for the algorithm. This string
60 | should provide a basic description about what the algorithm does and the
61 | parameters and outputs associated with it..
62 | """
63 | return self.tr("Relief visualization toolbox, Multi-scale relief model. Calculates Multi-scale relief model.")
64 |
65 | def initAlgorithm(self, config=None):
66 | """
67 | Here we define the inputs and output of the algorithm, along
68 | with some other properties.
69 | """
70 | self.addParameter(
71 | QgsProcessingParameterRasterLayer(
72 | self.INPUT,
73 | self.tr('Input DEM raster layer'),
74 | [QgsProcessing.TypeRaster]
75 | )
76 | )
77 | self.addParameter(
78 | QgsProcessingParameterNumber(
79 | name="VE_FACTOR",
80 | description="Vertical exaggeration factor",
81 | type=QgsProcessingParameterNumber.Double,
82 | defaultValue=1,
83 | minValue=-1000,
84 | maxValue=1000
85 | )
86 | )
87 | self.addParameter(
88 | QgsProcessingParameterNumber(
89 | name="FEATURE_MIN",
90 | description="Feature minimum",
91 | type=QgsProcessingParameterNumber.Double,
92 | defaultValue=1,
93 | minValue=0,
94 | maxValue=1000
95 | )
96 | )
97 | self.addParameter(
98 | QgsProcessingParameterNumber(
99 | name="FEATURE_MAX",
100 | description="Feature maximum",
101 | type=QgsProcessingParameterNumber.Double,
102 | defaultValue=5,
103 | minValue=0,
104 | maxValue=1000
105 | )
106 | )
107 | self.addParameter(
108 | QgsProcessingParameterNumber(
109 | name="SCALING_FACTOR",
110 | description="Scaling factor",
111 | type=QgsProcessingParameterNumber.Integer,
112 | defaultValue=3,
113 | minValue=1,
114 | maxValue=20
115 | )
116 | )
117 | self.addParameter(
118 | QgsProcessingParameterBoolean(
119 | name="SAVE_AS_8BIT",
120 | description="Save as 8bit raster",
121 | defaultValue=False
122 | )
123 | )
124 | self.addParameter(
125 | QgsProcessingParameterRasterDestination(
126 | self.OUTPUT,
127 | self.tr('Output visualization raster layer')
128 | )
129 | )
130 |
131 | def processAlgorithm(self, parameters, context, feedback):
132 | """
133 | Here is where the processing itself takes place.
134 | """
135 | dem_layer = self.parameterAsRasterLayer(
136 | parameters,
137 | self.INPUT,
138 | context
139 | )
140 | ve_factor = float(self.parameterAsDouble(
141 | parameters,
142 | self.VE_FACTOR,
143 | context
144 | ))
145 | feature_min = float(self.parameterAsDouble(
146 | parameters,
147 | self.FEATURE_MIN,
148 | context
149 | ))
150 | feature_max = float(self.parameterAsDouble(
151 | parameters,
152 | self.FEATURE_MAX,
153 | context
154 | ))
155 | scaling_factor = int(self.parameterAsDouble(
156 | parameters,
157 | self.SCALING_FACTOR,
158 | context
159 | ))
160 | save_8bit = bool(self.parameterAsBool(
161 | parameters,
162 | self.SAVE_AS_8BIT,
163 | context
164 | ))
165 | visualization_path = (self.parameterAsOutputLayer(
166 | parameters,
167 | self.OUTPUT,
168 | context,
169 | ))
170 |
171 | dem_path = str(dem_layer.source())
172 |
173 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
174 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
175 | dem_arr = dict_arr_dem["array"]
176 | no_data = dict_arr_dem["no_data"]
177 |
178 | visualization_arr = rvt.vis.msrm(dem=dem_arr, resolution=resolution[0], feature_min=feature_min,
179 | feature_max=feature_max, scaling_factor=scaling_factor,
180 | ve_factor=ve_factor, no_data=no_data)
181 | if not save_8bit:
182 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
183 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
184 | else:
185 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
186 | float_arr=visualization_arr, visualization=RVTVisualization.MULTI_SCALE_RELIEF_MODEL)
187 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
188 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
189 |
190 | result = {self.OUTPUT: visualization_path}
191 | return result
192 |
--------------------------------------------------------------------------------
/processing_provider/rvt_svf.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTSvf(QgsProcessingAlgorithm):
19 | """
20 | RVT Sky-view factor.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | RADIUS = "RADIUS"
26 | NUM_DIRECTIONS = "NUM_DIRECTIONS"
27 | NOISE_REMOVE = "NOISE_REMOVE"
28 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
29 | OUTPUT = 'OUTPUT'
30 |
31 | noise_options = ["no removal", "low", "medium", "high"]
32 |
33 | def tr(self, string):
34 | """
35 | Returns a translatable string with the self.tr() function.
36 | """
37 | return QCoreApplication.translate('Processing', string)
38 |
39 | def createInstance(self):
40 | return RVTSvf()
41 |
42 | def name(self):
43 | """
44 | Returns the algorithm name, used for identifying the algorithm. This
45 | string should be fixed for the algorithm, and must not be localised.
46 | The name should be unique within each provider. Names should contain
47 | lowercase alphanumeric characters only and no spaces or other
48 | formatting characters.
49 | """
50 | return 'rvt_svf'
51 |
52 | def displayName(self):
53 | """
54 | Returns the translated algorithm name, which should be used for any
55 | user-visible display of the algorithm name.
56 | """
57 | return self.tr('RVT Sky-view factor')
58 |
59 | def shortHelpString(self):
60 | """
61 | Returns a localised short helper string for the algorithm. This string
62 | should provide a basic description about what the algorithm does and the
63 | parameters and outputs associated with it..
64 | """
65 | return self.tr("Relief visualization toolbox, Sky-view factor. Calculates Sky-view factor.")
66 |
67 | def initAlgorithm(self, config=None):
68 | """
69 | Here we define the inputs and output of the algorithm, along
70 | with some other properties.
71 | """
72 | self.addParameter(
73 | QgsProcessingParameterRasterLayer(
74 | self.INPUT,
75 | self.tr('Input DEM raster layer'),
76 | [QgsProcessing.TypeRaster]
77 | )
78 | )
79 | self.addParameter(
80 | QgsProcessingParameterNumber(
81 | name="VE_FACTOR",
82 | description="Vertical exaggeration factor",
83 | type=QgsProcessingParameterNumber.Double,
84 | defaultValue=1,
85 | minValue=-1000,
86 | maxValue=1000
87 | )
88 | )
89 | self.addParameter(
90 | QgsProcessingParameterNumber(
91 | name="RADIUS",
92 | description="Search radius [pixels]",
93 | type=QgsProcessingParameterNumber.Integer,
94 | defaultValue=10,
95 | minValue=10,
96 | maxValue=50
97 | )
98 | )
99 | self.addParameter(
100 | QgsProcessingParameterNumber(
101 | name="NUM_DIRECTIONS",
102 | description="Number of search directions",
103 | type=QgsProcessingParameterNumber.Integer,
104 | defaultValue=16,
105 | minValue=8,
106 | maxValue=64
107 | )
108 | )
109 | self.addParameter(
110 | QgsProcessingParameterEnum(
111 | name="NOISE_REMOVE",
112 | description="Level of noise removal",
113 | options=self.noise_options,
114 | defaultValue="no removal"
115 | )
116 | )
117 | self.addParameter(
118 | QgsProcessingParameterBoolean(
119 | name="SAVE_AS_8BIT",
120 | description="Save as 8bit raster",
121 | defaultValue=False
122 | )
123 | )
124 | self.addParameter(
125 | QgsProcessingParameterRasterDestination(
126 | self.OUTPUT,
127 | self.tr('Output visualization raster layer')
128 | )
129 | )
130 |
131 | def processAlgorithm(self, parameters, context, feedback):
132 | """
133 | Here is where the processing itself takes place.
134 | """
135 | dem_layer = self.parameterAsRasterLayer(
136 | parameters,
137 | self.INPUT,
138 | context
139 | )
140 |
141 | ve_factor = float(self.parameterAsDouble(
142 | parameters,
143 | self.VE_FACTOR,
144 | context
145 | ))
146 | radius = int(self.parameterAsInt(
147 | parameters,
148 | self.RADIUS,
149 | context
150 | ))
151 | nr_dir = int(self.parameterAsInt(
152 | parameters,
153 | self.NUM_DIRECTIONS,
154 | context
155 | ))
156 | noise = int(self.parameterAsEnum(
157 | parameters,
158 | self.NOISE_REMOVE,
159 | context
160 | ))
161 | save_8bit = bool(self.parameterAsBool(
162 | parameters,
163 | self.SAVE_AS_8BIT,
164 | context
165 | ))
166 | visualization_path = (self.parameterAsOutputLayer(
167 | parameters,
168 | self.OUTPUT,
169 | context,
170 | ))
171 |
172 | dem_path = str(dem_layer.source())
173 |
174 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
175 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
176 | dem_arr = dict_arr_dem["array"]
177 | no_data = dict_arr_dem["no_data"]
178 |
179 | visualization_arr = rvt.vis.sky_view_factor(dem=dem_arr, resolution=resolution[0], compute_svf=True,
180 | compute_asvf=False, compute_opns=False, svf_n_dir=nr_dir,
181 | svf_r_max=radius, svf_noise=noise, ve_factor=ve_factor,
182 | no_data=no_data)["svf"]
183 | if not save_8bit:
184 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
185 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
186 | else:
187 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
188 | float_arr=visualization_arr, visualization=RVTVisualization.SKY_VIEW_FACTOR
189 | )
190 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
191 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
192 | result = {self.OUTPUT: visualization_path}
193 | return result
194 |
--------------------------------------------------------------------------------
/processing_provider/rvt_local_dom.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTLocalDom(QgsProcessingAlgorithm):
19 | """
20 | RVT Local dominance.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | MIN_RADIUS = "MIN_RADIUS"
26 | MAX_RADIUS = "MAX_RADIUS"
27 | ANGULAR_RES = "ANGULAR_RES"
28 | OBSERVER_H = "OBSERVER_H"
29 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
30 | OUTPUT = 'OUTPUT'
31 |
32 | def tr(self, string):
33 | """
34 | Returns a translatable string with the self.tr() function.
35 | """
36 | return QCoreApplication.translate('Processing', string)
37 |
38 | def createInstance(self):
39 | return RVTLocalDom()
40 |
41 | def name(self):
42 | """
43 | Returns the algorithm name, used for identifying the algorithm. This
44 | string should be fixed for the algorithm, and must not be localised.
45 | The name should be unique within each provider. Names should contain
46 | lowercase alphanumeric characters only and no spaces or other
47 | formatting characters.
48 | """
49 | return 'rvt_ld'
50 |
51 | def displayName(self):
52 | """
53 | Returns the translated algorithm name, which should be used for any
54 | user-visible display of the algorithm name.
55 | """
56 | return self.tr('RVT Local dominance')
57 |
58 | def shortHelpString(self):
59 | """
60 | Returns a localised short helper string for the algorithm. This string
61 | should provide a basic description about what the algorithm does and the
62 | parameters and outputs associated with it..
63 | """
64 | return self.tr("Relief visualization toolbox, Local dominance. Calculates Local dominance.")
65 |
66 | def initAlgorithm(self, config=None):
67 | """
68 | Here we define the inputs and output of the algorithm, along
69 | with some other properties.
70 | """
71 | self.addParameter(
72 | QgsProcessingParameterRasterLayer(
73 | self.INPUT,
74 | self.tr('Input DEM raster layer'),
75 | [QgsProcessing.TypeRaster]
76 | )
77 | )
78 | self.addParameter(
79 | QgsProcessingParameterNumber(
80 | name="VE_FACTOR",
81 | description="Vertical exaggeration factor",
82 | type=QgsProcessingParameterNumber.Double,
83 | defaultValue=1,
84 | minValue=-1000,
85 | maxValue=1000
86 | )
87 | )
88 | self.addParameter(
89 | QgsProcessingParameterNumber(
90 | name="MIN_RADIUS",
91 | description="Minimum radius [pixels]",
92 | type=QgsProcessingParameterNumber.Integer,
93 | defaultValue=10,
94 | minValue=0,
95 | maxValue=100
96 | )
97 | )
98 | self.addParameter(
99 | QgsProcessingParameterNumber(
100 | name="MAX_RADIUS",
101 | description="Maximum radius [pixels]",
102 | type=QgsProcessingParameterNumber.Integer,
103 | defaultValue=20,
104 | minValue=0,
105 | maxValue=100
106 | )
107 | )
108 | self.addParameter(
109 | QgsProcessingParameterNumber(
110 | name="ANGULAR_RES",
111 | description="Number of angular directions",
112 | type=QgsProcessingParameterNumber.Integer,
113 | defaultValue=15,
114 | minValue=4,
115 | maxValue=32
116 | )
117 | )
118 | self.addParameter(
119 | QgsProcessingParameterNumber(
120 | name="OBSERVER_H",
121 | description="Height at which we observe the terrain",
122 | type=QgsProcessingParameterNumber.Double,
123 | defaultValue=1.7,
124 | minValue=0.5,
125 | maxValue=20
126 | )
127 | )
128 | self.addParameter(
129 | QgsProcessingParameterBoolean(
130 | name="SAVE_AS_8BIT",
131 | description="Save as 8bit raster",
132 | defaultValue=False
133 | )
134 | )
135 | self.addParameter(
136 | QgsProcessingParameterRasterDestination(
137 | self.OUTPUT,
138 | self.tr('Output visualization raster layer')
139 | )
140 | )
141 |
142 | def processAlgorithm(self, parameters, context, feedback):
143 | """
144 | Here is where the processing itself takes place.
145 | """
146 | dem_layer = self.parameterAsRasterLayer(
147 | parameters,
148 | self.INPUT,
149 | context
150 | )
151 |
152 | ve_factor = float(self.parameterAsDouble(
153 | parameters,
154 | self.VE_FACTOR,
155 | context
156 | ))
157 | min_rad = int(self.parameterAsInt(
158 | parameters,
159 | self.MIN_RADIUS,
160 | context
161 | ))
162 | max_rad = int(self.parameterAsInt(
163 | parameters,
164 | self.MAX_RADIUS,
165 | context
166 | ))
167 | angular_res = int(self.parameterAsInt(
168 | parameters,
169 | self.ANGULAR_RES,
170 | context
171 | ))
172 | observer_h = float(self.parameterAsDouble(
173 | parameters,
174 | self.OBSERVER_H,
175 | context
176 | ))
177 | save_8bit = bool(self.parameterAsBool(
178 | parameters,
179 | self.SAVE_AS_8BIT,
180 | context
181 | ))
182 | visualization_path = (self.parameterAsOutputLayer(
183 | parameters,
184 | self.OUTPUT,
185 | context,
186 | ))
187 |
188 | dem_path = str(dem_layer.source())
189 |
190 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
191 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
192 | dem_arr = dict_arr_dem["array"]
193 | no_data = dict_arr_dem["no_data"]
194 |
195 | visualization_arr = rvt.vis.local_dominance(dem=dem_arr, min_rad=min_rad, max_rad=max_rad,
196 | angular_res=angular_res, observer_height=observer_h,
197 | ve_factor=ve_factor, no_data=no_data)
198 | if not save_8bit:
199 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
200 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
201 | else:
202 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
203 | float_arr=visualization_arr, visualization=RVTVisualization.LOCAL_DOMINANCE
204 | )
205 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
206 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
207 |
208 | result = {self.OUTPUT: visualization_path}
209 | return result
210 |
--------------------------------------------------------------------------------
/processing_provider/rvt_opns.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTOpns(QgsProcessingAlgorithm):
19 | """
20 | RVT Sky-view factor.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | RADIUS = "RADIUS"
26 | NUM_DIRECTIONS = "NUM_DIRECTIONS"
27 | NOISE_REMOVE = "NOISE_REMOVE"
28 | OPNS_TYPE = "OPNS_TYPE"
29 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
30 | OUTPUT = 'OUTPUT'
31 |
32 | noise_options = ["no removal", "low", "medium", "high"]
33 | opns_options = ["Positive", "Negative"]
34 |
35 | def tr(self, string):
36 | """
37 | Returns a translatable string with the self.tr() function.
38 | """
39 | return QCoreApplication.translate('Processing', string)
40 |
41 | def createInstance(self):
42 | return RVTOpns()
43 |
44 | def name(self):
45 | """
46 | Returns the algorithm name, used for identifying the algorithm. This
47 | string should be fixed for the algorithm, and must not be localised.
48 | The name should be unique within each provider. Names should contain
49 | lowercase alphanumeric characters only and no spaces or other
50 | formatting characters.
51 | """
52 | return 'rvt_opns'
53 |
54 | def displayName(self):
55 | """
56 | Returns the translated algorithm name, which should be used for any
57 | user-visible display of the algorithm name.
58 | """
59 | return self.tr('RVT Openness')
60 |
61 | def shortHelpString(self):
62 | """
63 | Returns a localised short helper string for the algorithm. This string
64 | should provide a basic description about what the algorithm does and the
65 | parameters and outputs associated with it..
66 | """
67 | return self.tr("Relief visualization toolbox, Openness. Calculates Positive or Negative Openness.")
68 |
69 | def initAlgorithm(self, config=None):
70 | """
71 | Here we define the inputs and output of the algorithm, along
72 | with some other properties.
73 | """
74 | self.addParameter(
75 | QgsProcessingParameterRasterLayer(
76 | self.INPUT,
77 | self.tr('Input DEM raster layer'),
78 | [QgsProcessing.TypeRaster]
79 | )
80 | )
81 | self.addParameter(
82 | QgsProcessingParameterNumber(
83 | name="VE_FACTOR",
84 | description="Vertical exaggeration factor",
85 | type=QgsProcessingParameterNumber.Double,
86 | defaultValue=1,
87 | minValue=-1000,
88 | maxValue=1000
89 | )
90 | )
91 | self.addParameter(
92 | QgsProcessingParameterNumber(
93 | name="RADIUS",
94 | description="Search radius [pixels]",
95 | type=QgsProcessingParameterNumber.Integer,
96 | defaultValue=10,
97 | minValue=10,
98 | maxValue=50
99 | )
100 | )
101 | self.addParameter(
102 | QgsProcessingParameterNumber(
103 | name="NUM_DIRECTIONS",
104 | description="Number of search directions",
105 | type=QgsProcessingParameterNumber.Integer,
106 | defaultValue=16,
107 | minValue=8,
108 | maxValue=64
109 | )
110 | )
111 | self.addParameter(
112 | QgsProcessingParameterEnum(
113 | name="NOISE_REMOVE",
114 | description="Level of noise removal",
115 | options=self.noise_options,
116 | defaultValue="no removal"
117 | )
118 | )
119 | self.addParameter(
120 | QgsProcessingParameterEnum(
121 | name="OPNS_TYPE",
122 | description="Which Openness: Positive or Negative",
123 | options=self.opns_options,
124 | defaultValue="Positive"
125 | )
126 | )
127 | self.addParameter(
128 | QgsProcessingParameterBoolean(
129 | name="SAVE_AS_8BIT",
130 | description="Save as 8bit raster",
131 | defaultValue=False
132 | )
133 | )
134 | self.addParameter(
135 | QgsProcessingParameterRasterDestination(
136 | self.OUTPUT,
137 | self.tr('Output visualization raster layer')
138 | )
139 | )
140 |
141 | def processAlgorithm(self, parameters, context, feedback):
142 | """
143 | Here is where the processing itself takes place.
144 | """
145 | dem_layer = self.parameterAsRasterLayer(
146 | parameters,
147 | self.INPUT,
148 | context
149 | )
150 |
151 | ve_factor = float(self.parameterAsDouble(
152 | parameters,
153 | self.VE_FACTOR,
154 | context
155 | ))
156 | radius = int(self.parameterAsInt(
157 | parameters,
158 | self.RADIUS,
159 | context
160 | ))
161 | nr_dir = int(self.parameterAsInt(
162 | parameters,
163 | self.NUM_DIRECTIONS,
164 | context
165 | ))
166 | noise = int(self.parameterAsEnum(
167 | parameters,
168 | self.NOISE_REMOVE,
169 | context
170 | ))
171 | opns_type = int(self.parameterAsEnum(
172 | parameters,
173 | self.OPNS_TYPE,
174 | context
175 | ))
176 | save_8bit = bool(self.parameterAsBool(
177 | parameters,
178 | self.SAVE_AS_8BIT,
179 | context
180 | ))
181 | visualization_path = (self.parameterAsOutputLayer(
182 | parameters,
183 | self.OUTPUT,
184 | context,
185 | ))
186 |
187 | dem_path = str(dem_layer.source())
188 |
189 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
190 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
191 | dem_arr = dict_arr_dem["array"]
192 | no_data = dict_arr_dem["no_data"]
193 |
194 | vis = RVTVisualization.POSITIVE_OPENNESS
195 | if opns_type == 1:
196 | vis = RVTVisualization.NEGATIVE_OPENNESS
197 | dem_arr = dem_arr * -1 # negative openness is openness where dem * -1
198 | visualization_arr = rvt.vis.sky_view_factor(dem=dem_arr, resolution=resolution[0], compute_svf=False,
199 | compute_asvf=False, compute_opns=True, svf_n_dir=nr_dir,
200 | svf_r_max=radius, svf_noise=noise, ve_factor=ve_factor,
201 | no_data=no_data)["opns"]
202 | if not save_8bit:
203 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
204 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
205 | else:
206 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(float_arr=visualization_arr,
207 | visualization=vis)
208 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
209 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
210 |
211 | result = {self.OUTPUT: visualization_path}
212 | return result
213 |
--------------------------------------------------------------------------------
/processing_provider/rvt_asvf.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTASvf(QgsProcessingAlgorithm):
19 | """
20 | RVT Anisotropic Sky-view factor.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | RADIUS = "RADIUS"
26 | NUM_DIRECTIONS = "NUM_DIRECTIONS"
27 | NOISE_REMOVE = "NOISE_REMOVE"
28 | ANISOTROPY_LVL = "ANISOTROPY_LVL"
29 | ANISOTROPY_DIR = "ANISOTROPY_DIR"
30 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
31 | OUTPUT = 'OUTPUT'
32 |
33 | noise_options = ["no removal", "low", "medium", "high"]
34 | ani_lvl_options = ["low", "high"]
35 |
36 | def tr(self, string):
37 | """
38 | Returns a translatable string with the self.tr() function.
39 | """
40 | return QCoreApplication.translate('Processing', string)
41 |
42 | def createInstance(self):
43 | return RVTASvf()
44 |
45 | def name(self):
46 | """
47 | Returns the algorithm name, used for identifying the algorithm. This
48 | string should be fixed for the algorithm, and must not be localised.
49 | The name should be unique within each provider. Names should contain
50 | lowercase alphanumeric characters only and no spaces or other
51 | formatting characters.
52 | """
53 | return 'rvt_asvf'
54 |
55 | def displayName(self):
56 | """
57 | Returns the translated algorithm name, which should be used for any
58 | user-visible display of the algorithm name.
59 | """
60 | return self.tr('RVT Anisotropic Sky-view factor')
61 |
62 | def shortHelpString(self):
63 | """
64 | Returns a localised short helper string for the algorithm. This string
65 | should provide a basic description about what the algorithm does and the
66 | parameters and outputs associated with it..
67 | """
68 | return self.tr("Relief visualization toolbox, Anisotropic Sky-view factor. Calculates "
69 | "Anisotropic Sky-view factor.")
70 |
71 | def initAlgorithm(self, config=None):
72 | """
73 | Here we define the inputs and output of the algorithm, along
74 | with some other properties.
75 | """
76 | self.addParameter(
77 | QgsProcessingParameterRasterLayer(
78 | self.INPUT,
79 | self.tr('Input DEM raster layer'),
80 | [QgsProcessing.TypeRaster]
81 | )
82 | )
83 | self.addParameter(
84 | QgsProcessingParameterNumber(
85 | name="VE_FACTOR",
86 | description="Vertical exaggeration factor",
87 | type=QgsProcessingParameterNumber.Double,
88 | defaultValue=1,
89 | minValue=-1000,
90 | maxValue=1000
91 | )
92 | )
93 | self.addParameter(
94 | QgsProcessingParameterNumber(
95 | name="RADIUS",
96 | description="Search radius [pixels]",
97 | type=QgsProcessingParameterNumber.Integer,
98 | defaultValue=10,
99 | minValue=10,
100 | maxValue=50
101 | )
102 | )
103 | self.addParameter(
104 | QgsProcessingParameterNumber(
105 | name="NUM_DIRECTIONS",
106 | description="Number of search directions",
107 | type=QgsProcessingParameterNumber.Integer,
108 | defaultValue=16,
109 | minValue=8,
110 | maxValue=64
111 | )
112 | )
113 | self.addParameter(
114 | QgsProcessingParameterEnum(
115 | name="NOISE_REMOVE",
116 | description="Level of noise removal",
117 | options=self.noise_options,
118 | defaultValue="no removal"
119 | )
120 | )
121 | self.addParameter(
122 | QgsProcessingParameterEnum(
123 | name="ANISOTROPY_LVL",
124 | description="Level of anisotropy",
125 | options=self.ani_lvl_options,
126 | defaultValue="low"
127 | )
128 | )
129 | self.addParameter(
130 | QgsProcessingParameterNumber(
131 | name="ANISOTROPY_DIR",
132 | description="Main direction of anisotropy [deg]",
133 | type=QgsProcessingParameterNumber.Double,
134 | defaultValue=315,
135 | minValue=0,
136 | maxValue=360
137 | )
138 | )
139 | self.addParameter(
140 | QgsProcessingParameterBoolean(
141 | name="SAVE_AS_8BIT",
142 | description="Save as 8bit raster",
143 | defaultValue=False
144 | )
145 | )
146 | self.addParameter(
147 | QgsProcessingParameterRasterDestination(
148 | self.OUTPUT,
149 | self.tr('Output visualization raster layer')
150 | )
151 | )
152 |
153 | def processAlgorithm(self, parameters, context, feedback):
154 | """
155 | Here is where the processing itself takes place.
156 | """
157 | dem_layer = self.parameterAsRasterLayer(
158 | parameters,
159 | self.INPUT,
160 | context
161 | )
162 |
163 | ve_factor = float(self.parameterAsDouble(
164 | parameters,
165 | self.VE_FACTOR,
166 | context
167 | ))
168 | radius = int(self.parameterAsInt(
169 | parameters,
170 | self.RADIUS,
171 | context
172 | ))
173 | nr_dir = int(self.parameterAsInt(
174 | parameters,
175 | self.NUM_DIRECTIONS,
176 | context
177 | ))
178 | noise = int(self.parameterAsEnum(
179 | parameters,
180 | self.NOISE_REMOVE,
181 | context
182 | ))
183 | asvf_lvl = int(self.parameterAsEnum(
184 | parameters,
185 | self.ANISOTROPY_LVL,
186 | context
187 | ))
188 | asvf_lvl += 1
189 | asvf_dir = float(self.parameterAsDouble(
190 | parameters,
191 | self.ANISOTROPY_DIR,
192 | context
193 | ))
194 | save_8bit = bool(self.parameterAsBool(
195 | parameters,
196 | self.SAVE_AS_8BIT,
197 | context
198 | ))
199 | visualization_path = (self.parameterAsOutputLayer(
200 | parameters,
201 | self.OUTPUT,
202 | context,
203 | ))
204 |
205 | dem_path = str(dem_layer.source())
206 |
207 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
208 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
209 | dem_arr = dict_arr_dem["array"]
210 | no_data = dict_arr_dem["no_data"]
211 |
212 | visualization_arr = rvt.vis.sky_view_factor(dem=dem_arr, resolution=resolution[0], compute_svf=False,
213 | compute_asvf=True, compute_opns=False, svf_n_dir=nr_dir,
214 | svf_r_max=radius, svf_noise=noise, ve_factor=ve_factor,
215 | asvf_level=asvf_lvl, asvf_dir=asvf_dir, no_data=no_data)["asvf"]
216 | if not save_8bit:
217 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
218 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
219 | else:
220 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
221 | float_arr=visualization_arr, visualization=RVTVisualization.ANISOTROPIC_SKY_VIEW_FACTOR
222 | )
223 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
224 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
225 |
226 | result = {self.OUTPUT: visualization_path}
227 | return result
228 |
--------------------------------------------------------------------------------
/processing_provider/rvt_sky_illum.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTSim(QgsProcessingAlgorithm):
19 | """
20 | RVT Sky illumination.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | SKY_MODEL = "SKY_MODEL"
26 | NUM_DIRECTIONS = "NUM_DIRECTIONS"
27 | SHADOW_DIST = "SHADOW_DIST"
28 | SHADOW_AZIMUTH = "SHADOW_AZIMUTH"
29 | SHADOW_ELEVATION = "SHADOW_ELEVATION"
30 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
31 | OUTPUT = 'OUTPUT'
32 |
33 | sky_model_options = ["overcast", "uniform"]
34 |
35 | def tr(self, string):
36 | """
37 | Returns a translatable string with the self.tr() function.
38 | """
39 | return QCoreApplication.translate('Processing', string)
40 |
41 | def createInstance(self):
42 | return RVTSim()
43 |
44 | def name(self):
45 | """
46 | Returns the algorithm name, used for identifying the algorithm. This
47 | string should be fixed for the algorithm, and must not be localised.
48 | The name should be unique within each provider. Names should contain
49 | lowercase alphanumeric characters only and no spaces or other
50 | formatting characters.
51 | """
52 | return 'rvt_sim'
53 |
54 | def displayName(self):
55 | """
56 | Returns the translated algorithm name, which should be used for any
57 | user-visible display of the algorithm name.
58 | """
59 | return self.tr('RVT Sky illumination')
60 |
61 | def shortHelpString(self):
62 | """
63 | Returns a localised short helper string for the algorithm. This string
64 | should provide a basic description about what the algorithm does and the
65 | parameters and outputs associated with it..
66 | """
67 | return self.tr("Relief visualization toolbox, Sky illumination. Calculates Sky illumination.")
68 |
69 | def initAlgorithm(self, config=None):
70 | """
71 | Here we define the inputs and output of the algorithm, along
72 | with some other properties.
73 | """
74 | self.addParameter(
75 | QgsProcessingParameterRasterLayer(
76 | self.INPUT,
77 | self.tr('Input DEM raster layer'),
78 | [QgsProcessing.TypeRaster]
79 | )
80 | )
81 | self.addParameter(
82 | QgsProcessingParameterNumber(
83 | name="VE_FACTOR",
84 | description="Vertical exaggeration factor",
85 | type=QgsProcessingParameterNumber.Double,
86 | defaultValue=1,
87 | minValue=-1000,
88 | maxValue=1000
89 | )
90 | )
91 | self.addParameter(
92 | QgsProcessingParameterEnum(
93 | name="SKY_MODEL",
94 | description="Sky model",
95 | options=self.sky_model_options,
96 | defaultValue="overcast"
97 | )
98 | )
99 | self.addParameter(
100 | QgsProcessingParameterNumber(
101 | name="NUM_DIRECTIONS",
102 | description="Number of horizon search directions",
103 | type=QgsProcessingParameterNumber.Integer,
104 | defaultValue=32,
105 | minValue=8,
106 | maxValue=128
107 | )
108 | )
109 | self.addParameter(
110 | QgsProcessingParameterNumber(
111 | name="SHADOW_DIST",
112 | description="Max shadow modeling distance",
113 | type=QgsProcessingParameterNumber.Integer,
114 | defaultValue=100,
115 | minValue=10,
116 | maxValue=1000
117 | )
118 | )
119 | self.addParameter(
120 | QgsProcessingParameterNumber(
121 | name="SHADOW_AZIMUTH",
122 | description="Shadow azimuth",
123 | type=QgsProcessingParameterNumber.Double,
124 | defaultValue=315,
125 | minValue=0,
126 | maxValue=360
127 | )
128 | )
129 | self.addParameter(
130 | QgsProcessingParameterNumber(
131 | name="SHADOW_ELEVATION",
132 | description="Shadow elevation",
133 | type=QgsProcessingParameterNumber.Double,
134 | defaultValue=35,
135 | minValue=0,
136 | maxValue=90
137 | )
138 | )
139 | self.addParameter(
140 | QgsProcessingParameterBoolean(
141 | name="SAVE_AS_8BIT",
142 | description="Save as 8bit raster",
143 | defaultValue=False
144 | )
145 | )
146 | self.addParameter(
147 | QgsProcessingParameterRasterDestination(
148 | self.OUTPUT,
149 | self.tr('Output visualization raster layer')
150 | )
151 | )
152 |
153 | def processAlgorithm(self, parameters, context, feedback):
154 | """
155 | Here is where the processing itself takes place.
156 | """
157 | dem_layer = self.parameterAsRasterLayer(
158 | parameters,
159 | self.INPUT,
160 | context
161 | )
162 |
163 | ve_factor = float(self.parameterAsDouble(
164 | parameters,
165 | self.VE_FACTOR,
166 | context
167 | ))
168 | sky_model_enum = int(self.parameterAsEnum(
169 | parameters,
170 | self.SKY_MODEL,
171 | context
172 | ))
173 | sky_model = self.sky_model_options[sky_model_enum]
174 | nr_dir = int(self.parameterAsInt(
175 | parameters,
176 | self.NUM_DIRECTIONS,
177 | context
178 | ))
179 | max_fine_rad = float(self.parameterAsInt(
180 | parameters,
181 | self.SHADOW_DIST,
182 | context
183 | ))
184 | shadow_az = float(self.parameterAsDouble(
185 | parameters,
186 | self.SHADOW_AZIMUTH,
187 | context
188 | ))
189 | shadow_el = float(self.parameterAsDouble(
190 | parameters,
191 | self.SHADOW_ELEVATION,
192 | context
193 | ))
194 | save_8bit = bool(self.parameterAsBool(
195 | parameters,
196 | self.SAVE_AS_8BIT,
197 | context
198 | ))
199 | visualization_path = (self.parameterAsOutputLayer(
200 | parameters,
201 | self.OUTPUT,
202 | context,
203 | ))
204 |
205 | dem_path = str(dem_layer.source())
206 |
207 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
208 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
209 | dem_arr = dict_arr_dem["array"]
210 | no_data = dict_arr_dem["no_data"]
211 |
212 | visualization_arr = rvt.vis.sky_illumination(dem=dem_arr, resolution=resolution[0], sky_model=sky_model,
213 | max_fine_radius=max_fine_rad, num_directions=nr_dir,
214 | ve_factor=ve_factor,
215 | compute_shadow=True, shadow_az=shadow_az, shadow_el=shadow_el,
216 | no_data=no_data)
217 | if not save_8bit:
218 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
219 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
220 | else:
221 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
222 | float_arr=visualization_arr, visualization=RVTVisualization.SKY_ILLUMINATION
223 | )
224 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
225 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
226 |
227 | result = {self.OUTPUT: visualization_path}
228 | return result
229 |
--------------------------------------------------------------------------------
/processing_provider/rvt_fill_no_data.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (
3 | QgsProcessing,
4 | QgsProcessingAlgorithm,
5 | QgsProcessingParameterRasterLayer,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterDestination,
8 | QgsProcessingParameterEnum
9 | )
10 | from qgis import processing
11 | import numpy as np
12 | import rvt.default
13 | import rvt.blend
14 | import rvt.vis
15 | import os
16 |
17 |
18 | class RVTFillNoData(QgsProcessingAlgorithm):
19 | """
20 | RVT Fill no data.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | METHOD = 'METHOD'
25 | OUTPUT = 'OUTPUT'
26 |
27 | method_options = ["kd_tree", "nearest_neighbour"]
28 |
29 | def tr(self, string):
30 | """
31 | Returns a translatable string with the self.tr() function.
32 | """
33 | return QCoreApplication.translate('Processing', string)
34 |
35 | def createInstance(self):
36 | return RVTFillNoData()
37 |
38 | def name(self):
39 | """
40 | Returns the algorithm name, used for identifying the algorithm. This
41 | string should be fixed for the algorithm, and must not be localised.
42 | The name should be unique within each provider. Names should contain
43 | lowercase alphanumeric characters only and no spaces or other
44 | formatting characters.
45 | """
46 | return 'rvt_fill_no_data'
47 |
48 | def displayName(self):
49 | """
50 | Returns the translated algorithm name, which should be used for any
51 | user-visible display of the algorithm name.
52 | """
53 | return self.tr('RVT Fill no-data')
54 |
55 | def shortHelpString(self):
56 | """
57 | Returns a localised short helper string for the algorithm. This string
58 | should provide a basic description about what the algorithm does and the
59 | parameters and outputs associated with it..
60 | """
61 | return self.tr("Relief visualization toolbox, Function to fill no data. Note: DEM has to have defined no-data!")
62 |
63 | def initAlgorithm(self, config=None):
64 | """
65 | Here we define the inputs and output of the algorithm, along
66 | with some other properties.
67 | """
68 | self.addParameter(
69 | QgsProcessingParameterRasterLayer(
70 | self.INPUT,
71 | self.tr('Input DEM raster layer'),
72 | [QgsProcessing.TypeRaster]
73 | )
74 | )
75 | self.addParameter(
76 | QgsProcessingParameterEnum(
77 | name="METHOD",
78 | description="Interpolation method",
79 | options=self.method_options,
80 | defaultValue="nearest_neighbour"
81 | )
82 | )
83 | self.addParameter(
84 | QgsProcessingParameterRasterDestination(
85 | self.OUTPUT,
86 | self.tr('Output visualization raster layer')
87 | )
88 | )
89 |
90 | def processAlgorithm(self, parameters, context, feedback):
91 | """
92 | Here is where the processing itself takes place.
93 | """
94 | dem_layer = self.parameterAsRasterLayer(
95 | parameters,
96 | self.INPUT,
97 | context
98 | )
99 | method_enum = int(self.parameterAsEnum(
100 | parameters,
101 | self.METHOD,
102 | context
103 | ))
104 | method = self.method_options[method_enum]
105 | dem_out_path = (self.parameterAsOutputLayer(
106 | parameters,
107 | self.OUTPUT,
108 | context,
109 | ))
110 |
111 | dem_path = str(dem_layer.source())
112 |
113 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
114 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
115 | dem_arr = dict_arr_dem["array"]
116 | no_data = dict_arr_dem["no_data"]
117 |
118 | dem_arr[dem_arr == no_data] = np.nan
119 |
120 | dem_out = rvt.vis.fill_where_nan(dem=dem_arr, method=method)
121 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=dem_out_path,
122 | out_raster_arr=dem_out, e_type=6, no_data=np.nan)
123 |
124 | result = {self.OUTPUT: dem_out_path}
125 | return result
126 |
127 |
128 | class RVTFillNoDataIDW(QgsProcessingAlgorithm):
129 | """
130 | RVT Fill no data Inverse Distance Weighting interpolation.
131 | """
132 | # processing function parameters
133 | INPUT = 'INPUT'
134 | RADIUS = 'RADIUS'
135 | POWER = 'POWER'
136 | OUTPUT = 'OUTPUT'
137 |
138 | def tr(self, string):
139 | """
140 | Returns a translatable string with the self.tr() function.
141 | """
142 | return QCoreApplication.translate('Processing', string)
143 |
144 | def createInstance(self):
145 | return RVTFillNoDataIDW()
146 |
147 | def name(self):
148 | """
149 | Returns the algorithm name, used for identifying the algorithm. This
150 | string should be fixed for the algorithm, and must not be localised.
151 | The name should be unique within each provider. Names should contain
152 | lowercase alphanumeric characters only and no spaces or other
153 | formatting characters.
154 | """
155 | return 'rvt_fill_no_data_idw'
156 |
157 | def displayName(self):
158 | """
159 | Returns the translated algorithm name, which should be used for any
160 | user-visible display of the algorithm name.
161 | """
162 | return self.tr('RVT Fill no-data IDW')
163 |
164 | def shortHelpString(self):
165 | """
166 | Returns a localised short helper string for the algorithm. This string
167 | should provide a basic description about what the algorithm does and the
168 | parameters and outputs associated with it..
169 | """
170 | return self.tr("Relief visualization toolbox, Function to fill no data. Note: DEM has to have defined no-data!")
171 |
172 | def initAlgorithm(self, config=None):
173 | """
174 | Here we define the inputs and output of the algorithm, along
175 | with some other properties.
176 | """
177 | self.addParameter(
178 | QgsProcessingParameterRasterLayer(
179 | self.INPUT,
180 | self.tr('Input DEM raster layer'),
181 | [QgsProcessing.TypeRaster]
182 | )
183 | )
184 | self.addParameter(
185 | QgsProcessingParameterNumber(
186 | name="RADIUS",
187 | description="Search radius [pixels]",
188 | type=QgsProcessingParameterNumber.Integer,
189 | defaultValue=20,
190 | minValue=1,
191 | maxValue=200
192 | )
193 | )
194 | self.addParameter(
195 | QgsProcessingParameterNumber(
196 | name="POWER",
197 | description="Power",
198 | type=QgsProcessingParameterNumber.Double,
199 | defaultValue=2,
200 | minValue=0.2,
201 | maxValue=10
202 | )
203 | )
204 | self.addParameter(
205 | QgsProcessingParameterRasterDestination(
206 | self.OUTPUT,
207 | self.tr('Output visualization raster layer')
208 | )
209 | )
210 |
211 | def processAlgorithm(self, parameters, context, feedback):
212 | """
213 | Here is where the processing itself takes place.
214 | """
215 | dem_layer = self.parameterAsRasterLayer(
216 | parameters,
217 | self.INPUT,
218 | context
219 | )
220 | radius = int(self.parameterAsInt(
221 | parameters,
222 | self.RADIUS,
223 | context
224 | ))
225 | power = float(self.parameterAsDouble(
226 | parameters,
227 | self.POWER,
228 | context
229 | ))
230 | dem_out_path = (self.parameterAsOutputLayer(
231 | parameters,
232 | self.OUTPUT,
233 | context,
234 | ))
235 |
236 | dem_path = str(dem_layer.source())
237 |
238 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
239 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
240 | dem_arr = dict_arr_dem["array"]
241 | no_data = dict_arr_dem["no_data"]
242 |
243 | dem_arr[dem_arr == no_data] = np.nan
244 |
245 | dem_out = rvt.vis.fill_where_nan(dem=dem_arr, method=f"idw_{radius}_{power}")
246 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=dem_out_path,
247 | out_raster_arr=dem_out, e_type=6, no_data=np.nan)
248 |
249 | result = {self.OUTPUT: dem_out_path}
250 | return result
251 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #/***************************************************************************
2 | # QRVT
3 | #
4 | # RVT plugin lets you compute different visualizations from raster DEM.
5 | # -------------------
6 | # begin : 2020-10-12
7 | # git sha : $Format:%H$
8 | # copyright : © Copyright 2020 ZRC SAZU and University of Ljubljana
9 | # email : ziga.kokalj@zrc-sazu.si
10 | # ***************************************************************************/
11 | #
12 | #/***************************************************************************
13 | # * *
14 | # * This program is free software; you can redistribute it and/or modify *
15 | # * it under the terms of the GNU General Public License as published by *
16 | # * the Free Software Foundation; either version 2 of the License, or *
17 | # * (at your option) any later version. *
18 | # * *
19 | # ***************************************************************************/
20 |
21 | #################################################
22 | # Edit the following to match your sources lists
23 | #################################################
24 |
25 |
26 | #Add iso code for any locales you want to support here (space separated)
27 | # default is no locales
28 | # LOCALES = af
29 | LOCALES =
30 |
31 | # If locales are enabled, set the name of the lrelease binary on your system. If
32 | # you have trouble compiling the translations, you may have to specify the full path to
33 | # lrelease
34 | #LRELEASE = lrelease
35 | #LRELEASE = lrelease-qt4
36 |
37 |
38 | # translation
39 | SOURCES = \
40 | __init__.py \
41 | qrvt.py qrvt_dialog.py
42 |
43 | PLUGINNAME = rvt-qgis
44 |
45 | PY_FILES = \
46 | __init__.py \
47 | qrvt.py qrvt_dialog.py \
48 | rvt\__init__.py \
49 | rvt\default.py rvt\blend.py \
50 | processing_provider\provider.py
51 |
52 |
53 | UI_FILES = qrvt_dialog_base.ui qrvt_dialog_about.ui
54 |
55 | EXTRAS = metadata.txt icon.png loading.gif Makefile
56 |
57 | EXTRA_DIRS = rvt processing_provider settings i18n
58 |
59 | COMPILED_RESOURCE_FILES = resources.py
60 |
61 | PEP8EXCLUDE=pydev,resources.py,conf.py,third_party,ui
62 |
63 | # QGISDIR points to the location where your plugin should be installed.
64 | # This varies by platform, relative to your HOME directory:
65 | # * Linux:
66 | # .local/share/QGIS/QGIS3/profiles/default/python/plugins/
67 | # * Mac OS X:
68 | # Library/Application Support/QGIS/QGIS3/profiles/default/python/plugins
69 | # * Windows:
70 | # AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins'
71 |
72 | QGISDIR=C:\Users\Uporabnik\AppData/Roaming/QGIS/QGIS3/profiles/default/python/plugins
73 |
74 | #################################################
75 | # Normally you would not need to edit below here
76 | #################################################
77 |
78 | HELP = help/build/html
79 |
80 | PLUGIN_UPLOAD = $(c)/plugin_upload.py
81 |
82 | RESOURCE_SRC=$(shell grep '^ *@@g;s/.*>//g' | tr '\n' ' ')
83 |
84 | .PHONY: default
85 | default:
86 | @echo While you can use make to build and deploy your plugin, pb_tool
87 | @echo is a much better solution.
88 | @echo A Python script, pb_tool provides platform independent management of
89 | @echo your plugins and runs anywhere.
90 | @echo You can install pb_tool using: pip install pb_tool
91 | @echo See https://g-sherman.github.io/plugin_build_tool/ for info.
92 |
93 | compile: $(COMPILED_RESOURCE_FILES)
94 |
95 | %.py : %.qrc $(RESOURCES_SRC)
96 | pyrcc5 -o $*.py $<
97 |
98 | %.qm : %.ts
99 | $(LRELEASE) $<
100 |
101 | test: compile transcompile
102 | @echo
103 | @echo "----------------------"
104 | @echo "Regression Test Suite"
105 | @echo "----------------------"
106 |
107 | @# Preceding dash means that make will continue in case of errors
108 | @-export PYTHONPATH=`pwd`:$(PYTHONPATH); \
109 | export QGIS_DEBUG=0; \
110 | export QGIS_LOG_FILE=/dev/null; \
111 | nosetests -v --with-id --with-coverage --cover-package=. \
112 | 3>&1 1>&2 2>&3 3>&- || true
113 | @echo "----------------------"
114 | @echo "If you get a 'no module named qgis.core error, try sourcing"
115 | @echo "the helper script we have provided first then run make test."
116 | @echo "e.g. source run-env-linux.sh ; make test"
117 | @echo "----------------------"
118 |
119 | deploy: compile doc transcompile
120 | @echo
121 | @echo "------------------------------------------"
122 | @echo "Deploying plugin to your .qgis2 directory."
123 | @echo "------------------------------------------"
124 | # The deploy target only works on unix like operating system where
125 | # the Python plugin directory is located at:
126 | # $HOME/$(QGISDIR)/python/plugins
127 | mkdir -p $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
128 | cp -vf $(PY_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
129 | cp -vf $(UI_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
130 | cp -vf $(COMPILED_RESOURCE_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
131 | cp -vf $(EXTRAS) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
132 | cp -vfr i18n $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
133 | cp -vfr $(HELP) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)/help
134 | # Copy extra directories if any
135 | (foreach EXTRA_DIR,(EXTRA_DIRS), cp -R (EXTRA_DIR) (HOME)/(QGISDIR)/python/plugins/(PLUGINNAME)/;)
136 |
137 |
138 | # The dclean target removes compiled python files from plugin directory
139 | # also deletes any .git entry
140 | dclean:
141 | @echo
142 | @echo "-----------------------------------"
143 | @echo "Removing any compiled python files."
144 | @echo "-----------------------------------"
145 | find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname "*.pyc" -delete
146 | find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname ".git" -prune -exec rm -Rf {} \;
147 |
148 |
149 | derase:
150 | @echo
151 | @echo "-------------------------"
152 | @echo "Removing deployed plugin."
153 | @echo "-------------------------"
154 | rm -Rf $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
155 |
156 | zip: deploy dclean
157 | @echo
158 | @echo "---------------------------"
159 | @echo "Creating plugin zip bundle."
160 | @echo "---------------------------"
161 | # The zip target deploys the plugin and creates a zip file with the deployed
162 | # content. You can then upload the zip file on http://plugins.qgis.org
163 | rm -f $(PLUGINNAME).zip
164 | cd $(HOME)/$(QGISDIR)/python/plugins; zip -9r $(CURDIR)/$(PLUGINNAME).zip $(PLUGINNAME)
165 |
166 | package: compile
167 | # Create a zip package of the plugin named $(PLUGINNAME).zip.
168 | # This requires use of git (your plugin development directory must be a
169 | # git repository).
170 | # To use, pass a valid commit or tag as follows:
171 | # make package VERSION=Version_0.3.2
172 | @echo
173 | @echo "------------------------------------"
174 | @echo "Exporting plugin to zip package. "
175 | @echo "------------------------------------"
176 | rm -f $(PLUGINNAME).zip
177 | git archive --prefix=$(PLUGINNAME)/ -o $(PLUGINNAME).zip $(VERSION)
178 | echo "Created package: $(PLUGINNAME).zip"
179 |
180 | upload: zip
181 | @echo
182 | @echo "-------------------------------------"
183 | @echo "Uploading plugin to QGIS Plugin repo."
184 | @echo "-------------------------------------"
185 | $(PLUGIN_UPLOAD) $(PLUGINNAME).zip
186 |
187 | transup:
188 | @echo
189 | @echo "------------------------------------------------"
190 | @echo "Updating translation files with any new strings."
191 | @echo "------------------------------------------------"
192 | @chmod +x scripts/update-strings.sh
193 | @scripts/update-strings.sh $(LOCALES)
194 |
195 | transcompile:
196 | @echo
197 | @echo "----------------------------------------"
198 | @echo "Compiled translation files to .qm files."
199 | @echo "----------------------------------------"
200 | @chmod +x scripts/compile-strings.sh
201 | @scripts/compile-strings.sh $(LRELEASE) $(LOCALES)
202 |
203 | transclean:
204 | @echo
205 | @echo "------------------------------------"
206 | @echo "Removing compiled translation files."
207 | @echo "------------------------------------"
208 | rm -f i18n/*.qm
209 |
210 | clean:
211 | @echo
212 | @echo "------------------------------------"
213 | @echo "Removing uic and rcc generated files"
214 | @echo "------------------------------------"
215 | rm $(COMPILED_UI_FILES) $(COMPILED_RESOURCE_FILES)
216 |
217 | doc:
218 | @echo
219 | @echo "------------------------------------"
220 | @echo "Building documentation using sphinx."
221 | @echo "------------------------------------"
222 | cd help; make html
223 |
224 | pylint:
225 | @echo
226 | @echo "-----------------"
227 | @echo "Pylint violations"
228 | @echo "-----------------"
229 | @pylint --reports=n --rcfile=pylintrc . || true
230 | @echo
231 | @echo "----------------------"
232 | @echo "If you get a 'no module named qgis.core' error, try sourcing"
233 | @echo "the helper script we have provided first then run make pylint."
234 | @echo "e.g. source run-env-linux.sh ; make pylint"
235 | @echo "----------------------"
236 |
237 |
238 | # Run pep8 style checking
239 | #http://pypi.python.org/pypi/pep8
240 | pep8:
241 | @echo
242 | @echo "-----------"
243 | @echo "PEP8 issues"
244 | @echo "-----------"
245 | @pep8 --repeat --ignore=E203,E121,E122,E123,E124,E125,E126,E127,E128 --exclude $(PEP8EXCLUDE) . || true
246 | @echo "-----------"
247 | @echo "Ignored in PEP8 check:"
248 | @echo $(PEP8EXCLUDE)
249 |
--------------------------------------------------------------------------------
/pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 |
3 | # Specify a configuration file.
4 | #rcfile=
5 |
6 | # Python code to execute, usually for sys.path manipulation such as
7 | # pygtk.require().
8 | #init-hook=
9 |
10 | # Profiled execution.
11 | profile=no
12 |
13 | # Add files or directories to the blacklist. They should be base names, not
14 | # paths.
15 | ignore=CVS
16 |
17 | # Pickle collected data for later comparisons.
18 | persistent=yes
19 |
20 | # List of plugins (as comma separated values of python modules names) to load,
21 | # usually to register additional checkers.
22 | load-plugins=
23 |
24 |
25 | [MESSAGES CONTROL]
26 |
27 | # Enable the message, report, category or checker with the given id(s). You can
28 | # either give multiple identifier separated by comma (,) or put this option
29 | # multiple time. See also the "--disable" option for examples.
30 | #enable=
31 |
32 | # Disable the message, report, category or checker with the given id(s). You
33 | # can either give multiple identifiers separated by comma (,) or put this
34 | # option multiple times (only on the command line, not in the configuration
35 | # file where it should appear only once).You can also use "--disable=all" to
36 | # disable everything first and then reenable specific checks. For example, if
37 | # you want to run only the similarities checker, you can use "--disable=all
38 | # --enable=similarities". If you want to run only the classes checker, but have
39 | # no Warning level messages displayed, use"--disable=all --enable=classes
40 | # --disable=W"
41 | # see http://stackoverflow.com/questions/21487025/pylint-locally-defined-disables-still-give-warnings-how-to-suppress-them
42 | disable=locally-disabled,C0103
43 |
44 |
45 | [REPORTS]
46 |
47 | # Set the output format. Available formats are text, parseable, colorized, msvs
48 | # (visual studio) and html. You can also give a reporter class, eg
49 | # mypackage.mymodule.MyReporterClass.
50 | output-format=text
51 |
52 | # Put messages in a separate file for each module / package specified on the
53 | # command line instead of printing them on stdout. Reports (if any) will be
54 | # written in a file name "pylint_global.[txt|html]".
55 | files-output=no
56 |
57 | # Tells whether to display a full report or only the messages
58 | reports=yes
59 |
60 | # Python expression which should return a note less than 10 (10 is the highest
61 | # note). You have access to the variables errors warning, statement which
62 | # respectively contain the number of errors / warnings messages and the total
63 | # number of statements analyzed. This is used by the global evaluation report
64 | # (RP0004).
65 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
66 |
67 | # Add a comment according to your evaluation note. This is used by the global
68 | # evaluation report (RP0004).
69 | comment=no
70 |
71 | # Template used to display messages. This is a python new-style format string
72 | # used to format the message information. See doc for all details
73 | #msg-template=
74 |
75 |
76 | [BASIC]
77 |
78 | # Required attributes for module, separated by a comma
79 | required-attributes=
80 |
81 | # List of builtins function names that should not be used, separated by a comma
82 | bad-functions=map,filter,apply,input
83 |
84 | # Regular expression which should only match correct module names
85 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
86 |
87 | # Regular expression which should only match correct module level names
88 | const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
89 |
90 | # Regular expression which should only match correct class names
91 | class-rgx=[A-Z_][a-zA-Z0-9]+$
92 |
93 | # Regular expression which should only match correct function names
94 | function-rgx=[a-z_][a-z0-9_]{2,30}$
95 |
96 | # Regular expression which should only match correct method names
97 | method-rgx=[a-z_][a-z0-9_]{2,30}$
98 |
99 | # Regular expression which should only match correct instance attribute names
100 | attr-rgx=[a-z_][a-z0-9_]{2,30}$
101 |
102 | # Regular expression which should only match correct argument names
103 | argument-rgx=[a-z_][a-z0-9_]{2,30}$
104 |
105 | # Regular expression which should only match correct variable names
106 | variable-rgx=[a-z_][a-z0-9_]{2,30}$
107 |
108 | # Regular expression which should only match correct attribute names in class
109 | # bodies
110 | class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
111 |
112 | # Regular expression which should only match correct list comprehension /
113 | # generator expression variable names
114 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
115 |
116 | # Good variable names which should always be accepted, separated by a comma
117 | good-names=i,j,k,ex,Run,_
118 |
119 | # Bad variable names which should always be refused, separated by a comma
120 | bad-names=foo,bar,baz,toto,tutu,tata
121 |
122 | # Regular expression which should only match function or class names that do
123 | # not require a docstring.
124 | no-docstring-rgx=__.*__
125 |
126 | # Minimum line length for functions/classes that require docstrings, shorter
127 | # ones are exempt.
128 | docstring-min-length=-1
129 |
130 |
131 | [MISCELLANEOUS]
132 |
133 | # List of note tags to take in consideration, separated by a comma.
134 | notes=FIXME,XXX,TODO
135 |
136 |
137 | [TYPECHECK]
138 |
139 | # Tells whether missing members accessed in mixin class should be ignored. A
140 | # mixin class is detected if its name ends with "mixin" (case insensitive).
141 | ignore-mixin-members=yes
142 |
143 | # List of classes names for which member attributes should not be checked
144 | # (useful for classes with attributes dynamically set).
145 | ignored-classes=SQLObject
146 |
147 | # When zope mode is activated, add a predefined set of Zope acquired attributes
148 | # to generated-members.
149 | zope=no
150 |
151 | # List of members which are set dynamically and missed by pylint inference
152 | # system, and so shouldn't trigger E0201 when accessed. Python regular
153 | # expressions are accepted.
154 | generated-members=REQUEST,acl_users,aq_parent
155 |
156 |
157 | [VARIABLES]
158 |
159 | # Tells whether we should check for unused import in __init__ files.
160 | init-import=no
161 |
162 | # A regular expression matching the beginning of the name of dummy variables
163 | # (i.e. not used).
164 | dummy-variables-rgx=_$|dummy
165 |
166 | # List of additional names supposed to be defined in builtins. Remember that
167 | # you should avoid to define new builtins when possible.
168 | additional-builtins=
169 |
170 |
171 | [FORMAT]
172 |
173 | # Maximum number of characters on a single line.
174 | max-line-length=80
175 |
176 | # Regexp for a line that is allowed to be longer than the limit.
177 | ignore-long-lines=^\s*(# )??$
178 |
179 | # Allow the body of an if to be on the same line as the test if there is no
180 | # else.
181 | single-line-if-stmt=no
182 |
183 | # List of optional constructs for which whitespace checking is disabled
184 | no-space-check=trailing-comma,dict-separator
185 |
186 | # Maximum number of lines in a module
187 | max-module-lines=1000
188 |
189 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
190 | # tab).
191 | indent-string=' '
192 |
193 |
194 | [SIMILARITIES]
195 |
196 | # Minimum lines number of a similarity.
197 | min-similarity-lines=4
198 |
199 | # Ignore comments when computing similarities.
200 | ignore-comments=yes
201 |
202 | # Ignore docstrings when computing similarities.
203 | ignore-docstrings=yes
204 |
205 | # Ignore imports when computing similarities.
206 | ignore-imports=no
207 |
208 |
209 | [IMPORTS]
210 |
211 | # Deprecated modules which should not be used, separated by a comma
212 | deprecated-modules=regsub,TERMIOS,Bastion,rexec
213 |
214 | # Create a graph of every (i.e. internal and external) dependencies in the
215 | # given file (report RP0402 must not be disabled)
216 | import-graph=
217 |
218 | # Create a graph of external dependencies in the given file (report RP0402 must
219 | # not be disabled)
220 | ext-import-graph=
221 |
222 | # Create a graph of internal dependencies in the given file (report RP0402 must
223 | # not be disabled)
224 | int-import-graph=
225 |
226 |
227 | [DESIGN]
228 |
229 | # Maximum number of arguments for function / method
230 | max-args=5
231 |
232 | # Argument names that match this expression will be ignored. Default to name
233 | # with leading underscore
234 | ignored-argument-names=_.*
235 |
236 | # Maximum number of locals for function / method body
237 | max-locals=15
238 |
239 | # Maximum number of return / yield for function / method body
240 | max-returns=6
241 |
242 | # Maximum number of branch for function / method body
243 | max-branches=12
244 |
245 | # Maximum number of statements in function / method body
246 | max-statements=50
247 |
248 | # Maximum number of parents for a class (see R0901).
249 | max-parents=7
250 |
251 | # Maximum number of attributes for a class (see R0902).
252 | max-attributes=7
253 |
254 | # Minimum number of public methods for a class (see R0903).
255 | min-public-methods=2
256 |
257 | # Maximum number of public methods for a class (see R0904).
258 | max-public-methods=20
259 |
260 |
261 | [CLASSES]
262 |
263 | # List of interface methods to ignore, separated by a comma. This is used for
264 | # instance to not check methods defines in Zope's Interface base class.
265 | ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
266 |
267 | # List of method names used to declare (i.e. assign) instance attributes.
268 | defining-attr-methods=__init__,__new__,setUp
269 |
270 | # List of valid names for the first argument in a class method.
271 | valid-classmethod-first-arg=cls
272 |
273 | # List of valid names for the first argument in a metaclass class method.
274 | valid-metaclass-classmethod-first-arg=mcs
275 |
276 |
277 | [EXCEPTIONS]
278 |
279 | # Exceptions that will emit a warning when being caught. Defaults to
280 | # "Exception"
281 | overgeneral-exceptions=Exception
282 |
--------------------------------------------------------------------------------
/processing_provider/rvt_blender.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.blend
15 | import rvt.vis
16 | import os
17 |
18 |
19 | class RVTBlender(QgsProcessingAlgorithm):
20 | """
21 | RVT Blender.
22 | """
23 | # processing function parameters
24 | INPUT = 'INPUT'
25 | BLEND_COMBINATION = 'BLEND_COMBINATION'
26 | TERRAIN_TYPE = 'TERRAIN_TYPE'
27 | OUTPUT = 'OUTPUT'
28 | NOISE_REMOVE = "NOISE_REMOVE"
29 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
30 |
31 | # read default blender combinations from settings/json, read default terrain settings from settings/json
32 | default_blender_combinations_path = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)),
33 | "settings", "default_blender_combinations.json"))
34 | terrains_settings_path = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)),
35 | "settings", "default_terrains_settings.json"))
36 | combinations = rvt.blend.BlenderCombinations()
37 | terrains_settings = rvt.blend.TerrainsSettings()
38 | combinations.read_from_file(default_blender_combinations_path)
39 | terrains_settings.read_from_file(terrains_settings_path)
40 |
41 | # find out values for comboboxes
42 | combinations_names = []
43 | terrains_sett_names = []
44 | for combination in combinations.combinations:
45 | combinations_names.append(combination.name)
46 | for terrain_sett in terrains_settings.terrains_settings:
47 | terrains_sett_names.append(terrain_sett.name)
48 |
49 | def tr(self, string):
50 | """
51 | Returns a translatable string with the self.tr() function.
52 | """
53 | return QCoreApplication.translate('Processing', string)
54 |
55 | def createInstance(self):
56 | return RVTBlender()
57 |
58 | def name(self):
59 | """
60 | Returns the algorithm name, used for identifying the algorithm. This
61 | string should be fixed for the algorithm, and must not be localised.
62 | The name should be unique within each provider. Names should contain
63 | lowercase alphanumeric characters only and no spaces or other
64 | formatting characters.
65 | """
66 | return 'rvt_blender'
67 |
68 | def displayName(self):
69 | """
70 | Returns the translated algorithm name, which should be used for any
71 | user-visible display of the algorithm name.
72 | """
73 | return self.tr('RVT Blender')
74 |
75 | def shortHelpString(self):
76 | """
77 | Returns a localised short helper string for the algorithm. This string
78 | should provide a basic description about what the algorithm does and the
79 | parameters and outputs associated with it..
80 | """
81 | return self.tr("Relief visualization toolbox, Blender. Calculates blended visualization.")
82 |
83 | def initAlgorithm(self, config=None):
84 | """
85 | Here we define the inputs and output of the algorithm, along
86 | with some other properties.
87 | """
88 | self.addParameter(
89 | QgsProcessingParameterRasterLayer(
90 | self.INPUT,
91 | self.tr('Input DEM raster layer'),
92 | [QgsProcessing.TypeRaster]
93 | )
94 | )
95 | self.addParameter(
96 | QgsProcessingParameterEnum(
97 | name="BLEND_COMBINATION",
98 | description="Combination",
99 | options=self.combinations_names
100 | )
101 | )
102 | self.addParameter(
103 | QgsProcessingParameterEnum(
104 | name="TERRAIN_TYPE",
105 | description="Terrain type",
106 | options=self.terrains_sett_names
107 | )
108 | )
109 | self.addParameter(
110 | QgsProcessingParameterBoolean(
111 | name="SAVE_AS_8BIT",
112 | description="Save as 8bit raster",
113 | defaultValue=False
114 | )
115 | )
116 | self.addParameter(
117 | QgsProcessingParameterRasterDestination(
118 | self.OUTPUT,
119 | self.tr('Output visualization raster layer')
120 | )
121 | )
122 |
123 | def processAlgorithm(self, parameters, context, feedback):
124 | """
125 | Here is where the processing itself takes place.
126 | """
127 | dem_layer = self.parameterAsRasterLayer(
128 | parameters,
129 | self.INPUT,
130 | context
131 | )
132 | combination_name = self.combinations_names[int(self.parameterAsEnum(
133 | parameters,
134 | self.BLEND_COMBINATION,
135 | context
136 | ))]
137 | terrain_name = self.terrains_sett_names[int(self.parameterAsEnum(
138 | parameters,
139 | self.TERRAIN_TYPE,
140 | context
141 | ))]
142 | save_8bit = bool(self.parameterAsBool(
143 | parameters,
144 | self.SAVE_AS_8BIT,
145 | context
146 | ))
147 | visualization_path = (self.parameterAsOutputLayer(
148 | parameters,
149 | self.OUTPUT,
150 | context,
151 | ))
152 |
153 | dem_path = str(dem_layer.source())
154 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
155 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
156 | dem_arr = dict_arr_dem["array"]
157 | no_data = dict_arr_dem["no_data"]
158 |
159 | #if save_8bit = True save_float is False, can only output one
160 | save_float = True
161 | if save_8bit:
162 | save_float = False
163 |
164 | # advanced custom combinations (hard coded) blending (which can't be created in dialog)
165 | if combination_name == "Archaeological combined (VAT combined)":
166 | vat_combination_json_path = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)),
167 | "settings", "blender_VAT.json"))
168 | default_1 = rvt.default.DefaultValues() # VAT general
169 | default_2 = rvt.default.DefaultValues() # VAT flat
170 |
171 | vat_combination_1 = rvt.blend.BlenderCombination() # VAT general
172 | vat_combination_2 = rvt.blend.BlenderCombination() # VAT flat
173 | vat_combination_1.read_from_file(vat_combination_json_path)
174 | vat_combination_2.read_from_file(vat_combination_json_path)
175 | terrain_1 = self.terrains_settings.select_terrain_settings_by_name("general") # VAT general
176 | terrain_2 = self.terrains_settings.select_terrain_settings_by_name("flat") # VAT flat
177 | terrain_1.apply_terrain(default=default_1, combination=vat_combination_1) # VAT general
178 | terrain_2.apply_terrain(default=default_2, combination=vat_combination_2) # VAT flat
179 |
180 | dict_arr_res_nd = rvt.default.get_raster_arr(raster_path=dem_path)
181 | vat_combination_1.add_dem_arr(dem_arr=dict_arr_res_nd["array"],
182 | dem_resolution=dict_arr_res_nd["resolution"][0])
183 | vat_arr_1 = vat_combination_1.render_all_images(default=default_1, no_data=dict_arr_res_nd["no_data"])
184 | vat_combination_2.add_dem_arr(dem_arr=dict_arr_res_nd["array"],
185 | dem_resolution=dict_arr_res_nd["resolution"][0])
186 | vat_arr_2 = vat_combination_2.render_all_images(default=default_2, no_data=dict_arr_res_nd["no_data"])
187 |
188 | # blend VAT general and VAT flat together
189 | combination = rvt.blend.BlenderCombination()
190 | combination.create_layer(vis_method="VAT general", image=vat_arr_1, normalization="Value", minimum=0,
191 | maximum=1, blend_mode="Normal", opacity=50)
192 | combination.create_layer(vis_method="VAT flat", image=vat_arr_2, normalization="Value", minimum=0,
193 | maximum=1, blend_mode="Normal", opacity=100)
194 | combination.add_dem_path(dem_path=dem_path)
195 | combination.render_all_images(save_render_path=visualization_path, save_visualizations=False,
196 | save_float=save_float, save_8bit=save_8bit,
197 | no_data=no_data)
198 | elif combination_name == "enhanced Multi-Scale Topographic Position version 3":
199 | dict_arr_res_nd = rvt.default.get_raster_arr(raster_path=dem_path)
200 | e3mstp_arr = rvt.blend.e3mstp(dem=dict_arr_res_nd["array"], resolution=dict_arr_res_nd["resolution"][0],
201 | no_data=dict_arr_res_nd["no_data"])
202 | if save_float:
203 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
204 | out_raster_arr=e3mstp_arr, no_data=np.nan, e_type=6)
205 | else:
206 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
207 | out_raster_arr=rvt.vis.byte_scale(e3mstp_arr, c_min=0.0, c_max=1.0),
208 | no_data=np.nan, e_type=1)
209 | # normal combination blending
210 | else:
211 | # create default
212 | default = rvt.default.DefaultValues()
213 |
214 | # create combination
215 | combination = self.combinations.select_combination_by_name(combination_name)
216 | # apply terrain settings
217 | terrain_sett = self.terrains_settings.select_terrain_settings_by_name(terrain_name)
218 | terrain_sett.apply_terrain(default, combination)
219 | combination.add_dem_arr(dem_arr=dem_arr, dem_resolution=resolution[0])
220 | combination.add_dem_path(dem_path)
221 | combination.render_all_images(default=default, save_visualizations=False,
222 | save_render_path=visualization_path,
223 | save_float=save_float, save_8bit=save_8bit, no_data=no_data)
224 |
225 | result = {self.OUTPUT: visualization_path}
226 | return result
227 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/qrvt_dialog_about.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'qrvt_dialog_about.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.15.1
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt5 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_RvtAbout(object):
15 | def setupUi(self, RvtAbout):
16 | RvtAbout.setObjectName("RvtAbout")
17 | RvtAbout.resize(600, 700)
18 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(RvtAbout)
19 | self.verticalLayout_3.setObjectName("verticalLayout_3")
20 | self.verticalLayout = QtWidgets.QVBoxLayout()
21 | self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize)
22 | self.verticalLayout.setObjectName("verticalLayout")
23 | self.label = QtWidgets.QLabel(RvtAbout)
24 | self.label.setMinimumSize(QtCore.QSize(0, 0))
25 | self.label.setMaximumSize(QtCore.QSize(16777215, 16777215))
26 | font = QtGui.QFont()
27 | font.setPointSize(10)
28 | font.setBold(True)
29 | font.setWeight(75)
30 | self.label.setFont(font)
31 | self.label.setObjectName("label")
32 | self.verticalLayout.addWidget(self.label)
33 | self.horizontalLayout = QtWidgets.QHBoxLayout()
34 | self.horizontalLayout.setObjectName("horizontalLayout")
35 | self.label_2 = QtWidgets.QLabel(RvtAbout)
36 | self.label_2.setMinimumSize(QtCore.QSize(0, 0))
37 | self.label_2.setMaximumSize(QtCore.QSize(16777215, 16777215))
38 | self.label_2.setObjectName("label_2")
39 | self.horizontalLayout.addWidget(self.label_2)
40 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
41 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
42 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
43 | self.horizontalLayout_2.addItem(spacerItem)
44 | self.verticalLayout_2 = QtWidgets.QVBoxLayout()
45 | self.verticalLayout_2.setObjectName("verticalLayout_2")
46 | self.label_9 = QtWidgets.QLabel(RvtAbout)
47 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
48 | sizePolicy.setHorizontalStretch(0)
49 | sizePolicy.setVerticalStretch(0)
50 | sizePolicy.setHeightForWidth(self.label_9.sizePolicy().hasHeightForWidth())
51 | self.label_9.setSizePolicy(sizePolicy)
52 | self.label_9.setMinimumSize(QtCore.QSize(240, 147))
53 | self.label_9.setMaximumSize(QtCore.QSize(240, 147))
54 | self.label_9.setText("")
55 | self.label_9.setPixmap(QtGui.QPixmap("icon.png"))
56 | self.label_9.setScaledContents(True)
57 | self.label_9.setObjectName("label_9")
58 | self.verticalLayout_2.addWidget(self.label_9)
59 | self.horizontalLayout_2.addLayout(self.verticalLayout_2)
60 | spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
61 | self.horizontalLayout_2.addItem(spacerItem1)
62 | self.horizontalLayout.addLayout(self.horizontalLayout_2)
63 | self.verticalLayout.addLayout(self.horizontalLayout)
64 | self.label_3 = QtWidgets.QLabel(RvtAbout)
65 | self.label_3.setMinimumSize(QtCore.QSize(0, 0))
66 | self.label_3.setMaximumSize(QtCore.QSize(16777215, 16777215))
67 | self.label_3.setOpenExternalLinks(True)
68 | self.label_3.setObjectName("label_3")
69 | self.verticalLayout.addWidget(self.label_3)
70 | self.label_4 = QtWidgets.QLabel(RvtAbout)
71 | self.label_4.setMinimumSize(QtCore.QSize(0, 0))
72 | self.label_4.setMaximumSize(QtCore.QSize(16777215, 16777215))
73 | self.label_4.setObjectName("label_4")
74 | self.verticalLayout.addWidget(self.label_4)
75 | self.label_5 = QtWidgets.QLabel(RvtAbout)
76 | self.label_5.setMinimumSize(QtCore.QSize(0, 0))
77 | self.label_5.setMaximumSize(QtCore.QSize(16777215, 16777215))
78 | self.label_5.setObjectName("label_5")
79 | self.verticalLayout.addWidget(self.label_5)
80 | self.label_7 = QtWidgets.QLabel(RvtAbout)
81 | self.label_7.setObjectName("label_7")
82 | self.verticalLayout.addWidget(self.label_7)
83 | self.label_8 = QtWidgets.QLabel(RvtAbout)
84 | self.label_8.setOpenExternalLinks(True)
85 | self.label_8.setObjectName("label_8")
86 | self.verticalLayout.addWidget(self.label_8)
87 | self.label_6 = QtWidgets.QLabel(RvtAbout)
88 | self.label_6.setObjectName("label_6")
89 | self.verticalLayout.addWidget(self.label_6)
90 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
91 | self.horizontalLayout_3.setObjectName("horizontalLayout_3")
92 | spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
93 | self.horizontalLayout_3.addItem(spacerItem2)
94 | self.button_report_bug = QtWidgets.QPushButton(RvtAbout)
95 | self.button_report_bug.setObjectName("button_report_bug")
96 | self.horizontalLayout_3.addWidget(self.button_report_bug)
97 | spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
98 | self.horizontalLayout_3.addItem(spacerItem3)
99 | self.button_close = QtWidgets.QPushButton(RvtAbout)
100 | self.button_close.setObjectName("button_close")
101 | self.horizontalLayout_3.addWidget(self.button_close)
102 | spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
103 | self.horizontalLayout_3.addItem(spacerItem4)
104 | self.horizontalLayout_3.setStretch(0, 1)
105 | self.horizontalLayout_3.setStretch(1, 1)
106 | self.horizontalLayout_3.setStretch(2, 5)
107 | self.horizontalLayout_3.setStretch(3, 1)
108 | self.horizontalLayout_3.setStretch(4, 1)
109 | self.verticalLayout.addLayout(self.horizontalLayout_3)
110 | self.verticalLayout_3.addLayout(self.verticalLayout)
111 |
112 | self.retranslateUi(RvtAbout)
113 | QtCore.QMetaObject.connectSlotsByName(RvtAbout)
114 |
115 | def retranslateUi(self, RvtAbout):
116 | _translate = QtCore.QCoreApplication.translate
117 | RvtAbout.setWindowTitle(_translate("RvtAbout", "RvtAbout"))
118 | self.label.setText(_translate("RvtAbout", "Relief Visualization Toolbox (RVT) QGIS plugin, ver. 0.3"))
119 | self.label_2.setText(_translate("RvtAbout", " \n"
120 | "○ By: \n"
121 | "\n"
122 | " \n"
123 | "• Žiga Kokalj\n"
124 | "\n"
125 | " \n"
126 | "• Krištof Oštir\n"
127 | "\n"
128 | " \n"
129 | "• Klemen Zakšek\n"
130 | "\n"
131 | " \n"
132 | "• Peter Pehani\n"
133 | "\n"
134 | " \n"
135 | "• Klemen Čotar\n"
136 | "\n"
137 | " \n"
138 | "• Maja Somrak\n"
139 | "\n"
140 | " \n"
141 | "• Žiga Maroh (plugin author and maintainer)\n"
142 | " \n"
143 | "<\\body>\n"
144 | "<\\html>"))
145 | self.label_3.setText(_translate("RvtAbout", " \n"
146 | "○ Online resources: \n"
147 | "\n"
148 | " • RVT QGIS plugin GitHub \n"
149 | "\n"
150 | " • RVT core python library GitHub \n"
151 | "\n"
152 | " • RVT ArcGIS Pro raster functions GitHub \n"
153 | "\n"
154 | " • Old RVT \n"
155 | "\n"
156 | "<\\body>\n"
157 | "<\\html>"))
158 | self.label_4.setText(_translate("RvtAbout", " \n"
159 | "○ License agreement: \n"
160 | " This software is distributed without any warranty and without even the implied warranty of merchantability or fitness \n"
161 | " \n"
162 | " for a particulat pupose.\n"
163 | " \n"
164 | "<\\body>\n"
165 | "<\\html>"))
166 | self.label_5.setText(_translate("RvtAbout", " ○ Acknowledgment: \n"
167 | " \n"
168 | "Development of RVT was partly financed by the European Commission\'s Culture Programme through \n"
169 | " \n"
170 | "the ArchaeoLandscapes Europe project and by the Slovenian Research Agency core funding No. P2-0406,\n"
171 | " \n"
172 | " and by research projects No. J6-7085 and No. J6-9395.
"))
173 | self.label_7.setText(_translate("RvtAbout", " ○ Refrences: \n"
174 | " \n"
175 | "When using tools, please cite: \n"
176 | "• Kokalj, Ž., Somrak, M. 2019. Why Not a Single Image? Combining Visualizations to Facilitate Fieldwork and\n"
177 | " \n"
178 | " On-Screen Mapping. Remote Sensing 11(7): 747.\n"
179 | " \n"
180 | "• Zakšek, K., Oštir, K., Kokalj, Ž. 2011. Sky-View Factor as a Relief Visualization Technique.\n"
181 | " \n"
182 | " Remote Sensing 3: 398-415.\n"
183 | " \n"
184 | "• Kokalj, Ž., Zakšek, K., Oštir, K. 2011. Application of Sky-View Factor for the Visualization of Historic Landscape \n"
185 | " \n"
186 | "Features in Lidar-Derived Relief Models. Antiquity 85, 327: 263-273.\n"
187 | " \n"
188 | ""))
189 | self.label_8.setText(_translate("RvtAbout", "
○ Bugs and Suggestions: \n"
190 | " \n"
191 | "Please report any bugs to Issues or to email: ziga.maroh@icloud.com\n"
192 | " \n"
193 | " \n"
194 | "Suggestions for improvments can be sent to email: ziga.kokalj@zrc-sazu.si\n"
195 | " \n"
196 | ""))
197 | self.label_6.setText(_translate("RvtAbout", "
○ © Copyright: \n"
198 | " \n"
199 | "Research Center of the Slovenian Academy of Sciences and Arts (ZRC SAZU) and \n"
200 | " University of Ljubljana, Faculty of Civil and Geodetic Engineering (UL FGG), 2020\n"
201 | " \n"
202 | ""))
203 | self.button_report_bug.setText(_translate("RvtAbout", "Report a bug"))
204 | self.button_close.setText(_translate("RvtAbout", "Close"))
205 |
--------------------------------------------------------------------------------
/processing_provider/rvt_mstp.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QCoreApplication
2 | from qgis.core import (QgsProcessing,
3 | QgsFeatureSink,
4 | QgsProcessingException,
5 | QgsProcessingAlgorithm,
6 | QgsProcessingParameterNumber,
7 | QgsProcessingParameterRasterLayer,
8 | QgsProcessingParameterRasterDestination,
9 | QgsProcessingParameterEnum,
10 | QgsProcessingParameterBoolean)
11 | from qgis import processing
12 | import numpy as np
13 | import rvt.default
14 | import rvt.vis
15 | from rvt.default import RVTVisualization
16 |
17 |
18 | class RVTMstp(QgsProcessingAlgorithm):
19 | """
20 | RVT Multi-scale topographic position.
21 | """
22 | # processing function parameters
23 | INPUT = 'INPUT'
24 | VE_FACTOR = 'VE_FACTOR'
25 | LOCAL_SCALE_MIN = "LOCAL_SCALE_MIN"
26 | LOCAL_SCALE_MAX = "LOCAL_SCALE_MAX"
27 | LOCAL_SCALE_STEP = "LOCAL_SCALE_STEP"
28 | MESO_SCALE_MIN = "MESO_SCALE_MIN"
29 | MESO_SCALE_MAX = "MESO_SCALE_MAX"
30 | MESO_SCALE_STEP = "MESO_SCALE_STEP"
31 | BROAD_SCALE_MIN = "BROAD_SCALE_MIN"
32 | BROAD_SCALE_MAX = "BROAD_SCALE_MAX"
33 | BROAD_SCALE_STEP = "BROAD_SCALE_STEP"
34 | LIGHTNESS = "LIGHTNESS"
35 | SAVE_AS_8BIT = "SAVE_AS_8BIT"
36 | OUTPUT = 'OUTPUT'
37 |
38 | noise_options = ["no removal", "low", "medium", "high"]
39 |
40 | def tr(self, string):
41 | """
42 | Returns a translatable string with the self.tr() function.
43 | """
44 | return QCoreApplication.translate('Processing', string)
45 |
46 | def createInstance(self):
47 | return RVTMstp()
48 |
49 | def name(self):
50 | """
51 | Returns the algorithm name, used for identifying the algorithm. This
52 | string should be fixed for the algorithm, and must not be localised.
53 | The name should be unique within each provider. Names should contain
54 | lowercase alphanumeric characters only and no spaces or other
55 | formatting characters.
56 | """
57 | return 'rvt_mstp'
58 |
59 | def displayName(self):
60 | """
61 | Returns the translated algorithm name, which should be used for any
62 | user-visible display of the algorithm name.
63 | """
64 | return self.tr('RVT Multi-scale topographic position')
65 |
66 | def shortHelpString(self):
67 | """
68 | Returns a localised short helper string for the algorithm. This string
69 | should provide a basic description about what the algorithm does and the
70 | parameters and outputs associated with it..
71 | """
72 | return self.tr("Relief visualization toolbox, Multi-scale topographic position. "
73 | "Calculates Multi-scale topographic position.")
74 |
75 | def initAlgorithm(self, config=None):
76 | """
77 | Here we define the inputs and output of the algorithm, along
78 | with some other properties.
79 | """
80 | self.addParameter(
81 | QgsProcessingParameterRasterLayer(
82 | self.INPUT,
83 | self.tr('Input DEM raster layer'),
84 | [QgsProcessing.TypeRaster]
85 | )
86 | )
87 | self.addParameter(
88 | QgsProcessingParameterNumber(
89 | name="VE_FACTOR",
90 | description="Vertical exaggeration factor",
91 | type=QgsProcessingParameterNumber.Double,
92 | defaultValue=1,
93 | minValue=-1000,
94 | maxValue=1000
95 | )
96 | )
97 | self.addParameter(
98 | QgsProcessingParameterNumber(
99 | name="LOCAL_SCALE_MIN",
100 | description="Local scale minimum radius [pixels]",
101 | type=QgsProcessingParameterNumber.Integer,
102 | defaultValue=3,
103 | minValue=1,
104 | maxValue=1000000000
105 | )
106 | )
107 | self.addParameter(
108 | QgsProcessingParameterNumber(
109 | name="LOCAL_SCALE_MAX",
110 | description="Local scale maximum radius [pixels]",
111 | type=QgsProcessingParameterNumber.Integer,
112 | defaultValue=21,
113 | minValue=1,
114 | maxValue=1000000000
115 | )
116 | )
117 | self.addParameter(
118 | QgsProcessingParameterNumber(
119 | name="LOCAL_SCALE_STEP",
120 | description="Local scale step [pixels]",
121 | type=QgsProcessingParameterNumber.Integer,
122 | defaultValue=2,
123 | minValue=1,
124 | maxValue=1000000000
125 | )
126 | )
127 | self.addParameter(
128 | QgsProcessingParameterNumber(
129 | name="MESO_SCALE_MIN",
130 | description="Meso scale minimum radius [pixels]",
131 | type=QgsProcessingParameterNumber.Integer,
132 | defaultValue=23,
133 | minValue=1,
134 | maxValue=1000000000
135 | )
136 | )
137 | self.addParameter(
138 | QgsProcessingParameterNumber(
139 | name="MESO_SCALE_MAX",
140 | description="Meso scale maximum radius [pixels]",
141 | type=QgsProcessingParameterNumber.Integer,
142 | defaultValue=203,
143 | minValue=1,
144 | maxValue=1000000000
145 | )
146 | )
147 | self.addParameter(
148 | QgsProcessingParameterNumber(
149 | name="MESO_SCALE_STEP",
150 | description="Meso scale step [pixels]",
151 | type=QgsProcessingParameterNumber.Integer,
152 | defaultValue=18,
153 | minValue=1,
154 | maxValue=1000000000
155 | )
156 | )
157 | self.addParameter(
158 | QgsProcessingParameterNumber(
159 | name="BROAD_SCALE_MIN",
160 | description="Broad scale minimum radius [pixels]",
161 | type=QgsProcessingParameterNumber.Integer,
162 | defaultValue=223,
163 | minValue=1,
164 | maxValue=1000000000
165 | )
166 | )
167 | self.addParameter(
168 | QgsProcessingParameterNumber(
169 | name="BROAD_SCALE_MAX",
170 | description="Broad scale maximum radius [pixels]",
171 | type=QgsProcessingParameterNumber.Integer,
172 | defaultValue=2023,
173 | minValue=1,
174 | maxValue=1000000000
175 | )
176 | )
177 | self.addParameter(
178 | QgsProcessingParameterNumber(
179 | name="BROAD_SCALE_STEP",
180 | description="Broad scale step [pixels]",
181 | type=QgsProcessingParameterNumber.Integer,
182 | defaultValue=180,
183 | minValue=1,
184 | maxValue=1000000000
185 | )
186 | )
187 | self.addParameter(
188 | QgsProcessingParameterNumber(
189 | name="LIGHTNESS",
190 | description="Lightness of image",
191 | type=QgsProcessingParameterNumber.Double,
192 | defaultValue=1.2,
193 | minValue=0.1,
194 | maxValue=5.0
195 | )
196 | )
197 | self.addParameter(
198 | QgsProcessingParameterBoolean(
199 | name="SAVE_AS_8BIT",
200 | description="Save as 8bit raster",
201 | defaultValue=False
202 | )
203 | )
204 | self.addParameter(
205 | QgsProcessingParameterRasterDestination(
206 | self.OUTPUT,
207 | self.tr('Output visualization raster layer')
208 | )
209 | )
210 |
211 | def processAlgorithm(self, parameters, context, feedback):
212 | """
213 | Here is where the processing itself takes place.
214 | """
215 | dem_layer = self.parameterAsRasterLayer(
216 | parameters,
217 | self.INPUT,
218 | context
219 | )
220 | ve_factor = float(self.parameterAsDouble(
221 | parameters,
222 | self.VE_FACTOR,
223 | context
224 | ))
225 | local_scale_min = int(self.parameterAsInt(
226 | parameters,
227 | self.LOCAL_SCALE_MIN,
228 | context
229 | ))
230 | local_scale_max = int(self.parameterAsInt(
231 | parameters,
232 | self.LOCAL_SCALE_MAX,
233 | context
234 | ))
235 | local_scale_step = int(self.parameterAsInt(
236 | parameters,
237 | self.LOCAL_SCALE_STEP,
238 | context
239 | ))
240 | meso_scale_min = int(self.parameterAsInt(
241 | parameters,
242 | self.MESO_SCALE_MIN,
243 | context
244 | ))
245 | meso_scale_max = int(self.parameterAsInt(
246 | parameters,
247 | self.MESO_SCALE_MAX,
248 | context
249 | ))
250 | meso_scale_step = int(self.parameterAsInt(
251 | parameters,
252 | self.MESO_SCALE_STEP,
253 | context
254 | ))
255 | broad_scale_min = int(self.parameterAsInt(
256 | parameters,
257 | self.BROAD_SCALE_MIN,
258 | context
259 | ))
260 | broad_scale_max = int(self.parameterAsInt(
261 | parameters,
262 | self.BROAD_SCALE_MAX,
263 | context
264 | ))
265 | broad_scale_step = int(self.parameterAsInt(
266 | parameters,
267 | self.BROAD_SCALE_STEP,
268 | context
269 | ))
270 | lightness = int(self.parameterAsDouble(
271 | parameters,
272 | self.LIGHTNESS,
273 | context
274 | ))
275 | save_8bit = bool(self.parameterAsBool(
276 | parameters,
277 | self.SAVE_AS_8BIT,
278 | context
279 | ))
280 | visualization_path = (self.parameterAsOutputLayer(
281 | parameters,
282 | self.OUTPUT,
283 | context,
284 | ))
285 |
286 | dem_path = str(dem_layer.source())
287 |
288 | dict_arr_dem = rvt.default.get_raster_arr(dem_path)
289 | resolution = dict_arr_dem["resolution"] # (x_res, y_res)
290 | dem_arr = dict_arr_dem["array"]
291 | no_data = dict_arr_dem["no_data"]
292 |
293 | visualization_arr = rvt.vis.mstp(dem=dem_arr,
294 | local_scale=(local_scale_min, local_scale_max, local_scale_step),
295 | meso_scale=(meso_scale_min, meso_scale_max, meso_scale_step),
296 | broad_scale=(broad_scale_min, broad_scale_max, broad_scale_step),
297 | lightness=lightness, ve_factor=ve_factor,
298 | no_data=no_data)
299 | if not save_8bit:
300 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
301 | out_raster_arr=visualization_arr, e_type=6, no_data=np.nan)
302 | else:
303 | visualization_8bit_arr = rvt.default.DefaultValues().float_to_8bit(
304 | float_arr=visualization_arr, visualization=RVTVisualization.MULTI_SCALE_TOPOGRAPHIC_POSITION
305 | )
306 | rvt.default.save_raster(src_raster_path=dem_path, out_raster_path=visualization_path,
307 | out_raster_arr=visualization_8bit_arr, e_type=1, no_data=np.nan)
308 |
309 | result = {self.OUTPUT: visualization_path}
310 | return result
311 |
--------------------------------------------------------------------------------