Skip to content

Commit 7517a01

Browse files
authored
v.3.2.0 (#12)
* Updated submodule to match upstream * Cleanup algorithm src files * update test package and github test * troubleshoot tests noot running * typo in github actions * errors in github action * remove latest from test * update workflow * edit workflow * update workflow * workflow * Skip points outside the raster bounds in submodule * update tests * introduce postProcess to handle layers * update tests for impactmap * bump version --------- Co-authored-by: DPE
1 parent e1184cf commit 7517a01

File tree

11 files changed

+302
-436
lines changed

11 files changed

+302
-436
lines changed

.github/workflows/test_plugin.yml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333

3434
strategy:
3535
matrix:
36-
docker_tags: [release-3_28, latest]
36+
docker_tags: [release-3_28, release-3_36]
3737

3838
steps:
3939

@@ -45,12 +45,7 @@ jobs:
4545
- name: Docker pull and create qgis-testing-environment
4646
run: |
4747
docker pull "$DOCKER_IMAGE":${{ matrix.docker_tags }}
48-
docker run -d -e XDG_RUNTIME_DIR=/tmp/runtime-root --name qgis-testing-environment -v ${{ github.workspace }}:/tests_directory -e DISPLAY=:99 "$DOCKER_IMAGE":${{ matrix.docker_tags }}
49-
50-
- name: List mounted directory contents
51-
run: |
52-
docker exec qgis-testing-environment ls -la /tests_directory
53-
docker exec qgis-testing-environment ls -la /tests_directory/$PLUGIN_NAME
48+
docker run -d -e XDG_RUNTIME_DIR=/tmp/runtime-root --name qgis-testing-environment -v ${{ github.workspace }}:/tests_directory -e DISPLAY=:99 "$DOCKER_IMAGE":${{ matrix.docker_tags }} tail -f /dev/null
5449
5550
- name: Docker set up QGIS
5651
run: |
@@ -67,10 +62,16 @@ jobs:
6762
run: |
6863
docker exec qgis-testing-environment sh -c "touch /tests_directory/$PLUGIN_NAME/REMEDY_GIS_RiskTool/__init__.py"
6964
docker exec qgis-testing-environment ls -la /tests_directory/$PLUGIN_NAME/REMEDY_GIS_RiskTool
65+
66+
- name: Install and start Xvfb inside Docker container
67+
run: |
68+
docker exec qgis-testing-environment apt update
69+
docker exec qgis-testing-environment apt install -y xvfb
70+
docker exec qgis-testing-environment Xvfb :99 -screen 0 1024x768x24 &
7071
7172
- name: Docker run plugin tests
7273
run: |
73-
docker exec qgis-testing-environment sh -c "export PYTHONPATH=/root/.local/share/QGIS/QGIS3/profiles/default/python/plugins:$PYTHONPATH && qgis_testrunner.sh $TESTS_RUN_FUNCTION"
74+
docker exec qgis-testing-environment sh -c "export DISPLAY=:99; qgis_testrunner.sh $TESTS_RUN_FUNCTION"
7475
7576
Check-code-quality:
7677
runs-on: ubuntu-latest

geovita_processing_plugin/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
__date__ = '2024-01-17'
2727
__copyright__ = '(C) 2024 by DPE'
2828

29-
__version__ = "3.1.1"
29+
__version__ = "3.2.0"
3030

3131
import sys
3232
from pathlib import Path

geovita_processing_plugin/algorithms/BegrensSkadeExcavation.py

Lines changed: 102 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import traceback
3434
from pathlib import Path
35+
from datetime import datetime
3536

3637
from qgis.core import (
3738
Qgis,
@@ -49,11 +50,12 @@
4950
QgsProcessingParameterRasterLayer,
5051
QgsProcessingParameterString,
5152
QgsProject,
53+
QgsVectorLayer,
54+
QgsProcessingOutputFile,
5255
)
5356
from qgis.PyQt.QtCore import QCoreApplication
5457

5558
from ..REMEDY_GIS_RiskTool.BegrensSkade import mainBegrensSkade_Excavation
56-
from ..utilities.AddLayersTask import AddLayersTask
5759
from ..utilities.gui import GuiUtils
5860
from ..utilities.logger import CustomLogger
5961
from ..utilities.methodslib import (
@@ -117,7 +119,6 @@ def __init__(self):
117119
self.feature_name = None # Default value
118120
self.layers_info = {}
119121
self.styles_dir_path = Path()
120-
self.add_layers_task = AddLayersTask()
121122
self.logger.info("__INIT__ - Finished initialize BegrensSkadeExcavation ")
122123

123124
def tr(self, string):
@@ -205,15 +206,10 @@ def __getstate__(self):
205206
"RASTER_ROCK_SURFACE",
206207
"Input raster of depth to bedrock",
207208
]
208-
POREPRESSURE_ENUM = ["POREPRESSURE_ENUM", "Pore pressure reduction curves"]
209-
enum_porepressure = [
210-
"Lav poretrykksreduksjon",
211-
"Middels poretrykksreduksjon",
212-
"Høy poretrykksreduksjon",
213-
]
214-
POREPRESSURE_REDUCTION = [
215-
"POREPRESSURE_REDUCTION",
216-
"Porepressure reduction [kPa]",
209+
210+
POREWP_REDUCTION_M = [
211+
"POREWP_REDUCTION_M",
212+
"Porewater pressure reduction [m]",
217213
]
218214
DRY_CRUST_THICKNESS = [
219215
"DRY_CRUST_THICKNESS",
@@ -287,7 +283,7 @@ def initAlgorithm(self, config):
287283
self.EXCAVATION_DEPTH[0],
288284
self.tr(f"{self.EXCAVATION_DEPTH[1]}"),
289285
QgsProcessingParameterNumber.Double,
290-
defaultValue=0,
286+
defaultValue=10,
291287
minValue=0,
292288
)
293289
param.setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
@@ -322,24 +318,16 @@ def initAlgorithm(self, config):
322318
| QgsProcessingParameterDefinition.FlagOptional
323319
)
324320
self.addParameter(param)
325-
326-
param = QgsProcessingParameterEnum(
327-
self.POREPRESSURE_ENUM[0],
328-
self.tr(f"{self.POREPRESSURE_ENUM[1]}"),
329-
self.enum_porepressure,
330-
defaultValue=1,
331-
allowMultiple=False,
332-
)
333-
param.setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
334-
self.addParameter(param)
321+
335322
param = QgsProcessingParameterNumber(
336-
self.POREPRESSURE_REDUCTION[0],
337-
self.tr(f"{self.POREPRESSURE_REDUCTION[1]}"),
338-
defaultValue=50,
323+
self.POREWP_REDUCTION_M[0],
324+
self.tr(f"{self.POREWP_REDUCTION_M[1]}"),
325+
defaultValue=10,
339326
minValue=0,
340327
)
341328
param.setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
342329
self.addParameter(param)
330+
343331
param = QgsProcessingParameterNumber(
344332
self.DRY_CRUST_THICKNESS[0],
345333
self.tr(f"{self.DRY_CRUST_THICKNESS[1]}"),
@@ -462,8 +450,9 @@ def initAlgorithm(self, config):
462450
self.OUTPUT_FEATURE_NAME,
463451
self.tr(
464452
"Naming Conventions for Analysis and Features (Output feature name appended to file-names)"
465-
),
466-
)
453+
)
454+
),
455+
createOutput=True
467456
)
468457
self.addParameter(
469458
QgsProcessingParameterCrs(
@@ -478,6 +467,24 @@ def initAlgorithm(self, config):
478467
self.tr("Output Folder"),
479468
)
480469
)
470+
self.addOutput(
471+
QgsProcessingOutputFile(
472+
self.OUTPUT_BUILDING,
473+
self.tr("Output Buildings Shapefile"),
474+
)
475+
)
476+
self.addOutput(
477+
QgsProcessingOutputFile(
478+
self.OUTPUT_WALL,
479+
self.tr("Output Walls Shapefile"),
480+
)
481+
)
482+
self.addOutput(
483+
QgsProcessingOutputFile(
484+
self.OUTPUT_CORNER,
485+
self.tr("Output Corners Shapefile"),
486+
)
487+
)
481488

482489
self.logger.info("initAlgorithm - Done setting up the inputs.")
483490

@@ -661,10 +668,6 @@ def processAlgorithm(self, parameters, context, feedback):
661668
)
662669
return {}
663670

664-
porepressure_index = self.parameterAsEnum(
665-
parameters, self.POREPRESSURE_ENUM[0], context
666-
)
667-
pw_reduction_curve = self.enum_porepressure[porepressure_index]
668671
dry_crust_thk = self.parameterAsDouble(
669672
parameters, self.DRY_CRUST_THICKNESS[0], context
670673
)
@@ -675,8 +678,8 @@ def processAlgorithm(self, parameters, context, feedback):
675678
parameters, self.SOIL_DENSITY[0], context
676679
)
677680
ocr_value = self.parameterAsDouble(parameters, self.OCR[0], context)
678-
porewp_red = self.parameterAsInt(
679-
parameters, self.POREPRESSURE_REDUCTION[0], context
681+
porewp_red_m = self.parameterAsInt(
682+
parameters, self.POREWP_REDUCTION_M[0], context
680683
)
681684
janbu_ref_stress = self.parameterAsInt(
682685
parameters, self.JANBU_REF_STRESS[0], context
@@ -693,12 +696,11 @@ def processAlgorithm(self, parameters, context, feedback):
693696

694697
else:
695698
path_source_raster_rock_surface = None
696-
pw_reduction_curve = None
697699
dry_crust_thk = None
698700
dep_groundwater = None
699701
density_sat = None
700702
ocr_value = None
701-
porewp_red = None
703+
porewp_red_m = None
702704
janbu_ref_stress = None
703705
janbu_const = None
704706
janbu_m = None
@@ -769,12 +771,11 @@ def processAlgorithm(self, parameters, context, feedback):
769771
feedback.pushInfo(
770772
f"PROCESS - Param: dtb_raster = {path_source_raster_rock_surface}"
771773
)
772-
feedback.pushInfo(f"PROCESS - Param: pw_reduction_curve = {pw_reduction_curve}")
773774
feedback.pushInfo(f"PROCESS - Param: dry_crust_thk = {dry_crust_thk}")
774775
feedback.pushInfo(f"PROCESS - Param: dep_groundwater = {dep_groundwater}")
775776
feedback.pushInfo(f"PROCESS - Param: density_sat = {density_sat}")
776777
feedback.pushInfo(f"PROCESS - Param: OCR = {ocr_value}")
777-
feedback.pushInfo(f"PROCESS - Param: porewp_red = {porewp_red}")
778+
feedback.pushInfo(f"PROCESS - Param: porewp_red_m = {porewp_red_m}")
778779
feedback.pushInfo(f"PROCESS - Param: janbu_ref_stress = {janbu_ref_stress}")
779780
feedback.pushInfo(f"PROCESS - Param: janbu_const = {janbu_const}")
780781
feedback.pushInfo(f"PROCESS - Param: janbu_m = {janbu_m}")
@@ -797,12 +798,11 @@ def processAlgorithm(self, parameters, context, feedback):
797798
short_term_curve=short_term_curve,
798799
bLongterm=bLongterm,
799800
dtb_raster=str(path_source_raster_rock_surface),
800-
pw_reduction_curve=pw_reduction_curve,
801801
dry_crust_thk=dry_crust_thk,
802802
dep_groundwater=dep_groundwater,
803803
density_sat=density_sat,
804804
OCR=ocr_value,
805-
porewp_red=porewp_red,
805+
porewp_red_m=porewp_red_m,
806806
janbu_ref_stress=janbu_ref_stress,
807807
janbu_const=janbu_const,
808808
janbu_m=janbu_m,
@@ -821,7 +821,7 @@ def processAlgorithm(self, parameters, context, feedback):
821821
return {}
822822

823823
#################### HANDLE THE RESULT ###############################
824-
feedback.setProgress(80)
824+
feedback.setProgress(90)
825825
self.logger.info(f"PROCESS - OUTPUT BUILDINGS: {output_shapefiles[0]}")
826826
self.logger.info(f"PROCESS - OUTPUT WALL: {output_shapefiles[1]}")
827827
self.logger.info(f"PROCESS - OUTPUT CORNER: {output_shapefiles[2]}")
@@ -840,80 +840,89 @@ def processAlgorithm(self, parameters, context, feedback):
840840
"shape_path": output_shapefiles[1],
841841
"style_name": "WALL-ANGLE.qml",
842842
},
843-
"BUILDING-TOTAL-SETTLMENT": {
844-
"shape_path": output_shapefiles[0],
845-
"style_name": "BUILDING-TOTAL-SETTLMENT_sv_tot.qml",
846-
},
847843
"BUILDING-TOTAL-ANGLE": {
848844
"shape_path": output_shapefiles[0],
849845
"style_name": "BUILDING-TOTAL-ANGLE_max_angle.qml",
850846
},
847+
"BUILDING-TOTAL-SETTLMENT": {
848+
"shape_path": output_shapefiles[0],
849+
"style_name": "BUILDING-TOTAL-SETTLMENT_sv_tot.qml",
850+
}
851851
}
852852
if bVulnerability:
853853
self.layers_info.update(
854854
{
855-
"BUILDING-RISK-SETTLMENT": {
856-
"shape_path": output_shapefiles[0],
857-
"style_name": "BUILDING-TOTAL-RISK-SELLMENT_risk_tots.qml",
858-
},
859855
"BUILDING-RISK-ANGLE": {
860856
"shape_path": output_shapefiles[0],
861857
"style_name": "BUILDING-TOTAL-RISK-ANGLE_risk_angle.qml",
862858
},
859+
"BUILDING-RISK-SETTLMENT": {
860+
"shape_path": output_shapefiles[0],
861+
"style_name": "BUILDING-TOTAL-RISK-SELLMENT_risk_tots.qml",
862+
}
863863
}
864864
)
865865

866-
feedback.setProgress(90)
866+
feedback.setProgress(100)
867867
feedback.pushInfo("PROCESS - Finished processing!")
868+
868869
# Return the results of the algorithm.
869-
return {
870-
self.OUTPUT_BUILDING: output_shapefiles[0],
871-
self.OUTPUT_WALL: output_shapefiles[1],
872-
self.OUTPUT_CORNER: output_shapefiles[2],
873-
}
874-
870+
return {self.OUTPUT_BUILDING: output_shapefiles[0],
871+
self.OUTPUT_WALL: output_shapefiles[1],
872+
self.OUTPUT_CORNER: output_shapefiles[2],
873+
874+
}
875+
875876
def postProcessAlgorithm(self, context, feedback):
876877
"""
877-
Handles the post-processing steps of the algorithm, specifically adding output layers to the QGIS project.
878-
879-
This method creates and executes a process to add layers to the QGIS interface, applying predefined styles
880-
and organizing them within a specified group. It leverages the `AddLayersTask` class to manage layer
881-
addition in a way that ensures thread safety and proper GUI updates.
882-
883-
Parameters:
884-
- context (QgsProcessingContext): The context of the processing, providing access to the QGIS project and other relevant settings.
885-
- feedback (QgsProcessingFeedback): The object used to report progress and log messages back to the user.
886-
887-
Returns:
888-
- dict: An empty dictionary. This method does not produce output parameters but instead focuses on the side effect of adding layers to the project.
889-
890-
Note:
891-
This method sets up a task for layer addition, defining success and failure callbacks to provide user feedback.
892-
It manually starts the process and handles its completion.
878+
This method is called after processAlgorithm finishes.
879+
Here, we manually load the output shapefiles, apply QML styles,
880+
and place them under a custom group in the layer tree.
893881
"""
894-
######### EXPERIMENTAL ADD LAYERS TO GUI #########
895-
# Create the task
896-
self.add_layers_task.setParameters(
897-
self.layers_info,
898-
self.feature_name,
899-
self.styles_dir_path,
900-
self.logger,
901-
)
902-
903-
# Define a slot to handle the task completion
904-
def onTaskCompleted(success):
905-
if success:
906-
feedback.pushInfo("POSTPROCESS - Layers added successfully.")
907-
feedback.setProgress(100)
882+
project = context.project()
883+
root = project.layerTreeRoot()
884+
885+
# Create (or find) a group at the top level named by 'self.feature_name'.
886+
group_name = self.feature_name
887+
group = root.findGroup(group_name)
888+
if not group:
889+
group = root.insertGroup(0, group_name)
890+
891+
# 2) Loop through the entries stored in 'self.layers_info' defined during processAlgorithm
892+
for layer_label, layer_info in self.layers_info.items():
893+
shape_path = layer_info["shape_path"] # e.g. "C:/somefolder/buildings.shp"
894+
style_name = layer_info["style_name"] # e.g. "BUILDING-TOTAL-SETTLMENT_sv_tot.qml"
895+
896+
# Generate a unique layer name with timestamp
897+
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
898+
final_layer_name = f"{layer_label}_{timestamp}"
899+
900+
# Create the QgsVectorLayer from the file path
901+
layer = QgsVectorLayer(shape_path, final_layer_name, "ogr")
902+
if not layer.isValid():
903+
feedback.reportError(f"Could not load layer from file: {shape_path}")
904+
continue
905+
906+
# Load the QML style if it exists
907+
style_path = self.styles_dir_path / style_name # e.g. /path/to/styles/BUILDING-TOTAL-SETTLMENT_sv_tot.qml
908+
if style_path.is_file():
909+
layer.loadNamedStyle(str(style_path))
910+
layer.triggerRepaint()
908911
else:
909-
feedback.reportError("POSTPROCESS - Failed to add layers.")
910-
feedback.setProgress(100)
912+
feedback.reportError(f"Style file not found: {style_path}")
913+
914+
# Add the layer to the project (layer registry) *without* adding to the root TOC
915+
QgsProject.instance().addMapLayer(layer, False)
916+
917+
# Place the layer under the group at the bottom
918+
group.insertLayer(-1, layer)
911919

912-
# Connect the task's completed signal to the slot
913-
self.add_layers_task.taskCompleted.connect(onTaskCompleted)
920+
# Ensure the new layer node is visible
921+
node = group.findLayer(layer.id())
922+
if node:
923+
node.setItemVisibilityChecked(True)
914924

915-
# Start the task
916-
success = self.add_layers_task.run()
917-
self.add_layers_task.finished(success)
925+
feedback.pushInfo(f"Loaded and styled layer '{final_layer_name}' in group '{group_name}'.")
918926

919-
return {}
927+
feedback.pushInfo("postProcessAlgorithm complete.")
928+
return {}

0 commit comments

Comments
 (0)