Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

120 connect damo exporter #178

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 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
34 changes: 34 additions & 0 deletions docs/md_files/4_gebruik_plugin/k_schematisation_builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# **Schematisation builder**
HHNK heeft de werkwijze voor het opstellen en valideren van modellen geactualiseerd. De datachecker en modelbuilder zijn vervangen door de Schematisation builder.

... link naar andere pagina voor meer info (2_werkwijze_bwn)

## Werkproces
* Omschrijving uit welke stappen het werkproces bestaat
* Ondersteund door stroomschema

### Stap 0. Een project beginnen of een bestaand project verder oppakken


... plaatje UI volgt later na evt wijzigingen adhv sprint review
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo's graag opnemen met # TODO


### Stap 1. Data exporteren
Het exportproces begint met het selecteren van het bestand met de poldergrenzen. Zodra ingeladen, kan de export gestart worden door op de knop te drukken.

Er wordt een connectie gemaakt naar de DAMO database. Op basis van de polygoon (Polygon of MultiPolygon) wordt data opgehaald uit DAMO. De output wordt weggeschreven in een geopackage (DAMO.gpkg). Vervolgens wordt deze data direct omgezet in HyDAMO-formaat (HyDAMO.gpkg). De HyDAMO geopackage wordt automatisch ingeladen in QGIS met de juiste styling.

Hoe styling automatisch meegeven?

... plaatje UI volgt later na evt wijzigingen adhv sprint review

### Stap 2. Data valideren
...

### Stap x. Data verbeteren
...

### Stap x. Data omzetten tot 3Di model
...

## Achtergrond en uitgangspunten
... hier moet een link komen naar andere pagina (3_achtergronden_en_uitgangpunten)
186 changes: 186 additions & 0 deletions hhnk_threedi_plugin/gui/schematisation_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import os
from dataclasses import dataclass

import geopandas as gpd
import pandas as pd
from hhnk_threedi_tools.core.project import Project
from hhnk_threedi_tools.core.schematisation_builder.DAMO_exporter import DAMO_exporter
from osgeo import ogr
from PyQt5.QtWidgets import QMessageBox, QPlainTextEdit
from qgis.core import QgsLayerTreeGroup, QgsProject, QgsVectorLayer
from qgis.PyQt.QtCore import QObject

from hhnk_threedi_plugin.hhnk_toolbox_dockwidget import HHNK_toolboxDockWidget

BASE_FOLDER = r"\\corp.hhnk.nl\data\Hydrologen_data\Data\09.modellen_speeltuin"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dit lijkt niet hier thuis te horen maar in een local_settings of ergens anders?

TABLE_NAMES = ["HYDROOBJECT"]


@dataclass
class SchematisationBuilder:
"""
All actions in the schematisation_builder tab of the HHNK 3Di Toolbox.

UI includes:
- SelectProjectLabel : QLabel
- SelectProjectComboBox : QComboBox
- CreateProjectLabel : QLabel
- CreateProjectPlainTextEdit : QPlainTextEdit
- CreateProjectPushButton : QPushButton
- SchematisationBuilderVerticalSpacer : Spacer
- ProjectTabWidget : QTabWidget
- tab_status_0 : QWidget
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zonder het gezien te hebben, is deze naam beschrijvend genoeg?

- SelectPolderLabel : QLabel
- SelectPolderFileWidget : QgsFileWidget
- ExportDAMOandHyDAMOPushButton : QPushButton
- tab_status_1 : QWidget
- ValidatePushButton : QPushButton
"""

dockwidget: HHNK_toolboxDockWidget
prewritten_text_CreateProjectPlainTextEdit: str = "Enter project name here"

def __post_init__(self):
"""Connect all callback-functions to widgets."""
self._setup_callbacks()
self._initialize_ui()

def _setup_callbacks(self):
"""Setup all widget actions."""
dock = self.dockwidget

# Populate the combobox
self.populate_combobox()

# Top-level UI actions
dock.SelectProjectComboBox.currentIndexChanged.connect(self.on_project_selected)
dock.CreateProjectPlainTextEdit.focusInEvent = self.create_project_text_focus
dock.CreateProjectPushButton.clicked.connect(self.create_project)

# Tab 0 actions
dock.ExportDAMOandHyDAMOPushButton.clicked.connect(self.export_damo_and_hydamo)

# Tab 1 actions
dock.ValidatePushButton.clicked.connect(self.validate_project)

def _initialize_ui(self):
"""Initialize UI elements with default states."""
self.dockwidget.CreateProjectPlainTextEdit.setPlainText(self.prewritten_text_CreateProjectPlainTextEdit)
self.dockwidget.ProjectTabWidget.setCurrentIndex(0)
self.dockwidget.ExportDAMOandHyDAMOPushButton.setEnabled(True)

def populate_combobox(self):
"""Populate the combobox with folder names from the base folder."""
if os.path.exists(BASE_FOLDER):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

liefst zoveel mogelijk pathlib.Path gebruiken.

folder_names = [f for f in os.listdir(BASE_FOLDER) if os.path.isdir(os.path.join(BASE_FOLDER, f))]
self.dockwidget.SelectProjectComboBox.addItems(folder_names)
else:
QMessageBox.warning(None, "Error", f"Base folder not found: {BASE_FOLDER}")

def update_tab_based_on_status(self):
"""Switch to the correct tab based on the project status."""
if self.project_status in range(self.dockwidget.ProjectTabWidget.count()):
self.dockwidget.ProjectTabWidget.setCurrentIndex(self.project_status)
else:
QMessageBox.warning(None, "Error", f"Invalid project status: {self.project_status}")

def on_project_selected(self):
"""Handle project selection from the combo box."""
selected_folder = self.dockwidget.SelectProjectComboBox.currentText()
full_path = os.path.join(BASE_FOLDER, selected_folder)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path(BASE_FOLDER).joinpath(selected_folder)

self.project = Project(full_path)
self.project_status = self.project.retrieve_project_status()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gelijk aan self.project.project_status? Ook daar project.status logischer?

Wat zijn de mogelijke waarden van project_status? Is daar ergens domeintabel van?

Die retrieve_project_status zoals die nu in htt staat lijkt erop dat een @property handiger is?

@property
def status(self):
    return self._status

self.update_tab_based_on_status()

def create_project(self):
"""Handle creation of a new project."""
project_name = self.dockwidget.CreateProjectPlainTextEdit.toPlainText()
if project_name.strip() and project_name != self.prewritten_text_CreateProjectPlainTextEdit:
if project_name not in os.listdir(BASE_FOLDER):
full_path = os.path.join(BASE_FOLDER, project_name)
self.project = Project(full_path)
self.dockwidget.SelectProjectComboBox.addItem(project_name)
QMessageBox.information(None, "Project", f"Project created: {project_name}")
self.dockwidget.SelectProjectComboBox.setCurrentText(project_name)
self.project_status = self.project.retrieve_project_status()
self.update_tab_based_on_status()
else:
QMessageBox.warning(None, "Error", "Project name already exists.")
else:
QMessageBox.warning(None, "Error", "Project name cannot be empty or default text.")

def create_project_text_focus(self, event):
"""Clear the text in the plain text edit when it gains focus."""
if self.dockwidget.CreateProjectPlainTextEdit.toPlainText() == self.prewritten_text_CreateProjectPlainTextEdit:
self.dockwidget.CreateProjectPlainTextEdit.clear()
QPlainTextEdit.focusInEvent(self.dockwidget.CreateProjectPlainTextEdit, event)

def load_layers_from_geopackage(self, geopackage_path, group_name):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""
Load all layers from a GeoPackage into QGIS and group them under a specified group name.

Args:
geopackage_path (str): Path to the GeoPackage file.
group_name (str): Name of the group under which to load the layers.
"""
if not os.path.exists(geopackage_path):
raise FileNotFoundError(f"GeoPackage not found: {geopackage_path}")

# Get the QGIS project instance and create/retrieve the specified group
project = QgsProject.instance()
root = project.layerTreeRoot()
group = root.findGroup(group_name) or root.addGroup(group_name)

# Use OGR to list layers in the GeoPackage
data_source = ogr.Open(geopackage_path)
if not data_source:
raise ValueError(f"Unable to open GeoPackage: {geopackage_path}")

for i in range(data_source.GetLayerCount()):
layer_name = data_source.GetLayerByIndex(i).GetName()
layer_path = f"{geopackage_path}|layername={layer_name}"
layer = QgsVectorLayer(layer_path, layer_name, "ogr")

if layer.isValid():
project.addMapLayer(layer, addToLegend=False)
group.addLayer(layer)
else:
raise ValueError(f"Failed to load layer: {layer_name}")

def export_damo_and_hydamo(self):
"""Handle export of DAMO and HyDAMO."""
file_path = self.dockwidget.SelectPolderFileWidget.filePath()
damo_gpkg_path = os.path.join(self.project.project_folder, "01_source_data", "DAMO.gpkg")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dit zou al in de folderstructuur moeten staan. Dus hier;
self.project.project_folder.source_data.damo

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

project.project_folder is ook nog beetje dubbel? project.folder duidelijker. Maar het folder object is eigenlijk ook het project dus nog even naar kijken wat dit Project dan toevoegd.


if file_path:
# DAMO export
gdf_polder = gpd.read_file(file_path)
dict_gdfs_damo = DAMO_exporter(gdf_polder, TABLE_NAMES)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zie review Wouter htt. Lijkt me beter om opslaan per tabel te doen?

Daarnaast lijkt me dit functionaliteit die je in htt wilt hebben en niet in de plugin.


for table_name, damo_gdf in dict_gdfs_damo.items():
damo_gdf.to_file(damo_gpkg_path, layer=table_name, driver="GPKG")

# Load GeoPackage layers into QGIS
try:
damo_gpkg_path = os.path.join(self.project.project_folder, "01_source_data", "DAMO.gpkg")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tweede keer declaren zelfde variabele?

self.load_layers_from_geopackage(geopackage_path=damo_gpkg_path, group_name="DAMO")
except Exception as e:
QMessageBox.warning(None, "Error", f"Failed to load DAMO layers: {e}")

# Conversion to HyDAMO
#
#

QMessageBox.information(
None, "Export", f"DAMO exported for file: {file_path}"
) # TODO later rename to HyDAMO
self.project_status = 1
self.project.update_project_status(self.project_status)
self.update_tab_based_on_status()
self.dockwidget.ValidatePushButton.setEnabled(True)
else:
QMessageBox.warning(None, "Error", "No file selected for export.")

def validate_project(self):
"""Handle validation of the project."""
QMessageBox.information(None, "Validation", "Validation not implemented yet.")
11 changes: 8 additions & 3 deletions hhnk_threedi_plugin/hhnk_toolbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@
from hhnk_threedi_plugin.gui.model_splitter.model_splitter_dialog import (
modelSplitterDialog,
)
from hhnk_threedi_plugin.gui.modelbuilder import ModelBuilder
#from hhnk_threedi_plugin.gui.modelbuilder import ModelBuilder
from hhnk_threedi_plugin.gui.schematisation_builder import SchematisationBuilder
from hhnk_threedi_plugin.gui.new_project_dialog import newProjectDialog
from hhnk_threedi_plugin.hhnk_toolbox_dockwidget import HHNK_toolboxDockWidget
from hhnk_threedi_plugin.qgis_interaction.open_notebook import NotebookWidget
Expand Down Expand Up @@ -150,7 +151,8 @@ def __init__(self, iface):
self.one_d_two_d = None
self.polder_folder = None
self.current_source_paths = None
self.modelbuilder = None
#self.modelbuilder = None
self.schematisation_builder = None

self.debug = local_settings.DEBUG

Expand Down Expand Up @@ -620,7 +622,10 @@ def run(self):
# self.bank_levels.start_bank_levels_tests.connect(self.bank_levels_execution)

# define modelbuilder. Note, all callbacks and functions you can find in ModelBuilder class
self.modelbuilder = ModelBuilder(dockwidget=self.dockwidget)
#self.modelbuilder = ModelBuilder(dockwidget=self.dockwidget)

# define schematision_builder
self.schematisation_builder = SchematisationBuilder(dockwidget=self.dockwidget)

# note that for 'klimaatsomme
# n' functions are run from the widget
Expand Down
Loading