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,257 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from batoolset.settings.global_settings import set_UI # set the UI to qtpy
|
|
3
|
+
set_UI()
|
|
4
|
+
from math import sqrt
|
|
5
|
+
|
|
6
|
+
from qtpy.QtCore import QRectF
|
|
7
|
+
|
|
8
|
+
from batoolset.draw.shapes.circle2d import *
|
|
9
|
+
from batoolset.tools.logger import TA_logger
|
|
10
|
+
logger = TA_logger()
|
|
11
|
+
|
|
12
|
+
class Point2D(QPointF):
|
|
13
|
+
|
|
14
|
+
def __init__(self, *args, x=0,y=0, color=0xFFFFFF, fill_color=None, opacity=1., stroke=0.65, line_style=None,__version__=1.0, **kwargs):
|
|
15
|
+
# self.isSet = True
|
|
16
|
+
self.size = 5
|
|
17
|
+
if len(args)==2:
|
|
18
|
+
#TODO need fix size
|
|
19
|
+
super(Point2D, self).__init__(*args)
|
|
20
|
+
else:
|
|
21
|
+
# self.size = 5
|
|
22
|
+
if args:
|
|
23
|
+
super(Point2D, self).__init__(*args) # create an empty point for drawing
|
|
24
|
+
else:
|
|
25
|
+
super(Point2D, self).__init__(x,y)
|
|
26
|
+
|
|
27
|
+
if stroke is not None and stroke > 2:
|
|
28
|
+
self.size = stroke
|
|
29
|
+
self.color = color
|
|
30
|
+
self.fill_color = fill_color
|
|
31
|
+
self.stroke = stroke
|
|
32
|
+
self.opacity = opacity
|
|
33
|
+
self.theta = 0 # useless for a point but useful for compat
|
|
34
|
+
self.scale = 1
|
|
35
|
+
self.translation = QPointF()
|
|
36
|
+
self.line_style = line_style
|
|
37
|
+
self.__version__ = __version__
|
|
38
|
+
|
|
39
|
+
def set_opacity(self, opacity):
|
|
40
|
+
self.opacity = opacity
|
|
41
|
+
|
|
42
|
+
def set_line_style(self,style):
|
|
43
|
+
"""
|
|
44
|
+
allows lines to be dashed or dotted or have custom pattern
|
|
45
|
+
|
|
46
|
+
: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
|
|
47
|
+
:return:
|
|
48
|
+
"""
|
|
49
|
+
self.line_style = style
|
|
50
|
+
# if style is a list then assume custom pattern otherwise apply solidline
|
|
51
|
+
|
|
52
|
+
def contains(self, *args):
|
|
53
|
+
x=0
|
|
54
|
+
y=0
|
|
55
|
+
if isinstance(args[0], QPoint) or isinstance(args[0], QPointF):
|
|
56
|
+
x = args[0].x()
|
|
57
|
+
y = args[0].y()
|
|
58
|
+
if sqrt((x-self.x())**2+(y-self.y())**2)<10:
|
|
59
|
+
return True
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
def translate(self, *translation):
|
|
63
|
+
# if isinstance(translation, (QPoint, QPointF)):
|
|
64
|
+
if isinstance(translation[0], (int, float)):
|
|
65
|
+
translation = QPointF(translation[0], translation[1])
|
|
66
|
+
|
|
67
|
+
if isinstance(translation, tuple):
|
|
68
|
+
# not sure this is normal that I have to do that but if I don't do it dragging the ellipse in the demo image crashes the soft
|
|
69
|
+
translation = QPointF(translation[0])
|
|
70
|
+
|
|
71
|
+
self.setX(self.x() + translation.x())
|
|
72
|
+
self.setY(self.y() + translation.y())
|
|
73
|
+
|
|
74
|
+
def draw(self, painter, draw=True, parent=None):
|
|
75
|
+
if self.color is None and self.fill_color is None:
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
if draw:
|
|
79
|
+
painter.save()
|
|
80
|
+
painter.setOpacity(self.opacity)
|
|
81
|
+
if self.color is not None:
|
|
82
|
+
pen = QPen(QColor(self.color))
|
|
83
|
+
if self.stroke is not None:
|
|
84
|
+
pen.setWidthF(self.stroke)
|
|
85
|
+
if self.line_style is not None:
|
|
86
|
+
if self.line_style in [Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine]:
|
|
87
|
+
pen.setStyle(self.line_style)
|
|
88
|
+
elif isinstance(self.line_style, list):
|
|
89
|
+
pen.setStyle(Qt.CustomDashLine)
|
|
90
|
+
pen.setDashPattern(self.line_style)
|
|
91
|
+
painter.setPen(pen)
|
|
92
|
+
else:
|
|
93
|
+
painter.setPen(Qt.NoPen) # required to draw something filled without a border
|
|
94
|
+
if self.fill_color is not None:
|
|
95
|
+
painter.setBrush(QBrush(QColor(self.fill_color)))
|
|
96
|
+
point_to_draw = QPointF(self.x(), self.y())
|
|
97
|
+
|
|
98
|
+
# print('point_to_draw', point_to_draw)
|
|
99
|
+
|
|
100
|
+
if parent is not None and parent.scale is not None and parent.scale != 1:
|
|
101
|
+
point_to_draw = QPointF(point_to_draw.x()/parent.scale, self.y()/parent.scale)
|
|
102
|
+
|
|
103
|
+
if parent is not None:
|
|
104
|
+
point_to_draw = QPointF(point_to_draw.x()+parent.x(), point_to_draw.y()+parent.y())
|
|
105
|
+
|
|
106
|
+
# print('point_to_draw2', point_to_draw)
|
|
107
|
+
|
|
108
|
+
# if self.scale is not None and self.scale != 1:
|
|
109
|
+
# point_to_draw.setX(point_to_draw.x()*self.scale)
|
|
110
|
+
# point_to_draw.setY(point_to_draw.y()*self.scale)
|
|
111
|
+
# if self.translation is not None:
|
|
112
|
+
# point_to_draw.setX(point_to_draw.x()+self.translation.x())
|
|
113
|
+
# point_to_draw.setY(point_to_draw.y()+self.translation.y())
|
|
114
|
+
|
|
115
|
+
# painter.drawEllipse(point_to_draw.x()-self.stroke/2., point_to_draw.y()-self.stroke/2, self.stroke, self.stroke)
|
|
116
|
+
painter.drawEllipse(int(point_to_draw.x()-self.stroke/2.), int(point_to_draw.y()-self.stroke/2), int(self.stroke), int(self.stroke)) # why tale int here --> draw in float precision --> because there is no simple ellipse object in pyqt -−> see my ellipse implementation --> and fix that some day!!
|
|
117
|
+
# painter.drawEllipse(point_to_draw.x()-self.stroke/2., point_to_draw.y()-self.stroke/2, self.stroke, self.stroke) # why tale int here --> draw in float precision
|
|
118
|
+
painter.restore()
|
|
119
|
+
|
|
120
|
+
# def fill(self, painter, draw=True):
|
|
121
|
+
# if self.fill_color is None:
|
|
122
|
+
# return
|
|
123
|
+
# if draw:
|
|
124
|
+
# painter.save()
|
|
125
|
+
# painter.setBrush(QBrush(QColor(self.fill_color)))
|
|
126
|
+
# painter.setOpacity(self.opacity)
|
|
127
|
+
# if draw:
|
|
128
|
+
# painter.drawEllipse(self.x()-self.stroke/2., self.y()-self.stroke/2, self.stroke, self.stroke)
|
|
129
|
+
# painter.restore()
|
|
130
|
+
#
|
|
131
|
+
# def drawAndFill(self, painter):
|
|
132
|
+
# painter.save()
|
|
133
|
+
# self.draw(painter, draw=False)
|
|
134
|
+
# self.fill(painter, draw=False)
|
|
135
|
+
# size = max(self.size, self.stroke)
|
|
136
|
+
# painter.drawEllipse(self.x()-size/2., self.y()-size/2, size, size) # drawEllipse (x, y, w, h)
|
|
137
|
+
# painter.restore()
|
|
138
|
+
|
|
139
|
+
def boundingRect(self):
|
|
140
|
+
return QRectF(self.x()-self.stroke/2., self.y()-self.stroke/2, self.stroke, self.stroke)
|
|
141
|
+
|
|
142
|
+
def add(self, *args):
|
|
143
|
+
point = args[1]
|
|
144
|
+
self.setX(point.x())
|
|
145
|
+
self.setY(point.y())
|
|
146
|
+
|
|
147
|
+
# def set_P1(self, *args):
|
|
148
|
+
# if not args:
|
|
149
|
+
# logger.error("no coordinate set...")
|
|
150
|
+
# return
|
|
151
|
+
# if len(args) == 1:
|
|
152
|
+
# # self.moveTo(args[0].x(), args[0].y())
|
|
153
|
+
# self.setX(args[0].x())
|
|
154
|
+
# self.setY(args[0].y())
|
|
155
|
+
# else:
|
|
156
|
+
# # self.moveTo(QPointF(args[0], args[1]))
|
|
157
|
+
# self.setX(args[0])
|
|
158
|
+
# self.setY(args[1])
|
|
159
|
+
# # self.setX(point.x())
|
|
160
|
+
# # self.setY(point.y())
|
|
161
|
+
|
|
162
|
+
# def get_P1(self):
|
|
163
|
+
# return self
|
|
164
|
+
def setTopLeft(self, *args):
|
|
165
|
+
if args:
|
|
166
|
+
if len(args)==1:
|
|
167
|
+
# assume a QpointF
|
|
168
|
+
super().setP1(args[0])
|
|
169
|
+
elif len(args)==2:
|
|
170
|
+
super().setP1(QPointF(args[0], args[1]))
|
|
171
|
+
else:
|
|
172
|
+
logger.error('invalid args for top left')
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def topLeft(self):
|
|
176
|
+
return self
|
|
177
|
+
|
|
178
|
+
def getRect(self, *args, **kwargs):
|
|
179
|
+
return self.boundingRect()
|
|
180
|
+
|
|
181
|
+
def width(self):
|
|
182
|
+
return 0
|
|
183
|
+
|
|
184
|
+
def height(self):
|
|
185
|
+
return 0
|
|
186
|
+
|
|
187
|
+
def set_to_scale(self, factor):
|
|
188
|
+
self.scale = factor
|
|
189
|
+
|
|
190
|
+
def set_to_translation(self, translation):
|
|
191
|
+
self.translation = translation
|
|
192
|
+
|
|
193
|
+
def set_to_center(self, centroid):
|
|
194
|
+
if isinstance(centroid, (tuple, list)):
|
|
195
|
+
self.setX(centroid[0])
|
|
196
|
+
self.setY(centroid[1])
|
|
197
|
+
else:
|
|
198
|
+
self.setX(centroid.x())
|
|
199
|
+
self.setY(centroid.y())
|
|
200
|
+
|
|
201
|
+
def __repr__(self):
|
|
202
|
+
class_name = type(self).__name__
|
|
203
|
+
memory_address = hex(id(self))
|
|
204
|
+
return f"{class_name}-{memory_address}"
|
|
205
|
+
|
|
206
|
+
def to_dict(self):
|
|
207
|
+
x = self.x()
|
|
208
|
+
y = self.y()
|
|
209
|
+
|
|
210
|
+
# Create a dictionary representation of the values of the super object
|
|
211
|
+
output_dict = {
|
|
212
|
+
'x': x,
|
|
213
|
+
'y': y,
|
|
214
|
+
}
|
|
215
|
+
# Update the dictionary with the __dict__ of Rectangle2D
|
|
216
|
+
output_dict.update(self.__dict__)
|
|
217
|
+
return output_dict
|
|
218
|
+
|
|
219
|
+
if __name__ == '__main__':
|
|
220
|
+
# ça marche --> voici deux examples de shapes
|
|
221
|
+
test = Point2D(128, 128)
|
|
222
|
+
# print(test.x(), test.y(), test.width(), test.height())
|
|
223
|
+
print(test.contains(QPointF(128, 128)))
|
|
224
|
+
print(test.contains(QPointF(129, 129))) # why True ??? --> maybe ok but think
|
|
225
|
+
print(test.contains(QPointF(-1, -1)))
|
|
226
|
+
print(test.contains(QPointF(0, 0)))
|
|
227
|
+
print(test.contains(QPointF(100, 100)))
|
|
228
|
+
print(test.contains(QPointF(100, 100.1)))
|
|
229
|
+
print(test.x())
|
|
230
|
+
print(test.y())
|
|
231
|
+
print(test.translate(QPoint(10, 10)))
|
|
232
|
+
print(test.x())
|
|
233
|
+
print(test.y())
|
|
234
|
+
|
|
235
|
+
# p1 = test.p1()
|
|
236
|
+
# print(p1.x(), p1.y())
|
|
237
|
+
# p2 = test.p2()
|
|
238
|
+
# print(p2.x(), p2.y())
|
|
239
|
+
# print(test.arrow)
|
|
240
|
+
# print(test.length()) # sqrt 2 --> 141
|
|
241
|
+
# # if it's an arrow I can add easily all the stuff I need
|
|
242
|
+
#
|
|
243
|
+
# test = Rect2D(0, 0, 1, 1)
|
|
244
|
+
# p1 = test.p1()
|
|
245
|
+
# print(p1.x(), p1.y())
|
|
246
|
+
# p2 = test.p2()
|
|
247
|
+
# print(p2.x(), p2.y())
|
|
248
|
+
# print(test.arrow)
|
|
249
|
+
# import math
|
|
250
|
+
# print(test.length() == math.sqrt(2)) # sqrt 2
|
|
251
|
+
#
|
|
252
|
+
# test2 = Rect2D()
|
|
253
|
+
# p1 = test2.p1()
|
|
254
|
+
# print(p1.x(), p1.y())
|
|
255
|
+
# p2 = test2.p2()
|
|
256
|
+
# print(p2.x(), p2.y())
|
|
257
|
+
# print(test2.arrow)
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
from batoolset.settings.global_settings import set_UI # set the UI to qtpy
|
|
2
|
+
set_UI()
|
|
3
|
+
import os
|
|
4
|
+
from batoolset.draw.shapes.tools import rect_intersects_polygon, create_rect_centered_at, qpolygonf_to_list
|
|
5
|
+
from qtpy import QtCore
|
|
6
|
+
from qtpy.QtCore import QPointF, Qt
|
|
7
|
+
from qtpy.QtGui import QPolygonF, QTransform
|
|
8
|
+
from qtpy.QtGui import QPainter, QBrush, QPen, QImage, QColor
|
|
9
|
+
# from qtpy.Qt
|
|
10
|
+
# from qtpy.Qt import (QPaintEngine, QPaintDevice, QTransform, QBrush)
|
|
11
|
+
|
|
12
|
+
from batoolset.tools.logger import TA_logger
|
|
13
|
+
logger = TA_logger()
|
|
14
|
+
|
|
15
|
+
class Polygon2D(QPolygonF):
|
|
16
|
+
|
|
17
|
+
def __init__(self, *args, coords_as_list=None, color=0xFFFFFF, fill_color=None, opacity=1., stroke=0.65, line_style=None, theta=0,__version__=1.0, **kwargs):
|
|
18
|
+
super(Polygon2D, self).__init__()
|
|
19
|
+
self.isSet = False
|
|
20
|
+
if len(args) > 0:
|
|
21
|
+
if isinstance(args[0], (float,int)):
|
|
22
|
+
for i in range(0, len(args), 2):
|
|
23
|
+
self.append(QPointF(args[i], args[i+1]))
|
|
24
|
+
else:
|
|
25
|
+
# to handle list of vertices!!!
|
|
26
|
+
for pt in args:
|
|
27
|
+
self.append(QPointF(pt[0],pt[1]))
|
|
28
|
+
|
|
29
|
+
if 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.scale = 1
|
|
38
|
+
self.translation = QPointF()
|
|
39
|
+
self.line_style = line_style
|
|
40
|
+
# self.isSet = False
|
|
41
|
+
# rotation
|
|
42
|
+
self.theta = theta
|
|
43
|
+
self.__version__ = __version__
|
|
44
|
+
|
|
45
|
+
def set_rotation(self, theta):
|
|
46
|
+
self.theta = theta
|
|
47
|
+
|
|
48
|
+
def set_opacity(self, opacity):
|
|
49
|
+
self.opacity = opacity
|
|
50
|
+
|
|
51
|
+
def set_line_style(self,style):
|
|
52
|
+
"""
|
|
53
|
+
allows lines to be dashed or dotted or have custom pattern
|
|
54
|
+
|
|
55
|
+
: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
|
|
56
|
+
:return:
|
|
57
|
+
"""
|
|
58
|
+
self.line_style = style
|
|
59
|
+
# if style is a list then assume custom pattern otherwise apply solidline
|
|
60
|
+
|
|
61
|
+
def get_color(self):
|
|
62
|
+
return self.color
|
|
63
|
+
|
|
64
|
+
def get_fill_color(self):
|
|
65
|
+
return self.fill_color
|
|
66
|
+
|
|
67
|
+
def get_stroke_size(self):
|
|
68
|
+
return self.stroke
|
|
69
|
+
|
|
70
|
+
def get_points(self): #nb if closed it returns also the closing point (e.g. first==last) which may not always be desired! -−> maybe offer an option
|
|
71
|
+
points = []
|
|
72
|
+
for point in self:
|
|
73
|
+
points.append((point.x(), point.y()))
|
|
74
|
+
return points
|
|
75
|
+
|
|
76
|
+
def contains(self, *args,**kwargs):
|
|
77
|
+
# print("kwargs", kwargs)
|
|
78
|
+
extra=0
|
|
79
|
+
if kwargs:
|
|
80
|
+
if 'extra' in kwargs:
|
|
81
|
+
extra=kwargs['extra']
|
|
82
|
+
if len(args)!=1:
|
|
83
|
+
point = QPointF(float(args[0]),float(args[1]))
|
|
84
|
+
if extra:
|
|
85
|
+
return rect_intersects_polygon(create_rect_centered_at(point, extra), self)
|
|
86
|
+
else:
|
|
87
|
+
return self.containsPoint(point, Qt.OddEvenFill)
|
|
88
|
+
else:
|
|
89
|
+
if extra:
|
|
90
|
+
return rect_intersects_polygon(create_rect_centered_at(args[0], extra), self)
|
|
91
|
+
else:
|
|
92
|
+
return self.containsPoint(args[0], Qt.OddEvenFill)
|
|
93
|
+
|
|
94
|
+
def draw(self, painter, draw=True, parent=None):
|
|
95
|
+
if self.color is None and self.fill_color is None:
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
if draw:
|
|
99
|
+
painter.save()
|
|
100
|
+
painter.setPen(Qt.NoPen)
|
|
101
|
+
painter.setBrush(Qt.NoBrush)
|
|
102
|
+
painter.setOpacity(self.opacity)
|
|
103
|
+
if self.color is not None:
|
|
104
|
+
pen = QPen(QColor(self.color))
|
|
105
|
+
if self.stroke is not None:
|
|
106
|
+
pen.setWidthF(self.stroke)
|
|
107
|
+
if self.line_style is not None:
|
|
108
|
+
if self.line_style in [Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine]:
|
|
109
|
+
pen.setStyle(self.line_style)
|
|
110
|
+
elif isinstance(self.line_style, list):
|
|
111
|
+
pen.setStyle(Qt.CustomDashLine)
|
|
112
|
+
pen.setDashPattern(self.line_style)
|
|
113
|
+
painter.setPen(pen)
|
|
114
|
+
else:
|
|
115
|
+
painter.setPen(Qt.NoPen) # required to draw something filled without a border
|
|
116
|
+
if self.fill_color is not None:
|
|
117
|
+
painter.setBrush(QBrush(QColor(self.fill_color)))
|
|
118
|
+
else:
|
|
119
|
+
painter.setBrush(Qt.NoBrush)
|
|
120
|
+
polygon_to_draw = self.translated(0, 0)
|
|
121
|
+
|
|
122
|
+
# print(type(polygon_to_draw))
|
|
123
|
+
# print('polygon_to_draw.listVertices()', self.listVertices(polygon_to_draw))
|
|
124
|
+
|
|
125
|
+
if parent is not None and parent.scale is not None and parent.scale != 1:
|
|
126
|
+
polygon_to_draw = self.__get_scaled_polygon(polygon_to_draw,1. / parent.scale)
|
|
127
|
+
|
|
128
|
+
if parent is not None:
|
|
129
|
+
polygon_to_draw = polygon_to_draw.translated(parent.topLeft())
|
|
130
|
+
|
|
131
|
+
# print('polygon_to_draw.listVertices()2', self.listVertices(polygon_to_draw))
|
|
132
|
+
|
|
133
|
+
# if self.scale is not None and self.scale != 1:
|
|
134
|
+
# polygon_to_draw = self.__scaled()
|
|
135
|
+
|
|
136
|
+
# print('mid rect_to_plot', rect_to_plot)
|
|
137
|
+
# if self.translation is not None:
|
|
138
|
+
# # rect_to_plot.setX(rect_to_plot.x()+self.translation.x())
|
|
139
|
+
# # rect_to_plot.setY(rect_to_plot.y()+self.translation.y())
|
|
140
|
+
# polygon_to_draw.translate(self.translation.x(), self.translation.y())
|
|
141
|
+
|
|
142
|
+
if self.theta is not None and self.theta != 0:
|
|
143
|
+
painter.translate(polygon_to_draw.boundingRect().center())
|
|
144
|
+
painter.rotate(self.theta)
|
|
145
|
+
painter.translate(-polygon_to_draw.boundingRect().center())
|
|
146
|
+
|
|
147
|
+
# pen = QPen(QColor(self.color))
|
|
148
|
+
# painter.setPen(pen)
|
|
149
|
+
# pen.setWidthF(self.stroke)
|
|
150
|
+
painter.drawPolygon(polygon_to_draw)
|
|
151
|
+
# painter.setBrush(QBrush(QColor(0xFF0000)))
|
|
152
|
+
# painter.drawPolygon(polygon_to_draw)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
painter.restore()
|
|
156
|
+
|
|
157
|
+
# def fill(self, painter, draw=True):
|
|
158
|
+
# if self.fill_color is None:
|
|
159
|
+
# return
|
|
160
|
+
# if draw:
|
|
161
|
+
# painter.save()
|
|
162
|
+
# painter.setBrush(QBrush(QColor(self.fill_color)))
|
|
163
|
+
# painter.setOpacity(self.opacity)
|
|
164
|
+
# if draw:
|
|
165
|
+
# painter.drawPolygon(self)
|
|
166
|
+
# painter.restore()
|
|
167
|
+
#
|
|
168
|
+
# def drawAndFill(self, painter):
|
|
169
|
+
# painter.save()
|
|
170
|
+
# self.draw(painter, draw=False)
|
|
171
|
+
# self.fill(painter, draw=False)
|
|
172
|
+
# painter.drawPolygon(self)
|
|
173
|
+
# painter.restore()
|
|
174
|
+
|
|
175
|
+
# def setP1(self, point):
|
|
176
|
+
# self.append(point)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def add(self, *args, force=False):
|
|
180
|
+
if self.count() > 1 and not force:
|
|
181
|
+
self.remove(self.count()-1)
|
|
182
|
+
self.append(args[1])
|
|
183
|
+
# self.isSet = True
|
|
184
|
+
|
|
185
|
+
def listVertices(self, polygon=None): # redundant with get_points !
|
|
186
|
+
if polygon is None:
|
|
187
|
+
polygon = self
|
|
188
|
+
return [point for point in polygon]
|
|
189
|
+
|
|
190
|
+
def set_to_scale(self, factor):
|
|
191
|
+
self.scale = factor
|
|
192
|
+
|
|
193
|
+
def set_to_translation(self, translation):
|
|
194
|
+
self.translation = translation
|
|
195
|
+
|
|
196
|
+
def topLeft(self):
|
|
197
|
+
return self.boundingRect().topLeft()
|
|
198
|
+
|
|
199
|
+
# def get_P1(self):
|
|
200
|
+
# return self.boundingRect().topLeft()
|
|
201
|
+
|
|
202
|
+
# def set_P1(self, point):# see how to do that
|
|
203
|
+
def setTopLeft(self, point):# see how to do that
|
|
204
|
+
#self.append(point)
|
|
205
|
+
# get bounding box and set top left to P1
|
|
206
|
+
current_pos = self.boundingRect().topLeft()
|
|
207
|
+
self.translate(point.x()-current_pos.x(), point.y()-current_pos.y())
|
|
208
|
+
|
|
209
|
+
def __get_scaled_polygon(self, polygon, scale):
|
|
210
|
+
vertices = self.listVertices(polygon)
|
|
211
|
+
scaled_poly = QPolygonF()
|
|
212
|
+
for vx in vertices:
|
|
213
|
+
vx.setX(vx.x()*scale)
|
|
214
|
+
vx.setY(vx.y()*scale)
|
|
215
|
+
scaled_poly.append(vx)
|
|
216
|
+
# print(vertices)
|
|
217
|
+
return scaled_poly
|
|
218
|
+
|
|
219
|
+
def __scaled(self):
|
|
220
|
+
vertices = self.listVertices()
|
|
221
|
+
scaled_poly = QPolygonF()
|
|
222
|
+
for vx in vertices:
|
|
223
|
+
vx.setX(vx.x()*self.scale)
|
|
224
|
+
vx.setY(vx.y()*self.scale)
|
|
225
|
+
scaled_poly.append(vx)
|
|
226
|
+
return scaled_poly
|
|
227
|
+
|
|
228
|
+
def boundingRect(self):
|
|
229
|
+
polygon_to_draw = self.translated(0, 0)
|
|
230
|
+
try:
|
|
231
|
+
# print('tada')
|
|
232
|
+
if self.theta is not None and self.theta != 0:
|
|
233
|
+
# print('entering')
|
|
234
|
+
center = polygon_to_draw.boundingRect().center()
|
|
235
|
+
# print('entering2')
|
|
236
|
+
t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),
|
|
237
|
+
-center.y())
|
|
238
|
+
# print('entering3')
|
|
239
|
+
# transformed = self.setTransform(t)
|
|
240
|
+
# print('entering4')
|
|
241
|
+
# print(transformed)
|
|
242
|
+
# print(QRectF(min(transformed.p1().x(), transformed.p2().x()), min(transformed.p1().y(), transformed.p2().y()),
|
|
243
|
+
# abs(transformed.p2().x() - transformed.p1().x()), abs(transformed.p2().y() - transformed.p1().y())))
|
|
244
|
+
# return QRectF(min(transformed.p1().x(), transformed.p2().x()), min(transformed.p1().y(), transformed.p2().y()),
|
|
245
|
+
# abs(transformed.p2().x() - transformed.p1().x()), abs(transformed.p2().y() - transformed.p1().y()))
|
|
246
|
+
|
|
247
|
+
# copy.setT
|
|
248
|
+
# print('entering')
|
|
249
|
+
|
|
250
|
+
# t = QTransform().translate( center.x(), center.y()).rotate(self.theta).translate(-center.x(), -center.y())
|
|
251
|
+
# # print('entersd')
|
|
252
|
+
transformed = t.map(polygon_to_draw) # // mapRect() returns the bounding rect of the rotated rect
|
|
253
|
+
|
|
254
|
+
# print('rotated',rotatedRect )
|
|
255
|
+
# return rotatedRect
|
|
256
|
+
return transformed.boundingRect()
|
|
257
|
+
except:
|
|
258
|
+
pass
|
|
259
|
+
return polygon_to_draw.boundingRect()
|
|
260
|
+
|
|
261
|
+
def getRect(self, *args, **kwargs):
|
|
262
|
+
return self.boundingRect()
|
|
263
|
+
|
|
264
|
+
def width(self, *args, **kwargs):
|
|
265
|
+
return self.boundingRect().width()
|
|
266
|
+
|
|
267
|
+
def height(self, *args, **kwargs):
|
|
268
|
+
return self.boundingRect().height()
|
|
269
|
+
|
|
270
|
+
def set_to_center(self, centroid):
|
|
271
|
+
current_centroid = self.boundingRect().center()
|
|
272
|
+
if isinstance(centroid, (tuple, list)):
|
|
273
|
+
self.translate(centroid[0]-current_centroid.x(), centroid[1]-current_centroid.y())
|
|
274
|
+
else:
|
|
275
|
+
self.translate(centroid.x() - current_centroid.x(), centroid.y() - current_centroid.y())
|
|
276
|
+
|
|
277
|
+
def __repr__(self):
|
|
278
|
+
class_name = type(self).__name__
|
|
279
|
+
memory_address = hex(id(self))
|
|
280
|
+
return f"{class_name}-{memory_address}"
|
|
281
|
+
|
|
282
|
+
def to_dict(self):
|
|
283
|
+
# x = self.x()
|
|
284
|
+
# y = self.y()
|
|
285
|
+
|
|
286
|
+
# Create a dictionary representation of the values of the super object
|
|
287
|
+
output_dict = {
|
|
288
|
+
# 'x': x,
|
|
289
|
+
# 'y': y,
|
|
290
|
+
'coords_as_list': str(qpolygonf_to_list(self, unpack=True))
|
|
291
|
+
}
|
|
292
|
+
# Update the dictionary with the __dict__ of Rectangle2D
|
|
293
|
+
output_dict.update(self.__dict__)
|
|
294
|
+
return output_dict
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
if __name__ == '__main__':
|
|
298
|
+
|
|
299
|
+
test = Polygon2D(0, 0, 10, 0, 10, 20, 0, 20, 0, 0)
|
|
300
|
+
print(test.count()) # marche pas --> pas ajouté
|
|
301
|
+
print(test)
|
|
302
|
+
|
|
303
|
+
hexagon = Polygon2D()
|
|
304
|
+
print(hexagon)
|
|
305
|
+
hexagon.append(QPointF(10, 20))
|
|
306
|
+
hexagon.append(QPointF(10, 30))
|
|
307
|
+
hexagon.append(QPointF(20, 30))
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
# hexagon.append(QPointF(10, 20))
|
|
312
|
+
print(hexagon)
|
|
313
|
+
print(hexagon.isEmpty())
|
|
314
|
+
print(hexagon.count())
|
|
315
|
+
print(hexagon.stroke)
|
|
316
|
+
print(hexagon.get_stroke_size())
|
|
317
|
+
# ça marche maintenant
|
|
318
|
+
# print(hexagon.)
|
|
319
|
+
# trop cool l'acces aux points
|
|
320
|
+
for point in hexagon:
|
|
321
|
+
print(point)
|
|
322
|
+
|
|
323
|
+
print(hexagon.get_points())
|
|
324
|
+
# print(hexagon.contains(10, 20))
|
|
325
|
+
print(hexagon.contains(QPointF(10, 20)))
|
|
326
|
+
print(hexagon.contains(QPointF(10, 21)))
|
|
327
|
+
|
|
328
|
+
print(hexagon.isClosed()) #
|
|
329
|
+
hexagon.append(QPointF(10, 20)) # closing the hexagon --> the last and first point should be the same
|
|
330
|
+
print(hexagon.isClosed()) #
|
|
331
|
+
|
|
332
|
+
# print(hexagon.translate(10, 20)) # why none ???
|
|
333
|
+
# translate and so on can all be saved...
|
|
334
|
+
|
|
335
|
+
image = QImage('/E/Sample_images/sample_images_PA/mini/focused_Series012/handCorrection.png')
|
|
336
|
+
painter = QPainter()
|
|
337
|
+
painter.begin(image)
|
|
338
|
+
# painter.setOpacity(0.3);
|
|
339
|
+
painter.drawImage(0, 0, image)
|
|
340
|
+
painter.setPen(QtCore.Qt.blue)
|
|
341
|
+
painter.drawPolygon(hexagon)
|
|
342
|
+
hexagon.opacity = 0.7
|
|
343
|
+
painter.translate(10, 20)
|
|
344
|
+
hexagon.draw(painter) # ça marche pourrait overloader ça avec du svg
|
|
345
|
+
painter.end()
|
|
346
|
+
|
|
347
|
+
# painter.save()
|
|
348
|
+
# painter.setCompositionMode(QtGui.QPainter.CompositionMode_Clear)
|
|
349
|
+
# painter.eraseRect(r)
|
|
350
|
+
# painter.restore()
|
|
351
|
+
|
|
352
|
+
image.save('/E/trash/test_pyQT_draw.png', "PNG");
|
|
353
|
+
|
|
354
|
+
#pas mal TODO faire une classe drawsmthg qui dessine n'importe quelle forme que l'on lui passe avec des parametres de couleur, transparence, ...
|
|
355
|
+
|
|
356
|
+
# tt marche aps mal ça va très vite
|
|
357
|
+
|