geomerty: Add Sylvain work and start cleaning code (doesn't works).

mesh
Pierre-Antoine Rouby 2023-04-04 11:34:36 +02:00
parent f4dd46cd1a
commit 35ba2599fb
12 changed files with 3986 additions and 2 deletions

View File

@ -134,6 +134,7 @@ class Reach:
def copy(self, index_list: List[int]):
self.__list_copied_profiles.clear()
index_list = list(set(index_list)) # delete duplicate index
for index in index_list:
try:
self.__list_copied_profiles.append(deepcopy(self.get_profile_i(index)))

View File

@ -0,0 +1,108 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import copy
import numpy as np
import pandas as pd
from time import time
from Model.Geometry import PointXYZ
from Model.Geometry.ProfileXYZ import ProfileXYZ
from Model.Geometry.vector_1d import Vector1d
def update_station(list_header, list_point_xyz):
profile = ProfileXYZ(list_header, list_point_xyz)
if profile.nb_points >= 3:
return get_station(profile)
else:
pass
def get_station(profile: ProfileXYZ) -> np.ndarray:
"""Projection of the points of the profile on a plane.
Args:
profile: The profile
Returns:
Projection of the points of the profile on a plane.
"""
if profile.nb_points >= 3:
first_named_point = None
index_first_named_point = None
last_named_point = None
for index, point in enumerate(profile.points):
if point.point_is_named():
index_first_named_point = index
first_named_point = point
break
for point in profile.points[::-1]:
if point.point_is_named():
last_named_point = point
break
station = [] # abscisse en travers
constant = 0.0 # constante pour décaler l'origine de l'ascisse en travers caluculée.
if (first_named_point is not None) and (last_named_point is not None):
if first_named_point != last_named_point and first_named_point.x != last_named_point.x:
vector = Vector1d(first_named_point, last_named_point)
normalized_direction_vec = vector.normalized_direction_vector()
else:
vector = Vector1d(_first_point_not_nan(profile), _last_point_not_nan(profile))
normalized_direction_vec = vector.normalized_direction_vector()
for point in profile.points:
xi = point.x - first_named_point.x
yi = point.y - first_named_point.y
station_i = normalized_direction_vec[0] * xi + normalized_direction_vec[1] * yi
station.append(station_i)
station = np.array(station)
constant = station[index_first_named_point] # pour placer l'origine au premier point nomme.
elif first_named_point is None:
vector = Vector1d(_first_point_not_nan(profile), _last_point_not_nan(profile))
normalized_direction_vec = vector.normalized_direction_vector()
for point in profile.points:
xi = point.x - _first_point_not_nan(profile).x
yi = point.y - _first_point_not_nan(profile).y
station_i = normalized_direction_vec[0] * xi + normalized_direction_vec[1] * yi
station.append(station_i)
station = np.array(station)
index_profile_z_min = np.where(np.array(profile.z) == profile.z_min)[0][0]
constant = station[index_profile_z_min] # pour placer l'origine au fond ie à la cote minimale
# z_min du profil.
station = station - constant
return station
else:
return np.array(np.nan)
def _point_is_nan(point: PointXYZ):
return pd.isna(point.x) or pd.isna(point.y) or pd.isna(point.z)
def _first_point_not_nan(profile: ProfileXYZ):
first_point_not_nan = profile.points[0]
for point in profile.points:
if not _point_is_nan(point):
first_point_not_nan = point
break
return first_point_not_nan
def _last_point_not_nan(profile: ProfileXYZ):
last_point = profile.points[-1]
for point in profile.points[::-1]:
if not _point_is_nan(point):
last_point = point
break
return last_point

View File

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
import numpy as np
from Model.Geometry.PointXYZ import PointXYZ
class Vector1d:
def __init__(self, a: PointXYZ, b: PointXYZ):
self.A = a
self.B = b
def __repr__(self):
return "vecteur AB = ({}, {}, {})".format(
self.B.x - self.A.x,
self.B.y - self.A.y,
self.B.z - self.A.z
)
def vector1d(self):
return np.array([
self.B.x - self.A.x,
self.B.y - self.A.y,
self.B.z - self.A.z
])
def direction_vector(self):
return np.array([
self.B.x - self.A.x,
self.B.y - self.A.y,
0
])
def norm_vector(self):
return np.linalg.norm(self.vector1d())
def norm_direction_vector(self):
return np.linalg.norm(self.direction_vector())
def normalized_direction_vector(self):
return self.direction_vector() / self.norm_direction_vector()

View File

@ -2,6 +2,8 @@
import os
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QMainWindow, QApplication, QDesktopWidget,
QMdiArea, QMdiSubWindow, QDialog,
@ -25,12 +27,12 @@ class ASubWindow(QDialog):
self.name = name
self.parent = parent
self.parent.sub_win_add(name, self)
self.fixed_size()
# self.fixed_size()
def fixed_size(self):
width = self.frameGeometry().width()
height = self.frameGeometry().height()
# self.setFixedSize(width, height)
self.setFixedSize(width, height)
def closeEvent(self, event):
if not self.parent is None:

View File

@ -0,0 +1,330 @@
# -*- coding: utf-8 -*-
import os.path
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import (
QTableView, QAbstractItemView, QHeaderView
)
from View.Plot import MplCanvas, navigation_toolbar_2qt
file_path = os.path.abspath(os.path.dirname(__file__))
icon_path = f"{os.path.dirname(os.path.dirname(file_path))}/../../ui/ressources/"
class Ui_MainWindow(object):
def setupUi(self, MainWindowProfile):
MainWindowProfile.setObjectName("MainWindowProfile")
MainWindowProfile.resize(1089, 699)
self.centralwidget = QtWidgets.QWidget(MainWindowProfile)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.splitter = QtWidgets.QSplitter(self.centralwidget)
self.splitter.setOrientation(Qt.Horizontal)
self.splitter.setObjectName("splitter")
self.widget = QtWidgets.QWidget(self.splitter)
self.widget.setObjectName("widget")
self.verticalLayout_left = QtWidgets.QVBoxLayout(self.widget)
self.verticalLayout_left.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_left.setObjectName("verticalLayout_left")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
btn_size = QSize(30, 30)
self.btn_add = QtWidgets.QPushButton(self.widget)
self.btn_add.setMaximumSize(QtCore.QSize(30, 30))
self.btn_add.setText("")
self.btn_add.setObjectName("btn_add")
icon_btn_add = QtGui.QIcon()
icon_btn_add.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-add.png"))
self.btn_add.setIcon(icon_btn_add)
self.btn_add.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_add)
self.btn_delete = QtWidgets.QPushButton(self.widget)
self.btn_delete.setMaximumSize(QtCore.QSize(30, 30))
self.btn_delete.setText("")
self.btn_delete.setObjectName("btn_delete")
icon_btn_delete = QtGui.QIcon()
icon_btn_delete.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-remove.png"))
self.btn_delete.setIcon(icon_btn_delete)
self.btn_delete.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_delete)
self.btn_sort_asc_x = QtWidgets.QPushButton(self.widget)
self.btn_sort_asc_x.setMaximumSize(QtCore.QSize(30, 30))
self.btn_sort_asc_x.setText("")
self.btn_sort_asc_x.setObjectName("btn_sort_asc_x")
icon_btn_sort_asc_x = QtGui.QIcon()
icon_btn_sort_asc_x.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-sort-ascending.png"))
self.btn_sort_asc_x.setIcon(icon_btn_sort_asc_x)
self.btn_sort_asc_x.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_sort_asc_x)
self.btn_sort_desc_x = QtWidgets.QPushButton(self.widget)
self.btn_sort_desc_x.setMaximumSize(QtCore.QSize(30, 30))
self.btn_sort_desc_x.setText("")
self.btn_sort_desc_x.setObjectName("btn_sort_desc_x")
icon_btn_sort_desc_x = QtGui.QIcon()
icon_btn_sort_desc_x.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-sort-descending.png"))
self.btn_sort_desc_x.setIcon(icon_btn_sort_desc_x)
self.btn_sort_desc_x.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_sort_desc_x)
self.btn_sort_asc_y = QtWidgets.QPushButton(self.widget)
self.btn_sort_asc_y.setMaximumSize(QtCore.QSize(30, 30))
self.btn_sort_asc_y.setText("")
self.btn_sort_asc_y.setObjectName("btn_sort_asc_y")
icon_btn_sort_asc_y = QtGui.QIcon()
icon_btn_sort_asc_y.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-sort-ascending.png"))
self.btn_sort_asc_y.setIcon(icon_btn_sort_asc_y)
self.btn_sort_asc_y.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_sort_asc_y)
self.btn_sort_desc_y = QtWidgets.QPushButton(self.widget)
self.btn_sort_desc_y.setMaximumSize(QtCore.QSize(30, 30))
self.btn_sort_desc_y.setText("")
self.btn_sort_desc_y.setObjectName("btn_sort_desc_y")
icon_btn_sort_desc_y = QtGui.QIcon()
icon_btn_sort_desc_y.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-sort-descending.png"))
self.btn_sort_desc_y.setIcon(icon_btn_sort_desc_y)
self.btn_sort_desc_y.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_sort_desc_y)
self.btn_move_up = QtWidgets.QPushButton(self.widget)
self.btn_move_up.setMaximumSize(QtCore.QSize(30, 30))
self.btn_move_up.setText("")
self.btn_move_up.setObjectName("btn_move_up")
icon_btn_move_up = QtGui.QIcon()
icon_btn_move_up.addPixmap(
QtGui.QPixmap(f"{icon_path}up.png"))
self.btn_move_up.setIcon(icon_btn_move_up)
self.btn_move_up.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_move_up)
self.btn_move_down = QtWidgets.QPushButton(self.widget)
self.btn_move_down.setMaximumSize(QtCore.QSize(30, 30))
self.btn_move_down.setText("")
self.btn_move_down.setObjectName("btn_move_down")
icon_btn_move_down = QtGui.QIcon()
icon_btn_move_down.addPixmap(
QtGui.QPixmap(f"{icon_path}down.png"))
self.btn_move_down.setIcon(icon_btn_move_down)
self.btn_move_down.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_move_down)
self.btn_export = QtWidgets.QPushButton(self.widget)
self.btn_export.setMaximumSize(QtCore.QSize(30, 30))
self.btn_export.setText("")
self.btn_export.setObjectName("btn_export")
icon_btn_export = QtGui.QIcon()
icon_btn_export.addPixmap(
QtGui.QPixmap(f"{icon_path}export.png"))
self.btn_export.setIcon(icon_btn_export)
self.btn_export.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_export)
self.btn_copy = QtWidgets.QPushButton(self.widget)
self.btn_copy.setMaximumSize(QtCore.QSize(30, 30))
self.btn_copy.setText("")
self.btn_copy.setObjectName("btn_copy")
icon_btn_copy = QtGui.QIcon()
icon_btn_copy.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-copy.png"))
self.btn_copy.setIcon(icon_btn_copy)
self.btn_copy.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_copy)
self.btn_paste = QtWidgets.QPushButton(self.widget)
self.btn_paste.setMaximumSize(QtCore.QSize(30, 30))
self.btn_paste.setText("")
self.btn_paste.setObjectName("btn_paste")
icon_btn_paste = QtGui.QIcon()
icon_btn_paste.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-paste.png"))
self.btn_paste.setIcon(icon_btn_paste)
self.btn_paste.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_paste)
self.btn_check = QtWidgets.QPushButton(self.widget)
self.btn_check.setMaximumSize(QtCore.QSize(30, 30))
self.btn_check.setText("")
self.btn_check.setObjectName("btn_check")
icon_btn_check = QtGui.QIcon()
icon_btn_check.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-apply.png"))
self.btn_check.setIcon(icon_btn_check)
self.btn_check.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_check)
self.btn_go_back = QtWidgets.QPushButton(self.widget)
self.btn_go_back.setMaximumSize(QtCore.QSize(30, 30))
self.btn_go_back.setText("")
self.btn_go_back.setObjectName("btn_go_back")
icon_btn_go_back = QtGui.QIcon()
icon_btn_go_back.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-undo.png"))
self.btn_go_back.setIcon(icon_btn_go_back)
self.btn_go_back.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_go_back)
self.btn_reset = QtWidgets.QPushButton(self.widget)
self.btn_reset.setMaximumSize(QtCore.QSize(30, 30))
self.btn_reset.setText("")
self.btn_reset.setObjectName("btn_reset")
icon_btn_reset = QtGui.QIcon()
icon_btn_reset.addPixmap(
QtGui.QPixmap(f"{icon_path}cancel.png"))
self.btn_reset.setIcon(icon_btn_reset)
self.btn_reset.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_reset)
spacerItem = QtWidgets.QSpacerItem(30, 30, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.verticalLayout_left.addLayout(self.horizontalLayout)
self.tableView = QTableView(self.widget)
self.tableView.setStyleSheet(" QTableView { border: 1px solid black;\n"
" gridline-color: blue;\n"
" border-radius: 2px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: #218ede;\n"
" font-size: 11.5px;\n"
" font-family: Helvetica\n"
"\n"
" }")
# self.tableView.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
# self.tableView.setGridStyle(Qt.SolidLine)
self.tableView.setObjectName("tableView")
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) # permet de sélectionner une ligne entière
# self.tableView.verticalHeader().hide() # hide vertical/row headers
self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
# self.tableView.setSelectionMode(QAbstractItemView.MultiSelection)
# self.tableView.horizontalHeader().setStretchLastSection(True)
# self.tableView.setVisible(False)
self.tableView.resizeColumnsToContents()
self.tableView.resizeRowsToContents()
# self.tableView.setVisible(True)
# self.tableView.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) # pour que le tableau occupe
# toute la zone
self.tableView.setAlternatingRowColors(True) # colorie une ligne sur 2
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # ajuster la largeur du tableau
# self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked) # met en mode édition en cliquant sur une
# ligne https://doc.qt.io/qt-5/qabstractitemview.html#EditTrigger-enum NoEditTriggers, DoubleClicked,
# SelectedClicked, CurrentChanged
self.verticalLayout_left.addWidget(self.tableView)
self.widget1 = QtWidgets.QWidget(self.splitter)
self.widget1.setObjectName("widget1")
self.verticalLayout_right = QtWidgets.QVBoxLayout(self.widget1)
self.verticalLayout_right.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_right.setObjectName("verticalLayout_right")
self.label_graphic_help = QtWidgets.QLabel(self.widget1)
self.label_graphic_help.setMaximumSize(QtCore.QSize(16777215, 25))
self.label_graphic_help.setBaseSize(QtCore.QSize(0, 30))
self.label_graphic_help.setStyleSheet(
"QLabel { border: 1px solid blue;\n"
" gridline-color: blue;\n"
" border-radius: 3px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: black;\n"
" font-size: 11px;\n"
" font-family: Helvetica\n"
"}"
)
self.label_graphic_help.setObjectName("label_graphic_help")
self.verticalLayout_right.addWidget(self.label_graphic_help)
# self.graphicsView = QtWidgets.QGraphicsView(self.widget1)
# self.graphicsView.setObjectName("graphicsView")
# self.verticalLayout_right.addWidget(self.graphicsView)
self.my_canvas = MplCanvas.MplCanvas(width=5, height=4,
dpi=100)
self.my_canvas.setObjectName("my_canvas")
self.my_toolbar = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(self.my_canvas, self.widget1)
self.my_toolbar.setStyleSheet(
"QToolBar{ border: 1px solid darkGray;\n"
" gridline-color: blue;\n"
" border-radius: 4px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: #218ede;\n"
" font-size: 12px;\n"
" font-family: Helvetica\n"
"\n"
" }"
)
self.verticalLayout_right.addWidget(self.my_toolbar)
self.verticalLayout_right.addWidget(self.my_canvas)
self.horizontalLayout_2.addWidget(self.splitter)
MainWindowProfile.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindowProfile)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1089, 20))
self.menubar.setObjectName("menubar")
MainWindowProfile.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindowProfile)
self.statusbar.setObjectName("statusbar")
MainWindowProfile.setStatusBar(self.statusbar)
self.retranslateUi(MainWindowProfile)
QtCore.QMetaObject.connectSlotsByName(MainWindowProfile)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindowProfile", "MainWindowProfile"))
self.btn_add.setToolTip(_translate("MainWindowProfile", "Insérer un point"))
self.btn_delete.setToolTip(
_translate("MainWindowProfile", "Supprimer le/les point(s) sélectionnés"))
self.btn_sort_asc_x.setToolTip(
_translate("MainWindowProfile", "Trier les points par ordre croissant de X"))
self.btn_sort_desc_x.setToolTip(
_translate("MainWindowProfile", "Trier les points par ordre décroissant de X"))
self.btn_sort_asc_y.setToolTip(_translate("MainWindowProfile",
"Trier les points par ordre croissant de Y"
))
self.btn_sort_desc_y.setToolTip(_translate("MainWindowProfile",
"Trier les points par ordre décroissant de Y"))
self.btn_move_up.setToolTip(_translate("MainWindowProfile",
"Décaler le point sélectionné vers le haut"))
self.btn_move_down.setToolTip(_translate("MainWindowProfile",
"Décaler le point sélectionné vers le bas"))
self.btn_export.setToolTip(_translate("MainWindowProfile",
"Exporter (dans un fichier) les points du profil au format tabulé"))
self.btn_copy.setToolTip(
_translate("MainWindowProfile", "Copier la sélection au format tabulé"))
self.btn_paste.setToolTip(_translate("MainWindowProfile",
"Coller la sélection depuis le presse-papier au format tabulé"))
self.btn_check.setToolTip(_translate("MainWindowProfile",
"Vérifier la validité de la saisie et garder ou pas les modifications "
"apportées"))
self.btn_go_back.setToolTip(_translate("MainWindowProfile",
"Annuler toutes les modifications depuis la dernière validation"))
self.btn_reset.setToolTip(_translate("MainWindowProfile",
"Annuler toutes les modifications et revenir à l\'état initial"))
self.label_graphic_help.setToolTip(_translate("MainWindowProfile",
"Ligne d'eau : \n \tZ : Cote (m) \n \tA : Aire mouillée ("
"m\u00B2) \n \tp : "
"Périmètre mouillé (m) \n \tL : Largeur au miroir (m)"))
self.label_graphic_help.setText(
_translate("MainWindowProfile", "\'Maj + Clic\' : Ligne d\'eau & \'Ctrl + Clic\' : "
"Sélectionner des points"))

View File

@ -0,0 +1,425 @@
# -*- coding: utf-8 -*-
import sys
import os.path
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtWidgets import (
QAbstractItemView, QHeaderView
)
from View.Plot import (
MplCanvas, navigation_toolbar_2qt
)
file_path = os.path.abspath(os.path.dirname(__file__))
icon_path = f"{os.path.dirname(os.path.dirname(file_path))}/../../ui/resources/"
class Ui_MainWindow(object):
def setupUi(self, MainWindow_reach):
MainWindow_reach.setObjectName("MainWindow_reach")
MainWindow_reach.resize(1400, 800)
self.centralwidget = QtWidgets.QWidget(MainWindow_reach)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.splitter_3 = QtWidgets.QSplitter(self.centralwidget)
self.splitter_3.setOrientation(Qt.Horizontal)
self.splitter_3.setObjectName("splitter_3")
self.widget = QtWidgets.QWidget(self.splitter_3)
self.widget.setObjectName("widget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_section_order = QtWidgets.QLabel(self.widget)
self.label_section_order.setLayoutDirection(Qt.LeftToRight)
self.label_section_order.setObjectName("label_section_order")
self.label_section_order.setStyleSheet(
"QLabel{ border: 1px solid darkGray;\n"
" gridline-color: gray;\n"
" border-radius: 1px;\n"
" border-style: solid;\n"
" background-color: ; \n"
" selection-background-color: #218ede;\n"
" font-size: 12px;\n"
" font-family: Helvetica\n"
"\n"
" }"
)
self.verticalLayout.addWidget(self.label_section_order)
btn_size = QSize(30, 30)
self.btn_open = QtWidgets.QPushButton(self.widget)
self.btn_open.setMaximumSize(QtCore.QSize(30, 30))
self.btn_open.setObjectName("btn_open")
icon_btn_open = QtGui.QIcon()
icon_btn_open.addPixmap(
QtGui.QPixmap(f"{icon_path}open.png"))
self.btn_open.setIcon(icon_btn_open)
self.btn_open.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_open)
self.btn_add = QtWidgets.QPushButton(self.widget)
self.btn_add.setMaximumSize(QtCore.QSize(30, 30))
self.btn_add.setObjectName("btn_add")
icon_btn_add = QtGui.QIcon()
icon_btn_add.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk_add.png"))
self.btn_add.setIcon(icon_btn_add)
self.btn_add.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_add)
self.btn_delete = QtWidgets.QPushButton(self.widget)
self.btn_delete.setMaximumSize(QtCore.QSize(30, 30))
self.btn_delete.setObjectName("btn_delete")
icon_btn_delete = QtGui.QIcon()
icon_btn_delete.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-remove.png"))
self.btn_delete.setIcon(icon_btn_delete)
self.btn_delete.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_delete)
self.btn_edit = QtWidgets.QPushButton(self.widget)
self.btn_edit.setMaximumSize(QtCore.QSize(30, 30))
self.btn_edit.setObjectName("btn_edit")
icon_btn_edit = QtGui.QIcon()
icon_btn_edit.addPixmap(
QtGui.QPixmap(f"{icon_path}gnome-stock-edit.png"))
self.btn_edit.setIcon(icon_btn_edit)
self.btn_edit.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_edit)
self.btn_copy_selected_profile = QtWidgets.QPushButton(self.widget)
self.btn_copy_selected_profile.setMaximumSize(QtCore.QSize(30, 30))
self.btn_copy_selected_profile.setObjectName("btn_copy_selected_profile")
icon_btn_copy_selected_profile = QtGui.QIcon()
icon_btn_copy_selected_profile.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-copy.png"))
self.btn_copy_selected_profile.setIcon(icon_btn_copy_selected_profile)
self.btn_copy_selected_profile.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_copy_selected_profile)
self.btn_paste_selected_profile = QtWidgets.QPushButton(self.widget)
self.btn_paste_selected_profile.setMaximumSize(QtCore.QSize(30, 30))
self.btn_paste_selected_profile.setObjectName("btn_paste_selected_profile")
icon_btn_paste_selected_profile = QtGui.QIcon()
icon_btn_paste_selected_profile.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-paste.png"))
self.btn_paste_selected_profile.setIcon(icon_btn_paste_selected_profile)
self.btn_paste_selected_profile.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_paste_selected_profile)
self.btn_duplicate_selected_profile = QtWidgets.QPushButton(self.widget)
self.btn_duplicate_selected_profile.setMaximumSize(QtCore.QSize(30, 30))
self.btn_duplicate_selected_profile.setObjectName("btn_duplicate_selected_profile")
icon_btn_duplicate_selected_profile = QtGui.QIcon()
icon_btn_duplicate_selected_profile.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-dnd-multiple.png"))
self.btn_duplicate_selected_profile.setIcon(icon_btn_duplicate_selected_profile)
self.btn_duplicate_selected_profile.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_duplicate_selected_profile)
self.btn_sort_asc = QtWidgets.QPushButton(self.widget)
self.btn_sort_asc.setMaximumSize(QtCore.QSize(30, 30))
self.btn_sort_asc.setText("")
self.btn_sort_asc.setObjectName("btn_sort_asc")
icon_btn_sort_asc = QtGui.QIcon()
icon_btn_sort_asc.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-sort-ascending.png"))
self.btn_sort_asc.setIcon(icon_btn_sort_asc)
self.btn_sort_asc.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_sort_asc)
self.btn_sort_desc = QtWidgets.QPushButton(self.widget)
self.btn_sort_desc.setMaximumSize(QtCore.QSize(30, 30))
self.btn_sort_desc.setText("")
self.btn_sort_desc.setObjectName("btn_sort_desc")
icon_btn_sort_desc = QtGui.QIcon()
icon_btn_sort_desc.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-sort-descending.png"))
self.btn_sort_desc.setIcon(icon_btn_sort_desc)
self.btn_sort_desc.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_sort_desc)
self.btn_move_up = QtWidgets.QPushButton(self.widget)
self.btn_move_up.setMaximumSize(QtCore.QSize(30, 30))
self.btn_move_up.setText("")
self.btn_move_up.setObjectName("btn_move_up")
icon_btn_move_up = QtGui.QIcon()
icon_btn_move_up.addPixmap(
QtGui.QPixmap(f"{icon_path}up.png"))
self.btn_move_up.setIcon(icon_btn_move_up)
self.btn_move_up.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_move_up)
self.btn_move_down = QtWidgets.QPushButton(self.widget)
self.btn_move_down.setMaximumSize(QtCore.QSize(30, 30))
self.btn_move_down.setText("")
self.btn_move_down.setObjectName("btn_move_down")
icon_btn_move_down = QtGui.QIcon()
icon_btn_move_down.addPixmap(
QtGui.QPixmap(f"{icon_path}down.png"))
self.btn_move_down.setIcon(icon_btn_move_down)
self.btn_move_down.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_move_down)
self.btn_end_editing = QtWidgets.QPushButton(self.widget)
self.btn_end_editing.setMaximumSize(QtCore.QSize(30, 30))
self.btn_end_editing.setText("")
self.btn_end_editing.setObjectName("btn_end_editing")
icon_btn_save = QtGui.QIcon()
icon_btn_save.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-apply.png"))
self.btn_end_editing.setIcon(icon_btn_save)
self.btn_end_editing.setIconSize(btn_size)
self.horizontalLayout.addWidget(self.btn_end_editing)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.verticalLayout.addLayout(self.horizontalLayout)
self.tableView = QtWidgets.QTableView(self.widget)
self.tableView.setObjectName("tableView")
self.verticalLayout.addWidget(self.tableView)
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) # permet de sélectionner une ligne entière
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # ajuster la largeur du tableau
self.tableView.setAlternatingRowColors(True) # colorie une ligne sur 2
self.tableView.verticalHeader().hide() # hide vertical/row headers
self.tableView.setStyleSheet(
" QTableView { border: 1px solid black;\n"
" gridline-color: blue;\n"
" border-radius: 2px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: #218ede;\n"
" font-size: 12px;\n"
" font-family: Helvetica\n"
"\n"
" }"
)
self.tableView.resizeColumnsToContents()
self.tableView.resizeRowsToContents()
self.widget1 = QtWidgets.QWidget(self.splitter_3)
self.widget1.setObjectName("widget1")
self.gridLayout = QtWidgets.QGridLayout(self.widget1)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.splitter_2 = QtWidgets.QSplitter(self.widget1)
self.splitter_2.setOrientation(Qt.Vertical)
self.splitter_2.setObjectName("splitter_2")
self.splitter = QtWidgets.QSplitter(self.splitter_2)
self.splitter.setOrientation(Qt.Horizontal)
self.splitter.setObjectName("splitter")
self.verticalLayoutWidget_3 = QtWidgets.QWidget(self.splitter)
self.verticalLayoutWidget_3.setObjectName("verticalLayoutWidget_3")
self.verticalLayout_canvas_1 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_3)
self.verticalLayout_canvas_1.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_canvas_1.setObjectName("verticalLayout_canvas_1")
self.canvas_1 = MplCanvas.MplCanvas(width=5, height=4,
dpi=100) # QtWidgets.QGraphicsView(self.verticalLayoutWidget_3)
self.canvas_1.setObjectName("canvas_1")
self.toolbar_1 = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(self.canvas_1, self.centralwidget)
self.toolbar_1.setStyleSheet("QToolBar{ border: 1px solid darkGray;\n"
" gridline-color: blue;\n"
" border-radius: 4px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: #218ede;\n"
" font-size: 12px;\n"
" font-family: Helvetica\n"
"\n"
" }")
self.verticalLayout_canvas_1.addWidget(self.toolbar_1)
self.verticalLayout_canvas_1.addWidget(self.canvas_1)
self.verticalLayoutWidget_2 = QtWidgets.QWidget(self.splitter)
self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2")
self.verticalLayout_canvas_2 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_2)
self.verticalLayout_canvas_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_canvas_2.setObjectName("verticalLayout_canvas_2")
self.canvas_2 = MplCanvas.MplCanvas(width=5, height=4,
dpi=100) # QtWidgets.QGraphicsView(self.verticalLayoutWidget_2)
# self.canvas_2.setMouseTracking(False)
self.canvas_2.setObjectName("canvas_2")
self.toolbar_2 = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(self.canvas_2, self.centralwidget)
self.toolbar_2.setStyleSheet(
"QToolBar{ border: 1px solid darkGray;\n"
" gridline-color: blue;\n"
" border-radius: 4px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: #218ede;\n"
" font-size: 12px;\n"
" font-family: Helvetica\n"
"\n"
" }"
)
# self.frame_toolbar.addWidget(self.toolbar)
self.verticalLayout_canvas_2.addWidget(self.toolbar_2)
self.verticalLayout_canvas_2.addWidget(self.canvas_2)
self.verticalLayoutWidget = QtWidgets.QWidget(self.splitter_2)
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout_canvas_3 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout_canvas_3.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_canvas_3.setObjectName("verticalLayout_canvas_3")
self.canvas_3 = MplCanvas.MplCanvas(width=5, height=4,
dpi=100) # QtWidgets.QGraphicsView(self.verticalLayoutWidget)
self.canvas_3.setObjectName("canvas_3")
self.toolbar_3 = navigation_toolbar_2qt.PamHyrNavigationToolbar2QT(self.canvas_3, self.centralwidget)
self.toolbar_3.setStyleSheet(
"QToolBar{ border: 1px solid darkGray;\n"
" gridline-color: blue;\n"
" border-radius: 4px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: #218ede;\n"
" font-size: 12px;\n"
" font-family: Helvetica\n"
"\n"
" }"
)
# self.frame_toolbar.addWidget(self.toolbar)
self.verticalLayout_canvas_3.addWidget(self.toolbar_3)
# self.verticalLayout_canvas_3.addWidget(self.canvas_3)
# from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
# import matplotlib.pyplot as plt
# self.figure = plt.figure()
# self.canvas_3 = FigureCanvas(self.figure)
self.verticalLayout_canvas_3.addWidget(self.canvas_3)
self.gridLayout.addWidget(self.splitter_2, 0, 0, 3, 3)
self.verticalSlider = QtWidgets.QSlider(self.widget1)
self.verticalSlider.setMinimumSize(QtCore.QSize(30, 0))
self.verticalSlider.setOrientation(Qt.Vertical)
self.verticalSlider.setInvertedAppearance(True)
self.verticalSlider.setInvertedControls(False)
self.verticalSlider.setObjectName("verticalSlider")
self.gridLayout.addWidget(self.verticalSlider, 0, 3, 1, 1)
self.btn_slider_up = QtWidgets.QPushButton(self.widget1)
self.btn_slider_up.setMaximumSize(QtCore.QSize(30, 30))
self.btn_slider_up.setObjectName("btn_slider_up")
icon_btn_slider_up = QtGui.QIcon()
icon_btn_slider_up.addPixmap(
QtGui.QPixmap(f"{icon_path}go-up2.png"))
self.btn_slider_up.setIcon(icon_btn_slider_up)
self.btn_slider_up.setIconSize(btn_size)
self.gridLayout.addWidget(self.btn_slider_up, 1, 3, 1, 1)
self.btn_slider_down = QtWidgets.QPushButton(self.widget1)
self.btn_slider_down.setMaximumSize(QtCore.QSize(30, 30))
self.btn_slider_down.setObjectName("btn_slider_down")
icon_btn_slider_down = QtGui.QIcon()
icon_btn_slider_down.addPixmap(
QtGui.QPixmap(f"{icon_path}go-down1.png"))
self.btn_slider_down.setIcon(icon_btn_slider_down)
self.btn_slider_down.setIconSize(btn_size)
self.gridLayout.addWidget(self.btn_slider_down, 2, 3, 1, 1)
self.vertical_slider_label = QtWidgets.QLabel(self.widget1)
# self.vertical_slider_label.setLayoutDirection(Qt.RightToLeft)
# self.vertical_slider_label.setLayoutDirection(Qt.LeftToRight)
self.vertical_slider_label.setObjectName("vertical_slider_label")
self.gridLayout.addWidget(self.vertical_slider_label, 3, 2, 2, 1)
self.vertical_slider_label.setAlignment(Qt.AlignRight)
self.btn_slider_go_back = QtWidgets.QPushButton(self.widget1)
self.btn_slider_go_back.setMaximumSize(QtCore.QSize(30, 30))
self.btn_slider_go_back.setObjectName("btn_slider_go_back")
icon_btn_slider_go_back = QtGui.QIcon()
icon_btn_slider_go_back.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-go-back.png"))
self.btn_slider_go_back.setIcon(icon_btn_slider_go_back)
self.btn_slider_go_back.setIconSize(btn_size)
self.gridLayout.addWidget(self.btn_slider_go_back, 5, 0, 1, 1)
self.btn_slider_go_back.setEnabled(False)
self.btn_slider_go_forward = QtWidgets.QPushButton(self.widget1)
self.btn_slider_go_forward.setMaximumSize(QtCore.QSize(30, 30))
self.btn_slider_go_forward.setObjectName("btn_slider_go_forward")
icon_btn_slider_go_forward = QtGui.QIcon()
icon_btn_slider_go_forward.addPixmap(
QtGui.QPixmap(f"{icon_path}gtk-go-forward.png"))
self.btn_slider_go_forward.setIcon(icon_btn_slider_go_forward)
self.btn_slider_go_forward.setIconSize(btn_size)
self.gridLayout.addWidget(self.btn_slider_go_forward, 5, 1, 1, 1)
self.btn_slider_go_forward.setEnabled(False)
self.horizontalSlider = QtWidgets.QSlider(self.widget1)
self.horizontalSlider.setMinimumSize(QtCore.QSize(0, 30))
self.horizontalSlider.setOrientation(Qt.Horizontal)
self.horizontalSlider.setObjectName("horizontalSlider")
self.gridLayout.addWidget(self.horizontalSlider, 5, 2, 1, 1)
self.horizontalSlider.setEnabled(False)
self.horizontalLayout_2.addWidget(self.splitter_3)
MainWindow_reach.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow_reach)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1123, 20))
self.menubar.setObjectName("menubar")
MainWindow_reach.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow_reach)
self.statusbar.setObjectName("statusbar")
MainWindow_reach.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow_reach)
QtCore.QMetaObject.connectSlotsByName(MainWindow_reach)
def retranslateUi(self, MainWindow_reach):
_translate = QtCore.QCoreApplication.translate
self.name_reach = ""
self.mainwindow_title = _translate("MainWindow_reach", "Jeu de sections du Bief")
MainWindow_reach.setWindowTitle(self.mainwindow_title + f"{self.name_reach}")
self.text_section_order = _translate("MainWindow_reach", "\nOrdre des sections : "
"Amont --> Aval")
self.label_section_order.setText(f"{self.text_section_order}")
self.vertical_slider_value = ""
self.vertical_slider_label.setText(_translate("MainWindow_reach", "Pk = ") + f"{self.vertical_slider_value}")
self.btn_open.setToolTip(_translate("MainWindow_reach", " Importer une géométrie"))
self.btn_add.setToolTip(_translate("MainWindow_reach", " Nouveau profil"))
self.btn_delete.setToolTip(_translate("MainWindow_reach", " Supprimer le profil sélectionné"))
self.btn_edit.setToolTip(_translate("MainWindow_reach", " Éditer le profil sélectionné"))
self.btn_copy_selected_profile.setToolTip(_translate("MainWindow_reach", " Copier le profil sélectionné"))
self.btn_paste_selected_profile.setToolTip(_translate("MainWindow_reach", "Coller le profil en fin de liste ("
"penser à modifier le Pk avant de "
"trier)"))
self.btn_duplicate_selected_profile.setToolTip(
_translate("MainWindow_reach", " Dupliquer la section sélectionnée"))
self.btn_sort_asc.setToolTip(_translate("MainWindow_reach", " Trier les profils par ordre croissant des Pk"))
self.btn_sort_desc.setToolTip(_translate("MainWindow_reach", " Trier les profils par ordre décroissant des Pk"))
self.btn_move_up.setToolTip(_translate("MainWindow_reach", " Changer l'ordre des profils (en décalant le "
"profil sélectionné vers le haut)"))
self.btn_move_down.setToolTip(_translate("MainWindow_reach", " Changer l'ordre des profils (en décalant le "
"profil sélectionné vers le bas)"))
self.btn_end_editing.setToolTip(_translate("MainWindow_reach", " Terminer l'édition"))
self.tableView_header = [_translate("MainWindow_reach", "Nom"), _translate("MainWindow_reach", "Pk (m)"),
_translate("MainWindow_reach", "Type")]
self.toolbar_1._actions["isometric_view"].setShortcut(_translate("MainWindow_reach", "Alt+Z"))
self.toolbar_1._actions["isometric_view"].setToolTip(_translate("MainWindow_reach", "Vue isométrique (Alt+Z)"))
self.toolbar_2._actions["isometric_view"].setShortcut(_translate("MainWindow_reach", "Alt+E"))
self.toolbar_2._actions["isometric_view"].setToolTip(_translate("MainWindow_reach", "Vue isométrique (Alt+E)"))
self.toolbar_3._actions["isometric_view"].setShortcut(_translate("MainWindow_reach", "Alt+R"))
self.toolbar_3._actions["isometric_view"].setToolTip(_translate("MainWindow_reach", "Vue isométrique (Alt+R)"))
self.toolbar_1._actions["non_isometric_view"].setShortcut("Alt+S")
self.toolbar_1._actions["non_isometric_view"].setToolTip(
_translate("MainWindow_reach", "Vue globale automatique (Alt+S)"))
self.toolbar_2._actions["non_isometric_view"].setShortcut("Alt+D")
self.toolbar_2._actions["non_isometric_view"].setToolTip(
_translate("MainWindow_reach", "Vue globale automatique (Alt+D)"))
self.toolbar_3._actions["non_isometric_view"].setShortcut("Alt+F")
self.toolbar_3._actions["non_isometric_view"].setToolTip(
_translate("MainWindow_reach", "Vue globale automatique (Alt+F)"))

View File

@ -0,0 +1,422 @@
import numpy as np
import pandas as pd
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QMessageBox
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtCore import QModelIndex, Qt, QAbstractTableModel, QVariant, QCoreApplication
from ProfileXYZ import ProfileXYZ
import projection_pointXYZ
_translate = QCoreApplication.translate
class PandasModelEditable(QAbstractTableModel):
def __init__(self, profile: ProfileXYZ, table_header=None):
QAbstractTableModel.__init__(self)
if table_header is None:
self.header = ["X (m)", "Y (m)", "Z (m)", _translate("MainWindowProfile", "Nom"),
_translate("MainWindowProfile", "Abs en travers (m)")]
else:
self.header = table_header
self.profile = profile
data = pd.DataFrame({
self.header[0]: profile.x,
self.header[1]: profile.y,
self.header[2]: profile.z,
self.header[3]: profile.ld,
self.header[4]: projection_pointXYZ.get_station(profile)
})
self._data = data
def rowCount(self, parent=QModelIndex()):
return self._data.shape[0]
def columnCount(self, parent=QModelIndex()):
return self._data.shape[1]
def data(self, index, role=Qt.DisplayRole):
value = self._data.iloc[index.row()][index.column()]
if index.isValid():
if role == Qt.DisplayRole:
if index.column() != 4:
if isinstance(value, float):
return "%.4f" % value
else:
if isinstance(value, float):
return "%.3f" % value
return str(self._data.iloc[index.row(), index.column()])
if role == Qt.TextAlignmentRole:
return Qt.AlignHCenter | Qt.AlignVCenter
if index.column() == 2:
if role == Qt.ForegroundRole:
if value == min(self._data.iloc[:, index.column()]):
return QtGui.QColor("red")
elif value == max(self._data.iloc[:, index.column()]):
return QtGui.QColor("Blue")
if role == Qt.ToolTipRole:
if value == min(self._data.iloc[:, index.column()]):
return _translate("MainWindowProfile", "La cote du fond", "Z minimale")
elif value == max(self._data.iloc[:, index.column()]):
return _translate("MainWindowProfile", "La cote maximale", "Z maximale")
if index.column() == 3:
if value.strip().upper() in ["RG", "RD"]:
if role == Qt.FontRole:
font = QFont()
font.setBold(True)
return font
if role == Qt.ForegroundRole:
return QtGui.QColor("darkRed")
if role == Qt.ToolTipRole:
if value.strip().upper() == "RG":
return _translate("MainWindowProfile", "Rive gauche")
else:
return _translate("MainWindowProfile", "Rive droite")
if index.column() == 4:
if role == Qt.FontRole:
font = QFont()
font.setBold(True)
return font
if role == Qt.BackgroundRole:
return QtGui.QColor("#ededee")
return QVariant()
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.header[section]
if role == Qt.ToolTipRole and section == 4:
return _translate(
"MainWindowProfile",
"Abscisse en travers calculée en projétant les points"
" \nsur le plan défini par les deux points nommés extrêmes "
)
if orientation == Qt.Vertical and role == Qt.DisplayRole:
return self._data.index[section] + 1
return None
def setData(self, index, value, role=Qt.EditRole):
if role == Qt.EditRole:
try:
if index.column() == 3:
self._data.iat[index.row(), index.column()] = str(value)
elif index.column() == 0:
self._data.iat[index.row(), index.column()] = float(value)
elif index.column() == 1:
self._data.iat[index.row(), index.column()] = float(value)
elif index.column() == 2:
self._data.iat[index.row(), index.column()] = float(value)
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
self.header,
self._data.values.tolist()
)
self.dataChanged.emit(index, index)
except:
print('TODO')
self.QMessageBoxCritical(value)
return True
self.dataChanged.emit(index, index)
self.layoutChanged.emit()
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:150 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()
return self.createIndex(row, column, QModelIndex())
def flags(self, index):
return Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled
# @QtCore.pyqtSlot()
def insertRows(self, row, count, parent=QModelIndex()):
self.beginInsertRows(parent, row, row + count - 1)
indexes = [str(self.rowCount() + i) for i in range(count)]
left = self._data[0:row]
mid = pd.DataFrame(index=indexes, columns=self._data.columns)
right = self._data[row + count - 1:self.rowCount()]
self._data = pd.concat([left, mid, right])
for i in [3]:
self._data.iloc[:, i].replace(np.nan, '', inplace=True)
self._data.reset_index(drop=True, inplace=True)
try:
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
self.header,
self._data.values.tolist()
)
except:
print("TODO")
self.endInsertRows()
self.layoutChanged.emit()
# @QtCore.pyqtSlot()
def removeRows(self, row, count, parent=QModelIndex()):
self.beginRemoveRows(parent, row, row + count + 1)
self._data.drop(self._data.index[row], inplace=True)
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
self.header,
self._data.values.tolist()
)
self.endRemoveRows()
self.layoutChanged.emit()
def remove_rows1(self, row, count, parent=QModelIndex()):
self.beginRemoveRows(parent, row, row + count - 1)
left = self._data.iloc[0:row]
right = self._data.iloc[row + count:self.rowCount()]
self._data = pd.concat([left, right], axis=0, ignore_index=True)
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
self.header,
self._data.values.tolist()
)
self.endRemoveRows()
self.layoutChanged.emit()
def remove_rows(self, list_row_selected, parent=QModelIndex()):
self.beginRemoveRows(parent, list_row_selected[0], list_row_selected[-1])
try:
self._data.drop(self._data.index[list_row_selected], inplace=True)
self._data.reset_index(drop=True, inplace=True)
except:
print('TODO')
try:
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
self.header,
self._data.values.tolist()
)
except:
print("TODO")
self.endRemoveRows()
self.layoutChanged.emit()
def sort(self, column, order=Qt.AscendingOrder):
self.layoutAboutToBeChanged.emit()
colname = self._data.columns.tolist()[column]
self._data.sort_values(colname, ascending=order == Qt.AscendingOrder, inplace=True)
self._data.reset_index(inplace=True, drop=True)
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
self.header,
self._data.values.tolist()
)
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)
block_before_row = self._data.iloc[0:row_to_move]
selected_row = self._data.iloc[row_to_move:row_to_move + 1]
after_selcted_row = self._data.iloc[row_to_move + 1:row_to_move + 2]
block_after_row = self._data.iloc[row_to_move + 2:self.rowCount()]
self._data = pd.concat([block_before_row, after_selcted_row, selected_row, block_after_row], axis=0)
self._data.reset_index(inplace=True, drop=True)
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)
block_before_row = self._data.iloc[0:row_to_move - 1]
before_selected_row = self._data.iloc[row_to_move - 1:row_to_move]
selected_row = self._data.iloc[row_to_move:row_to_move + 1]
block_after_row = self._data.iloc[row_to_move + 1:self.rowCount()]
self._data = pd.concat([block_before_row, selected_row, before_selected_row, block_after_row], axis=0)
self._data.reset_index(inplace=True, drop=True)
self.endMoveRows()
self.layoutChanged.emit()
def copyTable(self, start_selection, end_selection):
end_selection = self.rowCount()
self._data.loc[start_selection:end_selection]\
.to_clipboard(header=None, index=False, excel=True, sep='\t')
def insert_df_to_idx(self, idx, df, df_insert):
"""
Args:
idx: is the index position in df where you want to insert new dataframe (df_insert)
df: dataframe
df_insert: dataframe to insert
Returns:
The dataframe df with df_insert inserted at index idx.
"""
return df.iloc[:idx, ].append(df_insert).append(df.iloc[idx:, ]).reset_index(drop=True)
def pasteTable(self, insertion_index):
self.layoutAboutToBeChanged.emit()
df = pd.read_clipboard(header=None, skip_blank_lines=True,
sep="\t", names=self.header)
self._data = self.insert_df_to_idx(insertion_index, self._data, df)
for i in [3]:
self._data.iloc[:, i].replace(np.nan, '', inplace=True)
self.layoutChanged.emit()
self._data.iloc[:, 4] = projection_pointXYZ.update_station(
self.header,
self._data.values.tolist()
)
@property
def model_data(self):
return self._data
@model_data.setter
def model_data(self, new_data):
self._data = new_data
self.layoutChanged.emit()
@property
def x(self):
return self._data.iloc[:, 0].tolist()
@property
def y(self):
return self._data.iloc[:, 1].tolist()
@property
def z(self):
return self._data.iloc[:, 2].tolist()
@property
def name(self):
return self._data.iloc[:, 3].tolist()
def get_data(self):
return self._data
@property
def station(self):
return self._data.iloc[:, 4].tolist()
def remove_duplicates_names(self):
counter_list = []
list_deleted_names = []
ind_ind = []
for ind, name_point in enumerate(self.name):
if name_point not in counter_list:
counter_list.append(name_point)
elif len(name_point.strip()) > 0 and name_point in counter_list:
ind_ind.append(ind)
if name_point not in list_deleted_names:
list_deleted_names.append(name_point)
for ind in ind_ind:
self._data.iat[ind, 3] = ""
def data_contains_nan(self) -> bool:
"""
Returns:
Returns True if the QTableView() contains np.nan
"""
return self._data.isnull().values.any()
def delete_empty_rows(self):
self.layoutAboutToBeChanged.emit()
self._data.dropna(inplace=True)
self._data.reset_index(drop=True, inplace=True)
self.layoutChanged.emit()
def valide_all_changes(self):
self.profile.x = self._data.iloc[:, 0]
self.profile.y = self._data.iloc[:, 1]
self.profile.z = self._data.iloc[:, 2]
self.profile.ld = self._data.iloc[:, 3]
class Delegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None, setModelDataEvent=None):
super(Delegate, self).__init__(parent)
self.setModelDataEvent = setModelDataEvent
def createEditor(self, parent, option, index):
"""
Args:
parent:
option:
index:
Returns:
Le widget (éditeur) pour éditer l'item se trouvant à l'index index.
"""
index.model().data(index, Qt.DisplayRole)
return QtWidgets.QLineEdit(parent)
def setEditorData(self, editor, index):
"""
Args:
editor: l'éditeur
index: l'index
Returns: permet de transmettre à l'éditeur editor les données à afficher à partir du modèle se trouvant
à l'index index.
"""
value = index.model().data(index, Qt.DisplayRole)
editor.setText(str(value))
def setModelData(self, editor, model, index):
"""
Args:
editor: l'éditeur
model: le modèle
index: l'index
Returns: permet de récupérer les données de l'éditeur et de les stocker à l'intérieur du modèle, à l'index
identifié par le paramètre index
"""
model.setData(index, editor.text())
if not self.setModelDataEvent is None:
self.setModelDataEvent()
def updateEditorGeometry(self, editor, option, index):
"""
Args:
editor: l'éditeur
option:
index: l'index
Returns: Permet de redimensionner l'éditeur à la bonne taille lorsque la taille de la vue change
"""
editor.setGeometry(option.rect)

File diff suppressed because it is too large Load Diff

934
src/View/GeometryWindow.py Normal file
View File

@ -0,0 +1,934 @@
import os
import pathlib
import sys
import csv
import time
from PyQt5 import QtWidgets
from PyQt5.QtCore import (
QModelIndex, Qt, QSettings, pyqtSlot,
QItemSelectionModel, QCoreApplication, QSize
)
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QFileDialog, QCheckBox
)
from View.Geometry.mainwindow_ui_reach import Ui_MainWindow
from View.Geometry import qtableview_reach
from View.Geometry import window_profileXYZ
_translate = QCoreApplication.translate
class GeomatryWindow(ASubWindow):
def __init__(self, parent=None):
self.parent = parent
super(MainReach, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.tableView = self.ui.tableView
self.tableView_header = self.ui.tableView_header
self.model = None
self.filename = None
self.setup_model()
self.setup_connections()
def setup_connections(self):
self.ui.btn_open.clicked.connect(self.open_file_dialog)
self.ui.btn_sort_asc.clicked.connect(self.sort_ascending)
self.ui.btn_sort_desc.clicked.connect(self.sort_descending)
self.ui.btn_move_up.clicked.connect(self.move_row_up)
self.ui.btn_move_down.clicked.connect(self.move_row_down)
self.ui.btn_end_editing.clicked.connect(self.handleSave)
self.ui.btn_add.clicked.connect(self.insert_row)
self.ui.btn_delete.clicked.connect(self.delete_row)
self.ui.btn_edit.clicked.connect(self.edit_profile)
self.ui.verticalSlider.valueChanged.connect(self.changed_slider_value)
self.tableView.selectionModel().selectionChanged.connect(self.changed_slider_value)
self.ui.btn_slider_up.clicked.connect(self.decrement_value_slider)
self.ui.btn_slider_down.clicked.connect(self.increment_value_slider)
self.ui.btn_move_up.clicked.connect(self.changed_profile_slot)
def setup_model(self):
self.model = qtableview_reach.PandasModelEditableCreateReach([], self.ui.tableView_header)
self.tableView.setModel(self.model)
self.tableView.setItemDelegate(qtableview_reach.Delegate())
def open_file_dialog(self):
options = QFileDialog.Options()
DEFAULT_DIRECTORY = '/home/'
settings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'MyOrg', ) # application='MyApp', )
current_dir = settings.value('current_directory', DEFAULT_DIRECTORY, type=str)
options |= QFileDialog.DontUseNativeDialog
self.filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
_translate("MainWindow_reach", "Ouvrir un fichier"),
current_dir,
_translate("MainWindow_reach",
"Fichiers .ST (*.ST)") + ";;" +
_translate("MainWindow_reach",
"Fichiers textes (*.txt)") + ";; " +
_translate("MainWindow_reach",
"Tous les fichiers (*)"),
options=options
)
current_dir = os.path.split(self.filename)[0] or DEFAULT_DIRECTORY
settings.setValue('current_directory', current_dir)
if self.filename != "":
size = os.stat(self.filename).st_size
self.bief_name = pathlib.Path(self.filename).stem
self.setWindowTitle(f"{self.ui.mainwindow_title} {self.bief_name}")
self.model = qtableview_reach.PandasModelEditable(self.filename, self.tableView_header)
self.tableView.setModel(self.model)
self.update_text_label()
self.update_profile_windows()
self.graphic_1()
self.graphic_2()
self.graphic_3()
self.fichier_ouvert = True
# Profile selection when line change in table
self.tableView.selectionModel().selectionChanged.connect(
self.select_current_profile
)
# Update plot when profile data change
self.model.dataChanged.connect(self.update_graphic_1)
self.model.dataChanged.connect(self.update_graphic_2)
self.tableView.selectionModel().selectionChanged.connect(self.update_graphic_1)
self.tableView.selectionModel().selectionChanged.connect(self.update_graphic_2)
def update_text_label(self):
"""
Returns: Cette méthode met à jour le texte (en haut à gauche) indiquant le nombre de profils et
l'ordre des sections.
"""
if self.filename:
if self.model.rowCount() > 1:
self.ui.label_section_order.setText(
f"{self.model.rowCount()}" + " " +
_translate("MainWindow_reach", "profils") +
f"{self.ui.text_section_order}"
)
else:
self.ui.label_section_order.setText(
f"{self.model.rowCount()}" + " " +
_translate("MainWindow_reach", "profil") +
f"{self.ui.text_section_order}"
)
def messagebox_profile_editing(self):
msg_box = QtWidgets.QMessageBox()
msg_box.setIcon(QtWidgets.QMessageBox.Information)
msg_box.setWindowTitle(_translate("MainWindow_reach",
"Édition des profils sélectionnés"))
msg_box.setText(_translate("MainWindow_reach",
"Vous avez sélectionné plus de 5 profils."
" \nSeuls les 5 premiers seront édités."))
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
return_value = msg_box.exec()
if return_value == QtWidgets.QMessageBox.Ok:
print('OK clicked')
def edit_profile(self):
list_selected_row = list(
set([index.row() for index in self.tableView.selectedIndexes()])
)
self.tableView.model().blockSignals(True)
if len(list_selected_row) > 5:
self.messagebox_profile_editing()
for selected_row in list_selected_row[:5]:
selected_row = int(selected_row)
profile_identifier = self.model.get_profile_selected_identifier(selected_row)
Pk = self.model.get_pk_i(selected_row)
profile_name = self.model.get_profile_name(selected_row)
if len(self.list_second_window) == 0:
self.second_window = window_profileXYZ.View(
selected_row + 1,
self.model.get_profile_via_identifier(profile_identifier),
pk=Pk, profile_name="", parent=self
)
self.second_window.window_title(
pk=Pk,
profile_name=profile_name,
profile_selected_num=selected_row
)
self.second_window.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
self.list_second_window.append(self.second_window)
self.second_window.show()
self.list_row.append(profile_identifier)
else:
if profile_identifier in self.list_row:
self.list_second_window[self.list_row.index(profile_identifier)]\
.window_title(
pk=Pk, profile_name=profile_name,
profile_selected_num=selected_row
)
self.list_second_window[
self.list_row.index(profile_identifier)
].setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
self.list_second_window[
self.list_row.index(profile_identifier)
].show()
else:
second_window1 = window_profileXYZ.View(
selected_row + 1,
self.model.get_profile_via_identifier(profile_identifier),
pk=Pk, profile_name="", parent=self
)
second_window1.window_title(
pk=Pk, profile_name=profile_name,
profile_selected_num=selected_row
)
second_window1.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
second_window1.show()
self.list_row.append(profile_identifier)
self.list_second_window.append(second_window1)
widgetList = QApplication.topLevelWidgets()
numWindows = len(widgetList)
self.tableView.model().blockSignals(False)
def wind_profile_changed(self):
self.second_window\
.datachanged_signal[bool]\
.connect(self.changed_profile_slot)
pyqtSlot(bool)
def changed_profile_slot(self, status):
print("status du changement ", status)
self.update_view1 = status
print(self.update_view1)
def update_graphic_1_profile(self):
if self.update_view1:
self.update_graphic_1()
print("update_graphic_1_profile")
def print_data(self):
print(self.model_data.profile)
def update_profile_windows(self):
self.list_second_window = []
self.list_row = []
def graphic_1(self):
self.ui.canvas_1.axes.cla()
self.ui.canvas_1.axes.grid(color='grey', linestyle='--', linewidth=0.5)
self.ui.canvas_1.axes.set_xlabel(
_translate("MainWindow_reach", "X (m)"), color='green', fontsize=12
)
self.ui.canvas_1.axes.set_ylabel(
_translate("MainWindow_reach", "Y (m)"), color='green', fontsize=12
)
self.get_x = self.model.get_x()
self.get_y = self.model.get_y()
self.line_xy = [
self.ui.canvas_1.axes.plot(x, y, color='r', lw=1., markersize=3, marker='+')
for x, y in zip(self.get_x, self.get_y)
]
self.get_x_complete_list_ld = self.model.get_x_complete_list_ld()
self.get_y_complete_list_ld = self.model.get_y_complete_list_ld()
self.line_ld_1 = self.ui.canvas_1.axes.plot(
self.get_x_complete_list_ld,
self.get_y_complete_list_ld
)
self.plot_selected_1, = self.ui.canvas_1.axes.plot(
self.model.get_x_profile_i(0),
self.model.get_y_profile_i(0), lw=1., markersize=3,
marker='+', color="b"
)
self.plot_selected_1.set_visible(False)
self.before_plot_selected_1, = self.ui.canvas_1.axes.plot(
self.model.get_x_profile_i(0),
self.model.get_y_profile_i(0), lw=1., markersize=3,
marker='+', color="k", linestyle="--"
)
self.before_plot_selected_1.set_visible(False)
self.after_plot_selected_1, = self.ui.canvas_1.axes.plot(
self.model.get_x_profile_i(0),
self.model.get_y_profile_i(0), lw=1., markersize=3,
marker='+', color="m", linestyle='--'
)
self.after_plot_selected_1.set_visible(False)
self.ui.canvas_1.figure.tight_layout()
self.ui.canvas_1.figure.canvas.draw_idle()
self.ui.toolbar_1.update()
def graphic_2(self):
self.tableView.model().blockSignals(True)
self.ui.canvas_2.axes.cla()
self.ui.canvas_2.axes.grid(color='grey', linestyle='--', linewidth=0.5)
self.ui.canvas_2.axes.set_xlabel(
_translate("MainWindow_reach", "Pk (m)"), color='green', fontsize=12
)
self.ui.canvas_2.axes.set_ylabel(
_translate("MainWindow_reach", "Cote (m)"), color='green', fontsize=12
)
self.get_pk = self.model.get_pk()
self.get_z_min = self.model.get_z_min()
self.get_z_max = self.model.get_z_max()
self.line_pk_zmin_zmax = self.ui.canvas_2.axes.vlines(
x=self.get_pk,
ymin=self.get_z_min, ymax=self.get_z_max,
color='r', lw=1.
)
self.plot_selected_2, = self.ui.canvas_2.axes.plot(
(self.get_pk[0], self.get_pk[0]),
(self.get_z_min[0], self.get_z_max[0]),
color='b', lw=1.8
)
self.plot_selected_2.set_visible(False)
self.before_plot_selected_2, = self.ui.canvas_2.axes.plot(
(self.get_pk[0], self.get_pk[0]),
(self.get_z_min[0], self.get_z_max[0]),
color='k', lw=1.6, linestyle='--'
)
self.before_plot_selected_2.set_visible(False)
self.after_plot_selected_2, = self.ui.canvas_2.axes.plot(
(self.get_pk[0], self.get_pk[0]),
(self.get_z_min[0], self.get_z_max[0]),
color='m', lw=1.6, linestyle='--'
)
self.after_plot_selected_2.set_visible(False)
try:
self.line_pk_zld = [
self.ui.canvas_2.axes.plot(
self.model.get_pk(), i, lw=1.
) for i in self.model.z_complete_guideline()
]
except:
print("TODO")
self.line_pk_zmin, = self.ui.canvas_2.axes.plot(
self.get_pk, self.get_z_min,
linestyle=":", lw=1.8,
color='lightgrey'
)
self.tableView.model().blockSignals(False)
self.ui.canvas_2.figure.tight_layout()
self.ui.canvas_2.figure.canvas.draw_idle()
self.ui.toolbar_2.update()
def update_graphic_1(self):
self.tableView.model().blockSignals(True)
for ind in range(self.model.rowCount()):
self.line_xy[ind][0].set_data(
self.model.get_x_profile_i(ind),
self.model.get_y_profile_i(ind)
)
for i in range(len(self.line_ld_1)):
self.line_ld_1[i].set_data(
[x[i] for x in self.get_x_complete_list_ld],
[y[i] for y in self.get_y_complete_list_ld]
)
self.tableView.model().blockSignals(False)
self.ui.canvas_1.figure.canvas.draw_idle()
def update_graphic_2(self):
self.tableView.model().blockSignals(True)
get_pk = self.model.get_pk()
get_z_min = self.model.get_z_min()
get_z_max = self.model.get_z_max()
self.line_pk_zmin.set_data(get_pk, get_z_min)
self.line_pk_zmin_zmax.remove()
self.line_pk_zmin_zmax = self.ui.canvas_2.axes.vlines(
x=get_pk,
ymin=get_z_min, ymax=get_z_max,
color='r', lw=1.
)
try:
for i in range(len(self.line_pk_zld)):
self.line_pk_zld[i][0].set_data(
get_pk, self.model.z_complete_guideline()[i]
)
except:
print("TODO")
self.tableView.model().blockSignals(False)
self.ui.canvas_2.axes.autoscale_view(True, True, True)
self.ui.canvas_2.figure.canvas.draw_idle()
def graphic_3(self):
self.tableView.model().blockSignals(True)
selected_profile = 0
station = self.model.get_station(selected_profile) # L'abscisse en travers
station_plus_1 = self.model.get_station(selected_profile + 1)
elevation = self.model.get_z_profile_i(selected_profile)
elevation_i_plus_1 = self.model.get_z_profile_i(selected_profile + 1)
ld = self.model.get_ld_profile_i(selected_profile)
self.ui.canvas_3.axes.cla()
self.ui.canvas_3.axes.grid(color='grey', linestyle='--', linewidth=0.5)
self.ui.canvas_3.axes.set_xlabel(
_translate("MainWindow_reach", "Abscisse en travers (m)"),
color='green', fontsize=12
)
self.ui.canvas_3.axes.set_ylabel(
_translate("MainWindow_reach", "Cote (m)"),
color='green', fontsize=12
)
self.ui.canvas_3.figure.tight_layout()
label_profile_i_minus_1 = _translate("MainWindow_reach", "Profil précédent")
label_profile_i = _translate("MainWindow_reach", "Profil sélectionné")
label_profile_i_plus_1 = _translate("MainWindow_reach", "Profil suivant")
color_profile_i_minus_1 = "k" # 'grey'
color_profile_i = 'b'
color_profile_i_plus_1 = 'm'
self.profile_i_minus_1, = self.ui.canvas_3.axes.plot(
[], [], label=label_profile_i_minus_1, lw=1.8,
linestyle='--', color=color_profile_i_minus_1
)
self.profile_i, = self.ui.canvas_3.axes.plot(
station, elevation, label=label_profile_i,
color=color_profile_i, lw=1.8
)
self.profile_i_plus_1, = self.ui.canvas_3.axes.plot(
station_plus_1, elevation_i_plus_1,
label=label_profile_i_plus_1,
color=color_profile_i_plus_1, lw=1.6, linestyle='--'
)
self.annotation_3 = []
self.complete_list_ld = self.model.get_complete_list_ld()
self.incomplete_list_ld = self.model.get_incomplete_list_ld()
line_2d = [[line_2D] for line_2D in self.line_ld_1]
self.color_complete_ld = self.get_line_ld_colors(line_2d)
self.color_incomplete_ld = 2 * ["#000000"]
x_ld_complete = []
y_ld_complete = []
color_scat_complete_ld = []
x_ld_incomplete = []
y_ld_incomplete = []
color_scat_incomplete_ld = []
for i, txt in enumerate(list(ld)):
if txt.strip() in self.complete_list_ld:
annotation_3 = self.ui.canvas_3.axes.annotate(
txt, (station[i], elevation[i]),
horizontalalignment='left',
verticalalignment='top', annotation_clip=True,
fontsize=10,
color=self.color_complete_ld[
self.complete_list_ld.index(txt)
]
)
annotation_3.set_position((station[i] + 0., elevation[i] + 0.))
self.annotation_3.append(annotation_3)
x_ld_complete.append(station[i])
y_ld_complete.append(elevation[i])
color_scat_complete_ld.append(self.color_complete_ld[self.complete_list_ld.index(txt)])
elif txt.strip() in self.incomplete_list_ld:
annotate = self.ui.canvas_3.axes.annotate(
txt, (station[i], elevation[i]), horizontalalignment='left',
verticalalignment='top', annotation_clip=True, fontsize=11,
color=self.color_incomplete_ld[
self.incomplete_list_ld.index(txt)
],
size=10
)
self.annotation_3.append(annotate)
x_ld_incomplete.append(station[i])
y_ld_incomplete.append(elevation[i])
color_scat_incomplete_ld.append(
self.color_incomplete_ld[self.incomplete_list_ld.index(txt)]
)
self.tableView.model().blockSignals(False)
self.ui.canvas_3.axes.legend(fancybox=True, shadow=True, fontsize=8)
self.ui.canvas_3.figure.tight_layout()
self.ui.canvas_3.figure.canvas.draw_idle()
self.ui.toolbar_3.update()
def update_annotate_3(self, ind: int):
self.tableView.model().blockSignals(True)
for a in self.annotation_3:
a.remove()
self.annotation_3[:] = []
x = self.get_station(ind)
y = self.get_elevation(ind)
ld = self.model.get_ld_profile_i(ind)
get_complete_list_ld = self.model.get_complete_list_ld()
get_incomplete_list_ld = self.model.get_incomplete_list_ld()
try:
x_ld_complete = []
color_scat_complete_ld = []
x_ld_incomplete = []
color_scat_incomplete_ld = []
for i, txt in enumerate(list(ld)):
if txt in get_complete_list_ld:
annotate = self.ui.canvas_3.axes.annotate(
txt, (x[i], y[i]), horizontalalignment='left',
verticalalignment='top', annotation_clip=True,
fontsize=11,
color=self.color_complete_ld[
get_complete_list_ld.index(txt)
],
size=10
)
self.annotation_3.append(annotate)
x_ld_complete.append([x[i], y[i]])
color_scat_complete_ld.append(
self.color_complete_ld[self.complete_list_ld.index(txt)]
)
elif txt in get_incomplete_list_ld:
annotate = self.ui.canvas_3.axes.annotate(
txt, (x[i], y[i]), horizontalalignment='left',
verticalalignment='top', annotation_clip=True,
fontsize=11,
color=self.color_incomplete_ld[
get_incomplete_list_ld.index(txt)
],
size=10
)
self.annotation_3.append(annotate)
x_ld_incomplete.append([x[i], y[i]])
color_scat_incomplete_ld.append(
self.color_incomplete_ld[get_incomplete_list_ld.index(txt)]
)
except:
print("FIXME")
self.tableView.model().blockSignals(False)
self.ui.canvas_3.figure.canvas.draw_idle()
def get_line_ld_colors(self, line_2d):
colors = []
for line in line_2d:
colors.append(line[0].get_color())
return colors
def get_station(self, ind: int):
return self.model.get_station(ind)
def get_elevation(self, ind: int):
return self.model.get_z_profile_i(ind)
def update_graphic_3(self, ind: int):
self.tableView.model().blockSignals(True)
selected_profile = ind
print(selected_profile)
if selected_profile == 0:
self.profile_i_minus_1.set_data([], [])
self.profile_i.set_data(
self.get_station(selected_profile),
self.get_elevation(selected_profile)
)
self.profile_i_plus_1.set_data(
self.get_station(selected_profile + 1),
self.get_elevation(selected_profile + 1)
)
elif selected_profile == self.model.rowCount() - 1:
self.profile_i_minus_1.set_data(
self.get_station(selected_profile - 1),
self.get_elevation(selected_profile - 1)
)
self.profile_i.set_data(
self.get_station(selected_profile),
self.get_elevation(selected_profile)
)
self.profile_i_plus_1.set_data([], [])
elif 0 < selected_profile < self.model.rowCount() - 1:
self.profile_i_minus_1.set_data(
self.get_station(selected_profile - 1),
self.get_elevation(selected_profile - 1)
)
self.profile_i.set_data(
self.get_station(selected_profile),
self.get_elevation(selected_profile)
)
self.profile_i_plus_1.set_data(
self.get_station(selected_profile + 1),
self.get_elevation(selected_profile + 1)
)
self.tableView.model().blockSignals(False)
self.update_annotate_3(selected_profile)
self.ui.canvas_3.axes.relim()
self.ui.canvas_3.axes.autoscale_view()
self.ui.canvas_3.figure.canvas.draw_idle()
def select_plot_graphic_1(self, ind: int):
self.tableView.model().blockSignals(True)
if 0 <= ind < self.model.rowCount():
self.plot_selected_1.set_data(self.model.get_x_profile_i(ind),
self.model.get_y_profile_i(ind))
self.plot_selected_1.set_visible(True)
self.tableView.model().blockSignals(False)
def select_plot_graphic_2(self, ind: int):
get_pk_i = self.get_pk_i(ind)
get_z_min_i = self.get_z_min_i(ind)
get_z_max_i = self.get_z_max_i(ind)
if 0 <= ind < self.model.rowCount():
self.plot_selected_2.set_data((get_pk_i, get_pk_i),
(get_z_min_i, get_z_max_i))
self.plot_selected_2.set_visible(True)
def select_before_plot_selected_1(self, ind: int):
if 0 <= ind < self.model.rowCount():
t0 = time.time()
self.before_plot_selected_1.set_data(
self.model.get_x_profile_i(ind),
self.model.get_y_profile_i(ind)
)
self.before_plot_selected_1.set_visible(True)
self.ui.canvas_1.figure.canvas.draw_idle()
def select_after_plot_selected_1(self, ind: int):
if 0 <= ind < self.model.rowCount():
self.after_plot_selected_1.set_data(
self.model.get_x_profile_i(ind),
self.model.get_y_profile_i(ind)
)
self.after_plot_selected_1.set_visible(True)
self.ui.canvas_1.figure.canvas.draw_idle()
def select_before_plot_selected_2(self, ind: int):
if 0 <= ind < self.model.rowCount():
t0 = time.time()
get_pk_i = self.get_pk_i(ind)
get_z_min_i = self.get_z_min_i(ind)
get_z_max_i = self.get_z_max_i(ind)
self.before_plot_selected_2.set_data(
(get_pk_i, get_pk_i),
(get_z_min_i, get_z_max_i)
)
self.before_plot_selected_2.set_visible(True)
self.ui.canvas_2.figure.canvas.draw_idle()
def select_after_plot_selected_2(self, ind: int):
if 0 <= ind < self.model.rowCount():
t0 = time.time()
get_pk_i = self.get_pk_i(ind)
get_z_min_i = self.get_z_min_i(ind)
get_z_max_i = self.get_z_max_i(ind)
self.after_plot_selected_2.set_data(
(get_pk_i, get_pk_i),
(get_z_min_i, get_z_max_i)
)
self.after_plot_selected_2.set_visible(True)
self.ui.canvas_2.figure.canvas.draw_idle()
def select_row_profile_slider(self, ind: int = 0):
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_current_profile(self):
self.tableView.model().blockSignals(True)
if len(self.tableView.selectedIndexes()) > 0:
row = self.index_selected_row
self.ui.verticalSlider.setValue(row)
self.select_plot_graphic_1(row)
self.select_plot_graphic_2(row)
if row == 0:
self.before_plot_selected_1.set_visible(False)
self.select_after_plot_selected_1(row + 1)
self.before_plot_selected_2.set_visible(False)
self.select_after_plot_selected_2(row + 1)
elif 0 < row < self.model.rowCount() - 1:
self.select_before_plot_selected_1(row - 1)
self.select_after_plot_selected_1(row + 1)
self.select_before_plot_selected_2(row - 1)
self.select_after_plot_selected_2(row + 1)
elif row == self.model.rowCount() - 1:
self.after_plot_selected_1.set_visible(False)
self.select_before_plot_selected_1(row - 1)
self.after_plot_selected_2.set_visible(False)
self.select_before_plot_selected_2(row - 1)
self.tableView.model().blockSignals(False)
self.update_graphic_3(row)
self.ui.canvas_1.figure.canvas.draw_idle()
self.ui.canvas_2.figure.canvas.draw_idle()
def changed_slider_value(self):
self.tableView.model().blockSignals(True)
if self.filename is not None:
self.ui.verticalSlider.setMaximum(self.model.rowCount() - 1)
slider_value = self.ui.verticalSlider.value()
pk = self.model.get_pk_profile_i(slider_value)
self.ui.vertical_slider_label.setText(
_translate("MainWindow_reach", "Pk : ") +
f"{pk}" + "\n" +
_translate("MainWindow_reach",
"Profil N° : ") +
f"{slider_value + 1}"
)
self.select_plot_graphic_1(slider_value)
self.select_plot_graphic_2(slider_value)
self.select_row_profile_slider(slider_value)
self.tableView.model().blockSignals(False)
def increment_value_slider(self):
if 0 <= self.ui.verticalSlider.value() < self.model.rowCount() - 1:
self.ui.verticalSlider.setValue(self.ui.verticalSlider.value() + 1)
def decrement_value_slider(self):
if 0 < self.ui.verticalSlider.value() < self.model.rowCount():
self.ui.verticalSlider.setValue(self.ui.verticalSlider.value() - 1)
def insert_row(self):
if len(self.tableView.selectedIndexes()) == 0:
self.model.insertRows(self.model.rowCount(), 1)
else:
row = self.index_selected_row
self.model.insertRows(row + 1, 1)
if self.filename is not None:
self.graphic_1()
self.graphic_2()
self.select_current_profile()
def delete_row(self):
rows = list(set(
[index.row() for index in self.tableView.selectedIndexes()]
))
if len(rows) > 0:
self.model.remove_rows(rows)
self.update_graphic_1()
self.select_current_profile()
self.graphic_2()
self.changed_slider_value()
@property
def index_selected_row(self):
return [index.row() for index in self.tableView.selectedIndexes()][0]
def sort_ascending(self):
self.model.sort_data(True)
self.select_current_profile()
self.changed_slider_value()
self.update_graphic_2()
self.update_graphic_3(self.index_selected_row)
def sort_descending(self):
self.model.sort_data(False)
self.select_current_profile()
self.changed_slider_value()
self.update_graphic_2()
self.update_graphic_3(self.index_selected_row)
def move_row_down(self):
row = self.index_selected_row
if row < self.model.rowCount() - 1:
self.model.moveRowDown(row)
self.update_graphic_3(row + 1)
self.ui.canvas_3.axes.relim()
self.ui.canvas_3.axes.autoscale_view()
if row < self.model.rowCount() - 2:
self.select_before_plot_selected_1(row)
self.select_after_plot_selected_1(row + 2)
self.select_before_plot_selected_2(row)
self.select_after_plot_selected_2(row + 2)
if row == self.model.rowCount() - 2:
self.select_before_plot_selected_1(self.model.rowCount() - 2)
self.after_plot_selected_1.set_visible(False)
self.select_before_plot_selected_2(self.model.rowCount() - 2)
self.after_plot_selected_2.set_visible(False)
self.update_graphic_2()
def move_row_up(self):
row = self.index_selected_row
if 0 < row <= self.model.rowCount() - 1:
self.model.moveRowUp(row)
if row == 1:
self.select_after_plot_selected_1(row)
self.before_plot_selected_1.set_visible(False)
self.select_after_plot_selected_2(row)
self.before_plot_selected_2.set_visible(False)
elif row == self.model.rowCount() - 1:
self.select_before_plot_selected_1(row - 2)
self.select_after_plot_selected_1(row)
self.select_before_plot_selected_2(row - 2)
self.select_after_plot_selected_2(row)
else:
self.select_before_plot_selected_1(row - 2)
self.select_after_plot_selected_1(row)
self.select_before_plot_selected_2(row - 2)
self.select_after_plot_selected_2(row)
self.update_graphic_2()
self.update_graphic_3(row - 1)
self.ui.canvas_3.axes.relim()
self.ui.canvas_3.axes.autoscale_view()
def handleSave(self):
options = QFileDialog.Options()
DEFAULT_DIRECTORY = '/home/'
settings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'MyOrg', )
current_dir = settings.value('current_directory', DEFAULT_DIRECTORY, type=str)
options |= QFileDialog.DontUseNativeDialog
filename, self.filters = QFileDialog.getSaveFileName(
self,
filter=_translate("MainWindow_reach",
"Fichiers .ST(*.ST ou *.st)")
+ ";; " +
_translate("MainWindow_reach", "Tous les fichiers "
"(*)"),
options=options
)
current_dir = os.path.split(filename)[0] or DEFAULT_DIRECTORY
if filename != '':
self.model.export_reach(filename)
def handleOpen(self):
self.filename, self.filterName = QFileDialog.getOpenFileName(self)
if self.filename != '':
with open(self.filename, 'r') as f:
reader = csv.reader(f, delimiter='\t')
header = next(reader)
buf = []
for row in reader:
row[0] = QCheckBox("-")
buf.append(row)
self.model = None
self.model = qtableview_reach.PandasModelEditable(buf)
self.tableView.setModel(self.model)
self.filename = ''
def get_lignes_directrices(self):
liste_lignes_directrices = [
data[1].iloc[:, 3].tolist() for data in self.model._data
]
return liste_lignes_directrices
def get_x(self):
return self.model.get_x()
def get_y(self):
return self.model.get_y()
def get_z(self):
return self.model.get_z()
def get_z_min(self):
return self.model.get_z_min()
def get_z_min_i(self, index):
return self.model.get_z_min_i(index)
def get_z_max_i(self, index):
return self.model.get_z_max_i(index)
def get_z_max(self):
return self.model.get_z_max()
def get_pk(self):
return self.model.get_pk()
def get_pk_i(self, index):
return self.model.get_pk_i(index)
def get_pk_z_ld(self):
return self.model.get_pk_z_ld()
def get_pk_z_ld_bis(self):
return self.model.get_pk_z_ld_bis()
@property
def model_data(self):
return self.model.model_data()

View File

@ -0,0 +1,34 @@
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
super(MplCanvas, self).__init__(fig)
self.axes = fig.add_subplot(111)
self.axes.format_coord = lambda x, y: '(x = ' + format(x, '1.4f') + ', \t' + ' y = ' + format(y, '1.4f') + ')'
self.axes.grid(color='green', linestyle='--', linewidth=0.5)
self.axes.yaxis.tick_left()
self.axes.xaxis.tick_bottom()
self.axes.spines[['top', 'right']].set_color('none')
self.figure.tight_layout()
self.add_arrows()
def add_arrows(self):
al = 8.
arrowprops = dict(
clip_on=True,
# frac=1.,
headwidth=5.,
facecolor='k'
)
kwargs = dict(
xycoords='axes fraction',
textcoords='offset points',
arrowprops=arrowprops,
)
self.axes.annotate("", (1, 0), xytext=(-al, 0), **kwargs)
self.axes.annotate("", (0, 1), xytext=(0, -al), **kwargs)

View File

@ -0,0 +1,488 @@
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
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:
print("Probleme de mise à jour ... update_select_point_point()")
try:
self.update_select_point_point_bis(self.x[row], self.y[row])
except:
print("index introuvable pour la mise à jour de l'affichage de la sélection du point."
"Editer les cases en 'nan'.")
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: abscisse
y: ordonnée
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} 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:
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

View File

@ -0,0 +1,162 @@
# -*- coding: utf-8 -*-
import os
import matplotlib as mpl
from matplotlib.backends import qt_compat
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QAction
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT
from PyQt5.QtCore import pyqtSignal, QSize
_translate = QtCore.QCoreApplication.translate
file_path = os.path.abspath(os.path.dirname(__file__))
class PamHyrNavigationToolbar2QT(NavigationToolbar2QT):
"""
Cette classe est une personnalisation de la toolbar (NavigationToolbar2QT). Elle permet l'internationnalisation et
l'ajout d'autres boutons à la toolbar initiale
"""
isometric_signal = pyqtSignal(str)
def __init__(self, canvas, parent):
"""
Args:
canvas: canvas de matplotlib
parent: parent du canvas
"""
self.my_canvas = canvas
self.toolitems = [
(None, None, None, None),
('Home', _translate("Toolbar", 'Vue originale'), 'home', 'home'),
(None, None, None, None),
('Back', _translate("Toolbar", 'Retour à la vue précédente'), 'back', 'back'),
('Forward', _translate("Toolbar", 'Passer à la vue suivante'), 'forward', 'forward'),
(None, None, None, None),
('Pan', _translate(
"Toolbar",
'Panoramique des axes avec la souris gauche, zoom avec la droite'
), 'move', 'pan'),
(None, None, None, None),
('Zoom', _translate("Toolbar", 'Zoom'), 'zoom_to_rect', 'zoom'),
(None, None, None, None),
('Isometric_view', _translate(
"Toolbar", 'Vue isométrique (Shift+W)'
), '', 'isometric_view'),
(None, None, None, None),
('GlobalView', _translate(
"Toolbar", 'Vue globale automatique (Shift+X)'
), '', 'non_isometric_view'),
(None, None, None, None),
('Save', _translate(
"Toolbar", 'Enregistrer la figure'
), 'filesave', 'save_figure'),
(None, None, None, None),
]
NavigationToolbar2QT.__init__(self, canvas, parent)
btn_size = QSize(30, 30)
icon_zoom = QtGui.QIcon()
icon_zoom.addPixmap(QtGui.QPixmap(
f"{os.path.dirname(os.path.dirname(file_path))}/resources/icons/zoom.png"
))
icon_btn_isometric_view = QtGui.QIcon()
icon_btn_isometric_view.addPixmap(
QtGui.QPixmap(f"{os.path.dirname(os.path.dirname(file_path))}/resources"
f"/icons/zoom_fit_11.png"))
icon_btn_global_view = QtGui.QIcon()
icon_btn_global_view.addPixmap(
QtGui.QPixmap(f"{os.path.dirname(os.path.dirname(file_path))}/resources/icons"
f"/zoom_fit.png"))
actions = self.findChildren(QAction)
self._actions["zoom"].setIcon(icon_zoom)
self._actions["isometric_view"].setIcon(icon_btn_isometric_view)
self._actions["non_isometric_view"].setIcon(icon_btn_global_view)
self.addSeparator()
self.set_style_sheet()
def save_figure(self, *args):
filetypes = self.canvas.get_supported_filetypes_grouped()
sorted_filetypes = sorted(filetypes.items())
default_filetype = self.canvas.get_default_filetype()
startpath = os.path.expanduser(mpl.rcParams['savefig.directory'])
start = os.path.join(startpath, self.canvas.get_default_filename())
filters = []
selectedFilter = None
for name, exts in sorted_filetypes:
exts_list = " ".join(['*.%s' % ext for ext in exts])
filter = '%s (%s)' % (name, exts_list)
if default_filetype in exts:
selectedFilter = filter
filters.append(filter)
filters = ';;'.join(filters)
fname, filter = qt_compat._getSaveFileName(
self.canvas.parent(),
_translate("MainWindow_reach", "Choisissez un nom de fichier à sauvegarder"),
start,
filters, selectedFilter)
if fname:
if startpath != "":
mpl.rcParams['savefig.directory'] = os.path.dirname(fname)
try:
self.canvas.figure.savefig(fname)
except Exception as e:
QtWidgets.QMessageBox.critical(
self, "Error saving file", str(e),
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton
)
def cursor1(self):
print("TODO")
def isometric_view(self):
self.my_canvas.axes.axis("equal")
self.my_canvas.figure.canvas.draw_idle()
self.isometric_signal[str].emit("vue iso")
def non_isometric_view(self):
self.my_canvas.axes.axis("tight")
self.my_canvas.toolbar.update()
self.my_canvas.figure.canvas.draw_idle()
def toolitems_translation(self):
self._actions['home'].setToolTip(_translate("Toolbar", "Vue originale"))
self._actions['back'].setToolTip(_translate("Toolbar", "Retour à la vue précédente"))
self._actions['forward'].setToolTip(_translate("Toolbar", "Passer à la vue suivante"))
self._actions['pan'].setToolTip(_translate("Toolbar", "Panoramique des axes avec la "
"souris gauche, zoom avec la droite"))
self._actions['zoom'].setToolTip(_translate("Toolbar", "Zoom"))
self._actions['save_figure'].setToolTip(_translate("Toolbar", "Enregistrer la figure"))
self.action_isometric_view.setToolTip(_translate("Toolbar", "Vue isométrique (Shift+W)"))
self.action_auto_global_view.setToolTip(_translate("Toolbar", "Vue globale automatique (Shift+X)"))
def set_style_sheet(self):
self.setStyleSheet(
"QToolBar{ border: 1px solid darkGray;\n"
" gridline-color: blue;\n"
" border-radius: 4px;\n"
" border-style: solid;\n"
" background-color: #EEF6FC; \n"
" selection-background-color: #218ede;\n"
" font-size: 12px;\n"
" font-family: Helvetica\n"
"\n"
" }"
)