From 731567369eec29852a7a86c83fca8ffb67a84739 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby <pierre-antoine.rouby@inrae.fr> Date: Tue, 7 May 2024 17:02:42 +0200 Subject: [PATCH] Geometry: Remove old OnPickEvent file. --- src/View/Geometry/Profile/Plot.py | 1 - src/View/Tools/Plot/OnPickEvent.py | 574 ----------------------------- 2 files changed, 575 deletions(-) delete mode 100644 src/View/Tools/Plot/OnPickEvent.py diff --git a/src/View/Geometry/Profile/Plot.py b/src/View/Geometry/Profile/Plot.py index 357bb5b8..5f488592 100644 --- a/src/View/Geometry/Profile/Plot.py +++ b/src/View/Geometry/Profile/Plot.py @@ -22,7 +22,6 @@ from math import dist, sqrt from tools import timer, trace from View.Tools.PamhyrPlot import PamhyrPlot -from View.Tools.Plot.OnPickEvent import OnpickEvent from PyQt5.QtCore import ( Qt, QCoreApplication, QItemSelectionModel diff --git a/src/View/Tools/Plot/OnPickEvent.py b/src/View/Tools/Plot/OnPickEvent.py deleted file mode 100644 index 44fae764..00000000 --- a/src/View/Tools/Plot/OnPickEvent.py +++ /dev/null @@ -1,574 +0,0 @@ -# mpl_canvas_onpick_event.py -- Pamhyr -# Copyright (C) 2023-2024 INRAE -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. - -import logging - -from time import time - -import numpy as np -from PyQt5 import QtWidgets -from PyQt5.QtCore import QItemSelectionModel, Qt -from PyQt5.QtWidgets import QApplication -from shapely.geometry.polygon import Polygon as ShapelyPolygon - -logger = logging.getLogger() - - -class OnpickEvent(object): - def __init__(self, ax, x, y, x_carto, y_carto, tableview=None): - """ - Args: - ax: objet Axes. - x: abscisse x1 du graphe (f(x1) = y1) à tracer. - y: ordonnée y1 du graphe (f(x1) = y1) à tracer. - x_carto: (vecteur) abscisse des points (X,Y,Z) du profil. - y_carto: (vecteur) abscisse des points (X,Y,Z) du profil - tableview: tableau (de type QtableView) 'associé' au grahique. - """ - self.ax = ax - self.x = x - self.y = y - self.x_carto = x_carto - self.y_carto = y_carto - self.tableView = tableview - self.counter_onclick = 0 - # self.select_point_plot() - self.count = 0 - self.annotation_onclick = self.ax.annotate( - "", - xytext=(np.mean(self.x), np.mean(self.y)), - xy=(np.mean(self.x), np.mean(self.y)), - horizontalalignment='center', - fontsize=8, - # fontstyle='italic', - fontweight='bold', - alpha=0.7 - ) - self.annotation_onclick.set_visible(False) - self.pos_x = 0 - self.zomm_xmin_xmax = self.ax.get_xlim() - self.plot_selec() - # self.select_point_plot() - self._largeur_miroir, = self.ax.plot( - self.x[1], self.y[1], - color='blue', lw=1.2, ls=":" - ) - - self.pt = [] - self.tableView.selectionModel()\ - .selectionChanged\ - .connect(self.update_select_point_point) - - def select_row_pt_clicked(self, ind: int = 0): - """ - Args: - ind: Indice de la ligne où se trouve le point le plus proche - 'visé'. - - Returns: Sélectionne la ligne (du tableau) correspondant au point le - plus proche 'visé' à la suite de l'événement onpick. - """ - if self.tableView is not None: - selectionModel = self.tableView.selectionModel() - index = self.tableView.model().index(ind, 0) - selectionModel.select( - index, - QItemSelectionModel.Rows | - QItemSelectionModel.ClearAndSelect | - QItemSelectionModel.Select - ) - self.tableView.scrollTo(index) - - def select_qtableview_row(self, event): - if self.tableView is not None: - self.tableView.setFocus() - ind = self.indice_points_onpick(event) - dataidx_ecran = self.index_pt_plus_proche_ecran(event) - self.select_row_pt_clicked(ind[dataidx_ecran]) - - def select_point_plot(self): - """ - Returns: sélectionne le(s) point(s) du graphique correspondant à - la/aux ligne(s) sélectionnée(s) dans le tableau. - """ - if self.tableView is not None: - rows = list(set( - [index.row() for index in self.tableView.selectedIndexes()] - )) - for row in rows: - pass - - def update_select_point_point(self): - if self.tableView is not None: - rows = list(set( - [index.row() for index in self.tableView.selectedIndexes()] - )) - - if len(rows) > 1: - for row in rows: - self.pt1 = self.ax.plot(self.x[row], self.y[row], - '+', c='Blue', markersize=7) - self.pt.append(self.pt1) - self.update_select_point_point_bis( - self.x[row], self.y[row]) - elif len(rows) == 1: - for row in rows: - try: - [pl[0].set_data([], []) - for pl in self.pt if len(self.pt) > 1] - except Exception: - logger.info("update_select_point_point: Update issue") - - try: - self.update_select_point_point_bis(self.x[row], - self.y[row]) - except Exception: - logger.info( - "update_select_point_point_bis: Update issue, " + - "possible index missing" - ) - - self.ax.figure.canvas.draw_idle() - - def plot_selec(self): - self.point_selec, = self.ax.plot(self.x[0], self.y[0], - '+', c='Blue', markersize=7) - self.point_selec.set_visible(False) - - def update_select_point_point_bis(self, x_ind, y_ind): - self.point_selec.set_data(x_ind, y_ind) - self.point_selec.set_visible(True) - self.ax.figure.canvas.draw_idle() - - def plot_selection_point(self, x, y): - """ - Args: - x: abscissa - y: ordinate - - Returns: sélectionne le point du graphique correspond à la ligne - sélectionnée dans le tableau. - """ - if self.tableView is not None: - self.select_point, = self.ax.plot( - x, y, - '+', c='Blue', - markersize=7 - ) - else: - self.select_point, = self.ax.plot([], []) - - def geometrie_sans_rebord(self): - rebord = True - z_sans_rebord = [i for i in self.y] - x_sans_rebord = [i for i in self.x] - - while rebord: - if z_sans_rebord[1] >= z_sans_rebord[0]: - z_sans_rebord.pop(0) - x_sans_rebord.pop(0) - else: - rebord = False - - rebord = True - while rebord: - if z_sans_rebord[-1] <= z_sans_rebord[-2]: - z_sans_rebord.pop() - x_sans_rebord.pop() - else: - rebord = False - - z_berge_basse = min(z_sans_rebord[0], z_sans_rebord[-1]) - - return z_berge_basse, z_sans_rebord, x_sans_rebord - - @property - def z_berge_basse(self): - return self.geometrie_sans_rebord()[0] - - @property - def z_sans_rebord(self): - return self.geometrie_sans_rebord()[1] - - @property - def x_sans_rebord(self): - return self.geometrie_sans_rebord()[2] - - @property - def z_fond(self): - return np.array(self.z_sans_rebord) - - @property - def z_point_bas(self): - """ - Returns: la cote (Zmin) du point le plus bas. - """ - return min(self.y) - - @property - def delta_x(self): - """" - Returns: la longueur entre les limites de la vue sur l'axe des x, - c'est-à -dire |x_max_visible - x_min_visible|. - """ - xgauche, xdroite = self.ax.get_xlim() - delta_x = abs(xdroite - xgauche) - return delta_x - - @property - def delta_y(self): - """ - Returns: la longueur entre les limites de la vue sur l'axe des y, - c'est à dire |y_max_visible - y_min_visible|. - """ - ybas, yhaut = self.ax.get_ylim() - delta_y = abs(yhaut - ybas) - return delta_y - - @staticmethod - def indice_points_onpick(event): - """ - Args: event - Returns: le(s) indexe(s) du/des point(s) (plus précisement les - coordonnées de points) capturé(s) par l'événement onpick - (voir picker) - """ - return event.ind - - def points_onpick(self, event): - """ - Args: - event: - Returns: une array contenant les coordonées des points qui se - trouvent dans la zone définie par l'événement onpick - (voir picker) - """ - thisline = event.artist - xdata = thisline.get_xdata() - ydata = thisline.get_ydata() - points_onpick = np.array( - [(xdata[i], ydata[i]) for i in self.indice_points_onpick(event)] - ) - return points_onpick - - def distance_normee(self, event): - """ - Args: - event: - Returns: la liste des distances normées (en m) entre les points - situés dans la région définie par l'événement onpick - (voir picker). - """ - ind = event.ind - thisline = event.artist - xdata = thisline.get_xdata() - ydata = thisline.get_ydata() - points_onpick = np.array([(xdata[i], ydata[i]) for i in ind]) - distances_normees = [ - (((x - event.mouseevent.xdata) / self.delta_x) ** 2 + - ((y - event.mouseevent.ydata) / self.delta_y) ** 2) ** (1 / 2) - for (x, y) in points_onpick - ] - return distances_normees - - def position_souris(self, event): - """ - Args: - event: - Returns: la position de la souris - """ - self.pos_souris = [(event.mouseevent.xdata, event.mouseevent.ydata)] - return self.pos_souris - - def distance_ecran(self, event): - """ - Args: - event: - Returns: la liste des distances 'visuelles' entre les points situés - dans la région définie par l'événement onpick (voir picker). - """ - bbox = self.ax.get_window_extent()\ - .transformed(self.ax.figure.dpi_scale_trans.inverted()) - ratio_w_sur_h = bbox.width / bbox.height - distances_ecran = [ - ( - ( - (x - event.mouseevent.xdata) / - (self.delta_x * ratio_w_sur_h) - ) ** 2 + - ( - (y - event.mouseevent.ydata) / - self.delta_y - ) ** 2 - ) ** (1 / 2) - for (x, y) in self.points_onpick(event) - ] - - return distances_ecran - - def distances(self, event): - """ - Args: - event: - Returns: la liste des distances entre la position de la souris et - tous les points se trouvant dans la zone définie par - l'événement onpick (voir picker) - """ - distances = np.linalg.norm( - self.points_onpick(event) - self.position_souris(event), - axis=1 - ) - - return distances - - def index_pt_plus_proche_ecran(self, event): - """ - Args: - event: - Returns: indice du point le plus proche visuellement de la position - du click. - """ - dataidx_ecran = np.argmin(self.distance_ecran(event)) - return dataidx_ecran - - def point_plus_proche_ecran(self, event): - point_onpick = self.points_onpick(event) - datapos_ecran = point_onpick[ - self.index_pt_plus_proche_ecran(event) - ] - - return self.points_onpick(event)[ - self.index_pt_plus_proche_ecran(event) - ] - - def index_pt_plus_proche(self, event): - """ - Args: - event: - Returns: indice du point le plus proche de la position du click. - """ - dataidx = np.argmin(self.distances(event)) - - return dataidx - - def point_plus_proche(self, event): - """ - Args: - event: - Returns: point le plus proche de la position du click - """ - point_onpick = self.points_onpick(event) - datapos = point_onpick[self.index_pt_plus_proche(event)] - - return datapos - - def annotate_onpick(self, x, y): - """ - Args: - x: abscisse du point à annoter. - y: ordonnée du point à annoter. - Returns: annote le point xy avec du texte text = xytext. - """ - return self.ax.annotate( - "X", xytext=(x, y), - xy=(x, y), fontsize=9, - bbox=dict( - boxstyle='round,pad=0.8', fc='yellow', alpha=0.75 - ), - arrowprops=dict( - arrowstyle='->', - connectionstyle='arc3,rad=0.', - color='blue' - ) - ) - - def on_ylims_change(self, event_ax): - return event_ax.get_ylim() - - def annotate_onclick(self, event): - if self.z_point_bas <= event.ydata: - self.count += 1 - - if event.ydata <= self.z_berge_basse: - A, p, L = self.calcul_ligne_eau(event.ydata) - else: - event.ydata = self.z_berge_basse - A, p, L = self.calcul_ligne_eau(event.ydata) - - etiq = f"Z = {event.ydata:.3f} m, A = {A:.3f} "\ - f"m\u00B2, p = {p:.3f} m, L = {L:.3f} m" - self.annotation_onclick.set_text(etiq) - x_min, x_max = self.ax.get_xlim() - self.pos_x_annotation = x_min + ((x_max - x_min) / 2) - - percent = 0 - y_ecran_lim = ((max(self.ax.set_ylim()) - - min(self.ax.set_ylim())) / 2) - - if abs(y_ecran_lim) > 4: - percent = 0.05 - elif 4 < abs(y_ecran_lim) < 1.5: - percent = 0.01 - elif 0.5 < abs(y_ecran_lim) < 1.5: - percent = 0.05 - elif 0.25 < abs(y_ecran_lim) < 0.5: - percent = 0.08 - elif 0 < abs(y_ecran_lim) < 0.25: - percent = 0.25 - else: - percent = 0.1 - - cte = 0. - if abs(event.ydata) < 100: - cte = 0.05 - else: - cte = event.y * 0.1 / 100 - - self.y_pos_text_param_hydrau = event.ydata + cte - self.annotation_onclick.set_position( - (self.pos_x_annotation, - self.y_pos_text_param_hydrau) - ) - - self.ax.callbacks.connect('ylim_changed', self.on_ylims_change) - - self.annotation_onclick.set_color("DarkBlue") - self.annotation_onclick.set_visible(True) - self.annotation_onclick.set_horizontalalignment('center') - - self.ax.figure.canvas.draw_idle() - - return self.annotation_onclick - - def largeur_au_miroir(self, event): - if event.ydata <= self.z_berge_basse: - self._largeur_miroir.set_data( - [min(self.x), max(self.x)], - [event.ydata, event.ydata] - ) - else: - self._largeur_miroir.set_data( - [min(self.x), max(self.x)], - [self.z_berge_basse, self.z_berge_basse] - ) - - return self._largeur_miroir - - def onpick(self, event): - modifiers = QApplication.keyboardModifiers() - - if modifiers == Qt.ControlModifier: - if event.mouseevent.inaxes == self.ax: - self.select_qtableview_row(event) - x_proche, y_proche = self.point_plus_proche_ecran(event) - self.update_select_point_point_bis(x_proche, y_proche) - - self.ax.figure.canvas.draw_idle() - - def onclick(self, event): - modifiers = QtWidgets.QApplication.keyboardModifiers() - if modifiers == Qt.ShiftModifier: - if event.inaxes == self.ax: - if self.z_point_bas < event.ydata: - try: - self.poly_col_bis.remove() - self.largeur_au_miroir(event) - except Exception: - self.largeur_au_miroir(event) - - self.annotate_onclick(event) - self.ax.figure.canvas.draw_idle() - - def remplir_zone_mouillee(self, x, y1, y2): - """ - Args: - x: Les coordonnées x des nœuds définissant la courbe. - y1: points définisant le polygone à déssiner. - y2: points définisant le polygone à déssiner. - Returns: dessine et colorie la région définie par le polygone. - """ - return self.ax.fill_between( - x, y1=y1, y2=y2, where=y1 > y2, interpolate=True, - facecolor='skyblue', alpha=0.7 - ) - - def calcul_ligne_eau(self, val: float) -> (float, float, float): - """ - Args: - val: Valeur de la cote Z à laquelle on veut caluler A , p et L. - Returns: la valeur de la section mouillée A, du périmètre mouillé p - et de la largeur au miroir L. - """ - largeur_miroir = 0. - section_mouillee_totale = 0. - perimetre_mouille_total = 0. - - if self.z_point_bas < val <= self.z_berge_basse: - z_eau = np.array([val] * (len(self.z_sans_rebord))) - self.poly_col_bis = self.remplir_zone_mouillee(self.x_sans_rebord, - z_eau, - self.z_sans_rebord) - liste_chemins = self.poly_col_bis.get_paths() - couleurs = ['crimson', 'pink'] * len(liste_chemins) - aire_calculee_shapely = None - perimetre_mouille_total_shapely = None - perimetre_shapely = 0. - perim_calc = 0. - - for polyg, coul in zip( - liste_chemins, - couleurs[0:len(liste_chemins)] - ): - points_polygone = polyg.vertices - xs = points_polygone[:, 0] - ys = points_polygone[:, 1] - - liste_points_miroir = [ - x for (x, y) in zip(xs, ys) if np.isclose(y, val) - ] - largeur_miroir_polygone = liste_points_miroir[-2] - \ - liste_points_miroir[0] - largeur_miroir += largeur_miroir_polygone - - polygone_shapely = ShapelyPolygon(points_polygone) - aire_calculee_shapely = polygone_shapely.area - perimetre_shapely = polygone_shapely.length - perimetre_mouille_total_shapely = ( - polygone_shapely.length - largeur_miroir - ) - liste_points_fond = [ - (x, y) for (x, y) in zip(xs, ys) if not np.isclose(y, val) - ] - x_pt_prec, y_pt_prec = max(liste_points_miroir), val - - perimetre = 0 - aire = 0 - - for un_point in liste_points_fond + [ - (min(liste_points_miroir), val) - ]: - x_pt_suivant, y_pt_suivant = un_point - perimetre += ((x_pt_prec - x_pt_suivant) ** 2 + - (y_pt_prec - y_pt_suivant) ** 2) ** (1 / 2) - aire += (((val - y_pt_prec) + (val - y_pt_suivant)) * - abs(x_pt_suivant - x_pt_prec) / 2) - x_pt_prec, y_pt_prec = x_pt_suivant, y_pt_suivant - perim_calc = perimetre - - perimetre_mouille_total = perimetre_shapely - largeur_miroir - section_mouillee_totale = aire_calculee_shapely - - return section_mouillee_totale, perimetre_mouille_total, largeur_miroir -- GitLab