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,1830 @@
1
+ # this seems to work better and better !!!
2
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
3
+ set_UI()
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ # from batoolset.draw.shapes.vectorgraphics2d import VectorGraphics2D
7
+ from batoolset.img import Img
8
+ from batoolset.lists.tools import move_left, move_right, is_iterable
9
+ import random
10
+ import sys
11
+ import traceback
12
+ # this will replace cols or rows and will be able to do both but more flexibly
13
+ from timeit import default_timer as timer
14
+ from batoolset.serialization.tools import create_objects_from_dict
15
+ from batoolset.draw.shapes.image2d import Image2D
16
+ from batoolset.draw.shapes.rectangle2d import Rectangle2D
17
+ from batoolset.draw.shapes.txt2d import TAText2D
18
+ from qtpy.QtCore import QRectF, QSizeF,QPointF
19
+ from qtpy.QtWidgets import QApplication
20
+ from qtpy.QtGui import QPainter, QColor, QBrush, QPen, QTransform
21
+ from batoolset.figure.alignment import pack2, align2, align_positions
22
+ from batoolset.tests.tools import are_ratios_almost_equal
23
+ from batoolset.draw.shapes.compute_optimal_size_all_merged import resize_rects_within_total_width, \
24
+ resize_rects_within_total_height
25
+
26
+ ORIENTATIONS = ["X","Y"] #,"grid"
27
+
28
+ def get_all_contained_images(obj):
29
+ """
30
+ Returns a list of all iterable elements in the given object.
31
+ """
32
+ # print(is_iterable(obj), obj)
33
+ if is_iterable(obj):
34
+ # obj is an iterable, so iterate over its elements
35
+ elements = []
36
+ for element in obj:
37
+ elements.extend(get_all_contained_images(element))
38
+ # if not elements:
39
+ # return None
40
+ return elements
41
+ else:
42
+ # obj is not an iterable, so return an empty list
43
+ return [obj]
44
+ # if not inner_elements:
45
+ # return None
46
+
47
+
48
+ # def get_imprecision2(grp, desired_size):
49
+ # if grp.orientation == 'X':
50
+ # take the first immutable stuff
51
+ def get_iterable_elements(obj):
52
+ """
53
+ Returns a list of all iterable elements in the given object.
54
+ """
55
+
56
+ # print(is_iterable(obj), obj)
57
+ if is_iterable(obj):
58
+ # obj is an iterable, so iterate over its elements
59
+ elements = [obj]
60
+ for element in obj:
61
+ elements.extend(get_iterable_elements(element))
62
+ # if not elements:
63
+ # return None
64
+ return elements
65
+ else:
66
+ # obj is not an iterable, so return an empty list
67
+ return []
68
+
69
+
70
+ def get_parent_of_obj(obj, shapes_to_draw):
71
+ if not shapes_to_draw:
72
+ return
73
+ if not isinstance(shapes_to_draw, list):
74
+ shapes_to_draw=[shapes_to_draw]
75
+
76
+ for shape in shapes_to_draw:
77
+ iterables = get_iterable_elements(shape)
78
+ if iterables:
79
+ for itr in iterables:
80
+ if obj in itr:
81
+ return itr
82
+
83
+
84
+ # def get_imprecision(grp, desired_size=None):
85
+ # # first = grp[0]
86
+ # # last = grp[-1]
87
+ #
88
+ # # print('first.immutable',first.immutable, last.immutable)
89
+ # #
90
+ # # if first.immutable:
91
+ # # for elm in grp:
92
+ # # if not elm.immutable:
93
+ # # first=elm
94
+ # # break
95
+ # # if last.immutable:
96
+ # # for elm in grp[::-1]:
97
+ # # if not elm.immutable:
98
+ # # last=elm
99
+ # # break
100
+ # #
101
+ # # print('first',first, grp.content[1]) -−> indeed I cannot use that
102
+ #
103
+ # # imprecisionX = abs(first.getRect().height() - last.getRect().height())
104
+ # # imprecisionY = abs(first.getRect().width() - last.getRect().width())
105
+ # # imprecision = min(abs(imprecisionX), abs(imprecisionY))
106
+ # if desired_size:
107
+ # imprecisionX = abs(grp.getRect().height() - desired_size)
108
+ # imprecisionY = abs(grp.getRect().width() -desired_size)
109
+ # else:
110
+ # imprecisionX = abs(grp.getRect().height() - int(round(grp.getRect().height())))
111
+ # imprecisionY = abs(grp.getRect().width() - int(round(grp.getRect().width())))
112
+ #
113
+ # imprecision = min(abs(imprecisionX), abs(imprecisionY))
114
+ #
115
+ # print('imprecision in pixels X', imprecisionX)
116
+ # print('imprecision in pixels Y', imprecisionY)
117
+ # print('imprecision', imprecision)
118
+
119
+ # def set_to_size_old(grp, size, nb_of_repeats=26):
120
+ # # even at 100 I get a small imprecision -−> maybe forget about that shit and take 26 always # dirty but ok for now -> I have bigger things to fix --> I tried 100 and it is perfect but 10 already seems to be enough --> maybe that is ok then --> even 3 is ok
121
+ # # for some reason the stuff needs to be run several times to converge --> maybe some day I'll get the reason but it is ok and does not take time to do so!!!
122
+ # for i in range(nb_of_repeats):
123
+ # grp.set_to_size_old(size)
124
+ # grp.size = size
125
+
126
+ def set_to_size(grp, size, nb_of_repeats=26):
127
+ # even at 100 I get a small imprecision -−> maybe forget about that shit and take 26 always # dirty but ok for now -> I have bigger things to fix --> I tried 100 and it is perfect but 10 already seems to be enough --> maybe that is ok then --> even 3 is ok
128
+ # for some reason the stuff needs to be run several times to converge --> maybe some day I'll get the reason but it is ok and does not take time to do so!!!
129
+ for i in range(nb_of_repeats):
130
+ grp.set_to_size(size)
131
+ # grp.size = size
132
+
133
+
134
+ def set_to_width(grp, desired_width, nb_of_repeats=26):
135
+ # in fact that was not so hard to do
136
+ # Calculate the current aspect ratio of the object
137
+
138
+ if grp.orientation != 'X':
139
+ for i in range(nb_of_repeats):
140
+
141
+ current_width = grp.getRect(all=True).width()
142
+ current_height = grp.getRect(all=True).height()
143
+
144
+ # print('falbala',current_width, current_height, desired_width)
145
+ if current_width < 0 or current_height<0:
146
+ # TODO --> KEEP DEV NOTE THIS PREVENTS INFINITE LOOPS WITH NEGATIVE VALUES
147
+ #
148
+ # current_width = grp.getRect().width()
149
+ # current_height = grp.getRect().height()
150
+ # print('falbala fixed', current_width, current_height, desired_width)
151
+ current_width = 512
152
+ current_height = 512
153
+
154
+ aspect_ratio = current_height / current_width if current_width != 0 else 0
155
+
156
+ factor_from_current_width_to_desired_width = desired_width/current_width
157
+ desired_height = current_height * factor_from_current_width_to_desired_width
158
+
159
+ # corresponding_desired_height = current_width * aspect_ratio
160
+
161
+ # corresponding_desired_height = current_width*aspect_ratio
162
+ # factor_from_current_width_to_predicted_height = corresponding_desired_height/
163
+
164
+ grp.set_to_size(desired_height)
165
+ grp.size = grp.width()
166
+
167
+ # print('aspect_ratio CURRENT CHECK ', aspect_ratio, grp.getRect(), desired_width, desired_height)
168
+ else:
169
+ set_to_size(grp, desired_width, nb_of_repeats=nb_of_repeats)
170
+ grp.size = grp.width()
171
+
172
+ def set_to_height(grp, desired_height, nb_of_repeats=26):
173
+ if grp.orientation != 'Y':
174
+ for i in range(nb_of_repeats):
175
+ current_width = grp.getRect(all=True).width()
176
+ current_height = grp.getRect(all=True).height()
177
+
178
+ # print('falbala',current_width, current_height, desired_width)
179
+ if current_width < 0 or current_height<0:
180
+ # TODO --> KEEP DEV NOTE THIS PREVENTS INFINITE LOOPS WITH NEGATIVE VALUES
181
+ #
182
+ # current_width = grp.getRect().width()
183
+ # current_height = grp.getRect().height()
184
+ # print('falbala fixed', current_width, current_height, desired_width)
185
+ current_width = 512
186
+ current_height = 512
187
+
188
+ aspect_ratio = current_width / current_height if current_height != 0 else 0
189
+
190
+ factor_from_current_height_to_desired_height = desired_height / current_height
191
+ desired_width = current_width * factor_from_current_height_to_desired_height
192
+
193
+ grp.set_to_size(desired_width)
194
+ grp.size = grp.height()
195
+
196
+ # print('aspect_ratio CURRENT CHECK ', aspect_ratio, grp.getRect(), desired_width, desired_height)
197
+ else:
198
+ set_to_size(grp, desired_height, nb_of_repeats=nb_of_repeats)
199
+ grp.size = grp.height()
200
+
201
+
202
+ # Calculate the new height based on the desired width and the aspect ratio
203
+ # new_height = desired_width * aspect_ratio
204
+ def set_to_width_im2d(rect, desired_width):
205
+ current_width = rect.width()
206
+ current_height = rect.height()
207
+ aspect_ratio = current_height / current_width if current_width != 0 else 0
208
+
209
+ factor_from_current_width_to_desired_width = desired_width / current_width
210
+ desired_height = current_height * factor_from_current_width_to_desired_width
211
+
212
+ # corresponding_desired_height = current_width * aspect_ratio
213
+
214
+ rect.set_to_scale(current_width / desired_width)
215
+ # corresponding_desired_height = current_width*aspect_ratio
216
+ # factor_from_current_width_to_predicted_height = corresponding_desired_height/
217
+ # grp.set_to_size(desired_height)
218
+ # return new_rect
219
+
220
+ def set_to_height_im2d(rect, desired_height):
221
+ # current_width = rect.width()
222
+ # current_height = rect.height()
223
+ # aspect_ratio = current_width / current_height if current_height != 0 else 0
224
+ #
225
+ # desired_width = current_width * (desired_height / current_height)
226
+ # rect.set_to_scale(1./(desired_width/desired_height))
227
+
228
+ current_width = rect.width()
229
+ current_height =rect.height()
230
+ aspect_ratio = current_width / current_height if current_height != 0 else 0
231
+
232
+ factor_from_current_height_to_desired_height = desired_height / current_height
233
+ desired_width = current_width * factor_from_current_height_to_desired_height
234
+
235
+ # grp.set_to_size(desired_width)
236
+ rect.set_to_scale(current_height/desired_height)
237
+
238
+ # new_rect = QRectF(rect.x(), rect.y(), desired_width, desired_height)
239
+
240
+ # return new_rect
241
+
242
+ # def set_to_width(grp, size, nb_of_repeats=26):
243
+ # for i in range(nb_of_repeats):
244
+ # grp.set_to_size(size)
245
+
246
+ def areIndicesOverlapping(indices_of_all_shapes):
247
+
248
+ # Iterate over the indices_of_all_shapes list
249
+ for i in range(len(indices_of_all_shapes) - 1):
250
+ # Get the current and next elements
251
+ curr = indices_of_all_shapes[i]
252
+ next = indices_of_all_shapes[i + 1]
253
+
254
+ # print('curr, next', curr, next)
255
+
256
+ # Check if the elements overlap
257
+ if curr[1] >= next[0]:
258
+ # print('Overlap found between elements', i, 'and', i + 1)
259
+ return True
260
+ return False
261
+
262
+
263
+ class Group(Rectangle2D):
264
+ _count=0 # this is a class variable
265
+
266
+ # NB maybe is text could contain the text position instead of true such as above or below --> and it would adjust to stuff below it --> TODO
267
+ def __init__(self, *args, space=3, x=None,y=None, width=None, height=None, fill_color=None, content=None, orientation=ORIENTATIONS[0], size=512, isText=False, add_empty_images_instead_of_None=True,**kwargs): # TODO DO NOT CALL IT ORIENTATION AS IT CAN BE MIXED WITH ANGLE -−> NEED SMARTER NAME
268
+ # if kwargs:
269
+ # print('ignored parameters', kwargs)
270
+
271
+ if x is not None and y is not None and width is not None and height is not None:
272
+ super(Rectangle2D, self).__init__(x,y,width,height)
273
+ else:
274
+ super(Rectangle2D, self).__init__()
275
+
276
+ # if self.width() == 0 and self.height==0:
277
+ # self.setWidth(size)
278
+ # self.setHeight(size)
279
+
280
+
281
+ # in fact I need to reload content
282
+
283
+
284
+ self.content = []
285
+ self.space = space
286
+ self.orientation=orientation
287
+ if args:
288
+ for arg in args:
289
+ if isinstance(arg, str):
290
+ arg = Image2D(arg) # TODO --> need make this smarter especially with custom code files
291
+ if arg is None and add_empty_images_instead_of_None:
292
+ if self.content:
293
+ last = self.content[-1]
294
+ if isinstance(last, Image2D):
295
+ w,h = last.get_raw_size()
296
+ tmp = Image2D(width=w, height=h, crop_left=last.crop_left, crop_right=last.crop_right,crop_top=last.crop_top,crop_bottom=last.crop_bottom, theta=last.theta) # a true clone of the last
297
+ self.content.append(tmp)
298
+ else:
299
+ if arg is not None:
300
+ self.content.append(arg)
301
+
302
+ if isinstance(content, dict):
303
+ # Reload content from serialized object
304
+ content = create_objects_from_dict(content)
305
+ self.content.extend(content)
306
+
307
+ # print(self.content)
308
+ # if size is not None:
309
+ self.size = size # maybe useful and I need to store that ??? -−> the good thing is that it will not change and so it is better
310
+ # set_to_size(self,size) # shall I use that ??? --> maybe ...
311
+ self.set_to_size(self.size) # very good but maybe I also need to update it
312
+ set_to_width(self, self.size) # for now force size in x only to simplify things
313
+ Group._count += 1
314
+ self.ID = Group._count
315
+ self.fill_color = fill_color
316
+ self.immutable = False
317
+ self.isText = isText # this is just for pure text groups (will have a different behaviour on double click)
318
+ # self.scale = 1
319
+
320
+ @classmethod
321
+ def reset_count(cls):
322
+ cls._count = 0
323
+
324
+ # List-like behavior
325
+ def __getitem__(self, key):
326
+ # print(key)
327
+ return self.content[key]
328
+
329
+ def __len__(self):
330
+ return len(self.content)
331
+
332
+ def __iter__(self):
333
+ return iter(self.content)
334
+
335
+ def index(self, item):
336
+ return self.content.index(item)
337
+ # def __delitem__(self, index):
338
+ # del self[index]
339
+ #
340
+ def remove(self, *value):
341
+
342
+ try:
343
+
344
+ # print('stuff to be removed', value)
345
+
346
+ # del self.content(value)
347
+ # idx = self.content.index(value)
348
+ # del self[idx]
349
+ # self.content.remove(value)
350
+ # self.content = [x for x in self.content if x not in value]
351
+ for element in value:
352
+ try:
353
+ self.content.remove(element)
354
+ except:
355
+ pass
356
+ for inner in self.content:
357
+ try:
358
+ inner.remove(*value)
359
+ if inner.isEmpty():
360
+ self.content.remove(inner)
361
+ except:
362
+ pass
363
+
364
+ if not self.isEmpty():
365
+ try:
366
+ # print('resizing', self, self.content)
367
+ set_to_size(self,self.width() if self.orientation == 'X' else self.height())
368
+ except:
369
+ # print('just for info for now, comment that lines in the future')
370
+ traceback.print_exc()
371
+ print('just for info for now, comment that lines in the future')
372
+ pass
373
+ # i need go through all the stuff inside --> not that easy
374
+ # shall I resize it ??? TODO --> PROBABLY YES BECAUSE SIMPLER
375
+
376
+ except:
377
+ traceback.print_exc()
378
+ pass
379
+
380
+ def update(self):
381
+ try:
382
+ if not self.isEmpty():
383
+ # print('updating', self, self.content)
384
+ # set_to_size(self, self.width() if self.orientation == 'X' else self.height())
385
+ set_to_size(self, self.size)
386
+ except:
387
+ traceback.print_exc()
388
+ print('just for info for now, comment that lines in the future')
389
+ pass
390
+
391
+ def isEmpty(self):
392
+ return not self.content
393
+
394
+ def pack(self):
395
+ pack2(self.space, self.orientation,False, *self.content)
396
+
397
+ def align(self):
398
+ if self.orientation == 'X':
399
+ align2(align_positions[0], *self.content) # align top
400
+ else:
401
+ align2(align_positions[2], *self.content) # align Left
402
+
403
+ def set_to_scale(self, scale):
404
+ # the set to scale should change the size of the object --> either in width or in height depending on the object
405
+ # TODO
406
+ # maybe need repack if it is a group
407
+
408
+
409
+ # print('I have been called', scale)
410
+
411
+ # the scale of this one has to be magic and launch many more stuff
412
+
413
+ if self.orientation == 'X':
414
+ self.set_to_size(self.width() / scale)
415
+ else:
416
+ self.set_to_size(self.height()/scale)
417
+ # self.scale = 1
418
+ # pass
419
+
420
+ # def set_to_size_neo(self, desired_size):
421
+ # all_ok=False
422
+ #
423
+ # for elm in self:
424
+ # if elm.isText:
425
+ # all_ok=True
426
+ # break
427
+ #
428
+ # # print('all_ok', all_ok)
429
+ #
430
+ # if not all_ok:
431
+ # return self.set_to_size_old(desired_size)
432
+ #
433
+ # if self.orientation == 'X':
434
+ # max_w = 0
435
+ # max_h = 0
436
+ # failed_images = []
437
+ # text_images = []
438
+ # individual_width = []
439
+ # individual_height = []
440
+ # for elm in self:
441
+ # # try:
442
+ # if elm.isText:
443
+ # individual_width.append(elm.annotations[0].width(all=True))
444
+ # individual_height.append(elm.annotations[0].height(all=True))
445
+ # max_w = max(elm.annotations[0].width(all=True), max_w)
446
+ # max_h = max(elm.annotations[0].height(all=True), max_h)
447
+ # text_images.append(elm)
448
+ # else:
449
+ # # pass # if fails this is not a text image
450
+ # failed_images.append(elm) # if image is failed then we have it
451
+ #
452
+ # # I need to fit to the desired width
453
+ # desired_width = desired_size
454
+ # target_width_without_txt = desired_width - sum(individual_width)
455
+ #
456
+ # # fit into a group with the desired stuff
457
+ #
458
+ # print('max_w, max_h', max_w, max_h)
459
+ # print('individual_width', individual_width)
460
+ # print('individual_height', individual_height)
461
+ # print('desired_width', desired_width)
462
+ # print('target_width_without_txt',
463
+ # target_width_without_txt) # it is probably a bit more complex because I need also the spacer and the nb of elems of the spacer inside and outside
464
+ # print('elems in', len(failed_images))
465
+ # print('elems out', len(self) - len(failed_images))
466
+ # # try to do the fit --> TODO
467
+ #
468
+ # # TODO --> pack to the size
469
+ # # incompressible_space_of_group = (len(self.paint.EZFIG_panel.selected_shape)-1)*3
470
+ # incompressible_space_of_group = (len(text_images)) * self.space
471
+ # target_width_without_txt -= incompressible_space_of_group
472
+ #
473
+ # # I need fit the stuff
474
+ #
475
+ # # create a sub group for the failed images and set its size
476
+ # tmp = Group(*failed_images, space=self.space, orientation='X', size=target_width_without_txt)
477
+ # set_to_width(tmp, target_width_without_txt)
478
+ #
479
+ # # then get the height of the group
480
+ #
481
+ # max_h = tmp.height()
482
+ # # put the other images back into their stuff and just launch the packing of the group
483
+ # # and resize the images to that size
484
+ #
485
+ # for iii, elm in enumerate(text_images):
486
+ # # elm.scale=1.
487
+ # elm.setHeight(max_h)
488
+ # elm.setWidth(individual_width[iii])
489
+ # elm.set_to_scale(1)
490
+ #
491
+ # self.pack()
492
+ # self.align()
493
+ # self.update_bounds()
494
+ # # self.update()
495
+ # else:
496
+ #
497
+ #
498
+ # print('entering orientation Y', self)
499
+ # # this works but the embeded does not --> why is that
500
+ #
501
+ # # i need to fit all the shapes without the stuff to the desired width then just readd the other stuff
502
+ #
503
+ # # I need get the height
504
+ #
505
+ # # ça marche --> ça donne un moyen facile de faire tout ce que je voulais
506
+ # # now we fix the code so that we fit the height of an object according to that of the others --> TODO
507
+ # max_w = 0
508
+ # max_h = 0
509
+ # failed_images = []
510
+ # text_images = []
511
+ # individual_width = []
512
+ # individual_height = []
513
+ # for elm in self:
514
+ # if elm.isText:
515
+ # individual_width.append(elm.annotations[0].width(all=True))
516
+ # individual_height.append(elm.annotations[0].height(all=True))
517
+ # max_w = max(elm.annotations[0].width(all=True), max_w)
518
+ # max_h = max(elm.annotations[0].height(all=True), max_h)
519
+ # text_images.append(elm)
520
+ # else:
521
+ # # pass # if fails this is not a text image
522
+ # failed_images.append(elm) # if image is failed then we have it
523
+ #
524
+ # # I need to fit to the desired width
525
+ # desired_width = desired_size # 256 #
526
+ # target_width_without_txt = desired_width # since it is a col it does not need all of that
527
+ #
528
+ # # fit into a group with the desired stuff
529
+ #
530
+ # print('max_w, max_h', max_w, max_h)
531
+ # print('individual_width', individual_width)
532
+ # print('individual_height', individual_height)
533
+ # print('desired_width', desired_width)
534
+ # print('target_width_without_txt',
535
+ # target_width_without_txt) # it is probably a bit more complex because I need also the spacer and the nb of elems of the spacer inside and outside
536
+ # print('elems in', len(failed_images))
537
+ # print('elems out', len(self) - len(failed_images))
538
+ # # try to do the fit --> TODO
539
+ #
540
+ # # TODO --> pack to the size
541
+ # # incompressible_space_of_group = (len(self.paint.EZFIG_panel.selected_shape)-1)*3
542
+ # incompressible_space_of_group = (len(text_images)) * 3
543
+ # # target_width_without_txt -= incompressible_space_of_group
544
+ #
545
+ # # I need fit the stuff
546
+ #
547
+ # # create a sub group for the failed images and set its size
548
+ # tmp = Group(*failed_images, space=3, orientation='X')
549
+ # set_to_width(tmp, target_width_without_txt)
550
+ #
551
+ # # then get the height of the group
552
+ #
553
+ # max_w = tmp.width()
554
+ # # put the other images back into their stuff and just launch the packing of the group
555
+ # # and resize the images to that size
556
+ #
557
+ # for iii, elm in enumerate(text_images):
558
+ # # elm.scale=1.
559
+ # elm.setHeight(individual_height[iii])
560
+ # elm.setWidth(max_w)
561
+ # elm.set_to_scale(1)
562
+ #
563
+ #
564
+ #
565
+ # # del tmp
566
+ # # just pack the shape and nothing else and set x to 0
567
+ # # align top and pack
568
+ # # self.paint.EZFIG_panel.selected_shape.pack()
569
+ # # self.paint.EZFIG_panel.selected_shape.align()
570
+ # # self.paint.EZFIG_panel.selected_shape.update_bounds()
571
+ #
572
+ # set_to_width(self, target_width_without_txt)
573
+ #
574
+ # print('inner update', self.update_bounds())
575
+
576
+ def set_to_size(self, desired_size):
577
+ sum_along_axis = self.get_incompressible_size(axis=self.orientation)
578
+ if self.orientation == 'X':
579
+ resize_rects_within_total_width(self.content, desired_size, sum_along_axis)
580
+ # resize_rects_within_total_width(self.content, desired_size, self.space)
581
+ else:
582
+ # resize_rects_within_total_height(self.content, desired_size, self.space)
583
+ resize_rects_within_total_height(self.content, desired_size, sum_along_axis)
584
+
585
+
586
+ # if True:
587
+ # print('beforesdsqdq0')
588
+ # self.check_coords()
589
+
590
+ self.pack()
591
+ # if True:
592
+ # print('beforesdsqdq1')
593
+ # self.check_coords()
594
+
595
+ self.align()
596
+ # if True:
597
+ # print('beforesdsqdq2')
598
+ # self.check_coords()
599
+ self.update_bounds()
600
+
601
+ # def set_to_size_old(self, desired_size):
602
+ # # for i in range(100): # weird but somehow I need a convergence and iteration stuff (is that due to a bug, can I iterate in a smarter manner) ???
603
+ # # print('entering the real shit')
604
+ # sum_along_axis = self.get_incompressible_size(axis=self.orientation)
605
+ # if self.orientation == 'X':
606
+ # resize_rects_within_total_width(self.content, desired_size, sum_along_axis)
607
+ # # resize_rects_within_total_width(self.content, desired_size, self.space)
608
+ # else:
609
+ # # resize_rects_within_total_height(self.content, desired_size, self.space)
610
+ # resize_rects_within_total_height(self.content, desired_size, sum_along_axis)
611
+ #
612
+ # # if True:
613
+ # # print('beforesdsqdq0')
614
+ # # self.check_coords()
615
+ #
616
+ # self.pack()
617
+ # # if True:
618
+ # # print('beforesdsqdq1')
619
+ # # self.check_coords()
620
+ #
621
+ # self.align()
622
+ # # if True:
623
+ # # print('beforesdsqdq2')
624
+ # # self.check_coords()
625
+ # self.update_bounds()
626
+
627
+ def check_coords(self):
628
+ for iii,img in enumerate(self):
629
+ print('iii', iii, '-->', img.getRect())
630
+
631
+ def checkAR(self):
632
+ for iii, rect in enumerate(self.content):
633
+ print(are_ratios_almost_equal(rect.width() / rect.height(), rect.width(all=True) / rect.height(all=True)), 'old AR', rect.width() / rect.height(), 'new AR', rect.width(all=True) / rect.height(all=True))
634
+
635
+ # NB THE RECT AND WIDTH OF GROUP SHOULD NOT BE SCALABLE !!! --> see how I can do this in a cleaner way !!!!
636
+ def getRect(self,*args, **kwargs):
637
+ # if args or kwargs:
638
+ return QRectF(self.x(), self.y(), self.width(), self.height())
639
+ # else:
640
+ # # return super().getRect()
641
+ # return QRectF(*super().getRect())
642
+ def width(self,*args, **kwargs):
643
+ # return self.width()
644
+ # else:
645
+ return super().width()
646
+
647
+ def height(self,*args, **kwargs):
648
+ # if args or kwargs:
649
+ # return self.height()
650
+ # else:
651
+ return super().height()
652
+
653
+ def update_bounds(self):
654
+ # Initialize bounding_rect with maximum and minimum values
655
+ bounding_rect = [float('inf'), float('inf'), float('-inf'), float('-inf')]
656
+
657
+ for rect in self.content:
658
+ bounding_rect[0] = min(bounding_rect[0], rect.x())
659
+ bounding_rect[1] = min(bounding_rect[1], rect.y())
660
+ bounding_rect[2] = max(bounding_rect[2], rect.x() + rect.width(all=True))
661
+ bounding_rect[3] = max(bounding_rect[3], rect.y() + rect.height(all=True))
662
+
663
+ self.setRect(bounding_rect[0], bounding_rect[1], bounding_rect[2] - bounding_rect[0],
664
+ bounding_rect[3] - bounding_rect[1])
665
+ # print('bounding rect', self.getRect(scale=True))
666
+
667
+
668
+
669
+
670
+ def getCombinedBoundsAtIndices(self, image_indices):
671
+ if not image_indices:
672
+ return None
673
+ # if isinstance(image_indices, int):
674
+ # in
675
+ # for each there will be a begin and an end
676
+ begin, end = image_indices
677
+ # if begin == end:
678
+ # print('same begin and end')
679
+
680
+ # print('begin, end', begin, end)
681
+
682
+
683
+
684
+ # how can I keep assocition despite serialization --> by storing the element into another --> but that would complicate a bit the things though -−> see how I can do that
685
+ # or just say if it should be associated to above or below ????
686
+ if begin>end: # begin should always be before end
687
+ begin, end = end, begin
688
+
689
+ if begin<0:
690
+ begin = 0
691
+ if end>=len(self.content):
692
+ end = len(self.content)-1
693
+ if end<0:
694
+ end=0
695
+
696
+ if begin>=0 and begin<len(self.content):
697
+ begin_rect = self.content[begin].getRect(all=True)
698
+ # print('begin_rect',begin_rect)
699
+ if begin==end:
700
+ return begin_rect
701
+ if end>=0 and end < len(self.content):
702
+ end_rect = self.content[end].getRect(all=True)
703
+ # print('end_rect',end_rect)
704
+
705
+ try:
706
+ return begin_rect.united(end_rect) # this returns the combined rect of begin and end coordinates -−> that is exactly what I want
707
+ except:
708
+ return None
709
+
710
+
711
+
712
+ # untested
713
+ def translate(self, *args):
714
+ if len(args) == 1:
715
+ point = args[0]
716
+ QRectF.translate(self, point.x(), point.y())
717
+ for img in self:
718
+ img.translate(point.x(), point.y())
719
+ else:
720
+ QRectF.translate(self, args[0], args[1])
721
+ for img in self:
722
+ img.translate(QPointF(args[0], args[1]))
723
+
724
+ # def swap(self, element1, element2): # so in fact it is not a swap it is a replace
725
+ # find element1 and replace it with element2
726
+ # swap can be seen as a chain of replace with inverting one by the other
727
+
728
+ # def replace(self, element1, element2):
729
+ # pass
730
+
731
+ # def swap(self, element1, element2):
732
+ # loop
733
+ # if not isinstance(__args[0], QPointF):
734
+ # for elm in self.content:
735
+ # if elm == __args[0]:
736
+ # return True
737
+ # if elm.contains(__args[0]):
738
+ # return True
739
+ # else:
740
+ # if super().contains(
741
+ # *__args): # if anything in there contains the point return the containing element else return False
742
+ # for elm in self.content:
743
+ # if elm.contains(*__args):
744
+ # return elm
745
+ # return True
746
+ # return False
747
+
748
+ def move_left(self, elements, distance=1):
749
+ if elements is None:
750
+ return
751
+ if distance <=0:
752
+ return
753
+ if not isinstance(elements, list):
754
+ elements = [elements]
755
+
756
+ list_of_iterables = get_iterable_elements(self)
757
+ for elm in list_of_iterables:
758
+ indices = [i for i, x in enumerate(elm.content) if x in elements]
759
+ elm.content = move_left(elm.content, indices, distance) # get indices
760
+
761
+
762
+ # TODO --> do it recursive inside -−> TODO
763
+
764
+
765
+ def move_right(self, elements, distance=1):
766
+ if elements is None:
767
+ return
768
+ if distance <=0:
769
+ return
770
+ if not isinstance(elements, list):
771
+ elements = [elements]
772
+ # indices = [i for i, x in enumerate(self.content) if x in elements]
773
+ # self.content = move_right(self.content, indices, distance) # get indices
774
+ list_of_iterables = get_iterable_elements(self)
775
+ for elm in list_of_iterables:
776
+ indices = [i for i, x in enumerate(elm.content) if x in elements]
777
+ elm.content = move_right(elm.content, indices, distance) # get indices
778
+
779
+ def draw_inner_layout_selection(self, painter):
780
+ painter.save()
781
+ try:
782
+ inner_elements = get_all_contained_images(self)
783
+ # painter.setPen(QPen(QColor(0, 255, 255)))
784
+
785
+ for elm in inner_elements:
786
+ # rect = elm.getRect(scale=True)
787
+ # painter.drawRect(rect)
788
+ elm.draw_inner_layout_selection(painter)
789
+ except:
790
+ print('inner error')
791
+ traceback.print_exc()
792
+ painter.restore()
793
+
794
+
795
+ def draw(self, painter, draw=True):
796
+
797
+ if draw:
798
+ painter.save()
799
+ rect_to_plot = self.getRect()
800
+ if self.fill_color is not None:
801
+ # if the user wants to really draw a bg with a given color between the images -−> then I draw this first before drawing anything else
802
+ painter.setBrush(QBrush(QColor(self.fill_color)))
803
+ painter.drawRect(rect_to_plot)
804
+
805
+ for img in self:
806
+ img.draw(painter, draw=draw)
807
+
808
+ painter.restore()
809
+
810
+ # debug
811
+ if False:
812
+ pen = QPen(QColor(0xFF00FF))
813
+ pen.setWidthF(3)
814
+ painter.setPen(pen)
815
+
816
+ # print('rect_to_plot',rect_to_plot)
817
+
818
+ painter.drawRect(rect_to_plot)
819
+
820
+ # as much as it is possible do get rid of fill to better organize the stuff
821
+ # def fill(self, painter, draw=True):
822
+ # if self.fill_color is None:
823
+ # return
824
+ # if draw:
825
+ # painter.save()
826
+ # for img in self:
827
+ # img.fill(painter, draw=draw)
828
+ # painter.restore()
829
+ #
830
+ # def drawAndFill(self, painter):
831
+ # painter.save()
832
+ # self.draw(painter, draw=True)
833
+ # painter.restore()
834
+
835
+ def get_incompressible_size(self, axis=None):
836
+ # return the meaningful incompressible state of the image
837
+ # pass
838
+ # if self.orientation == 'X':
839
+ # print('group_count', self._count)
840
+ if axis is None:
841
+ # print('sum_incompressible_along_axis2', self.space*(len(self.content)-1))
842
+ return self.space*(len(self.content)-1) # THAT IS NOT ENOUGH I ALSO NEED ALL THE PROGENY INCOMPRESSIBLE SPACE IN THIS ORIENTATION --> TODO
843
+ else:
844
+ sum_incompressible_along_axis = 0
845
+
846
+ # If I don't put the below line then the size works --> I am overestimating the stuff !!!
847
+ # for elm in self.content:
848
+ # sum_incompressible_along_axis+=elm.get_incompressible_size(axis=axis)
849
+ # for elm in self.content:
850
+ # sum_incompressible_along_axis+=elm.get_incompressible_size(axis=axis) # in fact I should not atke into account the others
851
+ if self.orientation == axis:
852
+ sum_incompressible_along_axis+=self.space*(len(self.content)-1)
853
+ # print('sum_incompressible_along_axis', axis, sum_incompressible_along_axis, len(self.content), self.space, self.orientation, self._count)
854
+ return sum_incompressible_along_axis
855
+
856
+ def setTopLeft(self, *args):
857
+ if args:
858
+ cur_top_left = self.topLeft()
859
+ # print('cur_top_left', cur_top_left, args)
860
+ if len(args)==1:
861
+ # # assume a QpointF
862
+ for img in self.content:
863
+ # img.moveTopLeft(args[0])
864
+ img.translate(args[0].x()-cur_top_left.x(), args[0].y()-cur_top_left.y())
865
+ elif len(args) == 2:
866
+ for img in self.content:
867
+ img.translate(args[0] - cur_top_left.x(), args[1] - cur_top_left.y())
868
+ self.update_bounds()
869
+ # elif len(args)==2:
870
+ # for img in self.content:
871
+ # img.moveTopLeft(QPointF(args[0], args[1]))
872
+ # else:
873
+ # # logger.error('invalid args for top left')
874
+ # print('invalid args for top left')
875
+
876
+ def replace(self, old, new): # NB THIS IS NOT RECURSIVE SO IT SHOULD BE USED ONLY WITH THE IMMEDIATE PARENT
877
+ if old in self.content:
878
+ self.content[self.content.index(old)]=new
879
+
880
+ def __contains__(self, item):
881
+ return item in self.content
882
+
883
+ def __setitem__(self, index, item):
884
+ self.content[index] = item
885
+
886
+ def contains(self, *__args):
887
+ # hacked contains that checks whether a point or an image is contained in the stuff
888
+ # see for images
889
+
890
+ # if not __args:
891
+ # return False
892
+ # if len(__args)==2:
893
+ # # check if an innner object contains a point and return it
894
+ # for elm in self.content:
895
+ # if elm.contains()
896
+ # else:
897
+ # if isinstance(__args[0],Rectangle2D):
898
+ # if self == __args[0]:
899
+ # return True
900
+ # else:
901
+ # return super().getRect(scale=True).contains(*__args)
902
+
903
+ if not isinstance(__args[0], QPointF):
904
+ for elm in self.content:
905
+ if elm == __args[0]:
906
+ # print('elm found by equal', elm, __args[0])
907
+ return True
908
+ try:
909
+ if __args[0] in elm: # I had to override contains in images to avoid issues
910
+ # print('elm found by other way', __args[0], elm, __args[0] in elm)
911
+ return True
912
+ except:
913
+ pass # if not iterable then anyway cannot contain the stuff
914
+ else:
915
+ if super().contains(*__args): # if anything in there contains the point return the containing element else return False
916
+ for elm in self.content:
917
+ if elm.contains(*__args):
918
+ return elm
919
+ return True
920
+ return False
921
+
922
+ def extend(self, lst):
923
+ try:
924
+ self.content.extend(lst)
925
+ except:
926
+ # self.content.add(lst) # in case it is not a list then just add is
927
+ self.add(lst)
928
+
929
+ def add(self, item):
930
+ self.content.append(item)
931
+
932
+ # be careful with that because this is what is compared when using == !!! so if poorly implemented this can have dramatic effects
933
+ def __str__(self):
934
+ # return f"group {self.ID}"
935
+ return self.__repr__()
936
+
937
+ def __repr__(self): # required to appear in the printed list
938
+ # return self.__str__()
939
+ class_name = type(self).__name__
940
+ memory_address = hex(id(self))
941
+ return f"{class_name}-{self.ID}-{memory_address}"
942
+
943
+
944
+
945
+ # probably the AR of the group should take into account the incompressible stuff --> this is why it is unfixed untill
946
+ # there is always a solution for 0 space --> how can I from the 0 space find all the other solutions???
947
+ if __name__ == '__main__':
948
+ img0 = Image2D('/E/Sample_images/counter/00.png')
949
+ img1 = Image2D('/E/Sample_images/counter/01.png')
950
+ img2 = Image2D('/E/Sample_images/counter/02.png')
951
+ img3 = Image2D('/E/Sample_images/counter/03.png')
952
+ img4 = Image2D('/E/Sample_images/counter/04.png')
953
+ img5 = Image2D('/E/Sample_images/counter/05.png')
954
+ img6 = Image2D('/E/Sample_images/counter/06.png')
955
+ img7 = Image2D('/E/Sample_images/counter/07.png')
956
+ img8 = Image2D('/E/Sample_images/counter/08.png')
957
+ img9 = Image2D('/E/Sample_images/counter/09.png')
958
+ img10 = Image2D('/E/Sample_images/counter/10.png')
959
+ img10b = Image2D('/E/Sample_images/counter/10.png')
960
+ if True:
961
+ grp1 = Group(Group(img0, img1, img2, img3), img4, Group(img5, Group(img6, img7, img8)), img9)
962
+ print(get_all_contained_images(grp1))
963
+ # print(get_iterable_elements(grp1))
964
+ sys.exit(0)
965
+
966
+ print('parent_of_obj',get_parent_of_obj(img9, grp1))
967
+ print('parent_of_obj',get_parent_of_obj(img4, grp1))
968
+ print('parent_of_obj',get_parent_of_obj(img0, grp1)) # there is a bug
969
+ print('parent_of_obj',get_parent_of_obj(img1, grp1))
970
+ print('parent_of_obj',get_parent_of_obj(img5, grp1))
971
+ print('parent_of_obj',get_parent_of_obj(img6, grp1))
972
+ print('parent_of_obj',get_parent_of_obj(img7, grp1))
973
+ print('parent_of_obj',get_parent_of_obj(img8, grp1))
974
+
975
+ sys.exit(0)
976
+
977
+
978
+
979
+ grp1 = Group(Group(img0,img1, img2, img3), img4, Group(img5, Group(img6, img7, img8)), img9)
980
+ # print('all_iterables',get_iterable_elements(grp1))
981
+ print(grp1.content)
982
+ print(grp1.content[0].content)
983
+ print(grp1.content[2].content)
984
+ print(grp1.content[2].content[1].content)
985
+ grp1.move_left([img1, img8, img9]) # really need to pass a list
986
+ print('out')
987
+ print(grp1.content)
988
+ print(grp1.content[0].content)
989
+ print(grp1.content[-1].content)
990
+ print(grp1.content[-1].content[1].content)
991
+ # print(grp1.content[2].content[1].content)
992
+ # print(grp1.content[2].content)
993
+ # print('bob')
994
+ grp1 = Group(img0,img1, img2, img3, img4,img5, img6, img7, img8, img9)
995
+ # print('all_iterables2', get_iterable_elements(grp1))
996
+
997
+
998
+
999
+
1000
+
1001
+ # sys.exit(0)
1002
+ print('old')
1003
+ grp1 = Group(img0, img1, img2, img3, img4, img5, img6, img7, img8, img9)
1004
+ print(grp1.content)
1005
+ grp1.move_left(img1) # really need to pass a list
1006
+ print(grp1.content)
1007
+ print('bob')
1008
+
1009
+
1010
+ grp1 = Group(img0, img1, img2, img3, img4, img5, img6, img7, img8, img9)
1011
+ print(grp1.content)
1012
+ grp1.move_left([img0, img1, img6])
1013
+ print(grp1.content)
1014
+
1015
+ grp1 = Group(img0, img1, img2, img3, img4, img5, img6, img7, img8, img9)
1016
+ print(grp1.content)
1017
+ grp1.move_right([img0, img1, img6])
1018
+ print(grp1.content)
1019
+
1020
+ print('with errors and missing')
1021
+ grp1 = Group(img0, img2, img3, img4, img5, img6, img7, img8, img9)
1022
+ print(grp1.content)
1023
+ grp1.move_left([img2, img1, img6])
1024
+ print(grp1.content)
1025
+
1026
+ grp1 = Group(img0, img2, img3, img4, img5, img6, img7, img8, img9)
1027
+ print(grp1.content)
1028
+ grp1.move_right([img0, img1, img6])
1029
+ print(grp1.content)
1030
+ grp1.move_right([img0, img1, img6])
1031
+ print(grp1.content)
1032
+ for i in range(10):
1033
+ grp1.move_right([img0, img1, img6])
1034
+ print(grp1.content)
1035
+ sys.exit(0)
1036
+
1037
+ if True:
1038
+
1039
+
1040
+
1041
+ grp1 = Group(img0, img1)
1042
+ print(isinstance(grp1, list))
1043
+ print(isinstance(grp1, Group)) # very good
1044
+ grp2 = Group(img2, img3)
1045
+ grp1.extend(grp2)
1046
+ print(grp1.content)
1047
+ grp1.extend(img10b)
1048
+ print(grp1.content)
1049
+
1050
+
1051
+
1052
+
1053
+ grp3 = Group(img4, img5)
1054
+ grp4 = Group(img6, img7)
1055
+ grp3.add(grp4)
1056
+ print(grp3.content)
1057
+
1058
+ grp5 = Group(img8, img9, img10)
1059
+ grp5.remove(img10)
1060
+ print(grp5.content)
1061
+
1062
+ grp5.add(Group(img10))
1063
+ print(grp5.content)
1064
+ grp5.remove(img10) # very good --> the parent group is empty
1065
+ print(grp5.content)
1066
+
1067
+
1068
+ # for extend --> maybe autodelete stuff
1069
+
1070
+
1071
+
1072
+
1073
+
1074
+
1075
+
1076
+
1077
+
1078
+
1079
+
1080
+
1081
+
1082
+
1083
+ sys.exit(0)
1084
+
1085
+ app = QApplication(sys.argv) # IMPORTANT KEEP !!!!!!!!!!! # required to use strings
1086
+ html = '''
1087
+ <!DOCTYPE html>
1088
+ <html>
1089
+ <head>
1090
+ <title>Font Face</title>
1091
+ </head>
1092
+ <body>
1093
+ <font color="red">
1094
+ <font face="Symbol" size="5">Symbol</font><br />
1095
+ <font face="Times New Roman" size="5">Times New Roman</font><br />
1096
+ <font face="Verdana" size="5">Verdana</font><br />
1097
+ <font face="Comic Sans MS" size="5">Comic Sans MS</font><br />
1098
+ <font face="WildWest" size="5">WildWest</font><br />
1099
+ <font face="Bedrock" size="5">Bedrock</font><br />
1100
+ </font>
1101
+ </body>
1102
+ </html>
1103
+ '''
1104
+
1105
+ html = '''
1106
+ <!DOCTYPE html>
1107
+ <html>
1108
+ <head>
1109
+ <title>Font Face</title>
1110
+ </head>
1111
+ <body>
1112
+ <font color="red">
1113
+ <font face="Symbol" size="5">Symbol</font><br />
1114
+ <font face="Times New Roman" size="5">Times New Roman</font><br />
1115
+ <font face="Bedrock" size="5">Bedrock</font><br />
1116
+ </font>
1117
+ </body>
1118
+ </html>
1119
+ '''
1120
+
1121
+ # this works super well -−> I can think of finalizing it very soon !!!
1122
+
1123
+ # VERY GOOD -−> TRY TO FIX ALL THE STUFF!!!
1124
+
1125
+ if True:
1126
+ # img1 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1127
+ # img2 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1128
+ # img3 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1129
+ # img4 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1130
+
1131
+ # img1 = Image2D(Img(np.zeros((256, 512)), dimensions='hw'))
1132
+ # img2 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1133
+ # img3 = Image2D(Img(np.zeros((256, 512)), dimensions='hw'))
1134
+ # img4 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1135
+ img1 = Image2D('/E/Sample_images/counter/00.png')
1136
+ img2 = Image2D('/E/Sample_images/counter/01.png')
1137
+ img3 = Image2D('/E/Sample_images/counter/02.png')
1138
+ img4 = Image2D('/E/Sample_images/counter/03.png')
1139
+ img5 = Image2D('/E/Sample_images/counter/05.png')
1140
+ img6 = Image2D('/E/Sample_images/counter/06.png')
1141
+ img7 = Image2D('/E/Sample_images/counter/07.png')
1142
+ img8 = Image2D('/E/Sample_images/counter/08.png')
1143
+ img9 = Image2D('/E/Sample_images/counter/09.png')
1144
+
1145
+ grp1 = Group(img1, img2)
1146
+ grp5 = Group(img5, img6, Group(img7, img8, orientation='Y'))
1147
+ grp2 = Group(img3, img4,grp5, orientation='Y')
1148
+
1149
+
1150
+
1151
+ grp3 = Group(grp1, grp2)
1152
+
1153
+
1154
+ set_to_size(grp3,512)
1155
+
1156
+ point = random.choice([QPointF(64,64),QPointF(430,100)])
1157
+ print(point)
1158
+ elements_under_selection = []
1159
+ elm = grp3
1160
+ while elm:
1161
+ if isinstance(elm, bool):
1162
+ break
1163
+ elements_under_selection.append(elm)
1164
+ elm = elm.contains(point)
1165
+ print(elements_under_selection)
1166
+
1167
+
1168
+ # this is the code to get all the elements below the stuff
1169
+
1170
+ # for elm in elements_under_selection:
1171
+ # print(type(elm))
1172
+ #
1173
+ # elm = grp3.contains(QPointF(64,64))
1174
+ # if elm:
1175
+ # print('contained',elm)
1176
+ # print(elm == img1)
1177
+ # print(elm == img2)
1178
+ # print(elm==grp1)
1179
+ # print(elm == grp2)
1180
+ # print(elm == grp3)
1181
+ # else:
1182
+ # print('not contained')
1183
+ #
1184
+ # elm = grp3.contains(QPointF(430,32))
1185
+ # if elm:
1186
+ # print('contained', elm)
1187
+ # print(elm == img1)
1188
+ # print(elm == img2)
1189
+ # print(elm == grp1)
1190
+ # print(elm == grp2)
1191
+ # print(elm == grp3)
1192
+ # else:
1193
+ # print('not contained')
1194
+
1195
+ # print(group._count)
1196
+ # print(grp3, grp2)
1197
+
1198
+ print('grp3.contains(img1)', grp3.contains(img1))
1199
+ print('grp3.contains(img1)', grp3.contains(img4))
1200
+ print('grp3.contains(img1)', grp3.contains(img8))
1201
+ print('#'*20)
1202
+ print('grp3.contains(img1)', grp1.contains(img1))
1203
+ print('grp3.contains(img1)', grp1.contains(img4))
1204
+ print('grp3.contains(img1)', grp2.contains(img1))
1205
+ print('grp3.contains(img1)', grp2.contains(img4))
1206
+ print('grp3.contains(img1)', grp2.contains(img8))
1207
+
1208
+ preview(grp3)
1209
+
1210
+ sys.exit(0)
1211
+
1212
+ if False:
1213
+ '''
1214
+ solution of a grp that has two images in a row and 2 images in a col
1215
+ PyQt6.QtCore.QRectF(0.0, 0.0, 511.99999999999994, 202.99999999999997)
1216
+
1217
+ ###sub###
1218
+ PyQt6.QtCore.QRectF(0.0, 0.0, 408.99999999999994, 202.99999999999997)
1219
+ -−> PyQt6.QtCore.QRectF(0.0, 0.0, 202.99999999999997, 202.99999999999997)
1220
+ -−> PyQt6.QtCore.QRectF(205.99999999999997, 0.0, 202.99999999999997, 202.99999999999997)
1221
+ PyQt6.QtCore.QRectF(411.99999999999994, 0.0, 100.0, 202.99999999999997)
1222
+ -−> PyQt6.QtCore.QRectF(411.99999999999994, 0.0, 99.99999999999999, 99.99999999999999)
1223
+ -−> PyQt6.QtCore.QRectF(411.99999999999994, 102.99999999999999, 99.99999999999999, 99.99999999999999)
1224
+
1225
+ so each small rect in col should be 100*100 and each big rect should be 203*203
1226
+
1227
+ -> now figure the math for that
1228
+
1229
+ if I put all same size (no space) can I compute the rect and then adjust space so that it still fits ??? --> not so easy
1230
+
1231
+ total_uncompressible_width = 512-(3-1)*3 = 506
1232
+ target_height = 512/512+512/512+256/512 = 2.5 --> 202.4 --> I almost have it real AR for last is in fact 256/(512-3)
1233
+
1234
+ the real AR factor should be 2.492611 to get 202.9999999 of height for both col group and for --> how can I get there ????
1235
+ # there isn't probably any solution and I need iter but with a good initial guess
1236
+ # --> take AR by default and adjust
1237
+
1238
+ solution for two groups of 256x512 and 512x512 -−> 138.54
1239
+ PyQt6.QtCore.QRectF(0.0, 0.0, 512.0, 138.54545454545453)
1240
+ ###sub###
1241
+ PyQt6.QtCore.QRectF(0.0, 0.0, 418.6363636363636, 138.54545454545453)
1242
+ -−> PyQt6.QtCore.QRectF(0.0, 0.0, 277.09090909090907, 138.54545454545453)
1243
+ -−> PyQt6.QtCore.QRectF(280.09090909090907, 0.0, 138.54545454545453, 138.54545454545453)
1244
+ PyQt6.QtCore.QRectF(421.6363636363636, 0.0, 90.36363636363637, 138.54545454545453)
1245
+ -−> PyQt6.QtCore.QRectF(421.6363636363636, 0.0, 90.36363636363636, 45.18181818181818)
1246
+ -−> PyQt6.QtCore.QRectF(421.6363636363636, 48.18181818181818, 90.36363636363636, 90.36363636363636)
1247
+
1248
+ total_uncompressible_width = 512-(3-1)*3 = 506
1249
+ target_height = 512/256+512/512+ 90.363636/138.54545454545454 --> 3.652231 -−> perfect --> that is this one --> I need do it like that --> not that hard in fact
1250
+
1251
+ # je dois trouver 3.6 --> ça ne marche pas du tout -> réflechir en fait
1252
+
1253
+ # how can I handle the incompressible texts--> see that later
1254
+
1255
+ '''
1256
+ img1 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1257
+ img2 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1258
+ img3 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1259
+ img4 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1260
+
1261
+ img1 = Image2D(Img(np.zeros((256, 512)), dimensions='hw'))
1262
+ img2 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1263
+ img3 = Image2D(Img(np.zeros((256, 512)), dimensions='hw'))
1264
+ img4 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1265
+
1266
+ grp1 = group(img1,img2)
1267
+ grp2 = group(img3, img4, orientation='Y')
1268
+
1269
+ grp3 = group(grp1, grp2)
1270
+ # grp3.set_to_size(512)
1271
+ set_to_size(grp3,512)
1272
+
1273
+ print(grp3.getRect())
1274
+
1275
+ print(grp3.get_incompressible_size(axis=grp3.orientation)) # --> 6 --> ok
1276
+
1277
+ get_imprecision(grp3,512) # --> imprecision of 3 pixels
1278
+
1279
+
1280
+ print('###sub###')
1281
+
1282
+ for elm in grp3:
1283
+ print(elm.getRect(scale=True))
1284
+ for el in elm:
1285
+ print('-−> ', el.getRect(scale=True))
1286
+
1287
+ preview(grp3)
1288
+
1289
+
1290
+ sys.exit(0)
1291
+
1292
+ if True:
1293
+ # that works
1294
+
1295
+ img1 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1296
+ img2 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1297
+ img3 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1298
+ img4 = Image2D(Img(np.zeros((512,512)), dimensions='hw'))
1299
+
1300
+ img1 = Image2D(Img(np.zeros((256, 512)), dimensions='hw'))
1301
+ img2 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1302
+ img3 = Image2D(Img(np.zeros((256, 512)), dimensions='hw'))
1303
+ img4 = Image2D(Img(np.zeros((512, 512)), dimensions='hw'))
1304
+
1305
+ t = np.arange(0.0, 2.0, 0.01)
1306
+ s = 1 + np.sin(2 * np.pi * t)
1307
+ fig, ax = plt.subplots()
1308
+ ax.plot(t, s)
1309
+
1310
+ ax.set(xlabel='time (s)', ylabel='voltage (mV)', title=None)
1311
+ ax.grid()
1312
+
1313
+ # plt.show()
1314
+ # fig.savefig("test.png")
1315
+ # plt.show()
1316
+ # ça marche --> voici deux examples de shapes
1317
+ fig = VectorGraphics2D(fig, x=0, y=0, width=20., height=10.) # could also be used to create empty image with
1318
+
1319
+ svg = VectorGraphics2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/cartman.svg', x=12, y=0,
1320
+ width=1, height=1, fill_color=0xFFFFFF) # pb is I can change size if I don't put
1321
+
1322
+ # grp1 = group(img1,img2)
1323
+ # grp2 = group(img3, img4, orientation='Y')
1324
+ #
1325
+ # grp3 = group(grp1, grp2)
1326
+
1327
+
1328
+ # grp3 = group(img3, fig, space=42, orientation=random.choice(['X','Y']), fill_color=0xFF00FF)
1329
+ # grp3 = group(img3,fig, img1,svg, space=3, orientation=random.choice(['X','Y']), fill_color=0xFF00FF)
1330
+ grp3 = group(img3,fig, img1, space=3, orientation=random.choice(['X','Y']), fill_color=0xFF00FF)
1331
+
1332
+ # grp3.set_to_size(512)
1333
+ set_to_size(grp3,1024)
1334
+
1335
+ print(grp3.getRect())
1336
+
1337
+ print(grp3.get_incompressible_size(axis=grp3.orientation)) # --> 6 --> ok
1338
+
1339
+ get_imprecision(grp3,512) # --> imprecision of 3 pixels
1340
+
1341
+ print('###sub###')
1342
+
1343
+ for elm in grp3:
1344
+ print(elm.getRect(all=True))
1345
+ try:
1346
+ for el in elm:
1347
+ print('-−> ', el.getRect(all=True))
1348
+ except:
1349
+ pass
1350
+
1351
+
1352
+
1353
+ preview(grp3)
1354
+
1355
+ sys.exit(0)
1356
+
1357
+ if False:
1358
+
1359
+ # this now works I shouldn't take the text as immutable -−> I may need to resize the image every time text is added -−> need to think how I can do that
1360
+ # this is now broken because of immutable -> see how I can fix that
1361
+
1362
+ img1 = Image2D('/E/Sample_images/counter/01.png')
1363
+ img2 = Image2D('/E/Sample_images/counter/01.png')
1364
+ img3 = Image2D('/E/Sample_images/counter/02.png')
1365
+ text = TAText2D(html)
1366
+ # text.set_rotation(-45)
1367
+ text.color = 0xFF0000
1368
+
1369
+ # bug in set_to_scale of the stuff
1370
+
1371
+ grp = group(text,img3,img1, fill_color=0xFFFFFF, orientation=random.choice(['X','Y'])) # --> correct
1372
+ # grp = group(text, img3, img1, fill_color=0xFFFFFF, orientation='Y') # --> this is incorrect in height --> see how I can handle that
1373
+
1374
+ # I need a smarter code --> maybe only compute size of mutable and scale them to size
1375
+
1376
+ # for some reason I cannot always see the text --> what is this bug ???
1377
+ # debug it with just that
1378
+
1379
+ # I need get the exact size of the text --> because now it seems much bigger than it really is
1380
+
1381
+ # I also need to be able to change the pen color of text --> I need split text by colors
1382
+
1383
+ # shall I draw only the stuff within the rect ??? --> maybe
1384
+
1385
+ # set_to_size(grp,512)
1386
+ grp.set_to_size(512) # --> good this is ok in X but then why not in Y???
1387
+
1388
+ print(grp.getRect()) # not at all right size --> 307 --> not ok
1389
+
1390
+ get_imprecision(grp)
1391
+
1392
+ preview(grp)
1393
+
1394
+ sys.exit(0)
1395
+
1396
+
1397
+ if False:
1398
+
1399
+ # seems ok but see how to handle text ??? --> very hard because unscalable -−> or assume scalable and truncate the text
1400
+ # best is to treat it as an image with a fixed width and height
1401
+
1402
+ # I need to treat the text independently of the rest of the figure and to crop it to the height of the others when done
1403
+
1404
+
1405
+ #sufficient to reproduce the size bug
1406
+
1407
+ # mathematically it is unsolvable if uncompressible size is > to desired final size -−> I need a warning for the user !!! -−> TODO
1408
+
1409
+
1410
+ SPACE=10
1411
+ # SPACE=0
1412
+
1413
+ img1 = Image2D('/E/Sample_images/counter/00.png')
1414
+ img2 = Image2D('/E/Sample_images/counter/01.png')
1415
+ img3 = Image2D('/E/Sample_images/counter/02.png')
1416
+ img4 = Image2D('/E/Sample_images/counter/03.png')
1417
+ img5 = Image2D('/E/Sample_images/counter/05.png')
1418
+ img6 = Image2D('/E/Sample_images/counter/06.png')
1419
+ img7 = Image2D('/E/Sample_images/counter/07.png')
1420
+ img8 = Image2D('/E/Sample_images/counter/08.png')
1421
+ img9 = Image2D('/E/Sample_images/counter/09.png')
1422
+
1423
+ # I NEED MAKE SURE THAT THE SPACE IS NOT CRAEY OTHERWISE THAT CANNOT work
1424
+ grp1= group(img1,img2, img3, img4, img5, space=6)
1425
+ grp2= group(img6,img7, img8, img9, orientation='Y', space=3)
1426
+ grp3 = group(grp1, grp2, space=9, orientation=random.choice(['X','Y'])) # there is a big bug there
1427
+
1428
+ # also sufficient to reproduce the bug...
1429
+ # grp1 = group(img1,img2, space=200) # this is the space missing --> why this bug??? " --> YES THIS IS ALWAYS THE SPACE MISSING --> WHY IS THAT!!!
1430
+ # grp2 = group(img6, orientation='Y', space=SPACE*20)
1431
+ # grp3 = group(grp1, grp2, space=SPACE*2)
1432
+
1433
+ # indeed smthg needs be done recursively to match the size properly --> am I not getting the right size in some cases ????
1434
+ start = timer()
1435
+
1436
+ # doing it 100 time fixes the size difference but there is still smthg missing --> so there is some convergence issue somewhere
1437
+ # for i in range(26): # 5 to 10 times seems to be enough --> I can maybe live with that!!! # time is negligibly longer --> so I can afford to have that (it become a little bit longer if I go around 1000 there the error is null
1438
+ # grp3.set_to_size(512) # NB THE SET TO SIZE FIXED the BUG --> WHY DO I NEED TO DO IT TWICE
1439
+ set_to_size(grp3, 512)
1440
+
1441
+ print('total time', timer()-start)
1442
+
1443
+ # grp3.set_to_size(1024) # NB THE SET TO SIZE FIXED the BUG --> WHY DO I NEED TO DO IT TWICE
1444
+ # grp3.set_to_size(1024) # NB THE SET TO SIZE FIXED the BUG --> WHY DO I NEED TO DO IT TWICE
1445
+
1446
+ print(grp3.orientation)
1447
+ print(grp3.space)
1448
+ print(grp3.get_incompressible_size())
1449
+ print(grp3.get_incompressible_size(axis=grp3.orientation))
1450
+
1451
+ print(grp3.getRect()) # not ok --> probably need do this properly #(0.0, 0.0, 502.0, 218.7883919228763) vs (0.0, 0.0, 501.9999999999999, 216.95561080400537) when repeated once --> why not deterministic ???
1452
+
1453
+ # why not all same height --> they should have the same
1454
+
1455
+ # print(len(grp3))
1456
+
1457
+ # if I take the unpacked size and append to it the incompressible size I should get back to the right shape
1458
+
1459
+ print('####sub####')
1460
+ for elm in grp3:
1461
+ print(elm.getRect())
1462
+
1463
+ print(grp1.space)
1464
+ print(grp1.orientation)
1465
+
1466
+
1467
+ # imprecisionX = grp3[0].getRect().height()-grp3[1].getRect().height()
1468
+ # imprecisionY = grp3[0].getRect().width()-grp3[1].getRect().width()
1469
+ # imprecision = min(abs(imprecisionX), abs(imprecisionY))
1470
+ # print('imprecision in pixels X', imprecisionX)
1471
+ # print('imprecision in pixels Y', imprecisionY)
1472
+ # print('imprecision', imprecision)
1473
+ get_imprecision(grp3)
1474
+
1475
+ #-4.663263553084107e-09 for 16 repeats
1476
+ # imprecision in pixels 0.0 for 100 or 50 or 30 or 26 repeats
1477
+ # imprecision in pixels 8.526512829121202e-14 for 25 repeats
1478
+ # -1.4921397450962104e-11 for 20 repeats
1479
+ # --> 26 is the first where I really get 0 --> ok
1480
+
1481
+
1482
+ preview(grp3)
1483
+ sys.exit(0)
1484
+
1485
+ # Example usage:
1486
+ # custom_list = col(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
1487
+ # print(custom_list[0])
1488
+
1489
+ orientation='X' # all same height --> ok
1490
+ # orientation='Y' # pb --> not all same width but all same height --> NOT GOOD --> packing is ok and align also --> it is the scaling that sucks
1491
+ # almost ok but height is incorrect -−> not the target height --> need a fix
1492
+ # VERY GOOD --> NOW BOTH ARE FIXED -> TRY TO FINISH THAT VERY SOON -−> SHOULD BE DOABLE
1493
+
1494
+ # ça marche ce truc behaves as a rect and as a list --> very useful in a way for iter
1495
+ if False:
1496
+ grp = group(Rectangle2D(QRectF(0, 0, 100, 50)),
1497
+ Rectangle2D(QRectF(20, 20, 200, 100)),
1498
+ Rectangle2D(QRectF(30, 30, 300, 150)),
1499
+ Rectangle2D(QRectF(60, 30, 200, 120)),
1500
+ Rectangle2D(QRectF(30, 30, 300, 100)), orientation=orientation)
1501
+ else:
1502
+
1503
+ # --> all is ok and the size is an iteration issue -−> maybe then I should not worry about that
1504
+
1505
+ INCOMPRESSIBLE_SPACE_TEST =10 # --> setting it to 0 fixes the misalignment --> that means that this is the incompressible part of the stuff that matters -> I need make functions that return the amount of incompressible space so that the AR CAN BE PROPERLY COMPUTED
1506
+
1507
+ # grp = group(Image2D('/E/Sample_images/counter/00.png'), Image2D('/E/Sample_images/counter/01.png'),Image2D('/E/Sample_images/counter/02.png'),Image2D('/E/Sample_images/counter/03.png'))
1508
+ img1 = Image2D('/E/Sample_images/counter/00.png')
1509
+ img2 = Image2D('/E/Sample_images/counter/01.png')
1510
+ img3 = Image2D('/E/Sample_images/counter/02.png')
1511
+ img4 = Image2D('/E/Sample_images/counter/03.png')
1512
+
1513
+
1514
+ # it seems I had never reimplemented the rotation --> is that possible !!!
1515
+ img1.set_rotation(45)
1516
+ img3.set_rotation(-33)
1517
+ # img1 = Rectangle2D(QRectF(20, 20, 200, 100))
1518
+ # img1.set_rotation(45) # --> rotation roughly works for rectangle even though the bounds are not correct and the crop is not correct either!!!
1519
+ # but rotation
1520
+
1521
+ # if rotated by 90degrees I would need to change the dimensions of the image and see also how to handle the other rotations ??? --> NEED THINK -−> IF NOT SAME SIZE -−> NEED BE SMART !!! --> TODO
1522
+
1523
+ img4.set_rotation(90) # TODO --> needs a fix --> need swap the dimensions of the image -−> see how to code because maybe not that easy TODO
1524
+
1525
+ # I need to think but not a bad idea!!!
1526
+
1527
+
1528
+
1529
+
1530
+ grp = group(img1, img2, img3, img4, space=INCOMPRESSIBLE_SPACE_TEST/3)
1531
+
1532
+ print('rect',grp.getRect())
1533
+
1534
+ grp.setTopLeft(512, 256) # this seems to work
1535
+
1536
+ print('rect2', grp.getRect())
1537
+
1538
+
1539
+ img5 = Image2D('/E/Sample_images/counter/05.png')
1540
+ img6 = Image2D('/E/Sample_images/counter/06.png')
1541
+ img7 = Image2D('/E/Sample_images/counter/07.png')
1542
+ img7.set_rotation(180)
1543
+
1544
+
1545
+ grp2 = group(img5, img6, img7, space=INCOMPRESSIBLE_SPACE_TEST*3)
1546
+
1547
+ grp2.setTopLeft(512, 516)
1548
+
1549
+ print('rect3',grp2.getRect())
1550
+
1551
+ img8 = Image2D('/E/Sample_images/counter/08.png')
1552
+ img9 = Image2D('/E/Sample_images/counter/09.png')
1553
+
1554
+ # grp4 = group(img8,img9,orientation='Y')
1555
+ grp4 = group(img8,img9,grp,orientation='Y', space=INCOMPRESSIBLE_SPACE_TEST)
1556
+
1557
+
1558
+
1559
+ # ça marche aussi mais pr je ne sais quelle raison il y a un petit decalage ???
1560
+ html_neo = '''
1561
+ <!DOCTYPE html>
1562
+ <html>
1563
+ <head>
1564
+ <title>Font Face</title>
1565
+ <style>
1566
+ .red {
1567
+ color: red;
1568
+ }
1569
+ .symbol {
1570
+ font-family: Symbol;
1571
+ font-size: x-large;
1572
+ }
1573
+ .times-new-roman {
1574
+ font-family: "Times New Roman";
1575
+ font-size: x-large;
1576
+ }
1577
+ .verdana {
1578
+ font-family: Verdana;
1579
+ font-size: x-large;
1580
+ }
1581
+ .comic-sans-ms {
1582
+ font-family: "Comic Sans MS";
1583
+ font-size: x-large;
1584
+ }
1585
+ .wildwest {
1586
+ font-family: WildWest;
1587
+ font-size: x-large;
1588
+ }
1589
+ .bedrock {
1590
+ font-family: Bedrock;
1591
+ font-size: x-large;
1592
+ }
1593
+ </style>
1594
+ </head>
1595
+ <body>
1596
+ <div class="red">
1597
+ <div class="symbol">Symbol</div>
1598
+ <div class="times-new-roman">Times New Roman</div>
1599
+ <div class="verdana">Verdana</div>
1600
+ <div class="comic-sans-ms">Comic Sans MS</div>
1601
+ <div class="wildwest">WildWest</div>
1602
+ <div class="bedrock">Bedrock</div>
1603
+ </div>
1604
+ </body>
1605
+ </html>
1606
+ '''
1607
+
1608
+ # html=html_neo # i prefer the old way
1609
+
1610
+ # use the deprecated text size because
1611
+ # html = "<font color=blue size=24>this is a test<sup>2</sup><br></font><font color=green size=12>continued<sub>1</sub><br></font><font color=white size=12>test greek <font face='Symbol' size=32>a</font> another &alpha;<font face='Arial' color='Orange'>I am a sentence!</font>"
1612
+ text = TAText2D(html)
1613
+ text.set_rotation(-45)
1614
+ text.color = 0xFF0000 # color does not work !!! --> again needs be fixed !!!
1615
+ # text.set_rotation(90)
1616
+
1617
+ t = np.arange(0.0, 2.0, 0.01)
1618
+ s = 1 + np.sin(2 * np.pi * t)
1619
+ fig, ax = plt.subplots()
1620
+ ax.plot(t, s)
1621
+
1622
+ ax.set(xlabel='time (s)', ylabel='voltage (mV)', title=None)
1623
+ ax.grid()
1624
+
1625
+ # plt.show()
1626
+ # fig.savefig("test.png")
1627
+ # plt.show()
1628
+ # ça marche --> voici deux examples de shapes
1629
+ fig = VectorGraphics2D(fig, x=0, y=0, width=512, height=512) # could also be used to create empty image with
1630
+
1631
+ # there is a bug !!!!
1632
+ # grp5 = group(grp2, grp4,grp, orientation='Y') # ok but pb is they have no same height -−> see how I can fix that --> see how I can set height --> DO I ALWAYS NEED A TARGET HEIGHT OR CAN I TAKE THE SMALLEST OF THE TWO ???
1633
+ # grp5 = group(grp2,grp4, orientation=random.choice(['X','Y']), space=INCOMPRESSIBLE_SPACE_TEST, fill_color=0x00FFFF) # ok but pb is they have no same height -−> see how I can fix that --> see how I can set height --> DO I ALWAYS NEED A TARGET HEIGHT OR CAN I TAKE THE SMALLEST OF THE TWO ???
1634
+ # grp5 = group(grp2,group(text), grp4, orientation=random.choice(['X','Y']), space=INCOMPRESSIBLE_SPACE_TEST, fill_color=0x00FFFF) # ok but pb is they have no same height -−> see how I can fix that --> see how I can set height --> DO I ALWAYS NEED A TARGET HEIGHT OR CAN I TAKE THE SMALLEST OF THE TWO ???
1635
+ grp5 = group(grp2,fig, grp4, orientation=random.choice(['X','Y']), space=INCOMPRESSIBLE_SPACE_TEST, fill_color=0x00FFFF) # ok but pb is they have no same height -−> see how I can fix that --> see how I can set height --> DO I ALWAYS NEED A TARGET HEIGHT OR CAN I TAKE THE SMALLEST OF THE TWO ???
1636
+
1637
+ # I at least managed to display a text but will I manage to get its size and alike
1638
+ # text should always be incompressible in fact
1639
+
1640
+ # very good --> it works even with very very complex shapes !!!!
1641
+
1642
+ # see how I can convert this into an xml portable code
1643
+ # todo
1644
+
1645
+ # tt marche sublimement
1646
+
1647
+ # TODO --> CHECK HOW TO DO THAT AND WHY IT DOESN'T WORK !!!
1648
+
1649
+ # TODO add bg if desired for the images
1650
+
1651
+ # grp = grp5
1652
+
1653
+ # grp.set_to_size(1024) # do I have a bug here ???
1654
+ grp5.setTopLeft(0,0)
1655
+
1656
+ # shall I add <?xml version="1.0" ?>
1657
+
1658
+ if False:
1659
+ try:
1660
+ xml = object_to_xml(grp5)
1661
+ print(xml) # pickle serialization of the object would allow me to implement some sort of a save...
1662
+
1663
+ tst = xml_string_to_object(xml)
1664
+
1665
+ print(tst)
1666
+ except:
1667
+ traceback.print_exc()
1668
+
1669
+ # small error is likely due to packing --> TODO --> FIX IT
1670
+
1671
+ # here 26 is not enough --> I need a bit more
1672
+ # for i in range(26): # even at 100 I get a small imprecision -−> maybe forget about that shit and take 26 always # dirty but ok for now -> I have bigger things to fix --> I tried 100 and it is perfect but 10 already seems to be enough --> maybe that is ok then --> even 3 is ok
1673
+ # grp5.set_to_size(1024) # there is a super tiny misalignment --> is that real or a rounding artifact that would vanish with svg images
1674
+ set_to_size(grp5, 1024) # size is incorrect
1675
+
1676
+ print('text size', text.width(), text.height(), text.get_incompressible_size())
1677
+
1678
+ # --> the size is not respected --> there is a bug !!!
1679
+
1680
+ # imprecisionX = grp5[0].getRect().height() - grp5[1].getRect().height()
1681
+ # imprecisionY = grp5[0].getRect().width() - grp5[1].getRect().width()
1682
+ # imprecision = min(abs(imprecisionX), abs(imprecisionY))
1683
+ # print('imprecision in pixels X', imprecisionX)
1684
+ # print('imprecision in pixels Y', imprecisionY)
1685
+ # print('imprecision ', imprecision)
1686
+ get_imprecision(grp5)
1687
+
1688
+
1689
+ print(grp5.orientation)
1690
+ print(grp5.get_incompressible_size())
1691
+ print(grp5.get_incompressible_size(axis=grp5.orientation))
1692
+
1693
+ print(grp5.getRect()) # --> marche pas car 668.9099254763324 (0.0, 0.0, 237.55105999039787, 668.9099254763324) --> small bug somewhere --> size is ok if no space --> the pb comes from the space --> need a fix that is very smart
1694
+
1695
+ print('####INSIDE####')
1696
+ for elm in grp5:
1697
+ print(elm.getRect())
1698
+
1699
+ preview(grp5) # pb this causes the soft to exit --> I need make it modal or alike --> think of that
1700
+
1701
+
1702
+
1703
+
1704
+ # I may need to dissect the components
1705
+ # if this is an incompressible shit then setting all spaces to 0 would do the job !!
1706
+
1707
+
1708
+
1709
+ # very good it handles spaces too --> very good
1710
+
1711
+
1712
+
1713
+
1714
+
1715
+
1716
+
1717
+ # see how I can handle figures ???? --> I would need a smart stuff
1718
+ # see how I can generate the file !!! --> TODO
1719
+
1720
+
1721
+
1722
+
1723
+
1724
+
1725
+ if False:
1726
+ # do all of it
1727
+
1728
+
1729
+
1730
+ # # grp = group(img1)
1731
+ #
1732
+ grp3 = group(grp, grp2, orientation='Y')
1733
+
1734
+ # what happens if I add a group to another group -−> can I resize it and how will it determine the optimal size
1735
+
1736
+
1737
+ # can a row contain a group --> see
1738
+ # maybe I need the y ratio or the x and the incompressible height or width --> TODO
1739
+
1740
+
1741
+
1742
+
1743
+
1744
+
1745
+
1746
+ # grp3 = group(grp, grp2, orientation='X')
1747
+
1748
+
1749
+ # I am not very far apparently in Y --> am I doing a mistake ???? --> is that due to errors in incompressible stuff
1750
+
1751
+ # it roughly seems to work
1752
+
1753
+ # but is all of this working ???
1754
+
1755
+
1756
+
1757
+
1758
+ print('rect4', grp.getRect(), 'rect5',grp2.getRect())
1759
+
1760
+ grp = grp3
1761
+
1762
+
1763
+
1764
+
1765
+ # grp2.setTopLeft(512,256)
1766
+ # grp2=grp
1767
+
1768
+ # grp = grp2
1769
+
1770
+ # each group is ok but they cannot be combined
1771
+ # --> see what causes the bug
1772
+
1773
+ # shall I force a size on group creation -> force same height to be max height or min height upon creation --> min height is smartest
1774
+
1775
+
1776
+ # print(grp[0]) # first item
1777
+ # print(grp[-1]) # last item
1778
+ # print(grp.orientation)
1779
+ # print(len(grp))
1780
+ #
1781
+ # print(grp.width())
1782
+ # print(grp.getRect())
1783
+
1784
+ if False:
1785
+
1786
+ start = timer()
1787
+
1788
+ grp.set_to_size(512)
1789
+ grp.checkAR()
1790
+
1791
+ end = timer() - start
1792
+ print('bounds =', grp.getRect())
1793
+ print("elapsed time",end)
1794
+
1795
+ # this is super fast and works super well --> I have my killer app...
1796
+
1797
+ grp.orientation='Y'
1798
+ start = timer()
1799
+
1800
+ # grp.set_to_size(512)
1801
+ # grp.checkAR()
1802
+
1803
+ end = timer() - start
1804
+ print('bounds =', grp.getRect())
1805
+ print("elapsed time2", end)
1806
+ # grp.check()
1807
+
1808
+ # print(bounding_rect)
1809
+
1810
+ # very good --> I can access all the stuff in one go -> very cool
1811
+
1812
+ # very good --> all seems good
1813
+
1814
+ # group can be groups of images or of stuff
1815
+
1816
+ # see all I can do...
1817
+ # all is ok now !!!
1818
+ # all is good !!!
1819
+
1820
+ # very good --> now try to do the same with images and plot them --> should be easy !!!
1821
+ # then add functions to the group
1822
+
1823
+ # maybe offer panels as collections of rows or cols --> probably the simplest and allow empty images or spacers for incomplete panels
1824
+
1825
+ # try to draw
1826
+
1827
+ # TODO --> handle translations ... and alike
1828
+ # try to plot groups of groups
1829
+
1830
+ preview(grp)