diff --git a/src/Meshing/Internal.py b/src/Meshing/Internal.py index ed9a5c48..b2a0cf97 100644 --- a/src/Meshing/Internal.py +++ b/src/Meshing/Internal.py @@ -50,20 +50,23 @@ class InternalMeshing(AMeshingTool): elif limites[0] == limites[1]: return reach - self.st_to_m(reach, limites) - self.interpolate_transversal_step(reach, - limites, - step) - self.purge_aligned_points(reach) + # we never modify original profiles, we work on copies + m_profiles= self.st_to_m(reach, limites) + new_profiles = self.interpolate_transversal_step(m_profiles, + step) - return reach + for new_profiles2 in new_profiles: + for p in new_profiles2: + p.purge_aligned_points() + + return new_profiles def st_to_m(self, reach, limites): gl = reach.compute_guidelines() - profiles = reach.profiles[limites[0]:limites[1]+1] - - print(profiles) + profiles = [reach.profiles[i].copy() + for i in range(limites[0], limites[1]+1) + ] # we make sure that the lines are in the left-to-right order guide_list = [ @@ -86,9 +89,9 @@ class InternalMeshing(AMeshingTool): for i in range(len(guide_list) - 1): index1 = p.named_point_index(guide_list[i]) index2 = p.named_point_index(guide_list[i+1]) - if index2 - index1 > max_values[i + 1]: - max_values[i + 1] = index2 - index1 - max_values_index[i + 1] = j + if index2 - index1 > max_values[i+1]: + max_values[i+1] = index2 - index1 + max_values_index[i+1] = j index1 = p.named_point_index(guide_list[-1]) index2 = len(p) - 1 if index2 - index1 > max_values[-1]: @@ -104,46 +107,44 @@ class InternalMeshing(AMeshingTool): self.compl_sect(profiles[isect+1], profiles[isect], gl1[i], gl2[i]) + return profiles def interpolate_transversal_step(self, - reach, - limites, + profiles, step): # calcul number of intermediate profiles np = [] - for i in range(limites[0], limites[1]): - np.append(int((reach.profiles[i+1].rk - - reach.profiles[i].rk) / step) - 1) + for i in range(len(profiles)-1): + np.append(int((profiles[i+1].rk - + profiles[i].rk) / step) - 1) if np[-1] < 0: np[-1] = 0 - d = [] # ratios - p = [] # new profiles - ptr = int(limites[0]) - for i in range(limites[1] - limites[0]): + new_profiles = [] + for i in range(len(profiles)-1): + new_profiles2 = [] d = 1.0/float(np[i]+1) - ptr0 = ptr for j in range(np[i]): - p = reach.profiles[ptr0].copy() + p = profiles[i].copy() # RATIO entre les deux sections initiales dj = float(j+1)*d - ptr += 1 # next profile, original - for k in range(len(reach.profiles[ptr0].points)): - p.points[k].x = reach.profiles[ptr0].points[k].x + \ - dj*(reach.profiles[ptr].points[k].x - - reach.profiles[ptr0].points[k].x) - p.points[k].y = reach.profiles[ptr0].points[k].y + \ - dj*(reach.profiles[ptr].points[k].y - - reach.profiles[ptr0].points[k].y) - p.points[k].z = reach.profiles[ptr0].points[k].z + \ - dj*(reach.profiles[ptr].points[k].z - - reach.profiles[ptr0].points[k].z) - p.rk = reach.profiles[ptr0].rk + \ - dj*(reach.profiles[ptr].rk - - reach.profiles[ptr0].rk) + for k in range(len(profiles[i].points)): + p.points[k].x = profiles[i].points[k].x + \ + dj*(profiles[i+1].points[k].x - + profiles[i].points[k].x) + p.points[k].y = profiles[i].points[k].y + \ + dj*(profiles[i+1].points[k].y - + profiles[i].points[k].y) + p.points[k].z = profiles[i].points[k].z + \ + dj*(profiles[i+1].points[k].z - + profiles[i].points[k].z) + p.rk = profiles[i].rk + \ + dj*(profiles[i+1].rk - + profiles[i].rk) p.name = f'interpol{p.rk}' - reach.insert_profile(ptr, p) - ptr += 1 # next profile, original + new_profiles2.append(p) + new_profiles.append(new_profiles2) + return new_profiles def compl_sect(self, sect1, sect2, tag1, tag2): # sect1: reference section @@ -281,14 +282,14 @@ class InternalMeshing(AMeshingTool): origin_value=0.0, orientation=0): if reach is None or len(reach.profiles) == 0: - return reach + return [] nprof = reach.number_profiles if origin >= nprof or origin < 0: logger.warning( f"Origin outside reach" ) - return reach + return reach.get_rk() # orientation is the orintation of the bief: # 1: up -> downstream @@ -301,7 +302,8 @@ class InternalMeshing(AMeshingTool): else: sgn = sign(reach.profiles[-1].rk - reach.profiles[0].rk) - reach.profiles[origin].rk = origin_value + rk = [0.0]*nprof + rk[origin] = origin_value if origin < nprof - 1: for i in range(origin+1, nprof): @@ -312,8 +314,7 @@ class InternalMeshing(AMeshingTool): d2 = reach.profiles[i-1].named_point( directrices[1] ).dist_2d(reach.profiles[i].named_point(directrices[1])) - reach.profiles[i].rk = reach.profiles[i-1].rk \ - + (sgn * (d1 + d2) / 2) + rk[i] = rk[i-1] + (sgn * (d1 + d2) / 2) if origin > 0: for i in reversed(range(0, origin)): # 2D @@ -323,9 +324,6 @@ class InternalMeshing(AMeshingTool): d2 = reach.profiles[i+1].named_point( directrices[1] ).dist_2d(reach.profiles[i].named_point(directrices[1])) - reach.profiles[i].rk = reach.profiles[i+1].rk \ - - (sgn * (d1 + d2) / 2) + rk[i] = rk[i+1] - (sgn * (d1 + d2) / 2) - def purge_aligned_points(self, reach): - for p in reach.profiles: - p.purge_aligned_points() + return rk diff --git a/src/Model/Geometry/PointXYZ.py b/src/Model/Geometry/PointXYZ.py index b82e51e9..3215d009 100644 --- a/src/Model/Geometry/PointXYZ.py +++ b/src/Model/Geometry/PointXYZ.py @@ -278,7 +278,7 @@ class PointXYZ(Point): id=-1, name=self.name, x=self.x, y=self.y, z=self.z, - profile=self.profile, + profile=self._profile, status=self._status ) if self.is_deleted(): @@ -406,13 +406,3 @@ class PointXYZ(Point): d = np.sqrt(abs(a2 - pow((c2 - b2 + a2) / (2*np.sqrt(c2)), 2))) return d - - def copy(self): - p = PointXYZ(self.x, - self.y, - self.z, - self.name, - self._profile, - self._status) - p.sl = self.sl - return p diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index 6f5f05fd..8193c999 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -1109,14 +1109,12 @@ class ProfileXYZ(Profile, SQLSubModel): self.point(i+1).z = 0.5 * self.point(i).z + 0.5 * self.point(i+2).z def copy(self): - p = ProfileXYZ(self.id, - self.name, - self.rk, - self.reach, - self.num, - 0, - 0, 0, - self._status) + p = ProfileXYZ(id=self.id, + name=self.name, + rk=self.rk, + reach=self.reach, + num=self.num, + status=self._status) for i, k in enumerate(self.points): p.insert_point(i, k.copy()) diff --git a/src/Model/Geometry/Reach.py b/src/Model/Geometry/Reach.py index 8b24437f..21de29a4 100644 --- a/src/Model/Geometry/Reach.py +++ b/src/Model/Geometry/Reach.py @@ -220,6 +220,26 @@ class Reach(SQLSubModel): ) self.modified() + def hard_delete(self, indexes): + """Delete some elements in profile list + + Args: + indexes: The list of index to delete + + Returns: + Nothing. + """ + self._profiles = list( + map( + lambda p: p[1], + filter( + lambda e: e[0] not in indexes, + enumerate(self._profiles) + ) + ) + ) + self.modified() + def delete_profiles(self, profiles): """Delete some elements in profile list diff --git a/src/View/Geometry/Table.py b/src/View/Geometry/Table.py index bb60324f..33a7a9aa 100644 --- a/src/View/Geometry/Table.py +++ b/src/View/Geometry/Table.py @@ -250,12 +250,12 @@ class GeometryReachTableModel(PamhyrTableModel): self.layoutAboutToBeChanged.emit() self.layoutChanged.emit() - def meshing(self, mesher, data): + def meshing(self, mesher, data, tableView): self.layoutAboutToBeChanged.emit() self._undo.push( MeshingCommand( - self._data, mesher, data, "mesh" + self._data, mesher, data, tableView ) ) @@ -266,8 +266,8 @@ class GeometryReachTableModel(PamhyrTableModel): self.layoutAboutToBeChanged.emit() self._undo.push( - MeshingCommand( - self._data, mesher, data, "update_rk" + UpdateRKCommand( + self._data, mesher, data ) ) diff --git a/src/View/Geometry/UndoCommand.py b/src/View/Geometry/UndoCommand.py index c2de3232..9098d6b6 100644 --- a/src/View/Geometry/UndoCommand.py +++ b/src/View/Geometry/UndoCommand.py @@ -22,8 +22,10 @@ from copy import deepcopy from tools import trace, timer, logger_exception from PyQt5.QtWidgets import ( - QMessageBox, QUndoCommand, QUndoStack, QTableView + QMessageBox, QUndoCommand, QUndoStack, QTableView, ) +from PyQt5.QtCore import (QItemSelection, QItemSelectionRange, + QItemSelectionModel) from Model.Geometry import Reach from Model.Except import exception_message_box @@ -227,47 +229,109 @@ class ImportCommand(QUndoCommand): self._reach.insert_profile(self._row, profile) -class MeshingCommand(QUndoCommand): - def __init__(self, reach, mesher, data, command): +class UpdateRKCommand(QUndoCommand): + def __init__(self, reach, mesher, data): QUndoCommand.__init__(self) self._reach = reach self._data = data self._mesher = mesher - self._command = command + self._rks = reach.get_rk() - self._profiles = [p.copy() for p in reach.profiles] - self._profiles.reverse() - - self._new_profiles = None + self._new_rks = None def undo(self): - self._reach.purge() + for rk, profile in zip(self._rks, self._reach.profiles): + profile.rk = rk - for profile in self._profiles: - self._reach.insert_profile(0, profile) + def redo(self): + if self._new_rks is None: + self._new_rks = self._mesher.update_rk( + self._reach, + **self._data + ) + + for rk, profile in zip(self._new_rks, self._reach.profiles): + profile.rk = rk + +class MeshingCommand(QUndoCommand): + def __init__(self, reach, mesher, data, tableView): + QUndoCommand.__init__(self) + + self._reach = reach + self._data = data + self._limites = data["limites"] + self._mesher = mesher + + self._new_profiles = None + self._new_profiles_indexes = None + self._tableView = tableView + self._indexes = tableView.selectionModel().selection() + + rows = list( + set( + (i.row() for i in tableView.selectedIndexes()) + ) + ) + self._selected_rk = [self._reach.profile(r).rk for r in rows] + self._new_indexes = None + + def undo(self): + self._reach.hard_delete(self._new_profiles_indexes) + + # Update selection + selection = self._tableView.selectionModel() + selection.select( + self._indexes, + QItemSelectionModel.Rows | + QItemSelectionModel.ClearAndSelect | + QItemSelectionModel.Select + ) def redo(self): if self._new_profiles is None: - if self._command == "update_rk": - self._mesher.update_rk( - self._reach, - **self._data - ) - else: - self._mesher.meshing( - self._reach, - **self._data - ) + self._new_profiles = self._mesher.meshing( + self._reach, + **self._data + ) - self._new_profiles = [p.copy() for p in self._reach.profiles] - self._new_profiles.reverse() - else: - self._reach.purge() + if self._new_profiles_indexes is None: + k = self._limites[0] + self._new_profiles_indexes = [] + for i in range(self._limites[1] - self._limites[0]): + k += 1 + for p in self._new_profiles[i]: + self._new_profiles_indexes.append(k) + k += 1 - for profile in self._new_profiles: - self._reach.insert_profile(0, profile) + k = self._limites[0] + for i in range(self._limites[1] - self._limites[0]): + k += 1 + for p in self._new_profiles[i]: + self._reach.insert_profile(k, p) + k += 1 + # Update selection + if self._new_indexes is None: + ind = [] + for i in range(self._reach.number_profiles): + if self._reach.profile(i).rk in self._selected_rk: + ind.append(i) + self._tableView.setFocus() + self._new_indexes = QItemSelection() + if len(ind) > 0: + for i in ind: + self._new_indexes.append(QItemSelectionRange( + self._tableView.model().index(i, 0) + )) + + selection = self._tableView.selectionModel() + selection.select( + self._new_indexes, + QItemSelectionModel.Rows | + QItemSelectionModel.ClearAndSelect | + QItemSelectionModel.Select + ) class PurgeCommand(QUndoCommand): def __init__(self, reach, np_purge): diff --git a/src/View/Geometry/UpdateRKDialog.py b/src/View/Geometry/UpdateRKDialog.py index cd96346c..43a897c7 100644 --- a/src/View/Geometry/UpdateRKDialog.py +++ b/src/View/Geometry/UpdateRKDialog.py @@ -64,8 +64,17 @@ class UpdateRKDialog(PamhyrDialog): self._end_dir = self._gl[i] self._orientation = 0 - self._origin = self._reach.profile(0) - self._origin_value = self._reach.profile(0).rk + r = self.parent.tableView\ + .selectionModel()\ + .selectedRows() + if len(r) < 1: + self._origin = self._reach.profile(0) + self._origin_value = self._reach.profile(0).rk + self._origin_index = 0 + else: + self._origin = self._reach.profile(r[0].row()) + self._origin_value = self._reach.profile(r[0].row()).rk + self._origin_index = r[0].row() self._init_default_values_profiles() self._init_default_values_guidelines() @@ -80,6 +89,8 @@ class UpdateRKDialog(PamhyrDialog): .connect( self.changed_profile ) + self.find(QComboBox, "comboBox_origin")\ + .setCurrentIndex(self._origin_index) buttonbox = self.find(QButtonGroup, "buttonGroup_orientation") diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py index e3e1ac9b..b28754a5 100644 --- a/src/View/Geometry/Window.py +++ b/src/View/Geometry/Window.py @@ -323,29 +323,10 @@ class GeometryWindow(PamhyrWindow): logger_exception(e) return - ind = [] - for i in range(self._reach.number_profiles): - if self._reach.profile(i).rk in selected_rk: - ind.append(i) - self.tableView.setFocus() - selection = self.tableView.selectionModel() - index = QItemSelection() - if len(ind) > 0: - for i in ind: - index.append(QItemSelectionRange( - self.tableView.model().index(i, 0) - )) - selection.select( - index, - QItemSelectionModel.Rows | - QItemSelectionModel.ClearAndSelect | - QItemSelectionModel.Select - ) - def _edit_meshing(self, data): try: mesher = InternalMeshing() - self._table.meshing(mesher, data) + self._table.meshing(mesher, data, self.tableView) except Exception as e: logger_exception(e) @@ -370,7 +351,7 @@ class GeometryWindow(PamhyrWindow): def _update_rk(self, data): try: - mesher = MeshingWithMageMailleurTT() + mesher = InternalMeshing() self._table.update_rk(mesher, data) except Exception as e: logger_exception(e)