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.
Files changed (162) hide show
  1. batoolset/GUI/__init__.py +0 -0
  2. batoolset/GUI/list_gui.py +513 -0
  3. batoolset/GUI/multi_image_display.py +989 -0
  4. batoolset/GUI/open.py +325 -0
  5. batoolset/GUI/overlay_hints.py +45 -0
  6. batoolset/GUI/paint2.py +1345 -0
  7. batoolset/GUI/scrollablepaint.py +1152 -0
  8. batoolset/IJ_ROIs/__init__.py +0 -0
  9. batoolset/IJ_ROIs/tools.py +40 -0
  10. batoolset/PATH/__init__.py +0 -0
  11. batoolset/PATH/tools.py +79 -0
  12. batoolset/SQLite_tools/__init__.py +0 -0
  13. batoolset/SQLite_tools/tools.py +840 -0
  14. batoolset/__init__.py +0 -0
  15. batoolset/binary/__init__.py +0 -0
  16. batoolset/binary/tools.py +123 -0
  17. batoolset/binarytools/__init__.py +0 -0
  18. batoolset/binarytools/cell_center_detector.py +290 -0
  19. batoolset/clipboard_tools/__init__.py +0 -0
  20. batoolset/clipboard_tools/tools.py +7 -0
  21. batoolset/colors/__init__.py +0 -0
  22. batoolset/colors/colorgen.py +193 -0
  23. batoolset/colors/tools.py +22 -0
  24. batoolset/command_line/__init__.py +0 -0
  25. batoolset/command_line/tools.py +18 -0
  26. batoolset/dialogs/__init__.py +0 -0
  27. batoolset/dialogs/opensave.py +228 -0
  28. batoolset/dicts/__init__.py +0 -0
  29. batoolset/dicts/tools.py +299 -0
  30. batoolset/dims/__init__.py +0 -0
  31. batoolset/dims/tools.py +83 -0
  32. batoolset/draw/__init__.py +0 -0
  33. batoolset/draw/shapes/Position.py +183 -0
  34. batoolset/draw/shapes/__init__.py +0 -0
  35. batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
  36. batoolset/draw/shapes/circle2d.py +99 -0
  37. batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
  38. batoolset/draw/shapes/ellipse2d.py +336 -0
  39. batoolset/draw/shapes/freehand2d.py +235 -0
  40. batoolset/draw/shapes/group.py +1830 -0
  41. batoolset/draw/shapes/image2d.py +2469 -0
  42. batoolset/draw/shapes/line2d.py +575 -0
  43. batoolset/draw/shapes/point2d.py +257 -0
  44. batoolset/draw/shapes/polygon2d.py +357 -0
  45. batoolset/draw/shapes/polyline2d.py +235 -0
  46. batoolset/draw/shapes/rect2d.py +388 -0
  47. batoolset/draw/shapes/rectangle2d.py +601 -0
  48. batoolset/draw/shapes/scalebar.py +304 -0
  49. batoolset/draw/shapes/serializablefont.py +126 -0
  50. batoolset/draw/shapes/serializableguiparams.py +10 -0
  51. batoolset/draw/shapes/square2d.py +103 -0
  52. batoolset/draw/shapes/textorientation.py +45 -0
  53. batoolset/draw/shapes/tools.py +467 -0
  54. batoolset/draw/shapes/transform2D.py +350 -0
  55. batoolset/draw/shapes/txt2d.py +550 -0
  56. batoolset/draw/widgets/__init__.py +0 -0
  57. batoolset/draw/widgets/col.py +343 -0
  58. batoolset/draw/widgets/image_group.py +248 -0
  59. batoolset/draw/widgets/image_organizer.py +96 -0
  60. batoolset/draw/widgets/paint.py +184 -0
  61. batoolset/draw/widgets/vectorial.py +257 -0
  62. batoolset/figure/__init__.py +0 -0
  63. batoolset/figure/alignment.py +814 -0
  64. batoolset/figure/column.py +1117 -0
  65. batoolset/figure/fig_tools.py +285 -0
  66. batoolset/figure/minimal_debugger_scale_etc.py +139 -0
  67. batoolset/figure/panel.py +697 -0
  68. batoolset/figure/row.py +852 -0
  69. batoolset/figure/user_selection.py +287 -0
  70. batoolset/files/__init__.py +0 -0
  71. batoolset/files/tools.py +1321 -0
  72. batoolset/images/__init__.py +0 -0
  73. batoolset/images/tools.py +81 -0
  74. batoolset/img.py +5216 -0
  75. batoolset/linux/__init__.py +0 -0
  76. batoolset/linux/tools.py +72 -0
  77. batoolset/lists/__init__.py +0 -0
  78. batoolset/lists/tools.py +436 -0
  79. batoolset/luts/__init__.py +0 -0
  80. batoolset/luts/lut_minimal_test.py +1207 -0
  81. batoolset/matplolib/__init__.py +0 -0
  82. batoolset/matplolib/tools.py +44 -0
  83. batoolset/np_tools/__init__.py +0 -0
  84. batoolset/np_tools/tools.py +252 -0
  85. batoolset/np_tools/trash.py +15 -0
  86. batoolset/pandas_tools/__init__.py +0 -0
  87. batoolset/pandas_tools/tools.py +880 -0
  88. batoolset/partials/__init__.py +0 -0
  89. batoolset/partials/tools.py +83 -0
  90. batoolset/plot_tools/__init__.py +0 -0
  91. batoolset/plot_tools/tools.py +70 -0
  92. batoolset/pyqt/__init__.py +0 -0
  93. batoolset/pyqt/tools.py +691 -0
  94. batoolset/re_tools/__init__.py +0 -0
  95. batoolset/re_tools/tools.py +35 -0
  96. batoolset/serialization/__init__.py +0 -0
  97. batoolset/serialization/tools.py +1192 -0
  98. batoolset/sets/__init__.py +0 -0
  99. batoolset/sets/tools.py +109 -0
  100. batoolset/settings/__init__.py +0 -0
  101. batoolset/settings/global_settings.py +134 -0
  102. batoolset/strings/__init__.py +0 -0
  103. batoolset/strings/tools.py +225 -0
  104. batoolset/ta/__init__.py +0 -0
  105. batoolset/ta/database/__init__.py +0 -0
  106. batoolset/ta/database/advanced_sql_plotter.py +1170 -0
  107. batoolset/ta/database/my_qt_table.py +79 -0
  108. batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
  109. batoolset/ta/database/sql.py +2141 -0
  110. batoolset/ta/database/sql_column_name_dialog.py +122 -0
  111. batoolset/ta/measurements/TAmeasures.py +2226 -0
  112. batoolset/ta/measurements/__init__.py +0 -0
  113. batoolset/ta/measurements/measurements3D/__init__.py +0 -0
  114. batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
  115. batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
  116. batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
  117. batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
  118. batoolset/ta/measurements/nematic.py +562 -0
  119. batoolset/ta/measurements/nematic_measurements.py +107 -0
  120. batoolset/ta/segmentation/__init__.py +0 -0
  121. batoolset/ta/segmentation/neo_wshed.py +314 -0
  122. batoolset/ta/selections/__init__.py +0 -0
  123. batoolset/ta/selections/selection.py +329 -0
  124. batoolset/ta/tracking/__init__.py +0 -0
  125. batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
  126. batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
  127. batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
  128. batoolset/ta/tracking/registration.py +108 -0
  129. batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
  130. batoolset/ta/tracking/track_correction.py +238 -0
  131. batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
  132. batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
  133. batoolset/ta/utils/TA_tools.py +43 -0
  134. batoolset/ta/utils/__init__.py +0 -0
  135. batoolset/ta/utils/rps_tools.py +1783 -0
  136. batoolset/tests/__init__.py +0 -0
  137. batoolset/tests/rps_tools.py +51 -0
  138. batoolset/tests/tools.py +10 -0
  139. batoolset/tools/__init__.py +0 -0
  140. batoolset/tools/early_stopper_class.py +9 -0
  141. batoolset/tools/guided_data_recoverer.py +110 -0
  142. batoolset/tools/logger.py +100 -0
  143. batoolset/tools/mytimer.py +31 -0
  144. batoolset/tools/prompt_color.py +160 -0
  145. batoolset/tools/qthandler.py +118 -0
  146. batoolset/uitools/__init__.py +0 -0
  147. batoolset/uitools/blinker.py +56 -0
  148. batoolset/unsafe/__init__.py +0 -0
  149. batoolset/unsafe/tools.py +115 -0
  150. batoolset/utils/__init__.py +0 -0
  151. batoolset/utils/commontools.py +158 -0
  152. batoolset/utils/loadlist.py +728 -0
  153. batoolset/version.py +10 -0
  154. batoolset/xml/__init__.py +0 -0
  155. batoolset/xml/tools.py +65 -0
  156. batoolset/zip_tools/__init__.py +0 -0
  157. batoolset/zip_tools/tools.py +76 -0
  158. batoolset-0.1.0.dist-info/LICENSE +24 -0
  159. batoolset-0.1.0.dist-info/METADATA +45 -0
  160. batoolset-0.1.0.dist-info/RECORD +162 -0
  161. batoolset-0.1.0.dist-info/WHEEL +5 -0
  162. batoolset-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,317 @@
1
+ from batoolset.draw.shapes.rectangle2d import Rectangle2D
2
+ # from PyQt5.QtCore import QRectF, QSizeF
3
+ from qtpy.QtCore import QRectF, QSizeF
4
+
5
+ # def resize_rect_preserve_aspect_ratio(rect: Rectangle2D, new_height: float):
6
+ # current_width = rect.width()
7
+ # current_height = rect.height()
8
+ # aspect_ratio = current_width / current_height
9
+ #
10
+ # new_width = aspect_ratio * new_height
11
+ # # new_rect = Rectangle2D(QRectF(rect.x(), rect.y(), new_width, new_height)) # here I rather need to scale the rect
12
+ # # rect.set_to_scale(aspect_ratio)
13
+ # # dirty hack for test
14
+ # # rect = Rectangle2D(rect)
15
+ #
16
+ # # print(current_width, new_width)
17
+ #
18
+ # rect.set_to_scale(current_width/new_width)
19
+ #
20
+ # return rect
21
+
22
+
23
+
24
+
25
+ # TODO --> fuse all of this in a single super smart stuff
26
+
27
+
28
+
29
+
30
+ # can I use my own LLM there ???
31
+
32
+
33
+ def resize_rect_preserve_aspect_ratio(rect: Rectangle2D, new_width: float, new_height:float):
34
+ # I guess the bug is there
35
+ current_width = rect.width()
36
+ current_height = rect.height()
37
+
38
+
39
+ # if current_height == 0:
40
+ # return rect
41
+ # print(current_height)
42
+ aspect_ratio = float(current_width) / float(current_height)
43
+
44
+ # very good --> so I could fix it
45
+ if new_height is not None:
46
+ # if False: # this is to favor height
47
+ # new_height = new_size.height()
48
+ # # new_width = aspect_ratio * new_height if aspect_ratio < new_size.width() / new_size.height() else new_size.width() * current_height / current_width
49
+ new_width = aspect_ratio * new_height
50
+ rect.set_to_scale(1./(new_width/current_width))
51
+ else:
52
+ # new_width = new_size.width()
53
+ new_height = new_width/aspect_ratio
54
+ rect.set_to_scale(1./(new_height / current_height)) # TODO --> clean this code --> make it better
55
+
56
+ # new_rect = QRectF(rect.x(), rect.y(), new_width, new_height)
57
+ # return new_rect
58
+ return rect
59
+
60
+
61
+ def resize_rects(rects: list, target_width:float, target_height: float):
62
+ resized_rects = []
63
+ for rect in rects:
64
+ resized_rect = resize_rect_preserve_aspect_ratio(rect, target_width, target_height)
65
+ resized_rects.append(resized_rect)
66
+
67
+ return resized_rects
68
+
69
+ # I need get its size set its scale to 1 get just the text size yet crop the
70
+ def resize_incompressible_rects(rects: list, target_width:float, target_height: float):
71
+ # max_w = 0
72
+ # max_h = 0
73
+ # failed_images = []
74
+ # text_images = []
75
+ # individual_width = []
76
+ # individual_height = []
77
+ # for elm in self.paint.EZFIG_panel.selected_shape:
78
+ # try:
79
+ # print(elm, elm.annotations, elm.annotations[0], elm.annotations[0].width(all=True),
80
+ # elm.annotations[0].height(all=True))
81
+ # if len(elm.annotations) != 1:
82
+ # raise Exception('not good')
83
+ # individual_width.append(elm.annotations[0].width(all=True))
84
+ # individual_height.append(elm.annotations[0].height(all=True))
85
+ # max_w = max(elm.annotations[0].width(all=True), max_w)
86
+ # max_h = max(elm.annotations[0].height(all=True), max_h)
87
+ # text_images.append(elm)
88
+ # except:
89
+ # # pass # if fails this is not a text image
90
+ # failed_images.append(elm) # if image is failed then we have it
91
+
92
+
93
+
94
+ max_w = 0
95
+ max_h = 0
96
+ resized_rects = []
97
+ for rect in rects:
98
+ # resized_rect = resize_rect_preserve_aspect_ratio(rect, target_width, target_height)
99
+ # resized_rects.append(resized_rect)
100
+ txt_width = rect.annotations[0].width(all=True)
101
+ txt_height = rect.annotations[0].height(all=True)
102
+ max_w = max(txt_width, max_w)
103
+ max_h = max(txt_height, max_h)
104
+ # set the texts to their minimal size --> then resize the stuff in the very end so that all fits
105
+ rect.setWidth(txt_width)
106
+ rect.setHeight(txt_height)
107
+
108
+ return max_w, max_h, resized_rects
109
+
110
+ # def calculate_target_width(rects: list, max_total_height: float):
111
+ # total_aspect_ratio = sum(rect.height() / rect.width() for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
112
+ # target_width = max_total_height / total_aspect_ratio
113
+ # return target_width
114
+
115
+ # def calculate_target_height(rects: list, max_total_width: float):
116
+ # # in fact if there are incompressible ones here I need
117
+ # total_aspect_ratio = sum(rect.width() / rect.height() for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
118
+ # target_height = max_total_width / total_aspect_ratio
119
+ # return target_height
120
+
121
+
122
+ # def resize_rects_within_total_width(rects: list, max_total_width: float, space_in_px: float):
123
+ # incompressible_width = (len(rects) - 1) * space_in_px
124
+ # available_width = max_total_width - incompressible_width
125
+ #
126
+ # target_height = calculate_target_height(rects, available_width)
127
+ # resized_rects = resize_rects(rects, None, target_height) # --> indeed that works
128
+ #
129
+ # return resized_rects
130
+
131
+ # def resize_rects_within_total_height(rects: list, max_total_height: float, space_in_px: float):
132
+ # incompressible_height = (len(rects) - 1) * space_in_px
133
+ # available_height = max_total_height - incompressible_height
134
+ #
135
+ # target_width = calculate_target_width(rects, available_height)
136
+ # resized_rects = resize_rects(rects, target_width,None) # --> indeed that works
137
+ #
138
+ # return resized_rects
139
+
140
+ def resize_rects_within_total_width(rects: list, max_total_width: float, sum_incompressible_space_along_x: float):
141
+ # incompressible_width = (len(rects) - 1) * space_in_px
142
+ available_width = max_total_width - sum_incompressible_space_along_x
143
+ initial_width=available_width
144
+
145
+ total_incompressible_text_width = sum(rect.width(all=True) for rect in rects if rect.isText)
146
+
147
+ compressible = [rect for rect in rects if not rect.isText]
148
+ incompressible = [rect for rect in rects if rect.isText]
149
+
150
+ available_width-=total_incompressible_text_width
151
+
152
+ # print('total_incompressible_text_width',total_incompressible_text_width)
153
+ # print(compressible)
154
+ # print(incompressible)
155
+
156
+ # target_height = calculate_target_height(rects, available_width)
157
+
158
+ # total_aspect_ratio = sum(rect.width() / rect.height() for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
159
+ # total_aspect_ratio = sum(rect.getAR()for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
160
+ # total_aspect_ratio = sum(rect.getAR() for rect in rects) # immutable objects should be removed from the stuff -−> TODO
161
+
162
+ # print('final compressible', compressible)
163
+
164
+ total_aspect_ratio = sum(rect.getAR() for rect in compressible) # immutable objects should be removed from the stuff -−> TODO
165
+
166
+
167
+ # print('total_aspect_ratio modified',total_aspect_ratio)
168
+ # the idea is that I need to fit the non text stuff there
169
+
170
+
171
+
172
+ # if total_aspect_ratio == 0:
173
+ # print('DEBUG DABU')
174
+ # for rect in rects:
175
+ # print('tata', rect.getAR())
176
+
177
+
178
+ if total_aspect_ratio!=0: # this is just to avoid errors # maybe fit all to current otherwise
179
+ target_height = available_width / total_aspect_ratio
180
+ else:
181
+ target_height = available_width
182
+
183
+ # resized_rects = resize_rects(rects, None, target_height) # --> indeed that works
184
+ resized_compressible_rects = resize_rects(compressible, None, target_height) # --> indeed that works
185
+
186
+ # if resized_compressible_rects:
187
+ # target_width, target_height =
188
+ max_w, max_h, resized_incompressible_rects = resize_incompressible_rects(incompressible, None, target_height) # --> indeed that works
189
+ if compressible:
190
+ height = compressible[0].height(all=True)
191
+ else:
192
+ height = max_h
193
+ if incompressible : # incompressible
194
+ sum_of_widths = sum(rect.width(all=True) for rect in incompressible)
195
+ # Compute the scaling factor
196
+ scaling_factor = initial_width / sum_of_widths
197
+
198
+ # print('total_aspect_ratio in changed',scaling_factor)
199
+ for elm in incompressible:
200
+ elm.setWidth(elm.width(all=True)*scaling_factor)
201
+ elm.set_to_scale(1.)
202
+
203
+ if incompressible:
204
+ for elm in incompressible:
205
+ elm.setHeight(height)
206
+ elm.set_to_scale(1.)
207
+
208
+
209
+ # last thing to do -> if there is no compressible I need adjust the total size to the deisred by keeping height constant and increasing height
210
+ # by the rescaling factor
211
+
212
+
213
+
214
+ return rects # return all rects that have been modified in original order
215
+
216
+
217
+ def resize_rects_within_total_height(rects: list, max_total_height: float, sum_incompressible_space_along_y: float):
218
+ # incompressible_height = (len(rects) - 1) * space_in_px
219
+ available_height = max_total_height - sum_incompressible_space_along_y
220
+ initial_height=available_height
221
+ total_incompressible_text_height = sum(rect.getRect(all=True).height() for rect in rects if rect.isText)
222
+
223
+
224
+ # target_width = calculate_target_width(rects, available_height)
225
+
226
+ # total_aspect_ratio = sum(rect.height() / rect.width() for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
227
+ # total_aspect_ratio = sum(rect.getAR(invert=True) for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
228
+
229
+ compressible = [rect for rect in rects if not rect.isText]
230
+ incompressible = [rect for rect in rects if rect.isText]
231
+
232
+ available_height -= total_incompressible_text_height
233
+
234
+ # print('total_incompressible_text_height', total_incompressible_text_height)
235
+ # print(compressible)
236
+ # print(incompressible)
237
+
238
+ # target_height = calculate_target_height(rects, available_width)
239
+
240
+ # total_aspect_ratio = sum(rect.width() / rect.height() for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
241
+ # total_aspect_ratio = sum(rect.getAR()for rect in rects if not rect.immutable) # immutable objects should be removed from the stuff -−> TODO
242
+ # total_aspect_ratio = sum(rect.getAR() for rect in rects) # immutable objects should be removed from the stuff -−> TODO
243
+
244
+
245
+ # total_aspect_ratio = sum(rect.getAR(invert=True) for rect in rects) # immutable objects should be removed from the stuff -−> TODO
246
+ total_aspect_ratio = sum(rect.getAR(invert=True) for rect in compressible) # immutable objects should be removed from the stuff -−> TODO
247
+
248
+ # print('total_aspect_ratio modified', total_aspect_ratio)
249
+
250
+ if total_aspect_ratio != 0: # this is just to avoid errors # maybe fit all to current otherwise
251
+ target_width = available_height / total_aspect_ratio
252
+ else:
253
+ target_width = available_height
254
+
255
+ # target_width = available_height / total_aspect_ratio
256
+
257
+ # resized_rects = resize_rects(rects, target_width,None) # --> indeed that works
258
+ resized_compressible_rects = resize_rects(compressible, target_width, None) # --> indeed that works
259
+ max_w, max_h, resized_incompressible_rects = resize_incompressible_rects(incompressible, target_width,None) # --> indeed that works
260
+ if compressible:
261
+ width = compressible[0].width(all=True)
262
+ else:
263
+ width = max_w
264
+ if incompressible : # incompressible
265
+ sum_of_heights = sum(rect.height(all=True) for rect in incompressible)
266
+ # Compute the scaling factor
267
+ scaling_factor = initial_height / sum_of_heights
268
+
269
+ # print('total_aspect_ratio in chnaged',scaling_factor)
270
+ for elm in incompressible:
271
+ elm.setHeight(elm.height(all=True)*scaling_factor)
272
+ elm.set_to_scale(1.)
273
+
274
+ if incompressible:
275
+ for elm in incompressible:
276
+ elm.setWidth(width)
277
+ elm.set_to_scale(1.)
278
+
279
+ return rects
280
+
281
+
282
+ def resize_rects_within_grid(rects: list, grid_size: tuple, max_total_width: float, max_total_height: float, incompressible_width: float, incompressible_height: float, fit_in_width:int):
283
+ # this is a bit too complicated with grids as they will have complex incompressibility in width and height that will vary depending on the amount of rows and cols !!!!
284
+
285
+ # this sounds like good and simple code!!!
286
+ rows, cols = grid_size
287
+
288
+ # rather than passing the incompressible size I just would need to compute it per object on the fly !!!
289
+
290
+ available_width = max_total_width - (cols - 1) * incompressible_width # NB maybe this should be done per row ????
291
+ available_height = max_total_height - (rows - 1) * incompressible_height
292
+
293
+ target_width = available_width / cols
294
+ target_height = available_height / rows
295
+
296
+ if fit_in_width:
297
+ target_height=None
298
+ else:
299
+ target_width=None
300
+ # here I need to choose between width and height
301
+ # ideally always prefer width except if extends beyond height
302
+ # when resized
303
+ # start with width
304
+
305
+ # in fact I should take either here --> the best fit in width and or in height -−> auto take it
306
+ # print('sizes',target_width, available_width, max_total_width, target_height, available_height, max_total_height) #92.5 370.0 400 193.33333333333334 580.0 600
307
+
308
+ resized_rects = []
309
+ for rect in rects:
310
+ resized_rect = resize_rect_preserve_aspect_ratio(rect, target_width, target_height)
311
+ resized_rects.append(resized_rect)
312
+
313
+ return resized_rects
314
+
315
+
316
+
317
+ # I could make it smarter by reading the incompressible height from the image and from the packing -−> this is why I need a group maybe???
@@ -0,0 +1,336 @@
1
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
2
+ set_UI()
3
+ import os
4
+ from qtpy import QtWidgets
5
+ from qtpy.QtCore import QPoint, QPointF, Qt, QRectF
6
+ from qtpy.QtGui import QBrush, QPen, QColor, QTransform
7
+
8
+ from batoolset.tools.logger import TA_logger
9
+
10
+ logger = TA_logger()
11
+
12
+ class Ellipse2D(QtWidgets.QGraphicsEllipseItem):
13
+
14
+ isSet = False
15
+
16
+ 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):
17
+ if args:
18
+ super(Ellipse2D, self).__init__(*args)
19
+ else:
20
+ super(Ellipse2D, self).__init__(x,y,width,height)
21
+
22
+ # super(, self).__init__(*args)
23
+ # if not args:
24
+ # self.isSet = False
25
+ # else:
26
+ # self.isSet = True
27
+
28
+ # print('self.rect()',self.rect())
29
+
30
+ self.setRect(self.rect())
31
+ self.color = color
32
+ self.fill_color = fill_color
33
+ self.stroke = stroke
34
+ self.opacity = opacity
35
+ self.scale = 1
36
+ self.translation = QPointF()
37
+ self.line_style = line_style
38
+ # rotation
39
+ self.theta = theta
40
+ self.__version__ = __version__
41
+
42
+ def set_rotation(self, theta):
43
+ self.theta = theta
44
+
45
+ def set_opacity(self, opacity):
46
+ self.opacity = opacity
47
+
48
+ def set_line_style(self,style):
49
+ """
50
+ allows lines to be dashed or dotted or have custom pattern
51
+ :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
52
+ :return:
53
+ """
54
+ self.line_style = style
55
+ # if style is a list then assume custom pattern otherwise apply solidline
56
+
57
+ def draw(self, painter, draw=True, parent=None):
58
+ if self.color is None and self.fill_color is None:
59
+ return
60
+
61
+ if draw:
62
+ painter.save()
63
+ painter.setPen(Qt.NoPen)
64
+ painter.setBrush(Qt.NoBrush)
65
+ painter.setOpacity(self.opacity)
66
+ if self.color is not None:
67
+ pen = QPen(QColor(self.color))
68
+ if self.stroke is not None:
69
+ pen.setWidthF(self.stroke)
70
+ if self.line_style is not None:
71
+ if self.line_style in [Qt.SolidLine, Qt.DashLine, Qt.DashDotLine, Qt.DotLine, Qt.DashDotDotLine]:
72
+ pen.setStyle(self.line_style)
73
+ elif isinstance(self.line_style, list):
74
+ pen.setStyle(Qt.CustomDashLine)
75
+ pen.setDashPattern(self.line_style)
76
+ painter.setPen(pen)
77
+ else:
78
+ painter.setPen(Qt.NoPen)
79
+ if self.fill_color is not None:
80
+ painter.setBrush(QBrush(QColor(self.fill_color)))
81
+ rect_to_plot = self.rect().adjusted(0, 0, 0, 0) # just a copy of the rect --> TODO maybe do it in a cleaner way
82
+
83
+ if parent is not None and parent.scale is not None and parent.scale != 1:
84
+ rect_to_plot = self.__get_scaled_rect(rect_to_plot, 1. / parent.scale)
85
+
86
+ if parent is not None:
87
+ rect_to_plot = rect_to_plot.translated(parent.topLeft())
88
+
89
+ # if self.scale is not None and self.scale != 1:
90
+ # # TODO KEEP THE ORDER THIS MUST BE DONE THIS WAY OR IT WILL GENERATE PLENTY OF BUGS...
91
+ # new_width = rect_to_plot.width() * self.scale
92
+ # new_height = rect_to_plot.height() * self.scale
93
+ # # 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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
94
+ # # 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!!!
95
+ # rect_to_plot.setX(rect_to_plot.x() * self.scale)
96
+ # rect_to_plot.setY(rect_to_plot.y() * self.scale)
97
+ # rect_to_plot.setWidth(new_width)
98
+ # rect_to_plot.setHeight(new_height)
99
+ # if self.translation is not None:
100
+ # rect_to_plot.translate(self.translation)
101
+
102
+ # if self.color is not None:
103
+ # painter.drawRect(rect_to_plot)
104
+ # else:
105
+ # painter.fillRect(rect_to_plot, QColor(self.fill_color))
106
+ if self.theta is not None and self.theta != 0:
107
+ painter.translate(rect_to_plot.center())
108
+ painter.rotate(self.theta)
109
+ painter.translate(-rect_to_plot.center())
110
+
111
+ painter.drawEllipse(rect_to_plot)
112
+ painter.restore()
113
+
114
+
115
+ def __get_scaled_rect(self, rect_to_plot, scale):
116
+ rect = QRectF(rect_to_plot.x()*scale, rect_to_plot.y()*scale, rect_to_plot.width()*scale, rect_to_plot.height()*scale)
117
+ return rect
118
+
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.rect())
129
+ # painter.restore()
130
+ #
131
+ # # TODO pb will draw the shape twice.... ---> because painter drawpolygon is called twice
132
+ #
133
+ # def drawAndFill(self, painter):
134
+ # painter.save()
135
+ # self.draw(painter, draw=False)
136
+ # self.fill(painter, draw=False)
137
+ # painter.drawEllipse(self.rect())
138
+ # painter.restore()
139
+
140
+ def translate(self, *translation):
141
+ # if isinstance(translation[0], (QPointF, QPoint)):
142
+
143
+ # print('translation szouba', translation)
144
+
145
+ if isinstance(translation[0], (int, float)):
146
+ translation = QPointF(translation[0], translation[1])
147
+
148
+ if isinstance(translation, tuple):
149
+ # 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
150
+ translation= QPointF(translation[0])
151
+
152
+ # print('zoubi', type(translation))
153
+
154
+ self.moveBy(translation.x(), translation.y())
155
+ rect = self.rect()
156
+ rect.translate(translation.x(), translation.y())
157
+ self.setRect(rect)
158
+
159
+
160
+ def add(self, *args):
161
+ p1 = args[0]
162
+ p2 = args[1]
163
+ rect = self.rect()
164
+ rect.setWidth(abs(p1.x()-p2.x()))
165
+ rect.setHeight(abs(p1.y()-p2.y()))
166
+ x = p2.x()
167
+ y = p2.y()
168
+ if p1.x() < p2.x():
169
+ x = p1.x()
170
+ if p1.y() < p2.y():
171
+ y = p1.y()
172
+ rect.setX(x)
173
+ rect.setY(y)
174
+
175
+ self.setRect(rect)
176
+ # self.isSet = True
177
+
178
+ def boundingRect(self):
179
+ # should I return the scaled version or the orig --> think about it...
180
+ rect_to_plot = self.rect().adjusted(0, 0, 0, 0)
181
+ try:
182
+ # print('tada')
183
+ if self.theta is not None and self.theta!=0:
184
+ # print('entering')
185
+ center = rect_to_plot.center()
186
+ # print('entering2')
187
+ t = QTransform().translate(center.x(), center.y()).rotate(self.theta).translate(-center.x(),
188
+ -center.y())
189
+ # print('entering3')
190
+ # self.setTransform(t)
191
+ # self.transform()
192
+
193
+
194
+ # transformed = QRectF(self.rect())
195
+ # print('entering5', transformed)
196
+ # self.resetTransform()
197
+ # print('entering5', rect_to_plot)
198
+ # print('entering4')
199
+ transformed = t.mapRect(rect_to_plot)
200
+
201
+ # self.setTransform(t)
202
+ # self.transform()
203
+ #
204
+ # print(self.shape().boundingRect())
205
+ #
206
+ # # print(self.rect(), transformed)
207
+ #
208
+ # transformed = QRectF(self.shape().boundingRect())
209
+ # # self.resetTransform()
210
+
211
+ # not perfect but ok for now though --> bounds are not sharp at the edges upon rotation
212
+ # print('entering45', transformed)
213
+ return transformed
214
+ except:
215
+ pass
216
+ return rect_to_plot
217
+
218
+ # def get_P1(self):
219
+ def topLeft(self):
220
+ return self.boundingRect().topLeft()
221
+
222
+ def setTopLeft(self, point):
223
+ # TODO
224
+ # def set_P1(self, point):
225
+ rect = self.rect()
226
+ width = rect.width()
227
+ height = rect.height()
228
+ rect.setX(point.x())
229
+ rect.setY(point.y())
230
+ # required due to setX changing width and sety changing height
231
+ rect.setWidth(width)
232
+ rect.setHeight(height)
233
+ self.setRect(rect)
234
+
235
+ def set_to_scale(self, factor):
236
+ self.scale = factor
237
+
238
+ def set_to_translation(self, translation):
239
+ self.translation = translation
240
+
241
+ def __repr__(self):
242
+ class_name = type(self).__name__
243
+ memory_address = hex(id(self))
244
+ return f"{class_name}-{memory_address}"
245
+
246
+ def getRect(self, *args, **kwargs):
247
+ # if args or kwargs:
248
+ # # print('I am called')
249
+ # rect = QRectF(self.x(), self.y(), self.width() / self.scale, self.height() / self.scale)
250
+ # rect = rect.translated(rect.width()/2., rect.height()/2.)
251
+ # # rect.setX(rect.x()-rect.width()/2.)
252
+ # # rect.setY(rect.y()-rect.height()/2.)
253
+ # return rect
254
+ # else:
255
+ # # return super().getRect()
256
+ # return QRectF(*super().getRect())
257
+ return self.boundingRect()
258
+
259
+ def x(self, *args, **kwargs):
260
+ return self.boundingRect().x()
261
+
262
+ def y(self, *args, **kwargs):
263
+ return self.boundingRect().y()
264
+
265
+ def width(self, *args, **kwargs):
266
+ # if args or kwargs:
267
+ # return self.width() / self.scale
268
+ # else:
269
+ # return self.rect().width()
270
+ return self.boundingRect().width()
271
+
272
+ def height(self, *args, **kwargs):
273
+ # if args or kwargs:
274
+ # return self.height() / self.scale
275
+ # else:
276
+ # # return super().height()
277
+ # return self.rect().height()
278
+ return self.boundingRect().height()
279
+
280
+ def to_dict(self):
281
+ x = self.rect().x()
282
+ y = self.rect().y()
283
+ width = self.rect().width()
284
+ height = self.rect().height()
285
+
286
+ # Create a dictionary representation of the values of the super object
287
+ output_dict = {
288
+ 'x': x,
289
+ 'y': y,
290
+ 'width': width,
291
+ 'height': height,
292
+ }
293
+ # Update the dictionary with the __dict__ of Rectangle2D
294
+ output_dict.update(self.__dict__)
295
+ return output_dict
296
+
297
+
298
+ if __name__ == '__main__':
299
+ # ça marche --> voici deux examples de shapes
300
+ test = Ellipse2D(0, 0, 100, 100)
301
+ # print(test.x(), test.y(), test.width(), test.height())
302
+ print(test.contains(QPointF(50, 50)))
303
+ print(test.contains(QPointF(15, 15)))
304
+ print(test.contains(QPointF(-1, -1)))
305
+ print(test.contains(QPointF(0, 0)))
306
+ print(test.contains(QPointF(100, 100)))
307
+ print(test.contains(QPointF(100, 100.1)))
308
+ print(test.x())
309
+ print(test.y())
310
+ print(test.translate(QPoint(10, 10)))
311
+ print(test.x())
312
+ print(test.y())
313
+
314
+ # p1 = test.p1()
315
+ # print(p1.x(), p1.y())
316
+ # p2 = test.p2()
317
+ # print(p2.x(), p2.y())
318
+ # print(test.arrow)
319
+ # print(test.length()) # sqrt 2 --> 141
320
+ # # if it's an arrow I can add easily all the stuff I need
321
+ #
322
+ # test = Rect2D(0, 0, 1, 1)
323
+ # p1 = test.p1()
324
+ # print(p1.x(), p1.y())
325
+ # p2 = test.p2()
326
+ # print(p2.x(), p2.y())
327
+ # print(test.arrow)
328
+ # import math
329
+ # print(test.length() == math.sqrt(2)) # sqrt 2
330
+ #
331
+ # test2 = Rect2D()
332
+ # p1 = test2.p1()
333
+ # print(p1.x(), p1.y())
334
+ # p2 = test2.p2()
335
+ # print(p2.x(), p2.y())
336
+ # print(test2.arrow)