Source code for sec_interp.gui.ui.pages.dem_page

from __future__ import annotations

"""DEM configuration page."""

from typing import Any

from qgis.core import (
    Qgis,
    QgsUnitTypes,
)
from qgis.gui import QgsDoubleSpinBox, QgsMapLayerComboBox, QgsRasterBandComboBox
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtWidgets import QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit

from sec_interp.core.validation.project_validator import (
    ProjectValidator,
    ValidationParams,
)
from sec_interp.gui.main_dialog_config import DialogDefaults

from .base_page import BasePage


[docs] class DemPage(BasePage): """Configuration page for DEM/Raster settings."""
[docs] def __init__(self, iface: Any = None, parent: Any = None) -> None: """Initialize DEM page. Args: iface: QGIS interface (optional, for resolution calculation). parent: Parent widget. """ self.iface = iface super().__init__(QCoreApplication.translate("DemPage", "Digital Elevation Model"), parent) self.iface = iface
def _setup_ui(self) -> None: super()._setup_ui() self.group_layout = QGridLayout(self.group_box) self.group_layout.setSpacing(6) self._setup_raster_selection() self._setup_band_and_resolution() self._setup_profile_settings() # Connections self.raster_combo.layerChanged.connect(self.band_combo.setLayer) self.raster_combo.layerChanged.connect(self._update_resolution) def _setup_raster_selection(self): """Set up raster layer selection widgets.""" # Row 0: Raster Layer self.group_layout.addWidget(QLabel(self.tr("Raster Layer *")), 0, 0) self.raster_combo = QgsMapLayerComboBox() self.raster_combo.setFilters(Qgis.LayerFilters(Qgis.LayerFilter.RasterLayer)) self.raster_combo.setAllowEmptyLayer(True) self.raster_combo.setToolTip(self.tr("Select the raster DEM layer")) self.raster_combo.setCurrentIndex(0) self.group_layout.addWidget(self.raster_combo, 0, 1) self.lbl_raster_status = QLabel() self.lbl_raster_status.setFixedSize(16, 16) self.group_layout.addWidget(self.lbl_raster_status, 0, 2) def _setup_band_and_resolution(self): """Set up band and resolution display widgets.""" # Row 1: Band, Resolution self.group_layout.addWidget(QLabel(self.tr("Band")), 1, 0) self.band_combo = QgsRasterBandComboBox() self.band_combo.setMinimumWidth(150) self.band_combo.setToolTip(self.tr("Select the raster band")) self.group_layout.addWidget(self.band_combo, 1, 1) self.group_layout.addWidget(QLabel(self.tr("Resolution")), 1, 2) res_layout = QHBoxLayout() self.res_edit = QLineEdit() self.res_edit.setReadOnly(True) self.res_edit.setToolTip(self.tr("Raster resolution (auto-calculated)")) self.units_edit = QLineEdit() self.units_edit.setReadOnly(True) self.units_edit.setMaximumWidth(50) res_layout.addWidget(self.res_edit) res_layout.addWidget(self.units_edit) self.group_layout.addLayout(res_layout, 1, 3) def _setup_profile_settings(self): """Set up scale and exaggeration settings.""" self.settings_group = QGroupBox(self.tr("Profile Settings")) settings_layout = QGridLayout(self.settings_group) # Scale settings_layout.addWidget(QLabel(self.tr("Scale 1:")), 0, 0) self.scale_spin = QgsDoubleSpinBox() self.scale_spin.setRange(1, 1000000) self.scale_spin.setValue(float(DialogDefaults.SCALE)) self.scale_spin.setDecimals(0) settings_layout.addWidget(self.scale_spin, 0, 1) # Vertical Exaggeration settings_layout.addWidget(QLabel(self.tr("Vert. Exag.")), 1, 0) self.vertexag_spin = QgsDoubleSpinBox() self.vertexag_spin.setRange(0.1, 100.0) self.vertexag_spin.setValue(float(DialogDefaults.VERTICAL_EXAGGERATION)) self.vertexag_spin.setSingleStep(0.5) self.vertexag_spin.setDecimals(1) settings_layout.addWidget(self.vertexag_spin, 1, 1) # Insert before the stretch (which is the last item) count = self.main_layout.count() self.main_layout.insertWidget(count - 1, self.settings_group) def _update_resolution(self): """Calculate and update resolution and suggested scale.""" layer = self.raster_combo.currentLayer() if not layer: self.res_edit.clear() self.units_edit.clear() return # Simplified resolution logic ported from old dialog # For now, we use simple native resolution logic res = layer.rasterUnitsPerPixelX() units = layer.crs().mapUnits() try: res_val = float(res) self.res_edit.setText(f"{res_val:.2f}") except (ValueError, TypeError): self.res_edit.setText(str(res)) self.units_edit.setText(QgsUnitTypes.toString(units)) # Auto-calculate scale estimate (simplified) if units == QgsUnitTypes.DistanceUnit.Meters: scale = round((res * 2000) / 1000) * 1000 if scale > 0: self.scale_spin.setValue(scale)
[docs] def get_data(self) -> dict[str, Any]: """Get DEM configuration.""" return { "raster_layer": self.raster_combo.currentLayer(), "selected_band": self.band_combo.currentBand(), "scale": self.scale_spin.value(), "vertexag": self.vertexag_spin.value(), }
[docs] def validate(self) -> tuple[bool, str]: """Validate page settings. Returns: Tuple of (success, error message). """ if not self.raster_combo.currentLayer(): return False, self.tr("Raster layer is required") return True, ""
[docs] def is_complete(self) -> bool: """Check if required fields are filled if a layer is selected.""" data = self.get_data() params = ValidationParams(raster_layer=data["raster_layer"]) return ProjectValidator.is_dem_complete(params)