batoolset 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- batoolset/GUI/__init__.py +0 -0
- batoolset/GUI/list_gui.py +513 -0
- batoolset/GUI/multi_image_display.py +989 -0
- batoolset/GUI/open.py +325 -0
- batoolset/GUI/overlay_hints.py +45 -0
- batoolset/GUI/paint2.py +1345 -0
- batoolset/GUI/scrollablepaint.py +1152 -0
- batoolset/IJ_ROIs/__init__.py +0 -0
- batoolset/IJ_ROIs/tools.py +40 -0
- batoolset/PATH/__init__.py +0 -0
- batoolset/PATH/tools.py +79 -0
- batoolset/SQLite_tools/__init__.py +0 -0
- batoolset/SQLite_tools/tools.py +840 -0
- batoolset/__init__.py +0 -0
- batoolset/binary/__init__.py +0 -0
- batoolset/binary/tools.py +123 -0
- batoolset/binarytools/__init__.py +0 -0
- batoolset/binarytools/cell_center_detector.py +290 -0
- batoolset/clipboard_tools/__init__.py +0 -0
- batoolset/clipboard_tools/tools.py +7 -0
- batoolset/colors/__init__.py +0 -0
- batoolset/colors/colorgen.py +193 -0
- batoolset/colors/tools.py +22 -0
- batoolset/command_line/__init__.py +0 -0
- batoolset/command_line/tools.py +18 -0
- batoolset/dialogs/__init__.py +0 -0
- batoolset/dialogs/opensave.py +228 -0
- batoolset/dicts/__init__.py +0 -0
- batoolset/dicts/tools.py +299 -0
- batoolset/dims/__init__.py +0 -0
- batoolset/dims/tools.py +83 -0
- batoolset/draw/__init__.py +0 -0
- batoolset/draw/shapes/Position.py +183 -0
- batoolset/draw/shapes/__init__.py +0 -0
- batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
- batoolset/draw/shapes/circle2d.py +99 -0
- batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
- batoolset/draw/shapes/ellipse2d.py +336 -0
- batoolset/draw/shapes/freehand2d.py +235 -0
- batoolset/draw/shapes/group.py +1830 -0
- batoolset/draw/shapes/image2d.py +2469 -0
- batoolset/draw/shapes/line2d.py +575 -0
- batoolset/draw/shapes/point2d.py +257 -0
- batoolset/draw/shapes/polygon2d.py +357 -0
- batoolset/draw/shapes/polyline2d.py +235 -0
- batoolset/draw/shapes/rect2d.py +388 -0
- batoolset/draw/shapes/rectangle2d.py +601 -0
- batoolset/draw/shapes/scalebar.py +304 -0
- batoolset/draw/shapes/serializablefont.py +126 -0
- batoolset/draw/shapes/serializableguiparams.py +10 -0
- batoolset/draw/shapes/square2d.py +103 -0
- batoolset/draw/shapes/textorientation.py +45 -0
- batoolset/draw/shapes/tools.py +467 -0
- batoolset/draw/shapes/transform2D.py +350 -0
- batoolset/draw/shapes/txt2d.py +550 -0
- batoolset/draw/widgets/__init__.py +0 -0
- batoolset/draw/widgets/col.py +343 -0
- batoolset/draw/widgets/image_group.py +248 -0
- batoolset/draw/widgets/image_organizer.py +96 -0
- batoolset/draw/widgets/paint.py +184 -0
- batoolset/draw/widgets/vectorial.py +257 -0
- batoolset/figure/__init__.py +0 -0
- batoolset/figure/alignment.py +814 -0
- batoolset/figure/column.py +1117 -0
- batoolset/figure/fig_tools.py +285 -0
- batoolset/figure/minimal_debugger_scale_etc.py +139 -0
- batoolset/figure/panel.py +697 -0
- batoolset/figure/row.py +852 -0
- batoolset/figure/user_selection.py +287 -0
- batoolset/files/__init__.py +0 -0
- batoolset/files/tools.py +1321 -0
- batoolset/images/__init__.py +0 -0
- batoolset/images/tools.py +81 -0
- batoolset/img.py +5216 -0
- batoolset/linux/__init__.py +0 -0
- batoolset/linux/tools.py +72 -0
- batoolset/lists/__init__.py +0 -0
- batoolset/lists/tools.py +436 -0
- batoolset/luts/__init__.py +0 -0
- batoolset/luts/lut_minimal_test.py +1207 -0
- batoolset/matplolib/__init__.py +0 -0
- batoolset/matplolib/tools.py +44 -0
- batoolset/np_tools/__init__.py +0 -0
- batoolset/np_tools/tools.py +252 -0
- batoolset/np_tools/trash.py +15 -0
- batoolset/pandas_tools/__init__.py +0 -0
- batoolset/pandas_tools/tools.py +880 -0
- batoolset/partials/__init__.py +0 -0
- batoolset/partials/tools.py +83 -0
- batoolset/plot_tools/__init__.py +0 -0
- batoolset/plot_tools/tools.py +70 -0
- batoolset/pyqt/__init__.py +0 -0
- batoolset/pyqt/tools.py +691 -0
- batoolset/re_tools/__init__.py +0 -0
- batoolset/re_tools/tools.py +35 -0
- batoolset/serialization/__init__.py +0 -0
- batoolset/serialization/tools.py +1192 -0
- batoolset/sets/__init__.py +0 -0
- batoolset/sets/tools.py +109 -0
- batoolset/settings/__init__.py +0 -0
- batoolset/settings/global_settings.py +134 -0
- batoolset/strings/__init__.py +0 -0
- batoolset/strings/tools.py +225 -0
- batoolset/ta/__init__.py +0 -0
- batoolset/ta/database/__init__.py +0 -0
- batoolset/ta/database/advanced_sql_plotter.py +1170 -0
- batoolset/ta/database/my_qt_table.py +79 -0
- batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
- batoolset/ta/database/sql.py +2141 -0
- batoolset/ta/database/sql_column_name_dialog.py +122 -0
- batoolset/ta/measurements/TAmeasures.py +2226 -0
- batoolset/ta/measurements/__init__.py +0 -0
- batoolset/ta/measurements/measurements3D/__init__.py +0 -0
- batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
- batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
- batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
- batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
- batoolset/ta/measurements/nematic.py +562 -0
- batoolset/ta/measurements/nematic_measurements.py +107 -0
- batoolset/ta/segmentation/__init__.py +0 -0
- batoolset/ta/segmentation/neo_wshed.py +314 -0
- batoolset/ta/selections/__init__.py +0 -0
- batoolset/ta/selections/selection.py +329 -0
- batoolset/ta/tracking/__init__.py +0 -0
- batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
- batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
- batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
- batoolset/ta/tracking/registration.py +108 -0
- batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
- batoolset/ta/tracking/track_correction.py +238 -0
- batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
- batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
- batoolset/ta/utils/TA_tools.py +43 -0
- batoolset/ta/utils/__init__.py +0 -0
- batoolset/ta/utils/rps_tools.py +1783 -0
- batoolset/tests/__init__.py +0 -0
- batoolset/tests/rps_tools.py +51 -0
- batoolset/tests/tools.py +10 -0
- batoolset/tools/__init__.py +0 -0
- batoolset/tools/early_stopper_class.py +9 -0
- batoolset/tools/guided_data_recoverer.py +110 -0
- batoolset/tools/logger.py +100 -0
- batoolset/tools/mytimer.py +31 -0
- batoolset/tools/prompt_color.py +160 -0
- batoolset/tools/qthandler.py +118 -0
- batoolset/uitools/__init__.py +0 -0
- batoolset/uitools/blinker.py +56 -0
- batoolset/unsafe/__init__.py +0 -0
- batoolset/unsafe/tools.py +115 -0
- batoolset/utils/__init__.py +0 -0
- batoolset/utils/commontools.py +158 -0
- batoolset/utils/loadlist.py +728 -0
- batoolset/version.py +10 -0
- batoolset/xml/__init__.py +0 -0
- batoolset/xml/tools.py +65 -0
- batoolset/zip_tools/__init__.py +0 -0
- batoolset/zip_tools/tools.py +76 -0
- batoolset-0.1.0.dist-info/LICENSE +24 -0
- batoolset-0.1.0.dist-info/METADATA +45 -0
- batoolset-0.1.0.dist-info/RECORD +162 -0
- batoolset-0.1.0.dist-info/WHEEL +5 -0
- batoolset-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
from batoolset.settings.global_settings import set_UI # set the UI to qtpy
|
|
2
|
+
set_UI()
|
|
3
|
+
import os
|
|
4
|
+
from qtpy import QtCore
|
|
5
|
+
from qtpy.QtCore import QPointF, Qt
|
|
6
|
+
from qtpy.QtGui import QPainter, QBrush, QPen, QImage, QColor, QPolygonF
|
|
7
|
+
# from qtpy.Qt
|
|
8
|
+
# from qtpy.Qt import (QPaintEngine, QPaintDevice, QTransform, QBrush)
|
|
9
|
+
from batoolset.draw.shapes.polygon2d import Polygon2D
|
|
10
|
+
|
|
11
|
+
from batoolset.tools.logger import TA_logger
|
|
12
|
+
|
|
13
|
+
logger = TA_logger()
|
|
14
|
+
|
|
15
|
+
class PolyLine2D(Polygon2D):
|
|
16
|
+
|
|
17
|
+
def __init__(self, *args, coords_as_list=None,color=0xFFFFFF, opacity=1., stroke=0.65, line_style=None, theta=0, fill_color=None, __version__=1.0, **kwargs):
|
|
18
|
+
super(PolyLine2D, self).__init__()
|
|
19
|
+
points = []
|
|
20
|
+
if len(args) > 0:
|
|
21
|
+
if isinstance(args[0],tuple):
|
|
22
|
+
for i in range(0, len(args)):
|
|
23
|
+
self.append(QPointF(args[i][0], args[i][1]))
|
|
24
|
+
else:
|
|
25
|
+
for i in range(0, len(args), 2):
|
|
26
|
+
self.append(QPointF(args[i], args[i+1]))
|
|
27
|
+
|
|
28
|
+
if coords_as_list:
|
|
29
|
+
# print(coords_as_list)
|
|
30
|
+
for i in range(0, len(coords_as_list), 2):
|
|
31
|
+
self.append(QPointF(coords_as_list[i], coords_as_list[i + 1]))
|
|
32
|
+
|
|
33
|
+
self.color = color
|
|
34
|
+
self.fill_color = fill_color
|
|
35
|
+
self.stroke = stroke
|
|
36
|
+
self.opacity = opacity
|
|
37
|
+
self.isSet = False
|
|
38
|
+
self.line_style = line_style
|
|
39
|
+
# rotation
|
|
40
|
+
self.theta = theta
|
|
41
|
+
self.__version__ = __version__
|
|
42
|
+
|
|
43
|
+
def set_rotation(self, theta):
|
|
44
|
+
self.theta = theta
|
|
45
|
+
|
|
46
|
+
def set_opacity(self, opacity):
|
|
47
|
+
self.opacity = opacity
|
|
48
|
+
|
|
49
|
+
def set_line_style(self, style):
|
|
50
|
+
"""
|
|
51
|
+
allows lines to be dashed or dotted or have custom pattern
|
|
52
|
+
|
|
53
|
+
:param style: a list of numbers or any of the following Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine but not Qt.CustomDashLine, Qt.CustomDashLine is assumed by default if a list is passed in. None is also a valid value that resets the line --> assume plain line
|
|
54
|
+
:return:
|
|
55
|
+
"""
|
|
56
|
+
self.line_style = style
|
|
57
|
+
# if style is a list then assume custom pattern otherwise apply solidline
|
|
58
|
+
|
|
59
|
+
def draw(self, painter, draw=True, parent=None):
|
|
60
|
+
if self.color is None: # and self.fill_color is None
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
if draw:
|
|
64
|
+
painter.save()
|
|
65
|
+
pen = QPen(QColor(self.color))
|
|
66
|
+
if self.stroke is not None:
|
|
67
|
+
pen.setWidthF(self.stroke)
|
|
68
|
+
if self.line_style is not None:
|
|
69
|
+
if self.line_style in [Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine]:
|
|
70
|
+
pen.setStyle(self.line_style)
|
|
71
|
+
elif isinstance(self.line_style, list):
|
|
72
|
+
pen.setStyle(Qt.CustomDashLine)
|
|
73
|
+
pen.setDashPattern(self.line_style)
|
|
74
|
+
if self.color is not None:
|
|
75
|
+
painter.setPen(pen)
|
|
76
|
+
else:
|
|
77
|
+
painter.setPen(Qt.NoPen)
|
|
78
|
+
if self.fill_color is not None:
|
|
79
|
+
# print('coloring')
|
|
80
|
+
brush = QBrush(QColor(self.fill_color))
|
|
81
|
+
painter.setBrush(brush)
|
|
82
|
+
else:
|
|
83
|
+
painter.setBrush(Qt.NoBrush)
|
|
84
|
+
|
|
85
|
+
painter.setOpacity(self.opacity)
|
|
86
|
+
polyline_to_draw = self.translated(0, 0)
|
|
87
|
+
|
|
88
|
+
if parent is not None and parent.scale is not None and parent.scale != 1:
|
|
89
|
+
polyline_to_draw = self.__get_scaled_polyline(polyline_to_draw,1. / parent.scale)
|
|
90
|
+
|
|
91
|
+
if parent is not None:
|
|
92
|
+
polyline_to_draw = polyline_to_draw.translated(parent.topLeft())
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# print(polyline_to_draw)
|
|
96
|
+
|
|
97
|
+
# if self.scale is not None and self.scale != 1:
|
|
98
|
+
# polyline_to_draw = self.__scaled()
|
|
99
|
+
# print('mid rect_to_plot', rect_to_plot)
|
|
100
|
+
# if self.translation is not None:
|
|
101
|
+
# # rect_to_plot.setX(rect_to_plot.x()+self.translation.x())
|
|
102
|
+
# # rect_to_plot.setY(rect_to_plot.y()+self.translation.y())
|
|
103
|
+
# polyline_to_draw.translate(self.translation.x(), self.translation.y())
|
|
104
|
+
# painter.drawPolygon(polygon_to_draw)
|
|
105
|
+
if self.theta is not None and self.theta != 0:
|
|
106
|
+
painter.translate(polyline_to_draw.boundingRect().center())
|
|
107
|
+
painter.rotate(self.theta)
|
|
108
|
+
painter.translate(-polyline_to_draw.boundingRect().center())
|
|
109
|
+
|
|
110
|
+
# painter.drawPolygon(polyline_to_draw)
|
|
111
|
+
painter.drawPolyline(polyline_to_draw)
|
|
112
|
+
painter.restore()
|
|
113
|
+
#
|
|
114
|
+
# def fill(self, painter, draw=True):
|
|
115
|
+
# if self.fill_color is None:
|
|
116
|
+
# return
|
|
117
|
+
# if draw:
|
|
118
|
+
# painter.save()
|
|
119
|
+
# painter.setBrush(QBrush(QColor(self.fill_color)))
|
|
120
|
+
# painter.setOpacity(self.opacity)
|
|
121
|
+
# if draw:
|
|
122
|
+
# painter.drawPolyline(self)
|
|
123
|
+
# painter.restore()
|
|
124
|
+
#
|
|
125
|
+
# # TODO pb will draw the shape twice.... ---> because painter drawpolygon is called twice
|
|
126
|
+
# def drawAndFill(self, painter):
|
|
127
|
+
# painter.save()
|
|
128
|
+
# self.draw(painter, draw=False)
|
|
129
|
+
# self.fill(painter, draw=False)
|
|
130
|
+
# painter.drawPolyline(self)
|
|
131
|
+
# painter.restore()
|
|
132
|
+
#
|
|
133
|
+
# def setP1(self, point):
|
|
134
|
+
# self.append(point)
|
|
135
|
+
|
|
136
|
+
def add(self, *args, force=True):
|
|
137
|
+
if self.count() > 1:
|
|
138
|
+
self.remove(self.count()-1)
|
|
139
|
+
self.append(args[1])
|
|
140
|
+
# self.isSet = True
|
|
141
|
+
|
|
142
|
+
# def listVertices(self):
|
|
143
|
+
# return [point for point in self]
|
|
144
|
+
def listVertices(self, polygon=None):
|
|
145
|
+
if polygon is None:
|
|
146
|
+
polygon = self
|
|
147
|
+
return [point for point in polygon]
|
|
148
|
+
|
|
149
|
+
def __get_scaled_polyline(self, polygon, scale):
|
|
150
|
+
vertices = self.listVertices(polygon)
|
|
151
|
+
scaled_poly = QPolygonF()
|
|
152
|
+
for vx in vertices:
|
|
153
|
+
vx.setX(vx.x()*scale)
|
|
154
|
+
vx.setY(vx.y()*scale)
|
|
155
|
+
scaled_poly.append(vx)
|
|
156
|
+
# print(vertices)
|
|
157
|
+
return scaled_poly
|
|
158
|
+
|
|
159
|
+
# def __get_scaled_polyline(self, scale):
|
|
160
|
+
# vertices = self.listVertices()
|
|
161
|
+
# scaled_poly = QPolygonF()
|
|
162
|
+
# for vx in vertices:
|
|
163
|
+
# vx.setX(vx.x()*scale)
|
|
164
|
+
# vx.setY(vx.y()*scale)
|
|
165
|
+
# scaled_poly.append(vx)
|
|
166
|
+
# print(vertices)
|
|
167
|
+
# return scaled_poly
|
|
168
|
+
|
|
169
|
+
def __scaled(self):
|
|
170
|
+
vertices = self.listVertices()
|
|
171
|
+
scaled_poly = QPolygonF()
|
|
172
|
+
for vx in vertices:
|
|
173
|
+
vx.setX(vx.x()*self.scale)
|
|
174
|
+
vx.setY(vx.y()*self.scale)
|
|
175
|
+
scaled_poly.append(vx)
|
|
176
|
+
return scaled_poly
|
|
177
|
+
|
|
178
|
+
def __repr__(self):
|
|
179
|
+
class_name = type(self).__name__
|
|
180
|
+
memory_address = hex(id(self))
|
|
181
|
+
return f"{class_name}-{memory_address}"
|
|
182
|
+
|
|
183
|
+
if __name__ == '__main__':
|
|
184
|
+
test = PolyLine2D(0, 0, 10, 0,10, 20, 0, 20, 0, 0)
|
|
185
|
+
print(test.count()) # marche pas --> pas ajouté
|
|
186
|
+
print(test)
|
|
187
|
+
|
|
188
|
+
hexagon = PolyLine2D()
|
|
189
|
+
print(hexagon)
|
|
190
|
+
hexagon.append(QPointF(10, 20))
|
|
191
|
+
hexagon.append(QPointF(10, 30))
|
|
192
|
+
hexagon.append(QPointF(20, 30))
|
|
193
|
+
|
|
194
|
+
print(hexagon)
|
|
195
|
+
print(hexagon.isEmpty())
|
|
196
|
+
print(hexagon.count())
|
|
197
|
+
print(hexagon.stroke)
|
|
198
|
+
print(hexagon.get_stroke_size())
|
|
199
|
+
# ça marche maintenant
|
|
200
|
+
# print(hexagon.)
|
|
201
|
+
# trop cool l'acces aux points
|
|
202
|
+
for point in hexagon:
|
|
203
|
+
print(point)
|
|
204
|
+
|
|
205
|
+
print(hexagon.get_points())
|
|
206
|
+
print(hexagon.contains(QPointF(10, 20)))
|
|
207
|
+
print(hexagon.contains(QPointF(10, 21)))
|
|
208
|
+
|
|
209
|
+
print(hexagon.isClosed()) #
|
|
210
|
+
hexagon.append(QPointF(10, 20)) # closing the hexagon --> the last and first point should be the same
|
|
211
|
+
print(hexagon.isClosed()) #
|
|
212
|
+
#
|
|
213
|
+
# image = QImage('./../data/handCorrection.png')
|
|
214
|
+
# painter = QPainter()
|
|
215
|
+
# painter.begin(image)
|
|
216
|
+
# # painter.setOpacity(0.3);
|
|
217
|
+
# painter.drawImage(0, 0, image)
|
|
218
|
+
# painter.setPen(QtCore.Qt.blue)
|
|
219
|
+
# painter.drawPolygon(hexagon)
|
|
220
|
+
# hexagon.opacity = 0.7
|
|
221
|
+
# painter.translate(10, 20)
|
|
222
|
+
# hexagon.draw(painter) # ça marche pourrait overloader ça avec du svg
|
|
223
|
+
# painter.end()
|
|
224
|
+
#
|
|
225
|
+
# # painter.save()
|
|
226
|
+
# # painter.setCompositionMode(QtGui.QPainter.CompositionMode_Clear)
|
|
227
|
+
# # painter.eraseRect(r)
|
|
228
|
+
# # painter.restore()
|
|
229
|
+
#
|
|
230
|
+
# image.save('./../trash/test_pyQT_draw.png', "PNG");
|
|
231
|
+
#
|
|
232
|
+
# #pas mal TODO faire une classe drawsmthg qui dessine n'importe quelle forme que l'on lui passe avec des parametres de couleur, transparence, ...
|
|
233
|
+
|
|
234
|
+
# tt marche aps mal ça va très vite
|
|
235
|
+
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# code cleaning not finished... --> KEEP FOR COMPAT WITH OLD EPYSEG CODE (UNTIL CLEANING) --> BUT DO NOT USE ANYMORE
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from batoolset.settings.global_settings import set_UI # set the UI to qtpy
|
|
7
|
+
set_UI()
|
|
8
|
+
from qtpy.QtCore import QPointF, QRectF, Qt
|
|
9
|
+
from qtpy.QtGui import QBrush, QPen, QColor, QTransform
|
|
10
|
+
|
|
11
|
+
from batoolset.tools.logger import TA_logger
|
|
12
|
+
|
|
13
|
+
logger = TA_logger()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# TODO --> try to simplify that and finalize it once for good
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# rather use a dict as **kwargs to set opacity and alike --> that would allow me to handle much more flexibly my tools -−> this is not possible in fact possible but not very beautiful
|
|
21
|
+
'''
|
|
22
|
+
def __init__(self, *args, **kwargs):
|
|
23
|
+
# set default values for keyword arguments
|
|
24
|
+
color = kwargs.get('color', 0xFFFF00)
|
|
25
|
+
stroke = kwargs.get('stroke', 0.65)
|
|
26
|
+
|
|
27
|
+
'''
|
|
28
|
+
#
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Rect2D(QRectF):
|
|
32
|
+
"""
|
|
33
|
+
A custom class for 2D rectangles with additional features such as color, fill color, opacity, stroke, line style,
|
|
34
|
+
rotation, scale, and translation.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
*args: Variable-length arguments that can represent the rectangle coordinates.
|
|
38
|
+
color (int): Color of the rectangle in hexadecimal format (default: 0xFFFF00).
|
|
39
|
+
fill_color (int): Fill color of the rectangle in hexadecimal format (default: None).
|
|
40
|
+
opacity (float): Opacity value between 0.0 and 1.0 (default: 1.0).
|
|
41
|
+
stroke (float): Stroke width of the rectangle (default: 0.65).
|
|
42
|
+
line_style (Union[None, int, List[int]]): Line style of the rectangle. None for a solid line,
|
|
43
|
+
or any of the following values: Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine.
|
|
44
|
+
If a list of integers is provided, it represents a custom dash pattern (default: None).
|
|
45
|
+
theta (float): Rotation angle in degrees (default: 0.0).
|
|
46
|
+
**kwargs: Additional keyword arguments.
|
|
47
|
+
|
|
48
|
+
Attributes:
|
|
49
|
+
isSet (bool): Indicates whether the rectangle is set.
|
|
50
|
+
color (int): Color of the rectangle in hexadecimal format.
|
|
51
|
+
fill_color (int): Fill color of the rectangle in hexadecimal format.
|
|
52
|
+
stroke (float): Stroke width of the rectangle.
|
|
53
|
+
opacity (float): Opacity value between 0.0 and 1.0.
|
|
54
|
+
scale (float): Scaling factor of the rectangle (default: 1.0).
|
|
55
|
+
translation (QPointF): Translation of the rectangle.
|
|
56
|
+
line_style (Union[None, int, List[int]]): Line style of the rectangle.
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(self, *args, color=0xFFFF00, fill_color=None, opacity=1., stroke=0.65, line_style=None, theta=0, **kwargs):
|
|
61
|
+
super(Rect2D, self).__init__(*args)
|
|
62
|
+
if not args:
|
|
63
|
+
self.isSet = False
|
|
64
|
+
else:
|
|
65
|
+
self.isSet = True
|
|
66
|
+
self.color = color
|
|
67
|
+
self.fill_color = fill_color
|
|
68
|
+
self.stroke = stroke
|
|
69
|
+
self.opacity = opacity
|
|
70
|
+
self.isSet = False
|
|
71
|
+
self.scale = 1
|
|
72
|
+
self.translation = QPointF()
|
|
73
|
+
self.line_style = line_style
|
|
74
|
+
self.theta = theta
|
|
75
|
+
self.incompressible_width=0
|
|
76
|
+
self.incompressible_height=0
|
|
77
|
+
|
|
78
|
+
def set_rotation(self, theta):
|
|
79
|
+
"""
|
|
80
|
+
Set the rotation angle of the rectangle.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
theta (float): Rotation angle in degrees.
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
self.theta = theta
|
|
87
|
+
|
|
88
|
+
def set_opacity(self, opacity):
|
|
89
|
+
"""
|
|
90
|
+
Set the opacity value of the rectangle.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
opacity (float): Opacity value between 0.0 and 1.0.
|
|
94
|
+
|
|
95
|
+
"""
|
|
96
|
+
self.opacity = opacity
|
|
97
|
+
|
|
98
|
+
def set_line_style(self,style):
|
|
99
|
+
"""
|
|
100
|
+
allows lines to be dashed or dotted or have custom pattern
|
|
101
|
+
|
|
102
|
+
:param style: a list of numbers or any of the following Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine but not Qt.CustomDashLine, Qt.CustomDashLine is assumed by default if a list is passed in. None is also a valid value that resets the line --> assume plain line
|
|
103
|
+
:return:
|
|
104
|
+
"""
|
|
105
|
+
self.line_style = style
|
|
106
|
+
# if style is a list then assume custom pattern otherwise apply solidline
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def draw(self, painter, **kwargs):
|
|
110
|
+
# print(kwargs)
|
|
111
|
+
# if kwargs is not None and kwargs:
|
|
112
|
+
# pass
|
|
113
|
+
# else:
|
|
114
|
+
# return
|
|
115
|
+
|
|
116
|
+
if self.color is None and self.fill_color is None:
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
painter.save()
|
|
120
|
+
painter.setOpacity(self.opacity)
|
|
121
|
+
|
|
122
|
+
if self.color is not None:
|
|
123
|
+
pen = QPen(QColor(self.color))
|
|
124
|
+
if self.stroke is not None:
|
|
125
|
+
pen.setWidthF(self.stroke)
|
|
126
|
+
if self.line_style is not None:
|
|
127
|
+
if self.line_style in [Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine]:
|
|
128
|
+
pen.setStyle(self.line_style)
|
|
129
|
+
elif isinstance(self.line_style, list):
|
|
130
|
+
pen.setStyle(Qt.CustomDashLine)
|
|
131
|
+
pen.setDashPattern(self.line_style)
|
|
132
|
+
pen.setJoinStyle(Qt.MiterJoin)# RoundJoin #BevelJoin # some day offer the handling of that but later
|
|
133
|
+
# if kwargs['draw']==True:
|
|
134
|
+
|
|
135
|
+
# pen.setStyle(Qt.DashLine)
|
|
136
|
+
# pen.setStyle(Qt.CustomDashLine)
|
|
137
|
+
# pen.setDashPattern([1, 4, 5, 4])
|
|
138
|
+
|
|
139
|
+
painter.setPen(pen)
|
|
140
|
+
# if kwargs['fill']==True:
|
|
141
|
+
else:
|
|
142
|
+
painter.setPen(Qt.NoPen) # required to draw something filled without a border
|
|
143
|
+
|
|
144
|
+
# needed to have a filling color in a shape without contour
|
|
145
|
+
if self.fill_color is not None:
|
|
146
|
+
painter.setBrush(QBrush(QColor(self.fill_color)))
|
|
147
|
+
|
|
148
|
+
rect_to_plot = self.adjusted(0,0,0,0)
|
|
149
|
+
# print('begin rect_to_plot', rect_to_plot, self.scale)
|
|
150
|
+
# if kwargs['draw']==True or kwargs['fill']==True:
|
|
151
|
+
# if self.scale is None or self.scale==1:
|
|
152
|
+
# painter.drawRect(self)
|
|
153
|
+
# else:
|
|
154
|
+
# on clone le rect
|
|
155
|
+
if self.scale is not None and self.scale != 1:
|
|
156
|
+
# TODO KEEP THE ORDER THIS MUST BE DONE THIS WAY OR IT WILL GENERATE PLENTY OF BUGS...
|
|
157
|
+
new_width = rect_to_plot.width() * self.scale
|
|
158
|
+
new_height = rect_to_plot.height() * self.scale
|
|
159
|
+
# print(rect_to_plot.width(), rect_to_plot.height()) # here ok
|
|
160
|
+
# setX changes width --> why is that
|
|
161
|
+
|
|
162
|
+
# TODO BE EXTREMELY CAREFUL AS SETX AND SETY CAN CHANGE WIDTH AND HEIGHT --> ALWAYS TAKE SIZE BEFORE OTHERWISE THERE WILL BE A PB AND ALWAYS RESET THE SIZE WHEN SETX IS CALLED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
163
|
+
# Sets the left edge of the rectangle to the given x coordinate. May change the width, but will never change the right edge of the rectangle. --> NO CLUE WHY SHOULD CHANGE WIDTH THOUGH BUT BE CAREFUL!!!
|
|
164
|
+
rect_to_plot.setX(rect_to_plot.x()*self.scale)
|
|
165
|
+
rect_to_plot.setY(rect_to_plot.y()*self.scale)
|
|
166
|
+
# maybe to avoid bugs I should use translate instead rather that set x but ok anyways
|
|
167
|
+
# print(rect_to_plot.width(), rect_to_plot.height())# bug here --> too big
|
|
168
|
+
|
|
169
|
+
# print(new_height, new_height, self.width(), self.scale, self.scale* self.width())
|
|
170
|
+
rect_to_plot.setWidth(new_width)
|
|
171
|
+
rect_to_plot.setHeight(new_height)
|
|
172
|
+
|
|
173
|
+
# print('mid rect_to_plot', rect_to_plot)
|
|
174
|
+
if self.translation is not None:
|
|
175
|
+
|
|
176
|
+
# rect_to_plot.setX(rect_to_plot.x()+self.translation.x())
|
|
177
|
+
# rect_to_plot.setY(rect_to_plot.y()+self.translation.y())
|
|
178
|
+
rect_to_plot.translate(self.translation)
|
|
179
|
+
|
|
180
|
+
# print('rect to plot', rect_to_plot)
|
|
181
|
+
|
|
182
|
+
# if self.color is not None:
|
|
183
|
+
|
|
184
|
+
# rotation marche mais position est pas du tout bonne --> voir comment gérer ça ??
|
|
185
|
+
# center = rect_to_plot.center()
|
|
186
|
+
# painter.translate(center.x(), center.y())
|
|
187
|
+
# painter.rotate(45)
|
|
188
|
+
# rct = QRectF(-center.x(), -center.y(), rect_to_plot.width(), rect_to_plot.height())
|
|
189
|
+
# painter.drawRect(rct)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if self.theta is not None and self.theta != 0:
|
|
193
|
+
# this is only if a rotation should be applied
|
|
194
|
+
painter.translate(rect_to_plot.center())
|
|
195
|
+
# print('center', rect_to_plot.center())
|
|
196
|
+
# painter.setWorldTransform()
|
|
197
|
+
# print(painter.combinedTransform().)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# TODO use this maybe to get bounds of rotated shape properly...
|
|
202
|
+
# center = rect_to_plot.center()
|
|
203
|
+
# t = QTransform().translate( center.x(), center-y() ).rotate( angle ).translate( -center.x(), -center.y() )
|
|
204
|
+
# rotatedRect = t.mapToPolygon( rect_to_plot ) #// mapRect() returns the bounding rect of the rotated rect
|
|
205
|
+
|
|
206
|
+
# on dirait que c'est ça faut faire deux translations en x
|
|
207
|
+
|
|
208
|
+
painter.rotate(self.theta)
|
|
209
|
+
|
|
210
|
+
# ça marche faut deux translations
|
|
211
|
+
|
|
212
|
+
# painter.translate(rect_to_plot.width() / 2, -rect_to_plot.height() )
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
#see https://www.qtcentre.org/threads/15540-Rotating-a-rectangle-about-its-origin --> maybe ok
|
|
216
|
+
|
|
217
|
+
# difference = old center -
|
|
218
|
+
# old_center = self.boundingRect().center()
|
|
219
|
+
# trans = painter.combinedTransform()
|
|
220
|
+
# transformed = trans.mapRect(rect_to_plot)
|
|
221
|
+
|
|
222
|
+
# peut etre une piste mais a pas l'air de marcher
|
|
223
|
+
# print(self.boundingRect(), transformed)
|
|
224
|
+
# trans = transformed.center()-self.boundingRect().center()
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# width_dif = transformed.width()-self.boundingRect().width()
|
|
228
|
+
# width_dif/=2
|
|
229
|
+
# print('trans', trans, transformed.center(), self.boundingRect().center(), width_dif)
|
|
230
|
+
|
|
231
|
+
# painter.translate(-trans)
|
|
232
|
+
# only if rotation
|
|
233
|
+
painter.translate(-rect_to_plot.center())
|
|
234
|
+
painter.drawRect(rect_to_plot)
|
|
235
|
+
# else:
|
|
236
|
+
# painter.fillRect(rect_to_plot, QColor(self.fill_color))
|
|
237
|
+
|
|
238
|
+
painter.restore()
|
|
239
|
+
|
|
240
|
+
# TODO modify that to handle rotation etc...
|
|
241
|
+
def boundingRect(self, scaled=True):
|
|
242
|
+
# should I return the scaled version or the orig --> think about it...
|
|
243
|
+
if scaled:
|
|
244
|
+
# in fact scale only handles rotation and not scale --> the size is therefore wrong -->
|
|
245
|
+
try:
|
|
246
|
+
if self.theta is not None and self.theta!=0:
|
|
247
|
+
# print('entering')
|
|
248
|
+
center = self.center()
|
|
249
|
+
t = QTransform().translate( center.x(), center.y()).rotate(self.theta).translate(-center.x(), -center.y())
|
|
250
|
+
# print('entersd')
|
|
251
|
+
rotatedRect = t.mapRect( self ) #// mapRect() returns the bounding rect of the rotated rect
|
|
252
|
+
# print('rotated',rotatedRect )
|
|
253
|
+
return rotatedRect
|
|
254
|
+
except:
|
|
255
|
+
pass
|
|
256
|
+
return self
|
|
257
|
+
|
|
258
|
+
def add(self, *args):
|
|
259
|
+
point = args[1]
|
|
260
|
+
self.setWidth(point.x()-self.x()) # WHY IS THAT A - AND NOT A + ??? DID I DO A MISTAKE ??? −−> COULD BE # BUT KEEP LIKE THAT JUST IN CASE
|
|
261
|
+
self.setHeight(point.y()-self.y())
|
|
262
|
+
self.isSet = True
|
|
263
|
+
|
|
264
|
+
# def set_P1(self, *args):
|
|
265
|
+
# if not args:
|
|
266
|
+
# logger.error("no coordinate set...")
|
|
267
|
+
# return
|
|
268
|
+
# if len(args) == 1:
|
|
269
|
+
# self.moveTo(args[0].x(), args[0].y())
|
|
270
|
+
# else:
|
|
271
|
+
# self.moveTo(QPointF(args[0], args[1]))
|
|
272
|
+
|
|
273
|
+
# def get_P1(self):
|
|
274
|
+
# return QPointF(self.x(), self.y())
|
|
275
|
+
|
|
276
|
+
def set_to_scale(self, factor):
|
|
277
|
+
self.scale = factor
|
|
278
|
+
|
|
279
|
+
def set_to_translation(self, translation):
|
|
280
|
+
self.translation = translation
|
|
281
|
+
|
|
282
|
+
# hack to make column hashable to be able to add it to a dict, see https://stackoverflow.com/questions/10994229/how-to-make-an-object-properly-hashable
|
|
283
|
+
def __eq__(self, other):
|
|
284
|
+
try:
|
|
285
|
+
return hash(str(self)) == other.__hash__()
|
|
286
|
+
except:
|
|
287
|
+
return False
|
|
288
|
+
|
|
289
|
+
# hack to make column hashable to be able to add it to a dict, see https://stackoverflow.com/questions/10994229/how-to-make-an-object-properly-hashable
|
|
290
|
+
def __hash__(self):
|
|
291
|
+
return hash(str(self))
|
|
292
|
+
|
|
293
|
+
def getIncompressibleWidth(self):
|
|
294
|
+
return self.incompressible_width
|
|
295
|
+
|
|
296
|
+
def getIncompressibleHeight(self):
|
|
297
|
+
return self.incompressible_height
|
|
298
|
+
|
|
299
|
+
# can also be done like that
|
|
300
|
+
# def setTopLeft(self, x_or_rect, y=None):
|
|
301
|
+
# if y is None:
|
|
302
|
+
def setTopLeft(self, *args):
|
|
303
|
+
if args:
|
|
304
|
+
if len(args)==1:
|
|
305
|
+
# assume a QpointF
|
|
306
|
+
super().moveTopLeft(args[0])
|
|
307
|
+
elif len(args)==2:
|
|
308
|
+
super().moveTopLeft(QPointF(args[0], args[1]))
|
|
309
|
+
else:
|
|
310
|
+
logger.error('invalid args for top left')
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
if __name__ == '__main__':
|
|
314
|
+
# ça marche --> voici deux examples de shapes
|
|
315
|
+
test = Rect2D(10, 0, 100, 100)
|
|
316
|
+
print(test)
|
|
317
|
+
# print(test.get_P1())
|
|
318
|
+
|
|
319
|
+
test2 = Rect2D(QRectF(10, 0, 100, 100))
|
|
320
|
+
print('pt2', test2)
|
|
321
|
+
|
|
322
|
+
# then use my set_P1
|
|
323
|
+
print(test2.setTopLeft(10,20)) # setTopLeft really sucks because set top left crops the rect for unknown reason --> use moveTopLeft instead --> ça marche maintenant comme je pensais
|
|
324
|
+
print(test2)
|
|
325
|
+
sys.exit(0)
|
|
326
|
+
|
|
327
|
+
test.incompressible_width = 10
|
|
328
|
+
test.incompressible_height = 5
|
|
329
|
+
print(test.getIncompressibleWidth(),test.getIncompressibleHeight()) # --> that works --> this is a very easy way to get it then -−> this could also be borders around the image to fake it has the same size as another bigger image even if not --> can also be used by the tool that generates the stuff
|
|
330
|
+
# in the case of rows that should be the space between cols or rows and in the case of panels it is both
|
|
331
|
+
|
|
332
|
+
rect = QRectF(10, 0, 125, 256)
|
|
333
|
+
print(rect.x())
|
|
334
|
+
print(rect.y())
|
|
335
|
+
print(rect.width())
|
|
336
|
+
print(rect.height())
|
|
337
|
+
|
|
338
|
+
rect.setTopLeft(QPointF(10.,20.))
|
|
339
|
+
|
|
340
|
+
print('sum',rect.x()+rect.width(), type(rect.x()+rect.width())) # float
|
|
341
|
+
|
|
342
|
+
print(rect.topLeft()) # this is same as get_P1 --> maybe stick to that
|
|
343
|
+
|
|
344
|
+
rect.translate(10,20) # ça marche
|
|
345
|
+
print(rect)
|
|
346
|
+
|
|
347
|
+
print(test)
|
|
348
|
+
test.set_to_scale(0.5) #scale is not applied to the object so its size isn't the real size
|
|
349
|
+
# pb is that if I modify this class there will be tremendous repercusion on other classes --> be careful...
|
|
350
|
+
print('scaled test',test)
|
|
351
|
+
print('scaled test',test.boundingRect())
|
|
352
|
+
print('scaled test',test.boundingRect(scaled=True))
|
|
353
|
+
|
|
354
|
+
(test.x(), test.y(), test.width(), test.height())
|
|
355
|
+
print(test.contains(QPointF(50, 50)))
|
|
356
|
+
print(test.contains(QPointF(-1, -1)))
|
|
357
|
+
print(test.contains(QPointF(0, 0)))
|
|
358
|
+
print(test.contains(QPointF(100, 100)))
|
|
359
|
+
print(test.contains(QPointF(100, 100.1)))
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
# shall I do rotation
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
# p1 = test.p1()
|
|
367
|
+
# print(p1.x(), p1.y())
|
|
368
|
+
# p2 = test.p2()
|
|
369
|
+
# print(p2.x(), p2.y())
|
|
370
|
+
# print(test.arrow)
|
|
371
|
+
# print(test.length()) # sqrt 2 --> 141
|
|
372
|
+
# # if it's an arrow I can add easily all the stuff I need
|
|
373
|
+
#
|
|
374
|
+
# test = Rect2D(0, 0, 1, 1)
|
|
375
|
+
# p1 = test.p1()
|
|
376
|
+
# print(p1.x(), p1.y())
|
|
377
|
+
# p2 = test.p2()
|
|
378
|
+
# print(p2.x(), p2.y())
|
|
379
|
+
# print(test.arrow)
|
|
380
|
+
# import math
|
|
381
|
+
# print(test.length() == math.sqrt(2)) # sqrt 2
|
|
382
|
+
#
|
|
383
|
+
# test2 = Rect2D()
|
|
384
|
+
# p1 = test2.p1()
|
|
385
|
+
# print(p1.x(), p1.y())
|
|
386
|
+
# p2 = test2.p2()
|
|
387
|
+
# print(p2.x(), p2.y())
|
|
388
|
+
# print(test2.arrow)
|