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,601 @@
|
|
|
1
|
+
# this is the fully fixed version with the new rect
|
|
2
|
+
# THIS IS THE NEW VERSION OF THE CODE BUT IN ORDER NOT TO BREAK STUFF I WILL KEEP IT LIKE THAT
|
|
3
|
+
|
|
4
|
+
from batoolset.settings.global_settings import set_UI # set the UI to qtpy
|
|
5
|
+
set_UI()
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import traceback
|
|
9
|
+
from qtpy.QtCore import QPointF, QRectF, Qt, QRect
|
|
10
|
+
from qtpy.QtGui import QBrush, QPen, QColor, QTransform
|
|
11
|
+
from batoolset.tools.logger import TA_logger
|
|
12
|
+
|
|
13
|
+
logger = TA_logger()
|
|
14
|
+
|
|
15
|
+
# TODO --> try to simplify that and finalize it once for good
|
|
16
|
+
# 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
|
|
17
|
+
'''
|
|
18
|
+
def __init__(self, *args, **kwargs):
|
|
19
|
+
# set default values for keyword arguments
|
|
20
|
+
color = kwargs.get('color', 0xFFFF00)
|
|
21
|
+
stroke = kwargs.get('stroke', 0.65)
|
|
22
|
+
'''
|
|
23
|
+
|
|
24
|
+
class Rectangle2D(QRectF):
|
|
25
|
+
"""
|
|
26
|
+
A custom class for 2D rectangles with additional features such as color, fill color, opacity, stroke, line style,
|
|
27
|
+
rotation, scale, and translation.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
*args: Variable-length arguments that can represent the rectangle coordinates.
|
|
31
|
+
color (int): Color of the rectangle in hexadecimal format (default: 0xFFFF00).
|
|
32
|
+
fill_color (int): Fill color of the rectangle in hexadecimal format (default: None).
|
|
33
|
+
opacity (float): Opacity value between 0.0 and 1.0 (default: 1.0).
|
|
34
|
+
stroke (float): Stroke width of the rectangle (default: 0.65).
|
|
35
|
+
line_style (Union[None, int, List[int]]): Line style of the rectangle. None for a solid line,
|
|
36
|
+
or any of the following values: Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine.
|
|
37
|
+
If a list of integers is provided, it represents a custom dash pattern (default: None).
|
|
38
|
+
theta (float): Rotation angle in degrees (default: 0.0).
|
|
39
|
+
**kwargs: Additional keyword arguments.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
isSet (bool): Indicates whether the rectangle is set.
|
|
43
|
+
color (int): Color of the rectangle in hexadecimal format.
|
|
44
|
+
fill_color (int): Fill color of the rectangle in hexadecimal format.
|
|
45
|
+
stroke (float): Stroke width of the rectangle.
|
|
46
|
+
opacity (float): Opacity value between 0.0 and 1.0.
|
|
47
|
+
scale (float): Scaling factor of the rectangle (default: 1.0).
|
|
48
|
+
translation (QPointF): Translation of the rectangle.
|
|
49
|
+
line_style (Union[None, int, List[int]]): Line style of the rectangle.
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(self, *args,x=0, y=0, width=0, height=0, color=0xFFFFFF, fill_color=None, opacity=1., stroke=0.65, line_style=None, theta=0, __version__=1.0,**kwargs):
|
|
54
|
+
if args:
|
|
55
|
+
super(Rectangle2D, self).__init__(*args)
|
|
56
|
+
else:
|
|
57
|
+
super(Rectangle2D, self).__init__(x,y,width,height)
|
|
58
|
+
|
|
59
|
+
# if not args:
|
|
60
|
+
# self.isSet = False
|
|
61
|
+
# else:
|
|
62
|
+
# self.isSet = True
|
|
63
|
+
self.color = color
|
|
64
|
+
self.fill_color = fill_color
|
|
65
|
+
self.stroke = stroke
|
|
66
|
+
self.opacity = opacity
|
|
67
|
+
self.isSet = False
|
|
68
|
+
self.scale = 1
|
|
69
|
+
# self.translation = QPointF()
|
|
70
|
+
self.line_style = line_style
|
|
71
|
+
self.theta = theta
|
|
72
|
+
self.incompressible_width=0
|
|
73
|
+
self.incompressible_height=0
|
|
74
|
+
self.immutable = False
|
|
75
|
+
self.__init_called__ = True # this is just to be used to prevent non initialized images to exist
|
|
76
|
+
# self.__sel = None
|
|
77
|
+
self.__version__ = __version__
|
|
78
|
+
|
|
79
|
+
def set_rotation(self, theta):
|
|
80
|
+
"""
|
|
81
|
+
Set the rotation angle of the rectangle.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
theta (float): Rotation angle in degrees.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
self.theta = theta
|
|
88
|
+
|
|
89
|
+
def set_opacity(self, opacity):
|
|
90
|
+
"""
|
|
91
|
+
Set the opacity value of the rectangle.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
opacity (float): Opacity value between 0.0 and 1.0.
|
|
95
|
+
|
|
96
|
+
"""
|
|
97
|
+
self.opacity = opacity
|
|
98
|
+
|
|
99
|
+
def set_line_style(self,style):
|
|
100
|
+
"""
|
|
101
|
+
allows lines to be dashed or dotted or have custom pattern
|
|
102
|
+
|
|
103
|
+
: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
|
|
104
|
+
:return:
|
|
105
|
+
"""
|
|
106
|
+
self.line_style = style
|
|
107
|
+
# if style is a list then assume custom pattern otherwise apply solidline
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def draw(self, painter, parent=None, **kwargs):
|
|
111
|
+
# print(kwargs)
|
|
112
|
+
# if kwargs is not None and kwargs:
|
|
113
|
+
# pass
|
|
114
|
+
# else:
|
|
115
|
+
# return
|
|
116
|
+
# self.__sel = None
|
|
117
|
+
if self.color is None and self.fill_color is None:
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
painter.save()
|
|
121
|
+
|
|
122
|
+
painter.setPen(Qt.NoPen)
|
|
123
|
+
painter.setBrush(Qt.NoBrush)
|
|
124
|
+
|
|
125
|
+
painter.setOpacity(self.opacity)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if self.color is not None:
|
|
132
|
+
pen = QPen(QColor(self.color))
|
|
133
|
+
if self.stroke is not None:
|
|
134
|
+
pen.setWidthF(self.stroke)
|
|
135
|
+
if self.line_style is not None:
|
|
136
|
+
if self.line_style in [Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine]:
|
|
137
|
+
pen.setStyle(self.line_style)
|
|
138
|
+
elif isinstance(self.line_style, list):
|
|
139
|
+
pen.setStyle(Qt.CustomDashLine)
|
|
140
|
+
pen.setDashPattern(self.line_style)
|
|
141
|
+
pen.setJoinStyle(Qt.MiterJoin)# RoundJoin #BevelJoin # some day offer the handling of that but later
|
|
142
|
+
# if kwargs['draw']==True:
|
|
143
|
+
|
|
144
|
+
# pen.setStyle(Qt.DashLine)
|
|
145
|
+
# pen.setStyle(Qt.CustomDashLine)
|
|
146
|
+
# pen.setDashPattern([1, 4, 5, 4])
|
|
147
|
+
|
|
148
|
+
painter.setPen(pen)
|
|
149
|
+
# if kwargs['fill']==True:
|
|
150
|
+
else:
|
|
151
|
+
painter.setPen(Qt.NoPen) # required to draw something filled without a border
|
|
152
|
+
|
|
153
|
+
# needed to have a filling color in a shape without contour
|
|
154
|
+
if self.fill_color is not None:
|
|
155
|
+
painter.setBrush(QBrush(QColor(self.fill_color)))
|
|
156
|
+
|
|
157
|
+
# rect_to_plot = self.adjusted(0,0,0,0)
|
|
158
|
+
rect_to_plot = self.getRect(scale=True).adjusted(0,0,0,0)
|
|
159
|
+
|
|
160
|
+
if parent is not None and parent.scale is not None and parent.scale != 1:
|
|
161
|
+
rect_to_plot = self.__get_scaled_rect(rect_to_plot, 1. / parent.scale)
|
|
162
|
+
|
|
163
|
+
if parent is not None:
|
|
164
|
+
rect_to_plot = rect_to_plot.translated(parent.topLeft())
|
|
165
|
+
|
|
166
|
+
# print('rect_to_plot',rect_to_plot)
|
|
167
|
+
|
|
168
|
+
# print('begin rect_to_plot', rect_to_plot, self.scale)
|
|
169
|
+
# if kwargs['draw']==True or kwargs['fill']==True:
|
|
170
|
+
# if self.scale is None or self.scale==1:
|
|
171
|
+
# painter.drawRect(self)
|
|
172
|
+
# else:
|
|
173
|
+
# on clone le rect
|
|
174
|
+
# old crappy code --> forget and clean
|
|
175
|
+
# if self.scale is not None and self.scale != 1:
|
|
176
|
+
# # TODO KEEP THE ORDER THIS MUST BE DONE THIS WAY OR IT WILL GENERATE PLENTY OF BUGS...
|
|
177
|
+
# new_width = rect_to_plot.width() * self.scale
|
|
178
|
+
# new_height = rect_to_plot.height() * self.scale
|
|
179
|
+
# # print(rect_to_plot.width(), rect_to_plot.height()) # here ok
|
|
180
|
+
# # setX changes width --> why is that
|
|
181
|
+
#
|
|
182
|
+
# # 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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
183
|
+
# # 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!!!
|
|
184
|
+
# rect_to_plot.setX(rect_to_plot.x()*self.scale)
|
|
185
|
+
# rect_to_plot.setY(rect_to_plot.y()*self.scale)
|
|
186
|
+
# # maybe to avoid bugs I should use translate instead rather that set x but ok anyways
|
|
187
|
+
# # print(rect_to_plot.width(), rect_to_plot.height())# bug here --> too big
|
|
188
|
+
#
|
|
189
|
+
# # print(new_height, new_height, self.width(), self.scale, self.scale* self.width())
|
|
190
|
+
# rect_to_plot.setWidth(new_width)
|
|
191
|
+
# rect_to_plot.setHeight(new_height)
|
|
192
|
+
|
|
193
|
+
# print('mid rect_to_plot', rect_to_plot)
|
|
194
|
+
# if self.translation is not None:
|
|
195
|
+
#
|
|
196
|
+
# # rect_to_plot.setX(rect_to_plot.x()+self.translation.x())
|
|
197
|
+
# # rect_to_plot.setY(rect_to_plot.y()+self.translation.y())
|
|
198
|
+
# rect_to_plot.translate(self.translation)
|
|
199
|
+
|
|
200
|
+
# print('rect to plot', rect_to_plot)
|
|
201
|
+
|
|
202
|
+
# if self.color is not None:
|
|
203
|
+
|
|
204
|
+
# rotation marche mais position est pas du tout bonne --> voir comment gérer ça ??
|
|
205
|
+
# center = rect_to_plot.center()
|
|
206
|
+
# painter.translate(center.x(), center.y())
|
|
207
|
+
# painter.rotate(45)
|
|
208
|
+
# rct = QRectF(-center.x(), -center.y(), rect_to_plot.width(), rect_to_plot.height())
|
|
209
|
+
# painter.drawRect(rct)
|
|
210
|
+
# rotatedRect = rect_to_plot
|
|
211
|
+
|
|
212
|
+
if self.theta is not None and self.theta != 0:
|
|
213
|
+
# this is only if a rotation should be applied
|
|
214
|
+
painter.translate(rect_to_plot.center())
|
|
215
|
+
# print('center', rect_to_plot.center())
|
|
216
|
+
# painter.setWorldTransform()
|
|
217
|
+
# print(painter.combinedTransform().)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# TODO use this maybe to get bounds of rotated shape properly...
|
|
222
|
+
# center = rect_to_plot.center()
|
|
223
|
+
# t = QTransform().translate( center.x(), center.y() ).rotate( self.theta ).translate( -center.x(), -center.y() )
|
|
224
|
+
# rotatedRect = t.mapToPolygon( rect_to_plot.toRect() ) #// mapRect() returns the bounding rect of the rotated rect
|
|
225
|
+
|
|
226
|
+
# on dirait que c'est ça faut faire deux translations en x
|
|
227
|
+
|
|
228
|
+
painter.rotate(self.theta)
|
|
229
|
+
|
|
230
|
+
# ça marche faut deux translations
|
|
231
|
+
|
|
232
|
+
# painter.translate(rect_to_plot.width() / 2, -rect_to_plot.height() )
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
#see https://www.qtcentre.org/threads/15540-Rotating-a-rectangle-about-its-origin --> maybe ok
|
|
236
|
+
|
|
237
|
+
# difference = old center -
|
|
238
|
+
# old_center = self.boundingRect().center()
|
|
239
|
+
# trans = painter.combinedTransform()
|
|
240
|
+
# transformed = trans.mapRect(rect_to_plot)
|
|
241
|
+
|
|
242
|
+
# peut etre une piste mais a pas l'air de marcher
|
|
243
|
+
# print(self.boundingRect(), transformed)
|
|
244
|
+
# trans = transformed.center()-self.boundingRect().center()
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# width_dif = transformed.width()-self.boundingRect().width()
|
|
248
|
+
# width_dif/=2
|
|
249
|
+
# print('trans', trans, transformed.center(), self.boundingRect().center(), width_dif)
|
|
250
|
+
|
|
251
|
+
# painter.translate(-trans)
|
|
252
|
+
# only if rotation
|
|
253
|
+
painter.translate(-rect_to_plot.center())
|
|
254
|
+
painter.drawRect(rect_to_plot)
|
|
255
|
+
# else:
|
|
256
|
+
# painter.fillRect(rect_to_plot, QColor(self.fill_color))
|
|
257
|
+
|
|
258
|
+
painter.restore()
|
|
259
|
+
|
|
260
|
+
# self.__sel = rotatedRect
|
|
261
|
+
# if rotatedRect:
|
|
262
|
+
# if isinstance(rotatedRect, QRectF):
|
|
263
|
+
# return rotatedRect
|
|
264
|
+
# self.__sel =rotatedRect.boundingRect()
|
|
265
|
+
# return self.__sel
|
|
266
|
+
# else:
|
|
267
|
+
# return self.__sel
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def __get_scaled_rect(self, rect_to_plot, scale):
|
|
271
|
+
rect = QRectF(rect_to_plot.x()*scale, rect_to_plot.y()*scale, rect_to_plot.width()*scale, rect_to_plot.height()*scale)
|
|
272
|
+
return rect
|
|
273
|
+
|
|
274
|
+
# TODO modify that to handle rotation etc...
|
|
275
|
+
def boundingRect(self, scaled=True):
|
|
276
|
+
# should I return the scaled version or the orig --> think about it...
|
|
277
|
+
if scaled:
|
|
278
|
+
# in fact scale only handles rotation and not scale --> the size is therefore wrong -->
|
|
279
|
+
try:
|
|
280
|
+
if self.theta is not None and self.theta!=0:
|
|
281
|
+
# print('entering')
|
|
282
|
+
center = self.center()
|
|
283
|
+
t = QTransform().translate( center.x(), center.y()).rotate(self.theta).translate(-center.x(), -center.y())
|
|
284
|
+
# print('entersd')
|
|
285
|
+
rotatedRect = t.mapRect( self ) #// mapRect() returns the bounding rect of the rotated rect
|
|
286
|
+
# print('rotated',rotatedRect )
|
|
287
|
+
return rotatedRect
|
|
288
|
+
except:
|
|
289
|
+
pass
|
|
290
|
+
return self
|
|
291
|
+
|
|
292
|
+
# def add(self, *args):
|
|
293
|
+
# point = args[1]
|
|
294
|
+
# 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
|
|
295
|
+
# self.setHeight(point.y()-self.y())
|
|
296
|
+
# # self.isSet = True
|
|
297
|
+
|
|
298
|
+
# def set_P1(self, *args):
|
|
299
|
+
# if not args:
|
|
300
|
+
# logger.error("no coordinate set...")
|
|
301
|
+
# return
|
|
302
|
+
# if len(args) == 1:
|
|
303
|
+
# self.moveTo(args[0].x(), args[0].y())
|
|
304
|
+
# else:
|
|
305
|
+
# self.moveTo(QPointF(args[0], args[1]))
|
|
306
|
+
|
|
307
|
+
# def get_P1(self):
|
|
308
|
+
# return QPointF(self.x(), self.y())
|
|
309
|
+
|
|
310
|
+
def set_to_scale(self, factor):
|
|
311
|
+
self.scale = factor
|
|
312
|
+
|
|
313
|
+
# def set_to_translation(self, translation):
|
|
314
|
+
# self.translation = translation
|
|
315
|
+
|
|
316
|
+
# 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
|
|
317
|
+
def __eq__(self, other):
|
|
318
|
+
try:
|
|
319
|
+
return hash(str(self)) == other.__hash__()
|
|
320
|
+
except:
|
|
321
|
+
return False
|
|
322
|
+
|
|
323
|
+
# 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
|
|
324
|
+
def __hash__(self):
|
|
325
|
+
return hash(str(self))
|
|
326
|
+
|
|
327
|
+
def getIncompressibleWidth(self):
|
|
328
|
+
return self.incompressible_width
|
|
329
|
+
|
|
330
|
+
def getIncompressibleHeight(self):
|
|
331
|
+
return self.incompressible_height
|
|
332
|
+
|
|
333
|
+
def get_incompressible_size(self, axis=None):
|
|
334
|
+
# DO I REALLY NEED THAT ANYMORE --> SHALL IT NOT SIMPLY ALWAYS RETURN 0 ???
|
|
335
|
+
if axis:
|
|
336
|
+
if axis == 'X':
|
|
337
|
+
return self.getIncompressibleWidth()
|
|
338
|
+
else:
|
|
339
|
+
return self.getIncompressibleHeight()
|
|
340
|
+
return 0
|
|
341
|
+
|
|
342
|
+
# can also be done like that
|
|
343
|
+
# def setTopLeft(self, x_or_rect, y=None):
|
|
344
|
+
# if y is None:
|
|
345
|
+
def setTopLeft(self, *args):
|
|
346
|
+
if args:
|
|
347
|
+
if len(args)==1:
|
|
348
|
+
# assume a QpointF
|
|
349
|
+
super().moveTopLeft(args[0])
|
|
350
|
+
elif len(args)==2:
|
|
351
|
+
super().moveTopLeft(QPointF(args[0], args[1]))
|
|
352
|
+
else:
|
|
353
|
+
logger.error('invalid args for top left')
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
# def getRect(self,*args, **kwargs):
|
|
357
|
+
# if args or kwargs:
|
|
358
|
+
# if 'all' in kwargs:
|
|
359
|
+
# # print('in there!')
|
|
360
|
+
# # rect_to_plot = QRectF(*super().getRect())#QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
|
|
361
|
+
# rect_to_plot = QRectF(self.x(), self.y(), self.width() , self.height() )
|
|
362
|
+
# center = rect_to_plot.center()
|
|
363
|
+
# if self.theta:
|
|
364
|
+
# # t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),-center.y())
|
|
365
|
+
# # rotatedRect = t.mapToPolygon(rect_to_plot.toRect()) # // mapRect() returns the bounding rect
|
|
366
|
+
# t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),
|
|
367
|
+
# -center.y())
|
|
368
|
+
# rotatedPolygon = t.mapToPolygon(rect_to_plot.toRect()) # Map the rectangle to a rotated polygon
|
|
369
|
+
#
|
|
370
|
+
# # Create a QRectF from the bounding rectangle of the rotated polygon
|
|
371
|
+
# rotatedRect = QRectF(rotatedPolygon.boundingRect())
|
|
372
|
+
#
|
|
373
|
+
# if self.crop_left:
|
|
374
|
+
# rotatedRect.setWidth(rotatedRect.width()-self.crop_left)
|
|
375
|
+
# if self.crop_right:
|
|
376
|
+
# rotatedRect.setWidth(rotatedRect.width()-self.crop_right)
|
|
377
|
+
# if self.crop_top:
|
|
378
|
+
# rotatedRect.setHeight(rotatedRect.height()-self.crop_top)
|
|
379
|
+
# if self.crop_bottom:
|
|
380
|
+
# rotatedRect.setHeight(rotatedRect.height()-self.crop_bottom)
|
|
381
|
+
#
|
|
382
|
+
# rotatedRect.setWidth(rotatedRect.width()/self.scale)
|
|
383
|
+
# rotatedRect.setHeight(rotatedRect.height()/self.scale)
|
|
384
|
+
# else:
|
|
385
|
+
# if self.crop_left:
|
|
386
|
+
# rect_to_plot.setWidth(rect_to_plot.width() - self.crop_left)
|
|
387
|
+
# if self.crop_right:
|
|
388
|
+
# rect_to_plot.setWidth(rect_to_plot.width() - self.crop_right)
|
|
389
|
+
# if self.crop_top:
|
|
390
|
+
# rect_to_plot.setHeight(rect_to_plot.height() - self.crop_top)
|
|
391
|
+
# if self.crop_bottom:
|
|
392
|
+
# rect_to_plot.setHeight(rect_to_plot.height() - self.crop_bottom)
|
|
393
|
+
# rect_to_plot.setWidth(rect_to_plot.width() / self.scale)
|
|
394
|
+
# rect_to_plot.setHeight(rect_to_plot.height() / self.scale)
|
|
395
|
+
# return rect_to_plot
|
|
396
|
+
# try:
|
|
397
|
+
# return QRectF(rotatedRect.boundingRect())
|
|
398
|
+
# except:
|
|
399
|
+
# return rotatedRect
|
|
400
|
+
# # return QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
|
|
401
|
+
# else:
|
|
402
|
+
# # default to scaled object
|
|
403
|
+
# return QRectF(self.x(), self.y(), self.width()/self.scale, self.height()/self.scale)
|
|
404
|
+
# else:
|
|
405
|
+
# # return super().getRect()
|
|
406
|
+
# return QRectF(*super().getRect())
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def getRect(self,*args, **kwargs):
|
|
410
|
+
if args or kwargs:
|
|
411
|
+
if 'all' in kwargs:
|
|
412
|
+
# print('in there!')
|
|
413
|
+
# rect_to_plot = QRectF(*super().getRect())#QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
|
|
414
|
+
rect_to_plot = QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
|
|
415
|
+
center = rect_to_plot.center()
|
|
416
|
+
if self.theta:
|
|
417
|
+
# t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),-center.y())
|
|
418
|
+
# rotatedRect = t.mapToPolygon(rect_to_plot.toRect()) # // mapRect() returns the bounding rect
|
|
419
|
+
t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),
|
|
420
|
+
-center.y())
|
|
421
|
+
rotatedPolygon = t.mapToPolygon(rect_to_plot.toRect()) # Map the rectangle to a rotated polygon
|
|
422
|
+
|
|
423
|
+
# Create a QRectF from the bounding rectangle of the rotated polygon
|
|
424
|
+
rotatedRect = QRectF(rotatedPolygon.boundingRect())
|
|
425
|
+
else:
|
|
426
|
+
return rect_to_plot
|
|
427
|
+
try:
|
|
428
|
+
return QRectF(rotatedRect.boundingRect())
|
|
429
|
+
except:
|
|
430
|
+
return rotatedRect
|
|
431
|
+
# return QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
|
|
432
|
+
else:
|
|
433
|
+
# default to scaled object
|
|
434
|
+
return QRectF(self.x(), self.y(), self.width()/self.scale, self.height()/self.scale)
|
|
435
|
+
else:
|
|
436
|
+
# return super().getRect()
|
|
437
|
+
return QRectF(*super().getRect())
|
|
438
|
+
|
|
439
|
+
def width(self,*args, **kwargs):
|
|
440
|
+
if args or kwargs:
|
|
441
|
+
return self.width()/self.scale # this is probably incorrect but ok for now
|
|
442
|
+
else:
|
|
443
|
+
return super().width()
|
|
444
|
+
# return self.getRect(*args, **kwargs).width()
|
|
445
|
+
|
|
446
|
+
def height(self,*args, **kwargs):
|
|
447
|
+
if args or kwargs:
|
|
448
|
+
return self.height()/self.scale
|
|
449
|
+
else:
|
|
450
|
+
return super().height()
|
|
451
|
+
# return self.getRect(*args, **kwargs).height()
|
|
452
|
+
|
|
453
|
+
def getAR(self, invert=False):
|
|
454
|
+
# try:
|
|
455
|
+
if invert:
|
|
456
|
+
return float(self.height()) / float(self.width())
|
|
457
|
+
return float(self.width()) / float(self.height())
|
|
458
|
+
# except:
|
|
459
|
+
# return 1.
|
|
460
|
+
|
|
461
|
+
def contains(self, *__args):
|
|
462
|
+
try:
|
|
463
|
+
# if self.__sel:
|
|
464
|
+
# return self.__sel.contains(*__args)
|
|
465
|
+
if __args is not None and __args:
|
|
466
|
+
return self.getRect(all=True).contains(*__args)
|
|
467
|
+
else:
|
|
468
|
+
return False
|
|
469
|
+
# return self.getRect(scale=True).contains(*__args)
|
|
470
|
+
except:
|
|
471
|
+
# traceback.print_exc() # somehow this generates an error but does it make sense
|
|
472
|
+
# I have too many handling of rotations --> that may cause trouble too
|
|
473
|
+
# simplest is to really make the rect as it should be and as selection should be !!!
|
|
474
|
+
pass
|
|
475
|
+
return False
|
|
476
|
+
|
|
477
|
+
# def __str__(self):
|
|
478
|
+
# return f'rectangle {super().__str__()}'
|
|
479
|
+
def set_to_center(self, centroid):
|
|
480
|
+
w = self.width()
|
|
481
|
+
h = self.height()
|
|
482
|
+
if isinstance(centroid, (tuple, list)):
|
|
483
|
+
|
|
484
|
+
self.setX(centroid[0]-self.width()/2.)
|
|
485
|
+
self.setY(centroid[1]-self.height()/2.)
|
|
486
|
+
|
|
487
|
+
else:
|
|
488
|
+
self.setX(centroid.x()-self.width()/2.)
|
|
489
|
+
self.setY(centroid.y()-self.height()/2.)
|
|
490
|
+
self.setWidth(w)
|
|
491
|
+
self.setHeight(h)
|
|
492
|
+
def add(self, *args):
|
|
493
|
+
point = args[1]
|
|
494
|
+
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
|
|
495
|
+
self.setHeight(point.y()-self.y())
|
|
496
|
+
self.isSet = True
|
|
497
|
+
|
|
498
|
+
# def __repr__(self):
|
|
499
|
+
# default_repr = object.__repr__(self)
|
|
500
|
+
# class_name = type(self).__name__
|
|
501
|
+
# return f"{class_name}{default_repr}"
|
|
502
|
+
def __repr__(self):
|
|
503
|
+
class_name = type(self).__name__
|
|
504
|
+
memory_address = hex(id(self))
|
|
505
|
+
return f"{class_name}-{memory_address}"
|
|
506
|
+
|
|
507
|
+
def to_dict(self):
|
|
508
|
+
x = self.x()
|
|
509
|
+
y = self.y()
|
|
510
|
+
width = self.width()
|
|
511
|
+
height = self.height()
|
|
512
|
+
|
|
513
|
+
# Create a dictionary representation of the values of the super object
|
|
514
|
+
output_dict = {
|
|
515
|
+
'x': x,
|
|
516
|
+
'y': y,
|
|
517
|
+
'width': width,
|
|
518
|
+
'height': height,
|
|
519
|
+
}
|
|
520
|
+
# Update the dictionary with the __dict__ of Rectangle2D
|
|
521
|
+
output_dict.update(self.__dict__)
|
|
522
|
+
return output_dict
|
|
523
|
+
|
|
524
|
+
if __name__ == '__main__':
|
|
525
|
+
# ça marche --> voici deux examples de shapes
|
|
526
|
+
test = Rectangle2D(10, 0, 100, 100)
|
|
527
|
+
print(test)
|
|
528
|
+
# print(test.get_P1())
|
|
529
|
+
|
|
530
|
+
test2 = Rectangle2D(QRectF(10, 0, 100, 100))
|
|
531
|
+
print('pt2', test2)
|
|
532
|
+
|
|
533
|
+
# then use my set_P1
|
|
534
|
+
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
|
|
535
|
+
print(test2)
|
|
536
|
+
sys.exit(0)
|
|
537
|
+
|
|
538
|
+
test.incompressible_width = 10
|
|
539
|
+
test.incompressible_height = 5
|
|
540
|
+
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
|
|
541
|
+
# in the case of rows that should be the space between cols or rows and in the case of panels it is both
|
|
542
|
+
|
|
543
|
+
rect = QRectF(10, 0, 125, 256)
|
|
544
|
+
print(rect.x())
|
|
545
|
+
print(rect.y())
|
|
546
|
+
print(rect.width())
|
|
547
|
+
print(rect.height())
|
|
548
|
+
|
|
549
|
+
rect.setTopLeft(QPointF(10.,20.))
|
|
550
|
+
|
|
551
|
+
print('sum',rect.x()+rect.width(), type(rect.x()+rect.width())) # float
|
|
552
|
+
|
|
553
|
+
print(rect.topLeft()) # this is same as get_P1 --> maybe stick to that
|
|
554
|
+
|
|
555
|
+
rect.translate(10,20) # ça marche
|
|
556
|
+
print(rect)
|
|
557
|
+
|
|
558
|
+
print(test)
|
|
559
|
+
test.set_to_scale(0.5) #scale is not applied to the object so its size isn't the real size
|
|
560
|
+
# pb is that if I modify this class there will be tremendous repercusion on other classes --> be careful...
|
|
561
|
+
print('scaled test',test)
|
|
562
|
+
print('scaled test',test.boundingRect())
|
|
563
|
+
print('scaled test',test.boundingRect(scaled=True))
|
|
564
|
+
|
|
565
|
+
(test.x(), test.y(), test.width(), test.height())
|
|
566
|
+
print(test.contains(QPointF(50, 50)))
|
|
567
|
+
print(test.contains(QPointF(-1, -1)))
|
|
568
|
+
print(test.contains(QPointF(0, 0)))
|
|
569
|
+
print(test.contains(QPointF(100, 100)))
|
|
570
|
+
print(test.contains(QPointF(100, 100.1)))
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
# shall I do rotation
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
# ideally plot it so that I can test all
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
# p1 = test.p1()
|
|
580
|
+
# print(p1.x(), p1.y())
|
|
581
|
+
# p2 = test.p2()
|
|
582
|
+
# print(p2.x(), p2.y())
|
|
583
|
+
# print(test.arrow)
|
|
584
|
+
# print(test.length()) # sqrt 2 --> 141
|
|
585
|
+
# # if it's an arrow I can add easily all the stuff I need
|
|
586
|
+
#
|
|
587
|
+
# test = Rect2D(0, 0, 1, 1)
|
|
588
|
+
# p1 = test.p1()
|
|
589
|
+
# print(p1.x(), p1.y())
|
|
590
|
+
# p2 = test.p2()
|
|
591
|
+
# print(p2.x(), p2.y())
|
|
592
|
+
# print(test.arrow)
|
|
593
|
+
# import math
|
|
594
|
+
# print(test.length() == math.sqrt(2)) # sqrt 2
|
|
595
|
+
#
|
|
596
|
+
# test2 = Rect2D()
|
|
597
|
+
# p1 = test2.p1()
|
|
598
|
+
# print(p1.x(), p1.y())
|
|
599
|
+
# p2 = test2.p2()
|
|
600
|
+
# print(p2.x(), p2.y())
|
|
601
|
+
# print(test2.arrow)
|