4 graphWidget, a module for pymecavideo:
5 a program to track moving points
in a video frameset
7 Copyright (C) 2007 Jean-Baptiste Butet <ashashiwa
@gmail.com>
8 Copyright (C) 2023 Georges Khaznadar <georgesk
@debian.org>
10 This program
is free software: you can redistribute it
and/
or modify
11 it under the terms of the GNU General Public License
as published by
12 the Free Software Foundation, either version 3 of the License,
or
13 (at your option) any later version.
15 This program
is distributed
in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License
for more details.
20 You should have received a copy of the GNU General Public License
21 along
with this program. If
not, see <http://www.gnu.org/licenses/>.
24from PyQt6.QtCore import QThread, pyqtSignal, QLocale, QTranslator, Qt, \
25 QSize, QTimer, QObject, QRect, QPoint, QPointF, QEvent
26from PyQt6.QtGui
import QKeySequence, QIcon, QPixmap, QImage, QPainter, \
27 QCursor, QPen, QColor, QFont, QResizeEvent, QShortcut
28from PyQt6.QtWidgets
import QApplication, QMainWindow, QWidget, QLayout, \
29 QFileDialog, QTableWidgetItem, QInputDialog, QLineEdit, QMessageBox, \
30 QTableWidgetSelectionRange, QPushButton, QVBoxLayout
32import os, time, re, sys
35import pyqtgraph.exporters
38from version
import Version
39from vecteur
import vecteur
40from image_widget
import ImageWidget
41from globdef
import cible_icon, DOCUMENT_PATH, inhibe, pattern_float
42from toQimage
import toQImage
43from suivi_auto
import SelRectWidget
44from detect
import filter_picture
45from cadreur
import Cadreur, openCvReader
46from export
import Export, EXPORT_FORMATS
47from grandeurs
import grandeurs
50import interfaces.icon_rc
52from interfaces.Ui_graphWidget
import Ui_graphWidget
53from etatsGraph
import Etats
57 Widget principal de l'onglet grapheur
59 paramètres du constructeur :
60 @param parent l
'onglet des graphiques
62 def __init__(self, parent):
63 QWidget.__init__(self, parent)
64 Ui_graphWidget.__init__(self)
75 Crée des liens avec la fenêtre principale, le débogueur,
77 @param app la fenêtre principale
86 Connecte les signaux des sous-widgets
96 def dessine_graphe_avant(self):
103 """dessine les graphes avec pyqtgraph au moment où les combobox sont choisies"""
104 self.
dbg.p(2,
"rentre dans 'dessine_graphe'")
106 styles = {0: {
'pen':
None,
'symbol':
'+'}, 1: {
'pen': (0, 0, 0),
'symbol':
'+'}, 2: {
'pen': (
107 0, 0, 0),
'symbol':
None}}
115 abscisse = self.
comboBox_X.currentText().strip(
'|')
116 ordonnee = self.
comboBox_Y.currentText().strip(
'|')
118 pen, symbol = styles[style][
'pen'], styles[style][
'symbol']
122 if grandeurX ==
"Choisir ..." or grandeurY ==
"Choisir ...":
return
126 elif grandeurX
in self.
locals :
127 X = self.
locals[grandeurX]
130 elif grandeurY
in self.
locals :
131 Y = self.
locals[grandeurY]
134 X, Y = zip(*[(x, y)
for x,y
in zip(X, Y)
if x
is not None and y
is not None])
138 if X != []
and Y != []:
139 pg.setConfigOption(
'background',
'w')
140 pg.setConfigOption(
'foreground',
'k')
141 titre =
"%s en fonction de %s" % (ordonnee, abscisse)
145 elif 'V' in abscisse:
146 unite_x = abscisse+
'(m/s)'
147 elif 'E' in abscisse:
148 unite_x = abscisse+
'(J)'
149 elif 'A' in abscisse:
150 unite_x = abscisse+
'(m/s²)'
152 unite_x = abscisse+
'(m)'
156 elif 'V' in ordonnee:
157 unite_y = ordonnee+
'(m/s)'
158 elif 'E' in ordonnee:
159 unite_y = ordonnee+
'(J)'
160 elif 'A' in ordonnee:
161 unite_y = ordonnee+
'(m/s²)'
163 unite_y = ordonnee+
'(m)'
166 self.
graphW = pg.PlotWidget(
168 self.
graphW.setMenuEnabled(
False)
169 self.
graphW.setLabel(
'bottom', unite_x)
170 self.
graphW.setLabel(
'left', unite_y)
172 self.
vLayout.setContentsMargins(0, 0, 0, 0)
174 "verticalLayout_graph")
176 self.
graphW.plot(X, Y, pen=pen, symbol=symbol)
181 plotItem = self.
graphW.getPlotItem()
182 plotItem.setTitle(titre)
183 self.
graphW.setLabel(
'bottom', unite_x)
184 self.
graphW.setLabel(
'left', unite_y)
186 self.
graphW.plot(X, Y, pen=pen, symbol=symbol)
192 def enregistre_graphe(self):
193 if hasattr (self,
'pg_exporter'):
194 base_name = os.path.splitext(os.path.basename(self.
pointage.filename))[0]
195 defaultName = os.path.join(DOCUMENT_PATH, base_name+
'.png')
196 fichier = QFileDialog.getSaveFileName(
198 self.tr(
"Enregistrer le graphique"),
199 defaultName, self.tr(
"fichiers images(*.png)"))
203 def verifie_m_grapheur(self):
206 if not pattern_float.match(m):
207 QMessageBox.critical(
209 self.tr(
"MAUVAISE VALEUR !"),
210 self.tr(
"La valeur rentrée (m = {}) n'est pas compatible avec le calcul").format(m))
216 def verifie_g_grapheur(self):
219 if not pattern_float.match(g):
220 QMessageBox.critical(
222 self.tr(
"MAUVAISE VALEUR !"),
223 self.tr(
"La valeur rentrée (g = {}) n'est pas compatible avec le calcul").format(g))
230 self.
dbg.p(2,
"rentre dans 'affiche_grapheur'")
233 if not pattern_float.match(m)
or not pattern_float.match(g):
return
241 self.
locals[gr+str(obj)] = []
245 def cb_points(i, t, j, obj, p, v):
247 fonction de rappel pour une itération sur les dates
249 self.locals["X"+str(obj)].append(p.x
if p
else None)
250 self.
locals[
"Y"+str(obj)].append(p.y
if p
else None)
251 self.
locals[
"Vx"+str(obj)].append(v.x
if v
else None)
252 self.
locals[
"Vy"+str(obj)].append(v.y
if v
else None)
253 self.
locals[
"V"+str(obj)].append(v.norme
if v
else None)
254 self.
locals[
"Ec"+str(obj)].append(
255 0.5 * m * v.norme ** 2
if v
else None)
256 self.
locals[
"Epp"+str(obj)].append(
257 self.
pointage.sens_Y * m * g * p.y
if p
else None)
259 self.
pointage.iteration_data(
None, cb_points, unite=
"m")
264 self.
locals[
"Em"+str(obj)] = \
265 [ec + epp
if ec
is not None and epp
is not None else None
267 self.
locals[
"Ec"+str(obj)],
268 self.
locals[
"Epp"+str(obj)])]
270 liste0 = self.
locals[
"Vx"+str(obj)][1:-1]
271 liste1 = self.
locals[
"Vx"+str(obj)][2:]
272 self.
locals[
"Ax"+str(obj)] = [
None,
None] + \
273 [(v1 - v0) / deltaT
if v1
is not None and v0
is not None else None
274 for v1, v0
in zip(liste1, liste0)]
276 liste0 = self.
locals[
"Vy"+str(obj)][1:-1]
277 liste1 = self.
locals[
"Vy"+str(obj)][2:]
278 self.
locals[
"Ay"+str(obj)] = [
None,
None] + \
279 [(v1 - v0) / deltaT
if v1
is not None and v0
is not None else None
280 for v1, v0
in zip(liste1, liste0)]
282 self.
locals[
"A"+str(obj)] = \
283 [
vecteur(ax, ay).norme
if ax
is not None else None
285 self.
locals[
"Ax"+str(obj)],
286 self.
locals[
"Ay"+str(obj)]
294 self.tr(
"Choisir ..."))
296 self.tr(
"Choisir ..."))
299 for grandeur
in self.
locals.keys():
300 if self.
locals[grandeur] != []:
302 [grandeur[-2]
if grandeur[-2].isdigit()
else "", grandeur[-1]])
303 if 'prime' in grandeur :
305 grandeur_a_afficher =
'Vx'+numero
306 elif 'y' in grandeur :
307 grandeur_a_afficher =
'Vy'+numero
308 elif 'abs' in grandeur :
309 grandeur_a_afficher =
'Ax'+numero
310 elif 'ord' in grandeur :
311 grandeur_a_afficher =
'Ay'+numero
312 elif 'A' in grandeur
or 'V' in grandeur:
313 grandeur_a_afficher =
'|'+grandeur+
'|'
316 grandeur_a_afficher = grandeur
Une classe qui permet de définir les états pour le ccordWidget debut, A, AB, B, C,...
une classe pour des vecteurs 2D ; les coordonnées sont flottantes, et on peut accéder à celles-ci par...