Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add map2loop processing tool dialogs accessible from plugin menu - #54

Closed
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components
Closed

Add map2loop processing tool dialogs accessible from plugin menu#54
lachlangrose with Copilot wants to merge 196 commits into
mainfrom
copilot/create-separate-gui-components

Conversation

CopilotAI commented Oct 22, 2025

Copy link
Copy Markdown
Contributor

Overview

This PR implements popup dialog components for each of the map2loop processing tools, accessible from the plugin menu. These tools call the map2loop API classes directly instead of using QGIS processing algorithms, providing a more direct integration with the map2loop library.

Changes

Dialog Components Created

Five dialog components have been added in loopstructural/gui/map2loop_tools/:

  1. SamplerDialog - Contact sampling

    • Supports both Decimator and Spacing algorithms from map2loop
    • Calls SamplerDecimator and SamplerSpacing directly
    • Dynamic UI that adapts to sampler type selection
    • Proper validation for required vs. optional inputs
  2. SorterDialog - Automatic stratigraphic column sorting

    • Supports 6 sorting algorithms (Age-based, NetworkX, Adjacency α, Maximise contacts, Observation projections)
    • Dynamic UI that shows/hides fields based on selected algorithm
    • Special support for observation projections with structure data and DTM
  3. UserDefinedSorterDialog - Manual stratigraphic column definition

    • Table-based interface with add/remove/move up/down functionality
    • Intuitive ordering from youngest (top) to oldest (bottom)
  4. BasalContactsDialog - Basal contacts extraction

    • Integrates with geology, faults, and stratigraphic order layers
    • Configurable units to ignore
    • Outputs both basal contacts and all contacts
  5. ThicknessCalculatorDialog - Stratigraphic thickness calculation

    • Supports InterpolatedStructure and StructuralPoint methods
    • Full integration with orientation data, DTM, and contact layers
    • Configurable parameters for each method

Menu Integration

Added 5 new menu items under Plugins → LoopStructural:

  • Sampler
  • Automatic Stratigraphic Sorter
  • User-Defined Stratigraphic Column
  • Extract Basal Contacts
  • Thickness Calculator

Each menu item opens a popup dialog with the corresponding tool interface.

Direct map2loop API Usage

The sampler dialog demonstrates calling map2loop classes directly:

  • Imports SamplerDecimator and SamplerSpacing from map2loop.sampler
  • Converts QGIS layers to GeoDataFrames
  • Calls sampler methods directly: sampler.sample(spatial_data_gdf)
  • Converts results back to QGIS layers and adds to project

This pattern provides a thin interface layer over the map2loop API, allowing users to leverage map2loop's capabilities directly from QGIS.

Architecture

Each dialog follows established plugin patterns:

  • Dialog wrapper contains the corresponding widget
  • Widgets extend QWidget with corresponding .ui file loaded via uic.loadUi()
  • Implements get_parameters() and set_parameters() methods for reusability
  • Dynamic UI updates based on user selections
  • Automatic field combo box binding when layers change
  • Comprehensive input validation with user-friendly error messages

Design Philosophy Compliance

This implementation adheres to the plugin's architectural principles:

  • Thin Interface Layer: Dialogs handle only UI and user interaction, delegating all processing to map2loop API classes
  • Modularity: Each dialog is self-contained and can be launched independently from the menu
  • Object-Oriented Design: Clear responsibilities, proper encapsulation, and consistent interfaces
  • Code Quality: All code passes linting checks (ruff) and follows existing conventions

Files Added

loopstructural/gui/map2loop_tools/
├── __init__.py # Package exports
├── README.md # Comprehensive documentation
├── dialogs.py # Dialog wrappers for all tools
├── sorter_widget.py/.ui # Automatic sorter widget
├── user_defined_sorter_widget.py/.ui # User-defined sorter widget
├── sampler_widget.py/.ui # Sampler widget (calls map2loop directly)
├── basal_contacts_widget.py/.ui # Basal contacts widget
└── thickness_calculator_widget.py/.ui # Thickness calculator widget

Files Modified

  • loopstructural/plugin_main.py - Added menu items and dialog show methods

Usage Example

# From plugin menu: Plugins → LoopStructural → Sampler# This opens a dialog that:# 1. Collects user inputs via the widget UI# 2. Converts QGIS layers to map2loop formats# 3. Calls map2loop.sampler.SamplerSpacing or SamplerDecimator directly# 4. Converts results back and adds to QGIS project

Benefits

  • Direct API Access: Uses map2loop classes as an API, not through processing framework
  • Standard UX: Follows QGIS convention of tool dialogs accessible from plugin menu
  • No Interface Clutter: Tools don't take up dock widget space
  • Independent Access: Each tool can be launched individually
  • Maintainability: Changes to map2loop API can be incorporated directly

Testing

  • ✓ All Python files pass syntax compilation
  • ✓ All UI files validated as proper XML
  • ✓ Code passes ruff linting with no errors
  • ✓ Follows existing architectural patterns

Note: Full functional testing requires a QGIS environment with PyQt5, which is not available in CI. Manual testing in QGIS is recommended.

Related

This PR provides direct access to map2loop processing tools as an API within the plugin's GUI, making the workflow more streamlined for users performing geological modeling tasks.

Original prompt

Create separate widget/gui components for running each of the processing tools for map2loop. These need to be self contained with the ability to be incorporated into the main dock widget.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

lachlangroseand others added 30 commits June 17, 2025 10:43
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v9...v11)
---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
dependency-version: '11'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
ci: fix formatting of release-please
…ction-download-artifact-11
Bump dawidd6/action-download-artifact from 9 to 11
@lachlangrose

Copy link
Copy Markdown
Member

#64 contains these changes

@lachlangrose
lachlangrose deleted the copilot/create-separate-gui-components branch January 24, 2026 03:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationqualitytoolingUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@lachlangrose@rabii-chaarani@noellehmcheng