Geometry: Remove old OnPickEvent file.

setup.py
Pierre-Antoine Rouby 2024-05-07 17:02:42 +02:00
parent 317cbf904d
commit 731567369e
2 changed files with 0 additions and 575 deletions

View File

@ -22,7 +22,6 @@ from math import dist, sqrt
from tools import timer, trace from tools import timer, trace
from View.Tools.PamhyrPlot import PamhyrPlot from View.Tools.PamhyrPlot import PamhyrPlot
from View.Tools.Plot.OnPickEvent import OnpickEvent
from PyQt5.QtCore import ( from PyQt5.QtCore import (
Qt, QCoreApplication, QItemSelectionModel Qt, QCoreApplication, QItemSelectionModel

View File

@ -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 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