This repository was archived by the owner on Jan 18, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmap.py
More file actions
364 lines (330 loc) · 13.4 KB
/
Copy pathmap.py
File metadata and controls
364 lines (330 loc) · 13.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt5.QtCore import Qt, QRect, QSize, QLineF, QPointF
from PyQt5.QtWidgets import QWidget, QLabel, QInputDialog, QMessageBox
from PyQt5.QtGui import QPainter, QBrush, QColor, QPen, QPixmap, QMouseEvent, QPaintEvent, QPolygonF
from PIL import Image
from math import acos, sin, cos, pi, degrees
from fonctions.angleToFunction import angleToFunction
from fonctions.functionIntersect import functionIntersect
from fonctions.WGS84DecToDeg import WGS84DecToDeg
from fonctions.WGS84DegToDec import WGS84DegToDec
from fonctions.mareeCalculator import marreCalculator
from fonctions.routeFond import *
from uiFunctions import *
class DrawMap(QWidget):
"""
widget de la carte
@author: Maxime Favier
"""
def __init__(self, im, parentClass):
"""
Initialisation du widget pour la carte
@type im: str
@param im: Chemain d'acces de la carte
@type parentClass: Window
@param parentClass: classe principale de l'UI
"""
super().__init__()
self.parentClass = parentClass
self.line = []
self.fx = []
self.intersect = ()
self.gps = ()
self.arrow = []
self.ndDec, self.wdDec, self.westDec, self.nordDec = None, None, None, None
self.im = im
self.mode = "amer"
image = Image.open(im)
self.imSize = image.size
self.setMinimumWidth(image.size[0])
self.setMinimumHeight(image.size[1])
self.setMaximumWidth(image.size[0])
self.setMaximumHeight(image.size[1])
# self.init_ui()
def supprimerTraces(self):
"""supprime le tracé des amers"""
self.line = []
self.fx = []
self.intersect = ()
self.westDec, self.nordDec = None, None
self.parentClass.updateLabelsAmer("→", "→")
self.parentClass.updateLabelsError("→", "→")
self.update()
def paintEvent(self, event):
"""
impressions des formes sur la carte
@type event: QPaintEvent
"""
painter = QPainter(self)
pixmap = QPixmap(self.im)
painter.drawPixmap(self.rect(), pixmap)
painter.setRenderHint(QPainter.Antialiasing)
painter.setRenderHint(QPainter.HighQualityAntialiasing)
pen = QPen(Qt.black)
pen.setWidth(2)
painter.setPen(pen)
for line in self.line:
painter.drawLine(*line)
if self.intersect:
pen.setColor(Qt.blue)
painter.setPen(pen)
painter.drawEllipse(abs(self.intersect[0]) - 5, abs(self.intersect[1]) - 5, 10, 10)
if self.gps:
pen.setColor(Qt.red)
painter.setPen(pen)
painter.drawEllipse(self.gps[0] - 5, self.gps[1] - 5, 10, 10)
if self.arrow:
pen.setColor(Qt.darkGray)
painter.setPen(pen)
Arrow(painter, self.arrow[0], self.arrow[1])
return
def amerCreation(self, event):
"""
Creation du trace des amers et determination de la position
@type event: QMouseEvent
@param event: objet clic de souris
"""
pos = event.pos()
# fenetre demande angle de l'amer
deg, ok = QInputDialog.getDouble(self, "Angle de l'amer", "Angle de l'amer")
#deg = deg + 180
#deg = deg % 360
# si click ok
if ok:
# si angle valide
if 0. <= deg < 360.:
# supprime les anciens traces
if len(self.line) > 2:
self.supprimerTraces()
# cas 0 et 180
if deg == 0:
# self.line.append((pos.x(), 0, pos.x(), pos.y()))
# recalcule de a,b pour eviter le cas x=n
# la perte de la précision est negligeable dans notre cas ou l'echelle et la carte est petite
deg = deg + 10e-8
elif deg == 180:
# self.line.append((pos.x(), self.imSize[1], pos.x(), pos.y()))
# recalcule de a,b pour eviter le cas x=n
# la perte de la précision est negligeable dans notre cas ou l'echelle et la carte est petite
deg = deg + 10e-8
# calcul de la fonction de la droite
a, b = angleToFunction(deg, (pos.x(), pos.y()))
# print("ab", a, b)
# test des cas pour la direction
if deg >= 180:
y2 = -a * 1650 + b
x2 = 1650
else:
y2 = a * 1650 + b
x2 = -1650
# evite l'overflow du GUI
if y2 > 2147483647:
y2 = 2147483646
elif y2 < -2147483648:
y2 = -2147483648
self.fx.append((-a, b))
self.line.append((pos.x(), pos.y(), x2, y2))
# si 2 doites => calcul de l'intersection
if len(self.fx) == 2:
# print("calcul du pt")
try:
pt = functionIntersect(*self.fx[0], *self.fx[1])
except:
QMessageBox.critical(self, "Amer invalide", "deux amers différents sont requis")
self.supprimerTraces()
return
# conversion en pixel => degree decimal
self.westDec = 3.0 - (pt[0] * -0.000342936)
self.nordDec = 47.519635 + pt[1] * -0.000232025
# conversion en degrée
nordDeg = WGS84DecToDeg(self.nordDec)
westDeg = WGS84DecToDeg(self.westDec)
self.parentClass.updateLabelsAmer("{}° {}' {}\"N".format(*nordDeg),
"{}° {}' {}\"W".format(*westDeg))
self.intersect = pt
self.computeAmerGPSError()
# sinon angle invalide
else:
# Warning box angle invalide
QMessageBox.critical(self, "Angle invalide", "l'angle doit être entre 0 et 360°")
self.update()
def gpsDialogManager(self):
"""
Hook pour la fenetre de dialogue GPS
"""
dlg = GpsDialog(self)
if dlg.exec_():
pass
# print("Success!")
# else:
# print("Cancel!")
def getGpsCoordinates(self, ncord, wcord):
"""
Affiche le point GPS sur la carte
@type ncord: tuple
@param ncord: Cordonée sexadecimal Nord
@type wcord: tuple
@param wcord: Cordonée sexadecimal ouest
"""
self.parentClass.updateLabelsGPS("{}° {}' {}\"N".format(*ncord),
"{}° {}' {}\"W".format(*wcord))
self.ndDec = WGS84DegToDec(*ncord)
self.wdDec = WGS84DegToDec(*wcord)
# print(ndDec, wdDec)
xcoord = abs((self.wdDec - 3.0) / 0.000342936)
ycoord = abs((self.ndDec - 47.519635) / -0.000232025)
self.gps = (xcoord, ycoord)
self.update()
self.computeAmerGPSError()
# print(xcoord, ycoord)
def computeAmerGPSError(self):
"""
Calcul l'erreur entre le relevé des amers et la position GPS
"""
if self.ndDec and self.wdDec and self.nordDec and self.westDec:
ndelta = self.ndDec - self.nordDec
wdelta = self.wdDec - self.westDec
ndelta = WGS84DecToDeg(ndelta)
wdelta = WGS84DecToDeg(wdelta)
self.parentClass.updateLabelsError("{}° {}' {}\"N".format(*ndelta),
"{}° {}' {}\"W".format(*wdelta))
def mousePressEvent(self, event):
"""
Hook evenement clic de souris
@type event: QMouseEvent
@param event: objet clic de souris
"""
if self.mode == "amer":
self.amerCreation(event)
def mareeDialogManager(self):
"""Hook pour la fenetre de dialogue marée"""
dlg = MareeDialog(self, self.parentClass)
if dlg.exec_():
pass
def mareeProcessing(self, TMarreeHaute, HMarreeHaute, TMarreeBasse, HMarreeBasse, time):
""" Manager de calcul des informations de marée
@type TMarreeHaute: int
@param TMarreeHaute: heure de maree haute en min
@type HMarreeHaute: float
@param HMarreeHaute: hauteur de l'eau à maree haute
@type TMarreeBasse: int
@param TMarreeBasse: heure de maree basse en min
@type HMarreeBasse: float
@param HMarreeBasse: hauteur de l'eau à maree basse en min
@type time: int
@param time: temps de la journee"""
h = marreCalculator(TMarreeHaute, HMarreeHaute, TMarreeBasse, HMarreeBasse, time)
self.parentClass.updateMarre(None, "H = {} m".format(str(round(h, 3))))
def posTheoriqueDialogManager(self):
"""Hook pour la fenetre de dialogue de calcul de la position théorique"""
dlg = PositionTheorique(self, self.parentClass)
if dlg.exec_():
pass
def posTheoriqueProcessing(self, ncoord, wcoord, angleCourant, vitesseCourant, capCompas, declinaison, deviation,
deriveVent, xMin):
"""
Manager de calcul des information pour la position théorique
@type ncoord: tuple
@param ncoord: Cordonée sexadecimal Nord
@type wcoord: tuple
@param wcoord: Cordonée sexadecimal Ouest
@param angleCourant: angle du courant
@type angleCourant: float
@param vitesseCourant: vitesse du courant m/s
@type vitesseCourant: float
@param capCompas: cap compas (deg)
@type capCompas: float
@param declinaison: declinaison
@type declinaison: float
@param deviation: déviation
@type deviation: float
@param deriveVent: derive du vent
@type deriveVent: float
@param xMin: min de simulation
@type xMin: int
@author: Maxime Favier
"""
print("angleCourant=", angleCourant)
print("vitesseCourant=", vitesseCourant)
print("capCompas=", capCompas)
print("declinaison=", declinaison)
print("deviation=", deviation)
print("deriveVent=", deriveVent)
print("xMin=", xMin)
print("ncoord=", ncoord)
print("wcoord=", wcoord)
QMessageBox.warning(self, "Non implémenté", "Cette fonction n'est pas encore disponible")
def capTheoriqueManager(self):
"""Hook pour la fenetre de dialogue pour le calcul du cap"""
dlg = CapDialog(self)
if dlg.exec_():
pass
def capTheoriqueProcessing(self, ncoord1, wcoord1, ncoord2, wcoord2, d,D ,Der):
"""
Manager du calcul de cap
@type ncoord1: tuple
@param ncoord1: coordonnées deg/min/sec nord du pt A
@type wcoord1: tuple
@param wcoord1: coordonnées deg/min/sec ouest du pt A
@type ncoord2: tuple
@param ncoord2: coordonnées deg/min/sec nord du pt B
@type wcoord2: tuple
@param wcoord2: coordonnées deg/min/sec ouest du pt B
@type d: float
@param d: déviation
@type D: float
@param D: déclinaison
@type Der: float
@param Der: dérive au vent
@author: Maxime Favier
"""
# conversion en degré decimal
decNcoord1 = WGS84DegToDec(*ncoord1)
decWcoord1 = WGS84DegToDec(*wcoord1)
decNcoord2 = WGS84DegToDec(*ncoord2)
decWcoord2 = WGS84DegToDec(*wcoord2)
# conversion en pixel sur la carte
# point A :
xcoordA = abs((decWcoord1 - 3.0) / 0.000342936)
ycoordA = abs((decNcoord1 - 47.519635) / -0.000232025)
# print("pt A:", xcoordA, ycoordA)
# point B :
xcoordB = abs((decWcoord2 - 3.0) / 0.000342936)
ycoordB = abs((decNcoord2 - 47.519635) / -0.000232025)
# print("pt B:", xcoordB, ycoordB)
# calcul cap compas
Cc = route_compas(xcoordA, ycoordA, xcoordB, ycoordB)
# convertion Route de surface
Rs = route_surface(Cc, d, D, Der)
self.parentClass.updateCap(str(Cc)+" °", str(Rs)+" °")
# création de la flèche
self.arrow = [(xcoordA, ycoordA), (xcoordB, ycoordB)]
# maj de l'interface
self.update()
class Arrow:
"""
Classe pour la création de fleches
@author: Maxime Favier
@note: Inspiré de https://gist.github.com/reusee/2406975
"""
def __init__(self, painter, pos1, pos2):
self.arrowSize = 10.0
self.sourcePoint = QPointF(*pos1)
self.destPoint = QPointF(*pos2)
self.paint(painter)
def paint(self, painter):
line = QLineF(self.sourcePoint, self.destPoint)
if line.length() == 0.0:
return
painter.setPen(QPen(Qt.darkGray, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
painter.drawLine(line)
angle = acos(line.dx() / line.length())
if line.dy() >= 0:
angle = (2 * pi) - angle
destArrowP1 = self.destPoint + QPointF(sin(angle - pi / 3) * self.arrowSize,
cos(angle - pi / 3) * self.arrowSize)
destArrowP2 = self.destPoint + QPointF(sin(angle - pi + pi / 3) * self.arrowSize,
cos(angle - pi + pi / 3) * self.arrowSize)
painter.setBrush(Qt.darkGray)
painter.drawPolygon(QPolygonF([line.p2(), destArrowP1, destArrowP2]))