SecInterp - Detailed Project Architectureο
Comprehensive Technical Documentation for the SecInterp QGIS Plugin Version 3.11.0 | Last Updated: 2026-10-24
π Table of Contentsο
π― Overviewο
SecInterp (Section Interpreter) is a QGIS plugin designed for extracting and visualizing geological data in cross-sections. The plugin allows geologists to generate topographic profiles, project geological outcrops, and analyze structural data in a unified 2D view.
Key Featuresο
β Interactive Preview System with real-time rendering and adaptive LOD (Level of Detail) based on zoom.
β Parallel Processing for complex geological intersections.
β DEM & Profile Insights: DEM band statistics and profile-vs-DEM min/max/mean, plus gradient/single-color profile styling.
β CRS Safety: mixed-CRS warnings and a blocking check for mislabelled layer CRS.
β Adaptive Vertical Exaggeration (auto, clamped
0.5Γβ20Γ) with manual override.β Optional Smoothed Topography profile (distance-window moving average) with matching smoothed geology.
β Measurement Tools with automatic snapping.
β Drillhole Support with 3Dβ2D trajectory projection.
β Multi-format Export (SHP, GPKG, DXF, CSV, PDF, SVG, PNG).
π Directory Structureο
The project organization follows a highly modular architecture based on the Separation of Concerns (SoC) principle, decoupling the interface, business logic, and export formats. Each layer has a distinct responsibility and communicates through well-defined interfaces.
sec_interp/β plugin root βlayer_pluginΒ·plugin__init__.pyβ Plugin entry point (registers with QGIS) βrootΒ· docsec_interp_plugin.pyβ Root classSecInterp(facade) βsec_interp_pluginΒ· docplugin/β Plugin mixins composed bySecInterpβpluginΒ· docmetadata.txtβ QGIS plugin metadataMakefileβ Automation (deploy, tests, docs)logger_config.pyβlogger_configΒ· doc
core/βοΈ β Business Logic (QGIS-agnostic, thread-safe) βlayer_corecontroller.pyβ OrchestratorProfileControllerβcontrollerΒ· docdata_cache.pyβdata_cacheΒ· docexceptions.pyβexceptionsΒ· docperformance_metrics.pyβperformance_metricsΒ· docalgorithms.pyβ Reserved placeholder for pure business-logic algorithms βlayer_coredomain/β DTOsProfileData,GeologySegment; modulesdtos.py,entities.py,enums.py,spatial_meta.py,task_inputs.pyβdomainΒ·layer_core_domainΒ· docinterfaces/β ABCs for DI (IGeologyService,IDrillholeService,IPreviewService, β¦) βlayer_core_interfacesmodels/settings_model.pyβ Typed settings βlayer_core_modelsvalidation/β Modular pipeline βcore_validationΒ·layer_core_validationΒ· docvalidation/pipeline.py,layer_validator.py,field_validator.py,path_validator.py,project_validator.pyβcore_validationvalidation/crs_plausibility.pyβ Best-effort mislabelled-CRS detection from extent plausibility βcrs_plausibilityΒ· docvalidation/layer_metadata.pyβ QGIS-agnostic layer metadata for validation βlayer_metadataΒ· doc
utils/β Helpers (pure Python) βlayer_core_utilsutils/safe_loader.pyβsafe_loaderΒ· docutils/i18n.pyβcore_utilsΒ· docutils/geometry_utils/(measurement.py,optimization.py,processing.py) βlayer_core_utils_geometry_utils
services/β Concrete implementations βlayer_core_servicesservices/geology_service.pyβgeology_serviceΒ· docservices/structure_service.pyβstructure_serviceΒ· docservices/drillhole_service.pyβdrillhole_serviceΒ· docservices/export_service.pyβ 13-line compatibility shim βcore_servicesΒ· docservices/export/β Export package (orchestrator + handlers) βcore_services_exportΒ·layer_core_services_exportΒ· docservices/export/orchestrator.py,path_resolver.py,compat.py; map settings factory lives inexporters/map_settings.pyservices/export/handlers/(topography, geology, structures, drillholes, drillholes_3d, interpretations, axes) βlayer_core_services_export_handlers
services/preview_service.pyβpreview_serviceΒ· docservices/vertical_exaggeration_service.pyβvertical_exaggeration_serviceΒ· docservices/access_control_service.pyβcore_servicesΒ· docservices/drillhole/β Drillhole pipeline βlayer_core_services_drillholeservices/drillhole/collar_processor.pyβcollar_processorΒ· docservices/drillhole/survey_processor.pyβcore_services_drillholeΒ· docservices/drillhole/interval_processor.pyβinterval_processorΒ· docservices/drillhole/projection_engine.pyβcore_services_drillholeΒ· docservices/drillhole/trajectory_engine.pyβtrajectory_engineΒ· doc
gui/π₯οΈ β UI Layer (QGIS-dependent) βlayer_guigui/main_dialog.pyβSecInterpDialogorchestrator βmain_dialogΒ· docgui/dialog_dependencies.pyβ Narrow dependency containers injected into managers (composition root) βlayer_guigui/dialog_message_mixin.py,dialog_lifecycle_mixin.py,dialog_facade_mixin.pyβ Message / lifecycle / facade mixins βmain_dialoggui/interpretation_inheritance_mixin.py,interpretation_persistence_mixin.pyβ Attribute inheritance (nearest geology/drillhole) + project persistence βdialog_interpretation_managergui/main_dialog_config.py,main_dialog_utils.pyβ Dialog configuration, defaults and UI helpers βmain_dialoggui/utils.pyβ General-purpose UI helpers and user messaging βlayer_guigui/adapters/β Extract phase (QGIS β DTOs) βgui_adaptersΒ·layer_gui_adaptersΒ· docadapters/drillhole_extractor.pyβdrillhole_extractorΒ· docadapters/geology_extractor.pyβgeology_extractorΒ· docadapters/structure_extractor.pyβstructure_extractorΒ· docadapters/validation_extractor.pyβvalidation_extractorΒ· docadapters/profile_extractor.pyβprofile_extractorΒ· docadapters/feature_fetcher.py,layer_resolver.py,geometry.pyβgui_adapters
Managers (orchestration)
dialog_signal_manager.pyβdialog_signal_managerΒ· docdialog_input_manager.pyβdialog_input_managerΒ· docdialog_preview_manager.pyβdialog_preview_managerΒ· docdialog_export_manager.pyβdialog_export_managerΒ· docdialog_interpretation_manager.pyβdialog_interpretation_managerΒ· docdialog_state_manager.pyβdialog_state_managerΒ· docdialog_settings_persistence.pyβdialog_state_managerΒ· docdialog_tool_manager.pyβdialog_tool_managerΒ· doclayer_notification_manager.pyβlayer_notification_managerΒ· docui_status_manager.pyβui_status_managerΒ· doc
dialogs/β Modal dialogs βlayer_gui_dialogsdialogs/interpretation_properties_dialog.pyβlayer_gui_dialogs
Rendering Engine
preview_renderer.pyβpreview_rendererΒ· docpreview_layer_factory.pyβpreview_layer_factoryΒ· docpreview_axes_manager.pyβpreview_axes_managerΒ· docpreview_param_hasher.pyβ Render-parameter hashing for LOD cache invalidation βpreview_param_hasherΒ· docpreview_render_mixin.py,preview_callbacks_mixin.pyβ Rendering and async-task callback mixins βpreview_render_mixinΒ· docpreview_task_orchestrator.pyβ Queues, prioritizes and monitors background preview tasks βpreview_task_orchestratorΒ· docpreview_legend_renderer.pyβ Draws the legend (topography, structures, units) on aQPainterβpreview_legend_rendererΒ· docpreview_reporter.pyβpreview_stateΒ· docpreview_state.pyβpreview_stateΒ· docpreview_side_panel.pyβ collapsible legend side panel (per-unit hide/color/alias, interpretations list)
renderers/βgui_renderersΒ·layer_gui_renderersΒ· docrenderers/base_renderer.py,topo/geology/drillhole/structure/interpretation_renderer.py,color_manager.py
tasks/(geology_task.py,drillhole_task.py) βgui_tasksΒ·layer_gui_tasksΒ· doctools/β Interactive map tools βlayer_gui_toolstools/measure_tool.pyβmeasure_toolΒ· doctools/interpretation_tool.pyβinterpretation_toolΒ· doctools/snapper.py
ui/β Programmatic window + sidebar βlayer_gui_uiui/main_window.py,ui/sidebar.pyβgui_ui_pagesΒ· docui/pages/β Tab-based pages βlayer_gui_ui_pagesui/pages/base_page.py,dem_page.py,section_page.py,geology_page.py,structure_page.py,preview_page.pyβgui_ui_pagesui/pages/section_feature_selector.pyβ 2-vertex section selector (fid β label, label field) βgui_ui_pagesΒ· docui/pages/interpretation_page.pyβ compatibility shim forInterpretationTabΒ· docui/pages/drillhole_page.pyβdrillhole_pageΒ· docui/pages/drillhole/(collar / survey / interval tabs) βgui_ui_pages_drillholeΒ·layer_gui_ui_pages_drillholeΒ· docui/pages/settings_page.pyβsettings_pageΒ· docui/pages/settings/(default / advanced / symbology / interpretation tabs + persistence) βgui_ui_pages_settingsΒ·layer_gui_ui_pages_settingsΒ· doc
exporters/π€ β FactoryBaseExporterβlayer_exportersbase_exporter.pyβbase_exporterΒ· docvector_exporter.pyβvector_exporterΒ· docdxf_exporter.pyβdxf_exporterΒ· docprofile_exporters.py/csv_exporter.pyβprofile_exportersΒ·csv_exporterΒ· docinterpretation_3d_exporter.pyβinterpretation_3d_exporterΒ· docinterpretation_exporters.pyβinterpretation_exportersΒ· docdrillhole_3d_exporter.pyβdrillhole_3d_exporterΒ· docdrillhole_exporters.pyβdrillhole_exportersΒ· docpdf_exporter.pyβpdf_exporterΒ· docsvg_exporter.pyβsvg_exporterΒ· docimage_exporter.pyβimage_exporterΒ· doc
docs/π βARCHITECTURE_EN.md(this file) Β·ARCHITECTURE.mmdΒ·code_walkthrough_v2/vaulttests/π§ͺ βbase_test.py,core/,gui/,exporters/,integration/,agentic/,mcp/,mocks/,benchmarks/(Mock-First,unittest)scripts/π§ βsecurity_scan.pyΒ·build_docs.shΒ·i18n/Β·sync_vault_mirrors.shresources/π¨ βicons/,styles/,resources.qrcβresources.py
[!tip] En Obsidian este Γ‘rbol es navegable: cada
[slug](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/slug.md)abre la nota de la bΓ³veda y alimenta el Graph View. En GitHub/Sphinx usa el link[doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/slug.md)relativo. Los espejos endocs/code_walkthrough*/ARCHITECTURE_EN.mdse re-sincronizan conbash scripts/sync_vault_mirrors.sh.
ποΈ System Architectureο
Complete Architecture Diagramο
graph TD
classDef module fill:#f9f,stroke:#333,stroke-width:2px;
classDef manager fill:#e1f5fe,stroke:#0277bd,stroke-width:2px;
classDef service fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
classDef interface fill:#fff3e0,stroke:#ef6c00,stroke-width:2px,stroke-dasharray: 5 5;
classDef exporter fill:#fce4ec,stroke:#c2185b,stroke-width:2px;
classDef task fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px;
classDef renderer fill:#e0f2f1,stroke:#00695c,stroke-width:2px;
%% ========== ENTRY POINT ==========
QGIS[QGIS Application]
PLUGIN[sec_interp_plugin.py<br/>SecInterp Class<br/>Plugin Root]
%% ========== GUI LAYER ==========
subgraph GUI["π₯οΈ GUI Layer - User Interface"]
direction TB
MAIN[main_dialog.py<br/>SecInterpDialog]
subgraph MANAGERS["Managers (Orchestration)"]
direction TB
SIGNALS_MGR[dialog_signal_manager.py<br/>DialogSignalManager]:::manager
INPUT_MGR[dialog_input_manager.py<br/>DialogInputManager]:::manager
PREVIEW_MGR[dialog_preview_manager.py<br/>PreviewManager]:::manager
EXPORT_MGR[dialog_export_manager.py<br/>ExportManager]:::manager
INTERP_MGR[dialog_interpretation_manager.py<br/>InterpretationManager]:::manager
STATE_MGR[dialog_state_manager.py<br/>DialogStateManager]:::manager
SETTINGS_MGR[dialog_settings_persistence.py<br/>SettingsPersistence]:::manager
TOOL_MGR[dialog_tool_manager.py<br/>ToolManager]:::manager
LAYER_NOTIF[layer_notification_manager.py<br/>LayerNotificationManager]:::manager
UI_STATUS[ui_status_manager.py<br/>UIStatusManager]:::manager
end
subgraph RENDERING["Rendering Engine"]
direction TB
LAYER_FACTORY[preview_layer_factory.py<br/>PreviewLayerFactory]
AXES_MGR[preview_axes_manager.py<br/>PreviewAxesManager]
RENDERER[preview_renderer.py<br/>PreviewRenderer]
REPORTER[preview_reporter.py<br/>PreviewReporter]
PARAM_HASH[preview_param_hasher.py<br/>PreviewParamHasher]
PREVIEW_STATE[preview_state.py<br/>PreviewState]
end
subgraph RENDERERS["Specialized Renderers"]
direction TB
BASE_RENDERER[renderers/base_renderer.py<br/>BaseRenderer]:::renderer
TOPO_RENDERER[renderers/topo_renderer.py<br/>TopoRenderer]:::renderer
GEOLOGY_RENDERER[renderers/geology_renderer.py<br/>GeologyRenderer]:::renderer
DRILLHOLE_RENDERER[renderers/drillhole_renderer.py<br/>DrillholeRenderer]:::renderer
STRUCT_RENDERER[renderers/structure_renderer.py<br/>StructureRenderer]:::renderer
INTERP_RENDERER[renderers/interpretation_renderer.py<br/>InterpretationRenderer]:::renderer
COLOR_MGR[renderers/color_manager.py<br/>ColorManager]:::renderer
end
subgraph WORKERS["Async Tasks (QgsTask)"]
direction TB
TASK_ORCH[preview_task_orchestrator.py<br/>PreviewTaskOrchestrator]:::task
GEOLOGY_TASK[tasks/geology_task.py<br/>GeologyTask]:::task
DRILL_TASK[tasks/drillhole_task.py<br/>DrillholeTask]:::task
end
subgraph TOOLS["Map Tools"]
direction TB
MAP_TOOLS[tools/<br/>QgsMapTool Implementations]
end
subgraph UI_PAGES["UI Components"]
direction TB
PAGES[ui/pages/<br/>Tab-based Pages]
ADAPTERS[adapters/<br/>UI Adapters]
SIDE_PANEL[preview_side_panel.py<br/>Preview Side Panel]
SYMBOLOGY[symbology_tab.py<br/>Live Symbology]
end
MAIN --> MANAGERS
MAIN --> RENDERING
MAIN --> RENDERERS
MAIN --> WORKERS
MAIN --> TOOLS
MAIN --> UI_PAGES
MAIN --> SIDE_PANEL
MAIN --> SYMBOLOGY
MANAGERS --> RENDERING
MANAGERS --> WORKERS
MANAGERS --> UI_PAGES
WORKERS --> TASK_ORCH
RENDERING --> RENDERERS
end
%% ========== CORE LAYER ==========
subgraph CORE["βοΈ Core Layer - Business Logic"]
direction TB
CONTROLLER[controller.py<br/>ProfileController]
subgraph INTERFACES["Abstractions (DI) - interfaces/"]
direction TB
I_GEOL[interfaces/geology_interface.py<br/>IGeologyService]:::interface
I_DRILL[interfaces/drillhole_interface.py<br/>IDrillholeService]:::interface
I_STRUCT[interfaces/structure_interface.py<br/>IStructureService]:::interface
I_PREVIEW[interfaces/preview_interface.py<br/>IPreviewService]:::interface
I_CACHE[interfaces/cache_interface.py<br/>ICacheService]:::interface
I_RENDER3D[interfaces/i_renderer_3d.py<br/>IRenderer3D]:::interface
end
subgraph SERVICES["Concrete Services - services/"]
direction TB
GEOL_SVC[services/geology_service.py<br/>GeologyService]:::service
STRUCT_SVC[services/structure_service.py<br/>StructureService]:::service
DRILL_SVC[services/drillhole_service.py<br/>DrillholeService]:::service
EXPORT_SVC[services/export_service.py<br/>ExportService]:::service
PREVIEW_SVC[services/preview_service.py<br/>PreviewService]:::service
VE_SVC[services/vertical_exaggeration_service.py<br/>VerticalExaggerationService]:::service
ACCESS_SVC[services/access_control_service.py<br/>AccessControlService]:::service
subgraph DRILLHOLE_PKG["Drillhole Sub-system"]
direction TB
COLLAR_PROC[drillhole/collar_processor.py<br/>CollarProcessor]
SURVEY_PROC[drillhole/survey_processor.py<br/>SurveyProcessor]
INTERVAL_PROC[drillhole/interval_processor.py<br/>IntervalProcessor]
PROJ_ENGINE[drillhole/projection_engine.py<br/>ProjectionEngine]
TRAJ_ENGINE[drillhole/trajectory_engine.py<br/>TrajectoryEngine]
DRILL_SVC --> COLLAR_PROC
DRILL_SVC --> SURVEY_PROC
DRILL_SVC --> INTERVAL_PROC
DRILL_SVC --> TRAJ_ENGINE
COLLAR_PROC --> PROJ_ENGINE
SURVEY_PROC --> TRAJ_ENGINE
TRAJ_ENGINE --> PROJ_ENGINE
end
end
subgraph MODELS["Domain Models - models/"]
direction TB
SETTINGS_MODEL[models/settings_model.py<br/>SettingsModel]
end
subgraph DOMAIN["Domain Layer - domain/"]
direction TB
ENTITIES[Entities & DTOs<br/>ProfileData, GeologySegment,<br/>DrillholeData, etc.]
end
subgraph VALIDATION["Validation Pipeline - validation/"]
direction TB
BASE_VAL[base_validator.py<br/>BaseValidator]
PIPELINE[pipeline.py<br/>ValidationPipeline]
LAYER_VAL[layer_validator.py<br/>LayerValidator]
FIELD_VAL[field_validator.py<br/>FieldValidator]
PATH_VAL[path_validator.py<br/>PathValidator]
PROJECT_VAL[project_validator.py<br/>ProjectValidator]
PROJECT_VALS[project_validators.py<br/>ProjectValidators]
HELPERS[validation_helpers.py<br/>ValidationHelpers]
VALIDATORS[validators.py<br/>Validators]
end
subgraph UTILS["Utilities - utils/"]
direction TB
DRILL_UTIL[drillhole.py<br/>Drillhole Utils]
GEOL_UTIL[geology.py<br/>Geology Utils]
GEOM_UTIL[geometry_utils/<br/>Geometry Utilities]
I18N_UTIL[i18n.py<br/>i18n Utils]
IO_UTIL[io.py<br/>IO Utils]
META_UTIL[metadata_reader.py<br/>Metadata Reader]
PARSE_UTIL[parsing.py<br/>Parsing Utils]
RENDER_UTIL[rendering.py<br/>Rendering Utils]
SAFE_LOADER[safe_loader.py<br/>Safe Loader]
SAMPLE_UTIL[sampling.py<br/>Sampling Utils]
SPATIAL_UTIL[spatial.py<br/>Spatial Utils]
end
CONTROLLER --> INTERFACES
INTERFACES -.-> SERVICES
SERVICES --> MODELS
SERVICES --> DOMAIN
SERVICES --> VALIDATION
SERVICES --> UTILS
CONTROLLER --> VALIDATION
end
%% ========== EXPORTERS LAYER ==========
subgraph EXPORTERS["π€ Exporters Layer"]
direction TB
BASE_EXPORT[exporters/base_exporter.py<br/>BaseExporter]:::exporter
subgraph VECTOR["Vector Exporters"]
direction TB
VEC_EXPORT[exporters/vector_exporter.py<br/>VectorExporter<br/>GPKG/SHP/DXF]:::exporter
DXF_EXPORT[exporters/dxf_exporter.py<br/>DxfExporter]:::exporter
end
subgraph PROFILE["Profile Exporters"]
direction TB
PROF_EXPORT[exporters/profile_exporters.py<br/>ProfileExporters]:::exporter
CSV_EXPORT[exporters/csv_exporter.py<br/>CsvExporter]:::exporter
end
subgraph INTERP_3D["3D Geologic Export"]
direction TB
INTERP_3D[exporters/interpretation_3d_exporter.py<br/>Interpretation3DExporter]:::exporter
INTERP_EXP[exporters/interpretation_exporters.py<br/>InterpretationExporters]:::exporter
end
subgraph DRILL_3D["3D Drillhole Export"]
direction TB
DRILL_3D[exporters/drillhole_3d_exporter.py<br/>Drillhole3DExporter]:::exporter
DRILL_EXP[exporters/drillhole_exporters.py<br/>DrillholeExporters]:::exporter
end
subgraph DOCUMENT["Document Exporters"]
direction TB
PDF_EXPORT[exporters/pdf_exporter.py<br/>PdfExporter]:::exporter
SVG_EXPORT[exporters/svg_exporter.py<br/>SvgExporter]:::exporter
IMG_EXPORT[exporters/image_exporter.py<br/>ImageExporter]:::exporter
end
BASE_EXPORT --> VEC_EXPORT
BASE_EXPORT --> PROF_EXPORT
BASE_EXPORT --> INTERP_3D
BASE_EXPORT --> DRILL_3D
BASE_EXPORT --> PDF_EXPORT
BASE_EXPORT --> SVG_EXPORT
BASE_EXPORT --> IMG_EXPORT
VEC_EXPORT --> DXF_EXPORT
PROF_EXPORT --> CSV_EXPORT
INTERP_3D --> INTERP_EXP
DRILL_3D --> DRILL_EXP
end
%% ========== CONNECTIONS ==========
QGIS --> PLUGIN
PLUGIN --> MAIN
%% GUI -> Core
PREVIEW_MGR --> PREVIEW_SVC
EXPORT_MGR --> EXPORT_SVC
INTERP_MGR --> DRILL_SVC
INTERP_MGR --> GEOL_SVC
TOOL_MGR --> CONTROLLER
%% Workers -> Controller
TASK_ORCH --> CONTROLLER
GEOLOGY_TASK --> CONTROLLER
DRILL_TASK --> CONTROLLER
%% Core -> Exporters
EXPORT_SVC --> EXPORTERS
%% Styles
classDef plugin fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px,color:#fff
class PLUGIN plugin
π₯οΈ GUI Layer - User Interfaceο
1. Manager-Based Orchestration (main_dialog.py)ο
Main Class: SecInterpDialog
Responsibility: The main dialog no longer contains business logic. It coordinates specialized Managers that handle specific lifecycle events and UI state.
Key Managers (10 Specialized Managers)ο
Manager |
File |
Responsibility |
|---|---|---|
|
|
Centralizes all signal/slot connections to avoid spaghetti code. |
|
|
Manages input layer selection, schema validation, and layer compatibility. |
|
|
Coordinates the preview canvas, axes, LOD calculation, and render triggering. |
|
|
Maps UI selections to the |
|
|
Handles 2D/3D geological interpretation state and user interactions. |
|
|
Manages session persistence and UI defaults restoration. |
|
|
Handles QSettings-based persistence for plugin configuration. |
|
|
Manages |
|
|
Listens to QGIS layer tree changes and updates UI accordingly. |
|
|
Manages status bar messages, progress indicators, and user notifications. |
2. Rendering Engineο
Responsibility: Handles all preview canvas rendering with adaptive LOD and specialized renderers.
Core Rendering Componentsο
Component |
File |
Responsibility |
|---|---|---|
|
|
Main canvas renderer orchestrating specialized renderers. |
|
|
Creates temporary memory layers for preview visualization. |
|
|
Manages coordinate axes, grids, and scale annotations. |
|
|
Generates textual/tabular reports from preview data. |
|
|
Hashes render parameters for LOD cache invalidation. |
|
|
Encapsulates preview viewport, scale, and visibility state. |
Specialized Renderers (Renderer Pattern)ο
Renderer |
File |
Responsibility |
|---|---|---|
|
|
Abstract base with common rendering utilities. |
|
|
Renders topography profiles with elevation data. |
|
|
Renders geological units, contacts, and structures. |
|
|
Renders drillhole traces, intervals, and projections. |
|
|
Renders structural measurements (strike/dip, foliations). |
|
|
Renders user-drawn geological interpretations. |
|
|
Centralized color palette and legend management. |
LOD Optimization Methods (in PreviewRenderer):
Method |
Purpose |
Algorithm |
|---|---|---|
|
Line simplification |
Douglas-Peucker |
|
Local curvature calculation |
Angle between segments |
|
Adaptive sampling |
Curvature-based density |
3. Async Task System (QgsTask)ο
Responsibility: Offloads heavy computation to background threads keeping UI responsive.
Task |
File |
Responsibility |
|---|---|---|
|
|
Queues, prioritizes, and monitors background tasks. |
|
|
Background geological intersection calculations. |
|
|
Background drillhole trajectory processing. |
4. Map Tools & UI Componentsο
Map Tools (
tools/):QgsMapToolimplementations for interactive editing (pan, measure, interpretation drawing).UI Pages (
ui/pages/): Page components for each plugin module; Interpretation Settings is hosted as a tab inSettingsPage, not a sidebar page.Section feature selector (
ui/pages/section_feature_selector.py): only single-part lines with exactly two vertices; showsfid β label, supportsAutoor an attribute label field, and forwardssection_feature_idto preview/export/LOD.Interpretation settings tab (
ui/pages/settings/interpretation_tab.py): storage source (project JSON vs vector layer), custom fields and attribute inheritance;MainWindow.page_interpretationaliases the tab for compatibility.UI Adapters (
adapters/): Adapters bridging QGIS widgets to internal models.PreviewSidePanel (
preview_side_panel.py): Collapsible legend beside the preview, synchronized with the renderers; per-unit hide/color/alias, drillhole lithologies and the interpretations list.Symbology tab (
ui/pages/settings/symbology_tab.py,symbology_units.py): Live per-layer styles (topography, structures, drillholes, interpretations), the shared per-unit editor and the legend layout (position, font size, max items).
βοΈ Core Layer - Business Logicο
1. Interface-Driven Design (interfaces/)ο
Pattern: Dependency Injection (DI) via Abstract Base Classes (ABCs)
Responsibility: All services are defined as interfaces. The ProfileController consumes interfaces, allowing for easy mocking during testing and replacement of logic without affecting the GUI.
class IGeologyService(ABC):
@abstractmethod
def build_segments(self, context: GeologyContext, feedback: Any | None = None) -> Any:
"""Build geological segments from a detached context."""
Core Interfaces (6 Interfaces)ο
Interface |
File |
Purpose |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. ProfileController (controller.py)ο
Responsibility: Central orchestrator coordinating all services through their interfaces.
Concrete Services (7 Services)ο
Service |
File |
Responsibility |
|---|---|---|
|
|
Core intersection algorithms (outcrops, polygons, units). |
|
|
Structural data processing, validation, stereonets. |
|
|
3D trajectory calculation, 2D section projection, interval management. |
|
|
Central orchestrator for Exporters layer, format registry. |
|
|
Preview data preparation, LOD computation, render DTOs. |
|
|
Adaptive vertical exaggeration from profile aspect ratio and structural density. |
|
|
License validation, feature gating, user permissions. |
Drillhole Sub-system (5 Components)ο
Component |
File |
Responsibility |
|---|---|---|
|
|
Collar data validation, coordinate transformation. |
|
|
Survey data (azimuth/dip) processing, interpolation. |
|
|
Lithology/assay interval management, merging. |
|
|
3D trajectory calculation (minimum curvature, etc.). |
|
|
3Dβ2D projection onto section plane. |
Geology Sub-systemο
Geology processing is consolidated in
services/geology_service.py(the formerservices/geology/package was removed).
3. Domain Layerο
Domain Models (
models/settings_model.py):SettingsModelfor typed configuration.Entities & DTOs (
domain/): Immutable data transfer objects (ProfileData,GeologySegment,DrillholeData, etc.) for layer communication.
4. Validation Pipeline (validation/)ο
Modular validation framework with 11 validators coordinated by ValidationPipeline:
Validator |
File |
Scope |
|---|---|---|
|
|
Abstract base with common validation utilities. |
|
|
Orchestrates validators, aggregates results. |
|
|
QGIS layer structure, CRS, geometry type validation. |
|
|
Attribute field names, types, required fields. |
|
|
File/directory paths, permissions, existence. |
|
|
Project-level consistency (layers, settings). |
|
|
Composite project validation rules. |
|
|
Shared validation utilities, error formatting. |
|
|
Convenience functions for common validations. |
|
|
QGIS-agnostic layer metadata DTO consumed by the pipeline. |
|
|
Best-effort mislabelled-CRS detection from extent plausibility. |
5. Utilities (utils/)ο
11 specialized utility modules:
Utility |
File |
Purpose |
|---|---|---|
Drillhole Utils |
|
Drillhole-specific calculations, transformations. |
Geology Utils |
|
Geological computations, unit conversions. |
Geometry Utils |
|
Advanced geometry operations (intersections, buffers). |
i18n Utils |
|
Translation helpers, locale management. |
QGIS I/O |
|
Vector writer adapter (Shapefile/GPKG/DXF). |
Metadata Reader |
|
QGIS layer metadata extraction. |
Parsing Utils |
|
Text/CSV/XML parsing with error recovery. |
Rendering Utils |
|
Render-ready data preparation. |
Safe Loader |
|
Safe YAML/JSON loading with schema validation. |
Sampling Utils |
|
Statistical sampling, profile point generation. |
Spatial Utils |
|
Spatial queries, indexing, CRS operations. |
π€ Exporters Layerο
The Exporters layer implements the Factory Pattern via BaseExporter abstract class. All exporters consume QGIS-agnostic DTOs from core/domain.
Export Hierarchyο
BaseExporter (ABC)
βββ VectorExporter β DxfExporter
β βββ GPKG, SHP, DXF output
β βββ Layer-based feature export
βββ ProfileExporters β CsvExporter
β βββ Profile data (CSV, Excel)
β βββ Sampling results export
βββ Interpretation3DExporter β InterpretationExporters
β βββ 3D geological interpretations (Z-aware)
β βββ GeoPackage 3D, CityJSON
βββ Drillhole3DExporter β DrillholeExporters
β βββ 3D drillhole traces (Z-aware)
β βββ Interval data as 3D cylinders
βββ PdfExporter
β βββ Professional layouts with legends
β βββ Multi-page section reports
βββ SvgExporter
β βββ Vector graphics for publications
β βββ Scalable section diagrams
βββ ImageExporter
βββ PNG/JPG raster output
βββ High-DPI for presentations
Key Exportersο
Exporter |
File |
Formats |
Purpose |
|---|---|---|---|
|
|
GPKG, SHP, DXF |
Unified vector export for sections. |
|
|
DXF |
CAD-compatible export. |
|
|
CSV, XLSX |
Profile data tables, sampling results. |
|
|
CSV |
Raw data export. |
|
|
GPKG 3D, CityJSON |
3D geological interpretations. |
|
|
Multiple |
Interpretation-specific formats. |
|
|
GPKG 3D, WellKnown Text |
3D drillhole traces & intervals. |
|
|
Multiple |
Drillhole-specific formats. |
|
|
Professional section layouts. |
|
|
|
SVG |
Vector graphics for reports. |
|
|
PNG, JPG |
Raster images for presentations. |
Format Decouplingο
All exporters implement:
export(dto: ExportDTO, output_path: Path) -> ExportResultConsume only
core/domainDTOs (no QGIS dependencies)Return structured
ExportResultwith metadata (files created, features exported, warnings)
π¨ Design Principlesο
SecInterp v3.9.1 follows industry-standard architectural patterns to ensure high quality and testability.
Core Architectural Patternsο
Manager Pattern (GUI): Decouples the main window from individual feature logic (Export, Preview, etc.).
Dependency Injection (Core): Uses
core/interfacesto decouple theProfileControllerfrom concrete service implementations.Factory Pattern (Exporters): The
ExportServicedynamically selects the appropriateBaseExportersubclass.Observer Pattern (Signals): Extensive use of
qgis.PyQt.QtCore.pyqtSignalfor asynchronous communication between Core and GUI.DTO Pattern (Data Transfer Objects): All data passing between layers is encapsulated in immutable DTOs from
core/domain.
SOLID & Clean Codeο
Interface Segregation: Clients only depend on the specific service interfaces they need.
Single Responsibility: Each Manager and Service handles a unique, atomic part of the plugin workflow.
Thread Safety: Long-running operations only use
QgsTaskto avoid blocking the QGIS main thread.
π Extensibilityο
Adding a New Serviceο
Define the interface in
core/interfaces/(inheriting fromabc.ABC).Implement the concrete service in
core/services/.Register the service in
controller.pyand inject it into theProfileController.
Adding a New Export Formatο
Inherit from
BaseExporterinexporters/.Implement the
export()method using QGIS-agnostic logic.Update the
ExportServiceto include the new format in its registry.
π Project Metricsο
Metric |
Value |
|---|---|
Python Modules |
200 |
Source Lines of Code (SLOC) |
~24,400 |
Core Layer |
~34% |
GUI Layer |
~54% |
Exporters Layer |
~9% |
Plugin Layer |
~2% |
π Quality Assurance & Security Scanningο
SecInterp implements a multi-layered quality assurance strategy that replicates and extends the QGIS Plugin Portalβs automated scanning pipeline.
1. Local Security Scanning (Portal-Compatible)ο
The project includes a custom security scanner (scripts/security_scan.py) that runs the exact same tools used by QGIS Plugin Portal:
Tool |
Severity |
Purpose |
Configuration |
|---|---|---|---|
Bandit |
CRITICAL (Blocking) |
Static analysis for Python security vulnerabilities (shell injection, pickle, eval, hardcoded secrets, weak crypto, SQL injection) |
|
detect-secrets |
CRITICAL (Blocking) |
Scans for hardcoded credentials, API keys, private keys, high-entropy strings |
|
Flake8 |
INFO (Non-blocking) |
Code quality, PEP 8 style, syntax errors, undefined names |
|
Run locally:
make security-scan # Full portal-compatible scan
make pylint # Additional static analysis
make pep8 # Ruff-based style check (faster)
2. QGIS Plugin Analyzer (Deep Auditing)ο
For architectural and deep code quality audits beyond Portal scanning:
# Security (Bandit + detect-secrets)
uv run qgis-analyzer security .
# Internationalization coverage
uv run qgis-analyzer analyze i18n .
# Performance (UI blocks, expensive loops, signal leaks)
uv run qgis-analyzer analyze performance .
# Architecture (Core/GUI separation, QGIS API usage, circular deps)
uv run qgis-analyzer analyze architecture .
# Full HTML report
uv run qgis-analyzer analyze . --report
Workflow: /audit-plugin (agent @auditor with skills: project-context, coding-standards, i18n-standards)
3. Qt6 / QGIS 4 Migration Readinessο
Automated compatibility checking using the same tool QGIS Portal runs on upload:
make qt6-check # Dry-run check (pyqgis4-checker via Docker)
make qt6-fix # Auto-migrate enums to scoped Qt6 form (edits files)
4. Pre-Release Validation Pipelineο
Complete validation before any release candidate:
make pre-release # Runs: qt6-check + security-scan + docker-test
docker-test executes the full suite (763 tests, including 76 integration tests) in a clean QGIS Docker environment.
5. CI/CD Integrationο
All tools are configured to run in CI pipelines with:
Zero critical Bandit findings required for merge
Zero detect-secrets findings (above baseline) required for merge
Flake8 warnings reported but non-blocking
Full test suite (unit + integration) must pass
6. Configuration Files (Committed to Repo)ο
File |
Purpose |
Portal Compatible |
|---|---|---|
|
Bandit test selection, exclude dirs |
β |
|
detect-secrets baseline, filters, excludes |
β |
|
Flake8 rules, complexity, output format |
β |
|
Ruff, pytest, mypy config |
β οΈ (dev only) |
π Final Notesο
This document provides a detailed overview of the SecInterp plugin architecture. For development information, please refer to [README_DEV.md](file:///home/jmbernales/qgispluginsdev/sec_interp/README_DEV.md).
Last Updated: 2026-10-24 Plugin Version: 3.11.0 Author: Juan M. Bernales