diff --git a/src/Model/Geometry/PointXY.py b/src/Model/Geometry/PointXY.py index 2cd6907fe223d884644ccbb8fc3d730e111d43f3..65d7baf98c53f55cdc06cab342d74073e5ef5598 100644 --- a/src/Model/Geometry/PointXY.py +++ b/src/Model/Geometry/PointXY.py @@ -42,4 +42,4 @@ class PointAC(Point): Returns: Euclidean distance between the two points """ - return dist((p1.a(), p1.c()), (p2.a(), p2.c())) + return dist((p1.a, p1.c), (p2.a, p2.c)) diff --git a/src/Model/Geometry/PointXYZ.py b/src/Model/Geometry/PointXYZ.py index 4441a1d2b5b745c18d90a91d333963d2dc140903..efbb97c892ced09ac9cd565b74a9e1c1bdc1cee9 100644 --- a/src/Model/Geometry/PointXYZ.py +++ b/src/Model/Geometry/PointXYZ.py @@ -47,7 +47,7 @@ class PointXYZ(Point): Returns: True if at least one coordinate is as np.nan """ - return pd_is_na(self.x()) or pd_is_na(self.y()) or pd_is_na(self.z()) + return pd_is_na(self.x) or pd_is_na(self.y) or pd_is_na(self.z) @staticmethod def distance(p1, p2): @@ -60,4 +60,4 @@ class PointXYZ(Point): Returns: Euclidean distance between the two points """ - return dist((p1.x(), p1.y(), p1.z()), (p2.x(), p2.y(), p2.z())) + return dist((p1.x, p1.y, p1.z), (p2.x, p2.y, p2.z)) diff --git a/src/Model/Geometry/Profile.py b/src/Model/Geometry/Profile.py index 8243fa489b72f265ebd0da0956adda79c8d1a297..ebc28446e3eb842be371065ef72dedb6f877eb2c 100644 --- a/src/Model/Geometry/Profile.py +++ b/src/Model/Geometry/Profile.py @@ -1,13 +1,21 @@ # -*- coding: utf-8 -*- class Profile(object): - def __init__(self, kp:float = 0.0, name:str = ""): + def __init__(self, kp:float = 0.0, name:str = "", + code1: int = 0, code2: int = 0, + _type:str = ""): super(Profile, self).__init__() self._num = int(num) + self._code1 = int(code1) + self._code2 = int(code2) self._kp = float(kp) self._name = str(name) + self._points: List[Point] = [] + + self._profile_type = _type + @property def num(self): """ @@ -20,6 +28,34 @@ class Profile(object): def num(self, value: int): self._num = int(value) + @property + def code1(self): + """ + Returns: + Interpolation code 1. + """ + return self._code1 + + @code1.setter + def code1(self, value: int): + self._code1 = int(value) + + @property + def code2(self): + """ + Returns: + Interpolation code 2. + """ + return self._code2 + + @code2.setter + def code2(self, value: int): + self._code2 = int(value) + + @property + def nb_points(self): + return len(self._points) + @property def kp(self): """ @@ -41,5 +77,17 @@ class Profile(object): return self._name @name.setter - def name(self, other: str): - self._name = other + def name(self, value: str): + self._name = value.strip() + + @property + def profile_type(self): + """ + Returns: + Profile type. + """ + return self._profile_type + + @type.setter + def profile_type(self, value: str): + self._profile_type = value diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index 237ef6e3f339239847ba656902d470c4deaddfb2..d9d102ed694bf88f73d2008de95ac9e2a70a0dc5 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -8,7 +8,8 @@ from Model.Geometry.Profile import Profile from Model.Geometry.PointXYZ import PointXYZ class ProfileXYZ(Profile): - def __init__(self, num: int = 0, code1: int = 0, code2: int = 0, + def __init__(self, num: int = 0, + code1: int = 0, code2: int = 0, kp: float = 0., name: str = ""): """ProfileXYZ constructor @@ -16,7 +17,6 @@ class ProfileXYZ(Profile): num: The number of this profile code1: The interpolation code 1 code2: The interpolation code 2 - nb_points: Number of points kp: Kilometer point name: The name of profile @@ -27,46 +27,14 @@ class ProfileXYZ(Profile): num = num, name = name, kp = kp, + code1 = code1, code2 = code2, + _type = "XYZ", ) - self._code1 = int(code1) - self._code2 = int(code2) - self._nb_points = int(nb_points) - self._list_points: List[PointXYZ] = [] - def __repr__(self): df = pd.DataFrame(columns=["X", "Y", "Z", "Name"], data=[[p.x, p.y, p.z, p.name] for p in self._list_points]) - return f"\n{self.header}\n{df}" - - - @property - def code1(self): - """ - Returns: - Interpolation code 1. - """ - return self._code1 - - @code1.setter - def code1(self, value: int): - self._code1 = int(value) - - @property - def code2(self): - """ - Returns: - Interpolation code 2. - """ - return self._code2 - - @code2.setter - def code2(self, value: int): - self._code2 = int(value) - - @property - def nb_points(self): - return self._nb_points + return f"\nProfileXYZ : {self.name}\n{df}" @property def header(self): @@ -76,7 +44,7 @@ class ProfileXYZ(Profile): """ return np.array( [self._num, self._code1, self._code2, - self._nb_points, self._kp, self._name] + self.nb_points(), self._kp, self._name] ) def import_points(self, list_points: list): @@ -167,3 +135,44 @@ class ProfileXYZ(Profile): raise TypeError( f"{list_index} is instance of unexpected type '{type(list_index)}'" ) + + def filter_isnan(self, lst): + """Returns the input list without 'nan' element + + Args: + lst: The list to filter + + Returns: + The list without 'nan' + """ + return [x for x in lst if not np.isnan(x)] + + def x(self): + return [point.x for point in self._list_points] + + def y(self): + return [point.y for point in self._list_points] + + def z(self): + return [point.z for point in self._list_points] + + def names(self): + return [point.name for point in self._list_points] + + def x_max(self): + return max(self.filter_isnan(self.x)) + + def x_min(self): + return min(self.filter_isnan(self.x)) + + def y_max(self): + return max(self.filter_isnan(self.y)) + + def y_min(self): + return min(self.filter_isnan(self.y)) + + def z_max(self): + return max(self.filter_isnan(self.z)) + + def z_min(self): + return min(self.filter_isnan(self.z)) diff --git a/src/Model/Geometry/Reach.py b/src/Model/Geometry/Reach.py index 46decef0188014a79d2571663dbf0a26e1cb3d1d..7f4461184399cbdff1126d9ff8abf69c0ee3fac3 100644 --- a/src/Model/Geometry/Reach.py +++ b/src/Model/Geometry/Reach.py @@ -15,26 +15,47 @@ from Model.Except import FileFormatError, exception_message_box class Reach: def __init__(self, edge): self._edge = edge - self._list_profiles: List[Profile] = [] + self._profiles: List[Profile] = [] + + # Copy/Paste + self.__list_copied_profiles = [] def __repr__(self): - return f"\n===== Début liste des profils ======> {np.array(self._list_profiles)}" \ + return f"\n===== Début liste des profils ======> {np.array(self._profiles)}" \ f"\n<====== Fin liste des profils =====" + def profile(self, i): + """Returns profile at index i + + Args: + i: The index of profile + + Returns: + The profile at index i + """ + if i in self._profiles: + return self._profiles[i] + + return None + + @property + def profiles(self): + return self._profiles.copy() + @property def number_profiles(self): """ Returns: Number of profiles """ - return len(self._list_profiles) + return len(self._profiles) def get_geometry(self) -> List[Profile]: """ Returns: The profiles list. """ - return self._list_profiles + return self._profiles def get_profile_i(self, i: int) -> Profile: """ @@ -45,11 +66,11 @@ class Reach: The profile at index i. """ try: - return self._list_profiles[i] + return self._profiles[i] except IndexError: raise IndexError(f"Invalid profile index: {i}") - def add_XYZ(self): + def add_profile(self, index): """Add a new profile at the end of profiles list Returns: @@ -58,7 +79,8 @@ class Reach: nb_profile = self.number_profiles profile = ProfileXYZ() profile.num = nb_profile + 1 - self._list_profiles.append(profile) + self._profiles.insert(profile, index + 1) + # self._update_profile_numbers() def _update_profile_numbers(self): """Update profiles index @@ -79,7 +101,7 @@ class Reach: Nothing. """ profile = ProfileXYZ() - self._list_profiles.insert(index, profile) + self._profiles.insert(index, profile) self._update_profile_numbers() def delete(self, list_index: list): @@ -95,26 +117,50 @@ class Reach: if list_index: indices = sorted(list(set(list_index)), reverse=True) for idx in indices: - # if idx < len(self._list_profiles) : + # if idx < len(self._profiles) : try: - self._list_profiles.pop(idx) + self._profiles.pop(idx) self._update_profile_numbers() except IndexError: print(f"Invalid profile index: {idx}") except TypeError: if isinstance(list_index, int): - self._list_profiles.pop(list_index) + self._profiles.pop(list_index) self._update_profile_numbers() else: raise TypeError(f"{list_index} is instance of unexpected type '{type(list_index)}'") def _sort(self, is_reversed: bool = False): - self._list_profiles = sorted( - self._list_profiles, + self._profiles = sorted( + self._profiles, key=lambda profile: profile.kp(), reverse=is_reversed ) + def z_min(self): + """List of z min for each profile + + Returns: + List of z min for each profile + """ + return [profile.z_min() for profile in self._data.profiles] + + def z_max(self): + """List of z max for each profile + + Returns: + List of z max for each profile + """ + return [profile.z_max() for profile in self._data.profiles] + + def kp(self): + """List of profiles kp + + Returns: + List of profiles kp + """ + return [profile.kp for profile in self._data.profiles] + def sort_ascending(self): """Sort profiles by increasing KP @@ -144,7 +190,7 @@ class Reach: def paste(self): if self.__list_copied_profiles: for profile in self.__list_copied_profiles: - self._list_profiles.append(profile) + self._profiles.append(profile) def import_geometry(self, file_path_name: str): """Import a geometry from file (.ST or .st) @@ -162,7 +208,7 @@ class Reach: for ind, profile in enumerate(list_profile): prof = ProfileXYZ(*list_header[ind]) prof.import_points(profile) - self._list_profiles.append(prof) + self._profiles.append(prof) self._update_profile_numbers() except FileNotFoundError as e: print(e) @@ -225,3 +271,22 @@ class Reach: print("****** Fichier {} lu et traité en {} secondes *******".format(self.file_st, time() - t0)) return list_profile, list_header + + + # TODO: Move this function to model reach + def export_reach(self, filename): + with open(f"{filename}", "w") as file_st: + for index in range(len(self._profiles)): + profile = self._profiles[index] + + for v in profile.header: + file_st.write(f"{v:>6}") + file_st.write("\n") + + for point in self._data.profile[index_pro].points: + for i in [point.x, point.y, point.z, point.name]: + file_st.write(f"{i:>13.4f}") + file_st.write("\n") + + file_st.write(" 999.9990 999.9990 999.9990") + file_st.write("\n") diff --git a/src/Model/River.py b/src/Model/River.py index 5d6e9647c9e1c6bb0ba7aad93528035a03de7a92..027fd37ef173a4e82ef1ce9a4164e2496aaf685d 100644 --- a/src/Model/River.py +++ b/src/Model/River.py @@ -17,9 +17,11 @@ class RiverNode(Node): self._locker = None + @property def locker(self): return self._locker + @locker.setter def locker(self, locker): self._locker = locker @@ -35,9 +37,11 @@ class RiverReach(Edge): self._reach = None + @property def reach(self): return self._reach + @reach.setter def reach(self, reach:Reach): self._reach = reach diff --git a/src/View/Geometry/qtableview_reach.py b/src/View/Geometry/qtableview_reach.py index 22c8f2fc5402857be2c003a120c16cb60c2b3f0b..0a0bb274ff71adfb6df3bf096dcd4d76034a27d1 100644 --- a/src/View/Geometry/qtableview_reach.py +++ b/src/View/Geometry/qtableview_reach.py @@ -45,7 +45,7 @@ class PandasModelEditable(QAbstractTableModel): ] def rowCount(self, parent=QModelIndex()): - return len(self._data.profile) + return self._data.number_profiles def columnCount(self, parent=QModelIndex()): return len(self.headers) @@ -53,39 +53,29 @@ class PandasModelEditable(QAbstractTableModel): def data(self, index, role=Qt.DisplayRole): if index.isValid(): if role == Qt.DisplayRole and index.column() == 0: - value = self._data.profile[index.row()].name - return self._data.profile[index.row()].name + return self._data.profile(index.row()).name if role == Qt.DisplayRole and index.column() == 1: - return "%.4f" % float(self._data.profile[index.row()].pk) + kp = self._data.profile(index.row()).kp + return f"{kp:.4f}" if role == Qt.DisplayRole and index.column() == 2: - return self._data.profile[index.row()].profile_type + return self._data.profile(index.row()).profile_type for column in range(0, self.columnCount()): if index.column() == column and role == Qt.TextAlignmentRole: return Qt.AlignHCenter | Qt.AlignVCenter - # if role == Qt.BackgroundRole and index.column() == 1: - # return QtGui.QColor(Qt.lightGray) - - # if role == Qt.BackgroundRole and index.column() == 2: - # color = QtGui.QColor() - # data_i_profile_type = self._data.profile[index.row()].profile_type - - # if data_i_profile_type == self.profiles_type[1]: - # color = QtGui.QColor("magenta") - # elif data_i_profile_type == self.profiles_type[2]: - # color = QtGui.QColor("red") - # else: - # color = QtGui.QColor("lightgreen") - - # return color - if role == Qt.ForegroundRole and index.column() == 0: - if self._data.profile[index.row()].name == "Amont": + name = self._data.profile(index.row()).name\ + .strip()\ + .lower() + + if (name == "upstream" or + name == _translate("Geometry", "upstream")): return QtGui.QColor("Green") - elif self._data.profile[index.row()].name == "Aval": + elif (name == "downstream" or + name == _translate("Geometry", "downstream")): return QtGui.QColor("Red") return QVariant() @@ -95,31 +85,27 @@ class PandasModelEditable(QAbstractTableModel): if orientation == Qt.Horizontal: if section < len(self.headers): return self.headers[section] - else: - return "not implemented" else: - return "%d" % (section + 1) + return str(section + 1) if orientation == Qt.Vertical and role == Qt.DisplayRole: return self.headers[section] - return None + return QVariant() def setData(self, index, value, role=Qt.EditRole): row = index.row() column = index.column() if role == Qt.EditRole and index.column() != 2: - try: - if role == Qt.EditRole and index.column() == 0: - self._data.profile[index.row()].name = value + if role == Qt.EditRole and index.column() == 0: + self._data.profile(index.row()).name = value - if role == Qt.EditRole and index.column() == 1: - self._data.profile[index.row()].pk = float(value) + if role == Qt.EditRole and index.column() == 1: + self._data.profile(index.row()).pk = float(value) - self.dataChanged.emit(index, index) - except: - self.QMessageBoxCritical(value) + self.dataChanged.emit(index, index) + self.layoutChanged.emit() return True @@ -128,20 +114,6 @@ class PandasModelEditable(QAbstractTableModel): return False - @staticmethod - def QMessageBoxCritical(value): - msg = QMessageBox() - msg.setIcon(QMessageBox.Warning) - msg.setText("{} : Valeur saisie incorrecte".format(value)) - msg.setInformativeText("Seules les valeurs numériques sont autorisées.") - msg.setWindowTitle("Warning ") - msg.setStyleSheet("QLabel{min-width:250 px; font-size: 13px}; " - "QPushButton{ width:20px; font-size: 12px}; " - "background-color: Ligthgray ; " - "color : gray;font-size: 8pt; " - "color: #888a80;") - msg.exec_() - def index(self, row, column, parent=QModelIndex()): if not self.hasIndex(row, column, parent): return QModelIndex() @@ -149,27 +121,22 @@ class PandasModelEditable(QAbstractTableModel): return self.createIndex(row, column, QModelIndex()) def flags(self, index): + flg = Qt.ItemIsEnabled | Qt.ItemIsSelectable + if index.column() == 2: - return Qt.ItemIsEnabled | Qt.ItemIsSelectable + return flg else: - return Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled + return Qt.ItemIsEditable | flg # @QtCore.pyqtSlot() def insertRows(self, row, count, parent=QModelIndex()): self.beginInsertRows(parent, row, row + count - 1) self._data.add_profile(row) - self._data.profile[row].profile_type = "XYZ" self.endInsertRows() self.layoutChanged.emit() - def insertRows_(self, row, rowt=1, parent=QModelIndex()): - self.beginInsertRows(parent, row, rowt) - self._data.add_profile(row) - self.endInsertRows() - self.layoutChanged.emit() - def remove_rows(self, list_row_selected, parent=QModelIndex()): self.beginRemoveRows(parent, list_row_selected[0], list_row_selected[-1]) @@ -182,190 +149,31 @@ class PandasModelEditable(QAbstractTableModel): self.endRemoveRows() self.layoutChanged.emit() - def removeRows_(self, position, rows, parent=QModelIndex()): - self.beginRemoveRows(QModelIndex(), position, position + 1) - self._data.delete_profile(position) - self.endRemoveRows() - self.layoutChanged.emit() - - def export_reach(self, filename): - with open(f"{filename}", "w") as file_st: - for index_pro in range(len(self._data.profile)): - file_st.write(" ") - for head in self._data.headers[index_pro]: - file_st.write(str(head)) - file_st.write(" ") - file_st.write("\n") - - for point in self._data.profile[index_pro].points: - for i in [point.x, point.y, point.z, point.name]: - if isinstance(i, float): - if i >= 0: - file_st.write(" " + str("%.4f" % i)) - else: - file_st.write(" " + str("%.4f" % i)) - else: - file_st.write(" " + str(i)) - - file_st.write("\n") - file_st.write(" 999.9990 999.9990 999.9990") - file_st.write("\n") - def sort_data(self, _reverse): self.layoutAboutToBeChanged.emit() - self._data.sort_descending(_reverse) + + self._data.sort(_reverse) + self.layoutAboutToBeChanged.emit() self.layoutChanged.emit() def moveRowDown(self, row_to_move, parent=QModelIndex()): target = row_to_move + 2 self.beginMoveRows(parent, row_to_move, row_to_move, parent, target) + self._data.move_down_profile(row_to_move) + self.endMoveRows() self.layoutChanged.emit() def moveRowUp(self, row_to_move, parent=QModelIndex()): target = row_to_move + 1 self.beginMoveRows(parent, row_to_move - 1, row_to_move - 1, parent, target) + self._data.move_up_profile(row_to_move) - self.endMoveRows() - self.layoutChanged.emit() - def graphique(self, ax): + self.endMoveRows() self.layoutChanged.emit() - self.ax = ax - for i in range(len(self._data)): - self.ax.plot(self._data[i][1].iloc[:, 0], - self._data[i][1].iloc[:, 1], - color='r', lw=1., markersize=3, marker='+') - - def get_profile_selected(self, index): - return self._data.profile[index] - - def get_profile_selected_identifier(self, index): - return self._data.profile[index].headers[0] - - def get_profile_name(self, index): - return self._data.profile[index].name - - def get_profile_via_identifier(self, identifier): - profile, = [ - profile for profile in self._data.profile - if profile.headers[0] == str(identifier) - ] - return profile - - def get_z_min(self): - return self._data.get_bief_list_z_min() - - def get_z_min_i(self, index): - return self._data.profile[index].z_min - - def get_z_max(self): - """ - Returns: liste des z_max du profile - """ - return self._data.get_bief_list_z_max() - - def get_z_max_i(self, index): - return self._data.profile[index].z_max - - def get_pk(self): - """ - Returns: liste des Pk - """ - return self._data.get_bief_pk() - - def get_pk_i(self, index): - return self._data.profile[index].pk - - def get_x(self): - return self._data.get_bief_x() - - def get_y(self): - return self._data.get_bief_y() - - def get_x_complete_list_ld(self): - return self._data.get_bief_x_complete_ld() - - def get_y_complete_list_ld(self): - return self._data.get_bief_y_complete_ld() - - def get_z_complete_list_ld(self): - return self._data.get_bief_z_complete_ld() - - def get_pk_complete_list_ld(self): - return self._data.get_bief_pk_complete_guideline() - - def get_x_incomplete_list_ld(self): - pass - - def x_complete_guideline(self): - return [ - [ - profile.x_all_points_complete_guideline(name) - for profile in self._data.profile - ] for name in self._data.complete_guideline() - ] - - def y_complete_guideline(self): - return [ - [ - profile.y_all_points_complete_guideline(name) - for profile in self._data.profile - ] for name in self._data.complete_guideline() - ] - - def z_complete_guideline(self): - return [ - [ - profile.z_all_points_complete_guideline(name) - for profile in self._data.profile - ] for name in self._data.complete_guideline() - ] - - def get_station(self, index): - return self._data.get_station(index) - - def get_z(self): - return self._data.get_bief_z() - - def get_x_profile_i(self, index): - return self._data.profile[index].x - - def get_y_profile_i(self, index): - return self._data.profile[index].y - - def get_z_profile_i(self, index): - return self._data.profile[index].z - - def get_ld_profile_i(self, index): - return self._data.profile[index].ld - - def get_pk_profile_i(self, index): - return self._data.profile[index].pk - - def get_complete_list_ld(self): - return self._data.complete_guideline() - - def get_incomplete_list_ld(self): - return self._data.incomplete_guideline() - - def model_data(self): - return self._data - - def add_ld(self, *args): - lst = [] - for i in args: - list_i = [] - for j in range(len(i)): - l = i[1] - list_i.append(l) - lst.extend(list_i) - return lst, len(lst) - - def size_list_named_points(self): - return len(self.get_all_maned_points()) class Delegate(QtWidgets.QStyledItemDelegate): @@ -398,104 +206,6 @@ class Delegate(QtWidgets.QStyledItemDelegate): editor.setGeometry(option.rect) -class Delegate11(QtWidgets.QItemDelegate): - def __init__(self, owner, choices): - super().__init__(owner) - self.items = choices - - def createEditor(self, parent, option, index): - self.editor = QtWidgets.QComboBox(parent) - # self.editor.currentIndexChanged.connect(self.commit_editor) - self.editor.addItems(self.items) - return self.editor - - def paint(self, painter, option, index): - value = index.data(Qt.DisplayRole) - style = QtWidgets.QApplication.style() - opt = QtWidgets.QStyleOptionComboBox() - opt.text = str(value) - opt.rect = option.rect - style.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt, painter) - QtWidgets.QItemDelegate.paint(self, painter, option, index) - - # def commit_editor(self): - # editor = self.sender() - # color = QtGui.QColor() - # if editor.currentText() == "ProfilXYZ": - # color = QtGui.QColor("lightgreen") - # elif editor.currentText() == "ProfilAC": - # color = QtGui.QColor("red") - # qss = """QComboBox{background-color : %s;}""" % (color.name(),) - # editor.setStyleSheet(qss) - # self.commitData.emit(editor) - - def setEditorData(self, editor, index): - editor.blockSignals(True) - editor.setCurrentIndex(index.row()) # replacement - editor.blockSignals(False) - - # @pyqtSlot() - # def currentIndexChanged(self): - # self.commit_editor.emit(self.sender()) - - def setModelData(self, editor, model, index): - value = editor.currentText() - model.setData(index, Qt.DisplayRole, QVariant(value)) - - def updateEditorGeometry(self, editor, option, index): - editor.setGeometry(option.rect) - - -class Delegate1(QtWidgets.QStyledItemDelegate): - def __init__(self, owner, choices): - super().__init__(owner) - self.items = choices - - def paint(self, painter, option, index): - if isinstance(self.parent(), QtWidgets.QAbstractItemView): - self.parent().openPersistentEditor(index) - super(Delegate1, self).paint(painter, option, index) - - def createEditor(self, parent, option, index): - editor = QtWidgets.QComboBox(parent) - # editor.currentIndexChanged.connect(self.commit_editor) - editor.addItems(self.items) - return editor - - # def commit_editor(self): - # editor = self.sender() - # color = QtGui.QColor() - - # if editor.currentText() == "ProfilXYZ": - # color = QtGui.QColor("lightgreen") - # elif editor.currentText() == "ProfilAC": - # color = QtGui.QColor("red") - - # qss = """QComboBox{background-color : %s;}""" % (color.name(),) - # editor.setStyleSheet(qss) - # self.commitData.emit(editor) - - def setEditorData(self, editor, index): - editor.blockSignals(True) - text = index.model().data(index, Qt.DisplayRole) - try: - i = self.items.index(text) - except ValueError: - i = 0 - editor.setCurrentIndex(i) - editor.blockSignals(False) - - def setModelData(self, editor, model, index): - model.setData(index, editor.currentText(), Qt.DisplayRole) - - def updateEditorGeometry(self, editor, option, index): - editor.setGeometry(option.rect) - - @pyqtSlot() - def currentIndexChanged(self): - self.commitData.emit(self.sender()) - - class PandasModelEditableCreateReach(QAbstractTableModel): # TODO : Cette calsse permet juste d'éviter que l'application plante lorsque 'on essaye d'éditer le tablueau. Le # problème se trouve au niveau du délégué QtWidgets.QStyledItemDelegate. Il faudra prendre en compte le cas où @@ -631,285 +341,6 @@ class PandasModelEditableCreateReach(QAbstractTableModel): self.endMoveRows() self.layoutChanged.emit() - def graphique(self, ax): - self.layoutChanged.emit() - self.ax = ax - - for i in range(len(self._data)): - self.ax.plot(self._data[i][1].iloc[:, 0], - self._data[i][1].iloc[:, 1], - color='r', lw=1., markersize=3, marker='+') - - def get_z_min(self): - z_min = [] - - for row in range(self.rowCount()): - z_min.append(min(self._data[row][1].iloc[:, 2].tolist())) - - return z_min - - def get_z_max(self): - """ - Returns: liste des z_max du profile - """ - z_max = [] - - for row in range(self.rowCount()): - z_max.append(max(self._data[row][1].iloc[:, 2].tolist())) - - return z_max - - def get_pk(self): - """ - Returns: liste des Pk - """ - Pk = [ - float(self._data[row][0][4]) for row in range(self.rowCount()) - ] - - return Pk - - def get_x(self): - d = time.time() - x = [] - - for row in range(self.rowCount()): - lst = self._data[row][1].iloc[:, 0] # .tolist() - x.append(lst) - - return x - - def get_y(self): - y = [] - - for row in range(self.rowCount()): - lst = self._data[row][1].iloc[:, 1] # .tolist() - y.append(lst) - - return y - - def get_z(self): - z = [] - - for row in range(self.rowCount()): - z.append(float(self._data[row][1].iloc[:, 2])) - - return z - - def add_ld(self, *args): - lst = [] - - for i in args: - list_i = [] - for j in range(len(i)): - l = i[1] - list_i.append(l) - lst.extend(list_i) - - return lst, len(lst) - - def get_all_maned_points(self): - """ - Returns: la liste qui est l'union disjointe des listes de nom de points de tous les profils du profile - """ - # je considère une union disjointe au lieu d'une intersection pour prendre en compte d'éventuelles lignes - # directrices qui ne sont définies qu'à une partie du profile ie qui ne relient pas les deux deux profils - # extrêmes. - # NB : la liste retournée est "alphanumériquement" ordonnée ?! - liste = [data[1].iloc[:, 3].tolist() for data in self._data] - disjoint_union_ld = reduce(np.union1d, liste) - disjoint_union_ld_list = [ - element for element in disjoint_union_ld.tolist() if len(element.strip()) != 0 - ] - - return disjoint_union_ld_list - - def size_list_named_points(self): - return len(self.get_all_maned_points()) - - def get_complete_list_ld(self): - liste = [data[1].iloc[:, 3] for data in self._data] - intersection_ld = reduce(np.intersect1d, liste) - intersection_ld_list = [el for el in intersection_ld.tolist() if el != ""] - return intersection_ld_list - - def get_incomplete_list_ld(self): - """ - Returns : liste de noms de points nommés incomplets, c'est-à -dire, des points nommés définis que - sur un ou quelques profils seulement. Il s'agit de la liste des lignes directrices "incomplètes". - """ - liste = [data[1].iloc[:, 3] for data in self._data] - disjoint_union_ld = reduce(np.union1d, liste) - disjoint_union_ld_list = [el for el in disjoint_union_ld.tolist() if el != ""] - diff_union_instersect_ld = list( - set(disjoint_union_ld_list).symmetric_difference(set(self.get_complete_list_ld()))) - return diff_union_instersect_ld - - def get_x_y_named_points(self): - """ - Returns : les coordonnées (x,y) des points nommés "complets" et (éventuellement) "incomplets" - """ - list_x_y_ld = [] - list_x_y_ld_incomplete = [] - - liste = [data[1].iloc[:, 3] for data in self._data] - intersection_ld = reduce(np.intersect1d, liste) - intersection_ld_list = [el for el in intersection_ld.tolist() if el != ""] - disjoint_union_ld = reduce(np.union1d, liste) - disjoint_union_ld_list = [el for el in disjoint_union_ld.tolist() if el != ""] - diff_union_instersect_ld = list(set(disjoint_union_ld_list).symmetric_difference(set(intersection_ld_list))) - - if len(intersection_ld_list) != 0: - for data in self._data: - df = data[1] # .iloc[row, 3] - col_name = df.columns[3] # colonne (Name) des lignes directrices - col_x = df.columns[0] - col_y = df.columns[1] - list_name = df[col_name].to_list() # liste de noms de lignes directrices - list_x = df[col_x].to_list() - list_y = df[col_y].to_list() - list_ld = [[list_x[list_name.index(name)], list_y[list_name.index(name)], name] - for name in intersection_ld_list] - list_x_y_ld.append(list_ld) - if len(diff_union_instersect_ld) != 0: - list_ld_incomlete = [ - [list_x[list_name.index(name)], list_y[list_name.index(name)], name] - for name in diff_union_instersect_ld - if name in list_name - ] - - if len(list_ld_incomlete) != 0: - [list_x_y_ld_incomplete.append(i) for i in list_ld_incomlete] - - x_y_list_named_pt_i = [ - [listeld[i] for listeld in list_x_y_ld] - for i in range(len(intersection_ld_list)) - ] - - liste_x_ld = [[element[0] for element in x_y_list_named_pt_ii] - for x_y_list_named_pt_ii in x_y_list_named_pt_i] - - liste_y_ld = [[element[1] for element in x_y_list_named_pt_ii] - for x_y_list_named_pt_ii in x_y_list_named_pt_i] - - x_y_ld = [np.array([liste_x_ld[i], liste_y_ld[i]]) for i in range(len(x_y_list_named_pt_i))] - - if len(diff_union_instersect_ld) != 0: - x_y_list_named_pt_i_incomplete = [ - list(v) for _, v in - groupby(sorted(list_x_y_ld_incomplete, key=itemgetter(2)), - key=itemgetter(2)) - ] - - liste_x_ld_incomplete = [[element[0] for element in x_y_list_named_pt_ii] for x_y_list_named_pt_ii in - x_y_list_named_pt_i_incomplete] - liste_y_ld_incomplete = [[element[1] for element in x_y_list_named_pt_ii] for x_y_list_named_pt_ii in - x_y_list_named_pt_i_incomplete] - x_y_ld_incomplete = [np.array([liste_x_ld_incomplete[i], liste_y_ld_incomplete[i]]) for i in - range(len(x_y_list_named_pt_i_incomplete))] - else: - x_y_ld_incomplete = [] - return x_y_ld, x_y_ld_incomplete - else: - print("TODO") - return [] - - def get_pk_z_named_points(self): - list_pk_z_ld = [] - - for row in range(self.rowCount()): - df = self._data[row][1] # .iloc[row, 3] - col_name = df.columns[3] # colonne (Name) des lignes directrices - col_z = df.columns[2] - list_name = df[col_name].to_list() # liste de noms de lignes directrices - list_z = df[col_z].to_list() - Pk_i = float(self._data[row][0][4]) # le ième Pk - list_ld = [ - [Pk_i, list_z[list_name.index(name)], name] - for name in self.get_all_maned_points() - ] - - if len(list_ld) > 0: - list_pk_z_ld.append(list_ld) - - mon_list = [ - [listeld[i] for listeld in list_pk_z_ld] - for i in range(len(self.get_all_maned_points())) - ] - - liste_pk_ld = [ - [element[0] for element in mon_list[i]] - for i in range(len(mon_list)) - ] - liste_z_ld = [ - [element[1] for element in mon_list[i]] - for i in range(len(mon_list)) - ] - pk_z_ld = [ - np.array([liste_pk_ld[i], liste_z_ld[i]]) - for i in range(len(mon_list)) - ] - - return pk_z_ld - - def get_pk_z_ld(self): - """ - Returns: liste de [Pk, z, ld] par profil - liste de listes contenant les z des points nommés (lignes directrices) par profil - """ - - list_pk_z_ld = [] - list_pk_z_ld_incomplete = [] - - start = time.time() - liste = [data[1].iloc[:, 3].tolist() for data in self._data] - - intersection_ld = reduce(np.intersect1d, liste) - intersection_ld_list = [el for el in intersection_ld.tolist() if el != ""] - disjoint_union_ld = reduce(np.union1d, liste) - disjoint_union_ld_list = [el for el in disjoint_union_ld.tolist() if el != ""] - diff_union_instersect_ld = list(set(disjoint_union_ld_list).symmetric_difference(set(intersection_ld_list))) - - for row in range(self.rowCount()): - df = self._data[row][1] # .iloc[row, 3] - col_name = df.columns[3] # colonne (Name) des lignes directrices - col_z = df.columns[2] - list_name = df[col_name].to_list() # liste de noms de lignes directrices - list_z = df[col_z].to_list() - Pk_i = float(self._data[row][0][4]) # le ième Pk - - list_ld = [[Pk_i, list_z[list_name.index(name)], name] for name in - intersection_ld_list] # disjoint_union_ld_list] - - if len(diff_union_instersect_ld) != 0: - list_ld_incomlete = [[Pk_i, list_z[list_name.index(name)], name] for name in diff_union_instersect_ld if - name in list_name] - list_pk_z_ld_incomplete.append(list_ld_incomlete) - - if len(list_ld) > 0: - list_pk_z_ld.append(list_ld) - - my_list = [] - ll = [] - - for listeld in list_pk_z_ld: - ll.append(listeld[1]) - - ll0 = [listeld[1] for listeld in list_pk_z_ld] - mon_list = [[listeld[i] for listeld in list_pk_z_ld] for i in range(len(intersection_ld_list))] - liste_z_ld = [[el[1] for el in mon_list[i]] for i in range(len(mon_list))] - liste_pk_ld = [[el[0] for el in mon_list[i]] for i in range(len(mon_list))] - pk_z_ld = [np.array([liste_pk_ld[i], liste_z_ld[i]]) for i in range(len(mon_list))] - - for j in range(len(list_pk_z_ld[0])): - lst = [el[j][1] for el in list_pk_z_ld] - my_list.append(lst) - - return my_list # liste de listes contenant les z des points nommés (lignes directrices) par profil - - def model_data(self): - return self._data - class Delegate(QtWidgets.QStyledItemDelegate): # Lorsque l'on souhaite uniquement personnaliser l'édition des éléments dans une vue et non le rendu, @@ -941,56 +372,6 @@ class Delegate(QtWidgets.QStyledItemDelegate): """permet de redimensionner l'éditeur à la bonne taille lorsque la taille de la vue change""" editor.setGeometry(option.rect) - -class Delegate11(QtWidgets.QItemDelegate): - def __init__(self, owner, choices): - super().__init__(owner) - self.items = choices - - def createEditor(self, parent, option, index): - self.editor = QtWidgets.QComboBox(parent) - # self.editor.currentIndexChanged.connect(self.commit_editor) - self.editor.addItems(self.items) - return self.editor - - def paint(self, painter, option, index): - value = index.data(Qt.DisplayRole) - style = QtWidgets.QApplication.style() - opt = QtWidgets.QStyleOptionComboBox() - opt.text = str(value) - opt.rect = option.rect - style.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt, painter) - QtWidgets.QItemDelegate.paint(self, painter, option, index) - - - # def commit_editor(self): - # editor = self.sender() - # color = QtGui.QColor() - # if editor.currentText() == "ProfilXYZ": - # color = QtGui.QColor("lightgreen") - # elif editor.currentText() == "ProfilAC": - # color = QtGui.QColor("red") - # qss = """QComboBox{background-color : %s;}""" % (color.name(),) - # editor.setStyleSheet(qss) - # self.commitData.emit(editor) - - def setEditorData(self, editor, index): - editor.blockSignals(True) - editor.setCurrentIndex(index.row()) # replacement - editor.blockSignals(False) - - # @pyqtSlot() - # def currentIndexChanged(self): - # self.commit_editor.emit(self.sender()) - - def setModelData(self, editor, model, index): - value = editor.currentText() - model.setData(index, Qt.DisplayRole, QVariant(value)) - - def updateEditorGeometry(self, editor, option, index): - editor.setGeometry(option.rect) - - class Delegate1(QtWidgets.QStyledItemDelegate): def __init__(self, owner, choices): super().__init__(owner) @@ -1007,17 +388,6 @@ class Delegate1(QtWidgets.QStyledItemDelegate): editor.addItems(self.items) return editor - # def commit_editor(self): - # editor = self.sender() - # color = QtGui.QColor() - # if editor.currentText() == "ProfilXYZ": - # color = QtGui.QColor("lightgreen") - # elif editor.currentText() == "ProfilAC": - # color = QtGui.QColor("red") - # qss = """QComboBox{background-color : %s;}""" % (color.name(),) - # editor.setStyleSheet(qss) - # self.commitData.emit(editor) - def setEditorData(self, editor, index): editor.blockSignals(True) text = index.model().data(index, Qt.DisplayRole)