Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .github/workflows/test_plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:

strategy:
matrix:
docker_tags: [release-3_28, latest]
docker_tags: [release-3_28, release-3_36]

steps:

Expand All @@ -45,12 +45,7 @@ jobs:
- name: Docker pull and create qgis-testing-environment
run: |
docker pull "$DOCKER_IMAGE":${{ matrix.docker_tags }}
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 }}

- name: List mounted directory contents
run: |
docker exec qgis-testing-environment ls -la /tests_directory
docker exec qgis-testing-environment ls -la /tests_directory/$PLUGIN_NAME
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

- name: Docker set up QGIS
run: |
Expand All @@ -67,10 +62,16 @@ jobs:
run: |
docker exec qgis-testing-environment sh -c "touch /tests_directory/$PLUGIN_NAME/REMEDY_GIS_RiskTool/__init__.py"
docker exec qgis-testing-environment ls -la /tests_directory/$PLUGIN_NAME/REMEDY_GIS_RiskTool

- name: Install and start Xvfb inside Docker container
run: |
docker exec qgis-testing-environment apt update
docker exec qgis-testing-environment apt install -y xvfb
docker exec qgis-testing-environment Xvfb :99 -screen 0 1024x768x24 &

- name: Docker run plugin tests
run: |
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"
docker exec qgis-testing-environment sh -c "export DISPLAY=:99; qgis_testrunner.sh $TESTS_RUN_FUNCTION"

Check-code-quality:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion geovita_processing_plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
__date__ = '2024-01-17'
__copyright__ = '(C) 2024 by DPE'

__version__ = "3.1.1"
__version__ = "3.2.0"

import sys
from pathlib import Path
Expand Down
195 changes: 102 additions & 93 deletions geovita_processing_plugin/algorithms/BegrensSkadeExcavation.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import traceback
from pathlib import Path
from datetime import datetime

from qgis.core import (
Qgis,
Expand All @@ -49,11 +50,12 @@
QgsProcessingParameterRasterLayer,
QgsProcessingParameterString,
QgsProject,
QgsVectorLayer,
QgsProcessingOutputFile,
)
from qgis.PyQt.QtCore import QCoreApplication

from ..REMEDY_GIS_RiskTool.BegrensSkade import mainBegrensSkade_Excavation
from ..utilities.AddLayersTask import AddLayersTask
from ..utilities.gui import GuiUtils
from ..utilities.logger import CustomLogger
from ..utilities.methodslib import (
Expand Down Expand Up @@ -117,7 +119,6 @@ def __init__(self):
self.feature_name = None # Default value
self.layers_info = {}
self.styles_dir_path = Path()
self.add_layers_task = AddLayersTask()
self.logger.info("__INIT__ - Finished initialize BegrensSkadeExcavation ")

def tr(self, string):
Expand Down Expand Up @@ -205,15 +206,10 @@ def __getstate__(self):
"RASTER_ROCK_SURFACE",
"Input raster of depth to bedrock",
]
POREPRESSURE_ENUM = ["POREPRESSURE_ENUM", "Pore pressure reduction curves"]
enum_porepressure = [
"Lav poretrykksreduksjon",
"Middels poretrykksreduksjon",
"Høy poretrykksreduksjon",
]
POREPRESSURE_REDUCTION = [
"POREPRESSURE_REDUCTION",
"Porepressure reduction [kPa]",

POREWP_REDUCTION_M = [
"POREWP_REDUCTION_M",
"Porewater pressure reduction [m]",
]
DRY_CRUST_THICKNESS = [
"DRY_CRUST_THICKNESS",
Expand Down Expand Up @@ -287,7 +283,7 @@ def initAlgorithm(self, config):
self.EXCAVATION_DEPTH[0],
self.tr(f"{self.EXCAVATION_DEPTH[1]}"),
QgsProcessingParameterNumber.Double,
defaultValue=0,
defaultValue=10,
minValue=0,
)
param.setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
Expand Down Expand Up @@ -322,24 +318,16 @@ def initAlgorithm(self, config):
| QgsProcessingParameterDefinition.FlagOptional
)
self.addParameter(param)

param = QgsProcessingParameterEnum(
self.POREPRESSURE_ENUM[0],
self.tr(f"{self.POREPRESSURE_ENUM[1]}"),
self.enum_porepressure,
defaultValue=1,
allowMultiple=False,
)
param.setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(param)

param = QgsProcessingParameterNumber(
self.POREPRESSURE_REDUCTION[0],
self.tr(f"{self.POREPRESSURE_REDUCTION[1]}"),
defaultValue=50,
self.POREWP_REDUCTION_M[0],
self.tr(f"{self.POREWP_REDUCTION_M[1]}"),
defaultValue=10,
minValue=0,
)
param.setFlags(QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(param)

param = QgsProcessingParameterNumber(
self.DRY_CRUST_THICKNESS[0],
self.tr(f"{self.DRY_CRUST_THICKNESS[1]}"),
Expand Down Expand Up @@ -462,8 +450,9 @@ def initAlgorithm(self, config):
self.OUTPUT_FEATURE_NAME,
self.tr(
"Naming Conventions for Analysis and Features (Output feature name appended to file-names)"
),
)
)
),
createOutput=True
)
self.addParameter(
QgsProcessingParameterCrs(
Expand All @@ -478,6 +467,24 @@ def initAlgorithm(self, config):
self.tr("Output Folder"),
)
)
self.addOutput(
QgsProcessingOutputFile(
self.OUTPUT_BUILDING,
self.tr("Output Buildings Shapefile"),
)
)
self.addOutput(
QgsProcessingOutputFile(
self.OUTPUT_WALL,
self.tr("Output Walls Shapefile"),
)
)
self.addOutput(
QgsProcessingOutputFile(
self.OUTPUT_CORNER,
self.tr("Output Corners Shapefile"),
)
)

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

Expand Down Expand Up @@ -661,10 +668,6 @@ def processAlgorithm(self, parameters, context, feedback):
)
return {}

porepressure_index = self.parameterAsEnum(
parameters, self.POREPRESSURE_ENUM[0], context
)
pw_reduction_curve = self.enum_porepressure[porepressure_index]
dry_crust_thk = self.parameterAsDouble(
parameters, self.DRY_CRUST_THICKNESS[0], context
)
Expand All @@ -675,8 +678,8 @@ def processAlgorithm(self, parameters, context, feedback):
parameters, self.SOIL_DENSITY[0], context
)
ocr_value = self.parameterAsDouble(parameters, self.OCR[0], context)
porewp_red = self.parameterAsInt(
parameters, self.POREPRESSURE_REDUCTION[0], context
porewp_red_m = self.parameterAsInt(
parameters, self.POREWP_REDUCTION_M[0], context
)
janbu_ref_stress = self.parameterAsInt(
parameters, self.JANBU_REF_STRESS[0], context
Expand All @@ -693,12 +696,11 @@ def processAlgorithm(self, parameters, context, feedback):

else:
path_source_raster_rock_surface = None
pw_reduction_curve = None
dry_crust_thk = None
dep_groundwater = None
density_sat = None
ocr_value = None
porewp_red = None
porewp_red_m = None
janbu_ref_stress = None
janbu_const = None
janbu_m = None
Expand Down Expand Up @@ -769,12 +771,11 @@ def processAlgorithm(self, parameters, context, feedback):
feedback.pushInfo(
f"PROCESS - Param: dtb_raster = {path_source_raster_rock_surface}"
)
feedback.pushInfo(f"PROCESS - Param: pw_reduction_curve = {pw_reduction_curve}")
feedback.pushInfo(f"PROCESS - Param: dry_crust_thk = {dry_crust_thk}")
feedback.pushInfo(f"PROCESS - Param: dep_groundwater = {dep_groundwater}")
feedback.pushInfo(f"PROCESS - Param: density_sat = {density_sat}")
feedback.pushInfo(f"PROCESS - Param: OCR = {ocr_value}")
feedback.pushInfo(f"PROCESS - Param: porewp_red = {porewp_red}")
feedback.pushInfo(f"PROCESS - Param: porewp_red_m = {porewp_red_m}")
feedback.pushInfo(f"PROCESS - Param: janbu_ref_stress = {janbu_ref_stress}")
feedback.pushInfo(f"PROCESS - Param: janbu_const = {janbu_const}")
feedback.pushInfo(f"PROCESS - Param: janbu_m = {janbu_m}")
Expand All @@ -797,12 +798,11 @@ def processAlgorithm(self, parameters, context, feedback):
short_term_curve=short_term_curve,
bLongterm=bLongterm,
dtb_raster=str(path_source_raster_rock_surface),
pw_reduction_curve=pw_reduction_curve,
dry_crust_thk=dry_crust_thk,
dep_groundwater=dep_groundwater,
density_sat=density_sat,
OCR=ocr_value,
porewp_red=porewp_red,
porewp_red_m=porewp_red_m,
janbu_ref_stress=janbu_ref_stress,
janbu_const=janbu_const,
janbu_m=janbu_m,
Expand All @@ -821,7 +821,7 @@ def processAlgorithm(self, parameters, context, feedback):
return {}

#################### HANDLE THE RESULT ###############################
feedback.setProgress(80)
feedback.setProgress(90)
self.logger.info(f"PROCESS - OUTPUT BUILDINGS: {output_shapefiles[0]}")
self.logger.info(f"PROCESS - OUTPUT WALL: {output_shapefiles[1]}")
self.logger.info(f"PROCESS - OUTPUT CORNER: {output_shapefiles[2]}")
Expand All @@ -840,80 +840,89 @@ def processAlgorithm(self, parameters, context, feedback):
"shape_path": output_shapefiles[1],
"style_name": "WALL-ANGLE.qml",
},
"BUILDING-TOTAL-SETTLMENT": {
"shape_path": output_shapefiles[0],
"style_name": "BUILDING-TOTAL-SETTLMENT_sv_tot.qml",
},
"BUILDING-TOTAL-ANGLE": {
"shape_path": output_shapefiles[0],
"style_name": "BUILDING-TOTAL-ANGLE_max_angle.qml",
},
"BUILDING-TOTAL-SETTLMENT": {
"shape_path": output_shapefiles[0],
"style_name": "BUILDING-TOTAL-SETTLMENT_sv_tot.qml",
}
}
if bVulnerability:
self.layers_info.update(
{
"BUILDING-RISK-SETTLMENT": {
"shape_path": output_shapefiles[0],
"style_name": "BUILDING-TOTAL-RISK-SELLMENT_risk_tots.qml",
},
"BUILDING-RISK-ANGLE": {
"shape_path": output_shapefiles[0],
"style_name": "BUILDING-TOTAL-RISK-ANGLE_risk_angle.qml",
},
"BUILDING-RISK-SETTLMENT": {
"shape_path": output_shapefiles[0],
"style_name": "BUILDING-TOTAL-RISK-SELLMENT_risk_tots.qml",
}
}
)

feedback.setProgress(90)
feedback.setProgress(100)
feedback.pushInfo("PROCESS - Finished processing!")

# Return the results of the algorithm.
return {
self.OUTPUT_BUILDING: output_shapefiles[0],
self.OUTPUT_WALL: output_shapefiles[1],
self.OUTPUT_CORNER: output_shapefiles[2],
}

return {self.OUTPUT_BUILDING: output_shapefiles[0],
self.OUTPUT_WALL: output_shapefiles[1],
self.OUTPUT_CORNER: output_shapefiles[2],
}
def postProcessAlgorithm(self, context, feedback):
"""
Handles the post-processing steps of the algorithm, specifically adding output layers to the QGIS project.

This method creates and executes a process to add layers to the QGIS interface, applying predefined styles
and organizing them within a specified group. It leverages the `AddLayersTask` class to manage layer
addition in a way that ensures thread safety and proper GUI updates.

Parameters:
- context (QgsProcessingContext): The context of the processing, providing access to the QGIS project and other relevant settings.
- feedback (QgsProcessingFeedback): The object used to report progress and log messages back to the user.

Returns:
- dict: An empty dictionary. This method does not produce output parameters but instead focuses on the side effect of adding layers to the project.

Note:
This method sets up a task for layer addition, defining success and failure callbacks to provide user feedback.
It manually starts the process and handles its completion.
This method is called after processAlgorithm finishes.
Here, we manually load the output shapefiles, apply QML styles,
and place them under a custom group in the layer tree.
"""
######### EXPERIMENTAL ADD LAYERS TO GUI #########
# Create the task
self.add_layers_task.setParameters(
self.layers_info,
self.feature_name,
self.styles_dir_path,
self.logger,
)

# Define a slot to handle the task completion
def onTaskCompleted(success):
if success:
feedback.pushInfo("POSTPROCESS - Layers added successfully.")
feedback.setProgress(100)
project = context.project()
root = project.layerTreeRoot()

# Create (or find) a group at the top level named by 'self.feature_name'.
group_name = self.feature_name
group = root.findGroup(group_name)
if not group:
group = root.insertGroup(0, group_name)

# 2) Loop through the entries stored in 'self.layers_info' defined during processAlgorithm
for layer_label, layer_info in self.layers_info.items():
shape_path = layer_info["shape_path"] # e.g. "C:/somefolder/buildings.shp"
style_name = layer_info["style_name"] # e.g. "BUILDING-TOTAL-SETTLMENT_sv_tot.qml"

# Generate a unique layer name with timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
final_layer_name = f"{layer_label}_{timestamp}"

# Create the QgsVectorLayer from the file path
layer = QgsVectorLayer(shape_path, final_layer_name, "ogr")
if not layer.isValid():
feedback.reportError(f"Could not load layer from file: {shape_path}")
continue

# Load the QML style if it exists
style_path = self.styles_dir_path / style_name # e.g. /path/to/styles/BUILDING-TOTAL-SETTLMENT_sv_tot.qml
if style_path.is_file():
layer.loadNamedStyle(str(style_path))
layer.triggerRepaint()
else:
feedback.reportError("POSTPROCESS - Failed to add layers.")
feedback.setProgress(100)
feedback.reportError(f"Style file not found: {style_path}")

# Add the layer to the project (layer registry) *without* adding to the root TOC
QgsProject.instance().addMapLayer(layer, False)

# Place the layer under the group at the bottom
group.insertLayer(-1, layer)

# Connect the task's completed signal to the slot
self.add_layers_task.taskCompleted.connect(onTaskCompleted)
# Ensure the new layer node is visible
node = group.findLayer(layer.id())
if node:
node.setItemVisibilityChecked(True)

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

return {}
feedback.pushInfo("postProcessAlgorithm complete.")
return {}
Loading