mirror of
https://git.salome-platform.org/gitpub/modules/geom.git
synced 2025-03-31 13:24:29 +05:00
412 lines
11 KiB
Python
412 lines
11 KiB
Python
# -*- 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, \
|
|
QComboBox, QLabel, QPushButton, QMessageBox
|
|
|
|
from salome.geom.geomrepairadv.basedlg import BaseDlg
|
|
from salome.geom import geomBuilder
|
|
from libGEOM_Swig import GEOM_Swig
|
|
|
|
from .geomrepairadv_common import DlgRef_1Spin_QTD
|
|
from .geomrepairadv_execute import execute
|
|
from .geomrepairadv_logger import logger
|
|
import GEOM
|
|
|
|
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.
|
|
"""
|
|
|
|
SUBSHAPES_LABEL_TEXT = 'Sub-shapes: '
|
|
|
|
def __init__(self, selection_level = GEOM.EDGE):
|
|
# Path to Min/max script
|
|
self._minmax_algo = self.set_algoname('locate_subshapes_limits.py', True)
|
|
|
|
# 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)
|
|
|
|
# Add Min/Max button
|
|
self._minmax_button = QPushButton("Compute Min/Max")
|
|
self._minmax_button.clicked.connect(self.on_minmax_button_clicked)
|
|
|
|
# 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', 1000, decimals, max_value)
|
|
self._min_widget.SpinBox_DX.valueChanged.connect(self.on_limit_changed)
|
|
self._max_widget.SpinBox_DX.valueChanged.connect(self.on_limit_changed)
|
|
|
|
# Sub-shapes number
|
|
self._subshapes_selected = 0
|
|
self._subshapes_total = 0
|
|
self._subshapes_label = QLabel()
|
|
|
|
# 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._minmax_button, 1, 0)
|
|
layout.addWidget(self._type_widget, 2, 0)
|
|
layout.addWidget(self._min_widget, 3, 0)
|
|
layout.addWidget(self._max_widget, 4, 0)
|
|
layout.addWidget(self._subshapes_label, 5, 0)
|
|
layout.addWidget(self._select_button, 6, 0)
|
|
|
|
# Init base dialog
|
|
BaseDlg.__init__(
|
|
self,
|
|
main_widget,
|
|
'Locate Subshapes',
|
|
'locate_subshapes_algo.py',
|
|
True,
|
|
selection_level
|
|
)
|
|
|
|
# Adjust setup from a base class
|
|
self._sel_subshape_widget.hide()
|
|
self._is_copy_on = False # disable making a copy of object for algo script
|
|
|
|
|
|
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 set_limits(self, min_value, max_value):
|
|
"""
|
|
Sets given values for min/max limits.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
self._min_widget.SpinBox_DX.setValue(min_value)
|
|
self._max_widget.SpinBox_DX.setValue(max_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 set_subshapes_counters(self, selected, total):
|
|
"""
|
|
Set counters for selected and total subshapes.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
self._subshapes_selected = selected
|
|
self._subshapes_total = total
|
|
|
|
|
|
def update_subshapes_label(self):
|
|
"""
|
|
Updates a text of Sub-Shapes label.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
selected = str(self._subshapes_selected)
|
|
total = str(self._subshapes_total)
|
|
|
|
self._subshapes_label.setText(self.SUBSHAPES_LABEL_TEXT + selected + '/' + total)
|
|
|
|
|
|
def update_subshapes_info(self):
|
|
"""
|
|
Updates all info about Sub-Shapes in the dialog.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
# Default values when we don't have selected shapes
|
|
selected_ids = []
|
|
all_ids = []
|
|
|
|
if self._selected_object:
|
|
geompy = geomBuilder.New()
|
|
selected_ids = self.get_local_selection()
|
|
all_ids = geompy.SubShapeAllIDs(self._selected_object, self.get_selection_level())
|
|
|
|
# Update counters
|
|
self.set_subshapes_counters(len(selected_ids), len(all_ids))
|
|
|
|
# Update label
|
|
self.update_subshapes_label()
|
|
|
|
|
|
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)
|
|
|
|
# Clear pre selected sub-shapes list
|
|
self.on_select_subshape()
|
|
|
|
self.update_subshapes_info()
|
|
|
|
|
|
def select_subshapes_in_limits(self):
|
|
"""
|
|
Updates a text of Sub-Shapes label.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
if not self._selected_object:
|
|
return
|
|
|
|
# Get all sub-shapes
|
|
geompy = geomBuilder.New()
|
|
selection_level = self.get_selection_level()
|
|
subshapes = geompy.SubShapeAll(self._selected_object, selection_level)
|
|
|
|
# Iterate over ids to check if it fits to limits
|
|
param_ids = { GEOM.EDGE : 0, GEOM.FACE : 1, GEOM.SOLID : 2 }
|
|
param_index = param_ids[selection_level]
|
|
|
|
ids_to_select = []
|
|
|
|
limits = self.get_limits()
|
|
for shape in subshapes:
|
|
# Get properties as a list [theLength, theSurfArea, theVolume]
|
|
properties = geompy.BasicProperties(shape)
|
|
param = properties[param_index]
|
|
logger.debug('param: {}'.format(param))
|
|
|
|
# Check if it fits to the limits
|
|
if param >= limits[0] and param <= limits[1]:
|
|
# TODO: implement selections with GEOM_Swig_LocalSelector or something...
|
|
# Select sub-shape
|
|
sub_shape_id = geompy.GetSubShapeID(self._selected_object, shape)
|
|
ids_to_select.append(sub_shape_id)
|
|
else:
|
|
# Deselect sub-shape
|
|
pass
|
|
|
|
# Select sub-shapes with collected ids
|
|
geom_swig = GEOM_Swig()
|
|
geom_swig.setLocalSelection(ids_to_select)
|
|
logger.debug('ids_to_select: {}'.format(ids_to_select))
|
|
|
|
# Update displayed info
|
|
self.update_subshapes_info()
|
|
|
|
|
|
def on_limit_changed(self):
|
|
"""
|
|
One of the limits was changed.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
# TODO: Do we need an interactive change here?
|
|
# self.select_subshapes_in_limits()
|
|
|
|
|
|
def on_select_button_clicked(self):
|
|
"""
|
|
Show selection info on button click.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
# Doesn't make any sence without selected object
|
|
if not self._selected_object:
|
|
QMessageBox.warning(
|
|
None, 'Warning', 'You must select an object to see sub-shapes selected!')
|
|
return
|
|
|
|
self.select_subshapes_in_limits()
|
|
|
|
|
|
def on_minmax_button_clicked(self):
|
|
"""
|
|
Compute Min/Max limits on button click.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
# Doesn't make any sence without selected object
|
|
if not self._selected_object:
|
|
QMessageBox.warning(None, 'Warning', 'You must select an object to compute!')
|
|
return
|
|
|
|
# Execute a separated script the same way as it is expected for on_apply() but without dump
|
|
args = {
|
|
'result_name': 'dummy',
|
|
'selection_level': self.get_selection_level()
|
|
}
|
|
|
|
# Making Python dump and copy of selected object are disabled
|
|
# because we don't need for both of them here.
|
|
limits = execute(self._selected_object, self._minmax_algo, args, False, False)
|
|
if len(limits) >= 2:
|
|
self.set_limits(limits[0], limits[1])
|
|
|
|
|
|
def get_args(self):
|
|
"""
|
|
Collects arguments for a repair execution algorithm into a dictionary.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
Dictionary with arguments for execution.
|
|
"""
|
|
|
|
# Update selection with a current values
|
|
# TODO: should we call it here?
|
|
# In a worst case scenario we can run it twice
|
|
# if a user has just pressed selection button.
|
|
self.select_subshapes_in_limits()
|
|
|
|
# Collect current values for the execution
|
|
selected_ids = self.get_local_selection()
|
|
selection_level = self.get_selection_level()
|
|
min_selected = 0
|
|
|
|
if self.is_selection_valid(selected_ids, min_selected):
|
|
return {
|
|
'selected_ids': selected_ids,
|
|
'result_name': self.get_result_name(),
|
|
'selection_level': selection_level
|
|
}
|
|
|
|
return None
|
|
|
|
|
|
def on_select_object(self):
|
|
"""
|
|
Override parent's method to display sub-shapes info.
|
|
|
|
Args:
|
|
None.
|
|
|
|
Returns:
|
|
None.
|
|
"""
|
|
|
|
# Call parent method first
|
|
super().on_select_object()
|
|
|
|
# Update displayed info
|
|
self.update_subshapes_info()
|
|
|
|
|
|
# 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.locate_subshapes
|
|
if __name__ == '__main__':
|
|
app = QApplication(sys.argv)
|
|
|
|
dlg = LocateSubShapesDlg(None)
|
|
dlg.show()
|
|
|
|
sys.exit(app.exec_())
|