[bos #38044][EDF] (2023-T3) Support for automatic reparation. Updated UI.

This commit is contained in:
Konstantin Leontev 2024-03-12 21:24:39 +00:00 committed by DUC ANH HOANG
parent 127038b5d7
commit e113b6239c
9 changed files with 326 additions and 82 deletions

View File

@ -45,6 +45,7 @@ IF(SALOME_BUILD_GUI)
SET(_gui_SCRIPTS
basedlg.py
basedlg.ui
subshapes_basedlg.py
${geom_dlg_ref}/DlgRef_1Sel_QTD.ui
DlgRef_1Spin_QTD.ui # copied because original was promoted to SalomeApp_DoubleSpinBox
)

View File

@ -32,6 +32,7 @@ from libGEOM_Swig import GEOM_Swig
from .basedlg_ui import Ui_BaseDlg
from .geomrepairadv_execute import execute
from .geomrepairadv_logger import logger
from .geomrepairadv_common import DlgRef_1Sel_QTD, \
GEOM_RESULT_NAME_GRP, NAME_LBL, GEOM_SELECTED_LBL, GEOM_SELECTED_SHAPE
import GEOM
@ -236,6 +237,23 @@ class BaseDlg(Ui_BaseDlg, QWidget):
return self._result_widget.LineEdit1.text()
def set_selection_level(self, selection_level):
"""
Sets selection level.
Args:
selection_level - GEOM selection level.
Returns:
None.
"""
self._selection_level = selection_level
# Update selection for current object
self.on_select_object()
def set_selection(self, entry = None):
"""
Sets selection level to self._selection_level or resets it.
@ -291,6 +309,47 @@ class BaseDlg(Ui_BaseDlg, QWidget):
self.set_selection(entry)
def get_local_selection(self):
"""
Returns selected sub-shapes ids.
Args:
None.
Returns:
List of ids.
"""
geom_swig = GEOM_Swig()
selected_ids = geom_swig.getLocalSelection()
logger.debug('selected_ids: %s', selected_ids)
return selected_ids
def is_selection_valid(self, selected_ids, min_selected):
"""
Checks number of sub-shapes ids.
Args:
selected_ids - list of selected.
Returns:
True if we have valid number of ids.
"""
if len(selected_ids) < min_selected:
QMessageBox.warning(
None,
'Warning',
'The algorithm needs at least {} selected sub-shapes!\n'
'Operation was canceled.'.format(min_selected)
)
return False
return True
def closeEvent(self, event):
"""
Overrides default close envent to reset selection level.

View File

@ -53,7 +53,12 @@ class DlgRef_1Spin_QTD(Ui_DlgRef_1Spin_QTD, QWidget):
We need it because a class generated from ui file is derived from an object and
cannot be added as a widget to a dialog's layout.
"""
def __init__(self):
def __init__(self, title, default_value, decimals, max_value):
QWidget.__init__(self)
# Set up the user interface from Designer.
self.setupUi(self)
self.TextLabel1.setText(title)
self.SpinBox_DX.setValue(default_value)
self.SpinBox_DX.setDecimals(decimals)
self.SpinBox_DX.setMaximum(max_value)

View File

@ -22,8 +22,9 @@
import os
import sys
import importlib.util
from traceback import format_exc
from qtsalome import QApplication, QFileDialog
from qtsalome import QApplication, QFileDialog, QMessageBox
from salome.kernel.services import ObjectToID
from salome.geom.geomtools import GeomStudyTools
@ -68,7 +69,18 @@ def module_from_filename(filename):
logger.error('spec.loader is None for %s module!', module_name)
return None
spec.loader.exec_module(module)
try:
spec.loader.exec_module(module)
except FileNotFoundError:
logger.error(format_exc())
QMessageBox.warning(
None,
'Error',
'Cannot find module {}!\nOperation was canceled.'.format(module_name)
)
return None
return module

View File

@ -21,9 +21,11 @@
import sys
from qtsalome import QGridLayout, QFrame, QApplication
from qtsalome import QGridLayout, QFrame, QApplication, QComboBox, QLabel, QPushButton, QMessageBox
from salome.geom.geomrepairadv.basedlg import BaseDlg
from .geomrepairadv_common import DlgRef_1Spin_QTD
import GEOM
class LocateSubShapesDlg(BaseDlg):
@ -31,14 +33,141 @@ class LocateSubShapesDlg(BaseDlg):
Dialog for Locate Subshapes plugin that selects the sub-shapes of a compound
by length, area or volume depending on whether it is an EDGE, a FACE or a SOLID.
"""
def __init__(self, selection_level = GEOM.COMPOUND):
def __init__(self, selection_level = GEOM.EDGE):
# Implement widget's content here
main_widget = QFrame()
layout = QGridLayout(main_widget)
layout.setContentsMargins(0, 0, 0, 0)
# A combobox to choose measurment type
type_label = QLabel('Shape Measurement')
self._type_widget = QComboBox()
type_items = ['Length (EDGE)', 'Area (FACE)', 'Volume (SOLID)']
self._type_widget.insertItems(0, type_items)
self._type_widget.setToolTip('Select a type of shape measurement')
self._type_widget.currentIndexChanged.connect(self.on_measurment_type_changed)
# Min/max values widgets
decimals = 2
max_value = sys.float_info.max
self._min_widget = DlgRef_1Spin_QTD('Min', 0, decimals, max_value)
self._max_widget = DlgRef_1Spin_QTD('Max', 100, decimals, max_value)
# Add select button
self._select_button = QPushButton("Show Selected Sub-shapes")
self._select_button.clicked.connect(self.on_select_button_clicked)
# Add the widgets to layout
layout.addWidget(type_label, 0, 0)
layout.addWidget(self._type_widget, 1, 0)
layout.addWidget(self._min_widget, 2, 0)
layout.addWidget(self._max_widget, 3, 0)
layout.addWidget(self._select_button, 4, 0)
# Init base dialog
BaseDlg.__init__(
self, main_widget, 'Locate Subshapes', 'locate_subshapes_algo.py', False, selection_level)
self,
main_widget,
'Locate Subshapes',
'locate_subshapes_algo.py',
False,
selection_level
)
def get_limits(self):
"""
Returns current values for min/max limits.
Args:
None.
Returns:
List of limits [min, max].
"""
return [self._min_widget.SpinBox_DX.value(),
self._max_widget.SpinBox_DX.value()]
def get_measurment_type(self, index):
"""
Returns selection level based on current measurment type.
Args:
index - current combobox index.
Returns:
GEOM selection level value.
"""
measurment_types = {
0 : GEOM.EDGE,
1 : GEOM.FACE,
2 : GEOM.SOLID
}
return measurment_types[index]
def on_measurment_type_changed(self, index):
"""
Changes selection level on type changed.
Args:
index - current combobox index.
Returns:
None.
"""
selection_level = self.get_measurment_type(index)
self.set_selection_level(selection_level)
def on_select_button_clicked(self):
"""
Show selection info on button click.
Args:
None.
Returns:
None.
"""
#TODO: what are we going to do on this click?
# Should it do a separated script?
QMessageBox.warning(None, 'Warning', 'Not implemented yet')
def get_args(self):
"""
Collects arguments for a repair execution algorithm into a dictionary.
Args:
None.
Returns:
Dictionary with arguments for execution.
"""
selected_ids = self.get_local_selection()
current_index = self._type_widget.currentIndex()
selection_level = self.get_measurment_type(current_index)
limits = self.get_limits()
min_selected = 1
if self.is_selection_valid(selected_ids, min_selected):
return {
'selected_ids': selected_ids,
'result_name': self.get_result_name(),
'selection_level': selection_level,
'min_limit': limits[0],
'max_limit': limits[1]
}
return None
# For testing run as a module from geomrepairadv parent directory in

View File

@ -21,76 +21,19 @@
import sys
from qtsalome import QGridLayout, QFrame, QMessageBox, QApplication
from qtsalome import QApplication
from libGEOM_Swig import GEOM_Swig
from .geomrepairadv_logger import logger
from .basedlg import BaseDlg
from .geomrepairadv_common import DlgRef_1Spin_QTD
from .subshapes_basedlg import SubShapesBaseDlg
import GEOM
class MergeFacesDlg(BaseDlg):
class MergeFacesDlg(SubShapesBaseDlg):
"""
Dialog for Merge Faces plugin that merges selected faces with a given precision.
"""
def __init__(self, selection_level = GEOM.FACE):
# Make layout for new widgets
main_widget = QFrame()
layout = QGridLayout(main_widget)
layout.setContentsMargins(0, 0, 0, 0)
# Precision widget
self._precision_widget = DlgRef_1Spin_QTD()
self._precision_widget.TextLabel1.setText('Precision')
layout.addWidget(self._precision_widget, 0, 0)
BaseDlg.__init__(
self, main_widget, 'Merge Faces', 'merge_faces_algo.py', True, selection_level)
def get_precision(self):
"""
Returns current precision value.
Args:
None.
Returns:
Double.
"""
return self._precision_widget.SpinBox_DX.value()
def get_args(self):
"""
Collects arguments for a repair execution algorithm into a dictionary.
Args:
None.
Returns:
Dictionary with arguments for execution.
"""
geom_swig = GEOM_Swig()
faces_ids = geom_swig.getLocalSelection()
logger.debug('faces_ids: %s', faces_ids)
if len(faces_ids) < 2:
QMessageBox.warning(
None,
'Warning',
'The algorithm needs at least two selected faces!\nMerging was canceled.'
)
return None
return {
'faces_ids': faces_ids,
'result_name': self.get_result_name(),
'precision': self.get_precision()
}
SubShapesBaseDlg.__init__(
self, 'Merge Faces', 'merge_faces_algo.py', True, selection_level, 2)
# For testing run as a module from geomrepairadv parent directory in

View File

@ -52,14 +52,15 @@ def run(args_dict, progress_emitter):
if ('source_solid' not in args_dict or
'faces_ids' not in args_dict or
'result_name' not in args_dict):
'selected_ids' not in args_dict or
'result_name' not in args_dict or
'precision' not in args_dict):
logging.info('Cant execute an algo because the arguments are empty!')
return False
source_solid = args_dict['source_solid']
faces_ids = args_dict['faces_ids']
faces_ids = args_dict['selected_ids']
result_name = args_dict['result_name']

View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2014-2024 EDF
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# See https://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
#
# Author : Konstantin Leontev (OpenCascade S.A.S)
import sys
from qtsalome import QGridLayout, QFrame, QApplication
from .basedlg import BaseDlg
from .geomrepairadv_common import DlgRef_1Spin_QTD
class SubShapesBaseDlg(BaseDlg):
"""
Base dialog for Merge Faces and Union Edges plugins that provides
to algorithm selected faces with a given precision.
"""
def __init__(self, window_title, algo_name, is_default_location, selection_level, min_selected):
# Set min number of selected sub-shapes
self._min_selected = min_selected
# Make layout for new widgets
main_widget = QFrame()
layout = QGridLayout(main_widget)
layout.setContentsMargins(0, 0, 0, 0)
# Precision widget
self._precision_widget = DlgRef_1Spin_QTD('Precision', 0, 2, 100)
layout.addWidget(self._precision_widget, 0, 0)
BaseDlg.__init__(
self, main_widget, window_title, algo_name, is_default_location, selection_level)
def get_precision(self):
"""
Returns current precision value.
Args:
None.
Returns:
Double.
"""
return self._precision_widget.SpinBox_DX.value()
def get_args(self):
"""
Collects arguments for a repair execution algorithm into a dictionary.
Args:
None.
Returns:
Dictionary with arguments for execution.
"""
selected_ids = self.get_local_selection()
if self.is_selection_valid(selected_ids, self._min_selected):
return {
'selected_ids': selected_ids,
'result_name': self.get_result_name(),
'precision': self.get_precision()
}
return None
# For testing run as a module from geomrepairadv parent directory in
# Salome INSTALL, because the dialog needs a generated Ui_BaseDlg class
# that we don't have in the SOURCE.
# Example:
# $ python -m geomrepairadv.subshapes_basedlg
if __name__ == '__main__':
app = QApplication(sys.argv)
dlg = SubShapesBaseDlg('Test SubShapesBaseDlg', 'merge_faces_algo.py', True, None, 1)
dlg.show()
sys.exit(app.exec_())

View File

@ -21,23 +21,18 @@
import sys
from qtsalome import QGridLayout, QFrame, QApplication
from qtsalome import QApplication
from salome.geom.geomrepairadv.basedlg import BaseDlg
from .subshapes_basedlg import SubShapesBaseDlg
import GEOM
class UnionEdgesDlg(BaseDlg):
class UnionEdgesDlg(SubShapesBaseDlg):
"""
Dialog for Union Edges plugin that unifies edges of selected face.
"""
def __init__(self, selection_level = GEOM.COMPOUND):
# Implement widget's content here
main_widget = QFrame()
layout = QGridLayout(main_widget)
layout.setContentsMargins(0, 0, 0, 0)
BaseDlg.__init__(
self, main_widget, 'Union Edges', 'union_edges_algo.py', False, selection_level)
def __init__(self, selection_level = GEOM.FACE):
SubShapesBaseDlg.__init__(
self, 'Union Edges', 'union_edges_algo.py', False, selection_level, 1)
# For testing run as a module from geomrepairadv parent directory in