Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a422032
fix: dip direction now works
lachlangrose Aug 6, 2025
2cf97e4
chore: remove old unused code
lachlangrose Aug 6, 2025
d775a0e
chore: remove strat column in favour of using loopstructural implemen…
lachlangrose Aug 6, 2025
367c252
fix: add AddFaultDialog and AddFoldFrameDialog for fault and fold fra…
lachlangrose Aug 7, 2025
0c03c26
add a dialog window for adding fold frame/folds to the model. Current…
lachlangrose Aug 21, 2025
976afee
pass data manager to the model tab widget
lachlangrose Aug 21, 2025
596b2c5
add fold data to the data manager
lachlangrose Aug 21, 2025
67dc8d9
add fold frame and add fold to existing feature
lachlangrose Aug 21, 2025
e3f2d9d
stratigraphic column was reversed in widget
lachlangrose Aug 21, 2025
1f347a7
adding widget for folded foliation and structural frame details
lachlangrose Aug 21, 2025
33a5276
remove model setup tab
lachlangrose Aug 21, 2025
ee7e8cc
fix: move model_setup to own submodule. Change from add fold frame to…
lachlangrose Aug 22, 2025
136a6a5
fix: copy data to new feature name if name changes
lachlangrose Aug 25, 2025
a6d70ec
fix: use data arg, not specifc name
lachlangrose Aug 25, 2025
7cfd1ad
fix: add convert from feature to structural frame button
lachlangrose Aug 25, 2025
4c71c6c
fix: ensure geoh5py try catch actually has import in the block
lachlangrose Aug 25, 2025
422bc14
fix: remove layer name from delete button
lachlangrose Aug 25, 2025
3a253a6
fix: abstract data table into separate class
lachlangrose Aug 25, 2025
8948cde
fix: add data table to feature details panel
lachlangrose Aug 25, 2025
0bcc4da
fix: integrate layer selection table into add foliation dialog
lachlangrose Aug 26, 2025
5016afb
fix: upgrade LS
lachlangrose Aug 26, 2025
c4b649c
fix: replace items table with layer selection table in base feature d…
lachlangrose Aug 26, 2025
7b78503
fix: add unconformity button
lachlangrose Aug 26, 2025
a027910
fix: adding splot dialog
lachlangrose Aug 26, 2025
5c9dfe7
fix: convert from structural frame to fold frame
lachlangrose Aug 26, 2025
67b06ba
fix: add pyqtgraph
lachlangrose Aug 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 0 additions & 92 deletions loopstructural/gui/modelling/geological_model_tab.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .geological_model_tab import GeologicalModelTab
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import os

from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout
from PyQt5.uic import loadUi


class AddFaultDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
ui_path = os.path.join(os.path.dirname(__file__), 'add_fault_dialog.ui')
loadUi(ui_path, self)
self.setWindowTitle('Add Fault Feature')
# You can access widgets by their objectName from the .ui file
# Example: self.strike_input, self.dip_input, etc.

def get_fault_data(self):
return {
'strike': self.strike_input.value(),
'dip': self.dip_input.value(),
'centre': (
self.centre_x_input.value(),
self.centre_y_input.value(),
self.centre_z_input.value(),
),
'ellipsoid_extents': (
self.extent_x_input.value(),
self.extent_y_input.value(),
self.extent_z_input.value(),
),
'displacement': self.displacement_input.value(),
'pitch': self.pitch_input.value(),
'name': self.name_input.text(),
}
114 changes: 114 additions & 0 deletions loopstructural/gui/modelling/geological_model_tab/add_fault_dialog.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddFaultDialog</class>
<widget class="QDialog" name="AddFaultDialog">
<property name="windowTitle">
<string>Add Fault Feature</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelStrike">
<property name="text">
<string>Strike (°)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="strike_input"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelDip">
<property name="text">
<string>Dip (°)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="dip_input"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelCentre">
<property name="text">
<string>Centre (X, Y, Z)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="centreLayout">
<item>
<widget class="QDoubleSpinBox" name="centre_x_input"/>
</item>
<item>
<widget class="QDoubleSpinBox" name="centre_y_input"/>
</item>
<item>
<widget class="QDoubleSpinBox" name="centre_z_input"/>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelExtents">
<property name="text">
<string>Ellipsoid Extents (X, Y, Z)</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="extentsLayout">
<item>
<widget class="QDoubleSpinBox" name="extent_x_input"/>
</item>
<item>
<widget class="QDoubleSpinBox" name="extent_y_input"/>
</item>
<item>
<widget class="QDoubleSpinBox" name="extent_z_input"/>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelDisplacement">
<property name="text">
<string>Displacement</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="displacement_input"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelPitch">
<property name="text">
<string>Pitch (°)</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="pitch_input"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="labelName">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="name_input"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Ok|QDialogButtonBox::Cancel</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import os

from PyQt5.QtWidgets import QDialog, QDialogButtonBox
from PyQt5.uic import loadUi

from .layer_selection_table import LayerSelectionTable


class AddFoliationDialog(QDialog):
def __init__(self, parent=None, *, data_manager=None, model_manager=None):
super().__init__(parent)
self.data_manager = data_manager
self.model_manager = model_manager
ui_path = os.path.join(os.path.dirname(__file__), 'add_foliation_dialog.ui')
loadUi(ui_path, self)
self.setWindowTitle('Add Foliation')

# Create the layer selection table widget
self.layer_table = LayerSelectionTable(
data_manager=self.data_manager,
feature_name_provider=lambda: self.name,
name_validator=lambda: (self.name_valid, self.name_error)
)

# Replace or integrate with existing UI
self._integrate_layer_table()

self.buttonBox.accepted.connect(self.add_foliation)
self.buttonBox.rejected.connect(self.cancel)

self.modelFeatureComboBox.addItems(
[f.name for f in self.model_manager.features() if not f.name.startswith("__")]
)
self.name_valid = False
self.name_error = ""

def validate_name_field(text):
"""Validate the feature name field."""
valid = True
old_name = self.name
new_name = text.strip()

if not new_name:
valid = False
self.name_error = "Feature name cannot be empty."
elif new_name in [f.name for f in self.model_manager.features()]:
valid = False
self.name_error = "Feature name must be unique."
elif new_name in self.data_manager.feature_data:
valid = False
self.name_error = "Layer already exists in the data manager."

if not valid:
self.name_valid = False
self.feature_name_input.setStyleSheet("border: 1px solid red;")
else:
self.feature_name_input.setStyleSheet("")
self.name_valid = True

# Enable/disable the OK button based on validation
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(self.name_valid)

# If the name changes, update the data manager key and reinitialize table
if old_name != new_name and old_name in self.data_manager.feature_data:
# Save current table data
old_data = self.layer_table.get_table_data()

# Remove old key and set new key
self.data_manager.feature_data.pop(old_name, None)
if new_name and valid:
self.data_manager.feature_data[new_name] = old_data

# Update table to reflect new feature name
self.layer_table.initialize_feature_data()
self.layer_table.restore_table_state()

self.feature_name_input.textChanged.connect(validate_name_field)

@property
def name(self):
return self.feature_name_input.text().strip()

def add_foliation(self):
if not self.name_valid:
self.data_manager.logger(f'Name is invalid: {self.name_error}', log_level=2)
return

# Ensure table state is synchronized with data manager
self.layer_table.sync_table_with_data()

# Check if we have any layers selected
if not self.layer_table.has_layers():
self.data_manager.logger("No layers selected for the foliation.", log_level=2)
return

folded_feature_name = None
if self.modelFeatureComboBox.currentText() != "":
folded_feature_name = self.modelFeatureComboBox.currentText()

self.data_manager.add_foliation_to_model(self.name, folded_feature_name=folded_feature_name)
self.accept() # Close the dialog

def cancel(self):
# Clean up any temporary data if necessary
if self.name in self.data_manager.feature_data:
self.data_manager.feature_data.pop(self.name, None)
self.reject()

def _integrate_layer_table(self):
"""Integrate the layer table widget with the existing UI."""
# Try to replace existing table widget if it exists
if hasattr(self, 'items_table'):
table_parent = self.items_table.parent()

# Get the position of the original table
if hasattr(table_parent, 'layout') and table_parent.layout():
layout = table_parent.layout()

# Find the index of the original table in the layout
table_index = -1
for i in range(layout.count()):
item = layout.itemAt(i)
if item and item.widget() == self.items_table:
table_index = i
break

# Remove original widgets
if hasattr(self, 'items_table'):
self.items_table.setParent(None)
if hasattr(self, 'add_item_button'):
self.add_item_button.setParent(None)

# Insert new widget at the same position
if table_index >= 0:
layout.insertWidget(table_index, self.layer_table)
else:
layout.addWidget(self.layer_table)
else:
# Fallback: add to parent widget directly
if hasattr(table_parent, 'layout') and not table_parent.layout():
from PyQt5.QtWidgets import QVBoxLayout
layout = QVBoxLayout(table_parent)
table_parent.setLayout(layout)
layout.addWidget(self.layer_table)

# If no existing table found, try to add to main layout
elif hasattr(self, 'layout') and self.layout():
self.layout().addWidget(self.layer_table)
Loading
Loading