meerk40t 0.9.7030__py2.py3-none-any.whl → 0.9.7040__py2.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.
- meerk40t/balormk/clone_loader.py +3 -2
- meerk40t/balormk/controller.py +28 -11
- meerk40t/balormk/cylindermod.py +1 -0
- meerk40t/balormk/device.py +13 -9
- meerk40t/balormk/driver.py +9 -2
- meerk40t/balormk/galvo_commands.py +3 -1
- meerk40t/balormk/gui/gui.py +6 -0
- meerk40t/balormk/livelightjob.py +338 -321
- meerk40t/balormk/mock_connection.py +4 -3
- meerk40t/balormk/usb_connection.py +11 -2
- meerk40t/camera/camera.py +19 -14
- meerk40t/camera/gui/camerapanel.py +6 -0
- meerk40t/core/cutplan.py +109 -51
- meerk40t/core/elements/element_treeops.py +435 -140
- meerk40t/core/elements/elements.py +100 -9
- meerk40t/core/elements/shapes.py +259 -39
- meerk40t/core/elements/tree_commands.py +10 -5
- meerk40t/core/node/elem_ellipse.py +18 -8
- meerk40t/core/node/elem_image.py +51 -19
- meerk40t/core/node/elem_line.py +18 -8
- meerk40t/core/node/elem_path.py +18 -8
- meerk40t/core/node/elem_point.py +10 -4
- meerk40t/core/node/elem_polyline.py +19 -11
- meerk40t/core/node/elem_rect.py +18 -8
- meerk40t/core/node/elem_text.py +11 -5
- meerk40t/core/node/filenode.py +2 -8
- meerk40t/core/node/groupnode.py +11 -11
- meerk40t/core/node/image_processed.py +11 -5
- meerk40t/core/node/image_raster.py +11 -5
- meerk40t/core/node/node.py +64 -16
- meerk40t/core/node/refnode.py +2 -1
- meerk40t/core/svg_io.py +91 -34
- meerk40t/device/dummydevice.py +7 -1
- meerk40t/extra/vtracer.py +222 -0
- meerk40t/grbl/device.py +81 -8
- meerk40t/gui/about.py +20 -0
- meerk40t/gui/devicepanel.py +20 -16
- meerk40t/gui/gui_mixins.py +4 -0
- meerk40t/gui/icons.py +330 -253
- meerk40t/gui/laserpanel.py +8 -3
- meerk40t/gui/laserrender.py +41 -21
- meerk40t/gui/magnetoptions.py +158 -65
- meerk40t/gui/materialtest.py +229 -39
- meerk40t/gui/navigationpanels.py +229 -24
- meerk40t/gui/propertypanels/hatchproperty.py +2 -0
- meerk40t/gui/propertypanels/imageproperty.py +160 -106
- meerk40t/gui/ribbon.py +6 -1
- meerk40t/gui/scenewidgets/gridwidget.py +29 -32
- meerk40t/gui/scenewidgets/rectselectwidget.py +190 -192
- meerk40t/gui/simulation.py +75 -77
- meerk40t/gui/statusbarwidgets/defaultoperations.py +84 -48
- meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
- meerk40t/gui/tips.py +15 -1
- meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
- meerk40t/gui/wxmmain.py +242 -114
- meerk40t/gui/wxmscene.py +107 -24
- meerk40t/gui/wxmtree.py +4 -2
- meerk40t/gui/wxutils.py +60 -15
- meerk40t/image/imagetools.py +129 -65
- meerk40t/internal_plugins.py +4 -0
- meerk40t/kernel/kernel.py +39 -18
- meerk40t/kernel/settings.py +28 -9
- meerk40t/lihuiyu/device.py +24 -12
- meerk40t/main.py +1 -1
- meerk40t/moshi/device.py +20 -6
- meerk40t/network/console_server.py +22 -6
- meerk40t/newly/device.py +10 -3
- meerk40t/newly/gui/gui.py +10 -0
- meerk40t/ruida/device.py +22 -2
- meerk40t/ruida/loader.py +6 -3
- meerk40t/tools/geomstr.py +193 -125
- meerk40t/tools/rasterplotter.py +179 -93
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/RECORD +79 -78
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/zip-safe +0 -0
@@ -19,10 +19,7 @@ class GridWidget(Widget):
|
|
19
19
|
|
20
20
|
def __init__(self, scene, name=None, suppress_labels=False):
|
21
21
|
Widget.__init__(self, scene, all=True)
|
22
|
-
if name is None
|
23
|
-
self.name = "Standard"
|
24
|
-
else:
|
25
|
-
self.name = name
|
22
|
+
self.name = "Standard" if name is None else name
|
26
23
|
self.primary_grid_lines = None
|
27
24
|
self.secondary_grid_lines = None
|
28
25
|
self.background = None
|
@@ -157,28 +154,30 @@ class GridWidget(Widget):
|
|
157
154
|
# Primary grid
|
158
155
|
# We could be way too high
|
159
156
|
start_x = self.zero_x
|
160
|
-
|
161
|
-
|
157
|
+
dx = abs(self.primary_tick_length_x)
|
158
|
+
dy = abs(self.primary_tick_length_y)
|
159
|
+
while start_x - dx > self.min_x:
|
160
|
+
start_x -= dx
|
162
161
|
start_y = self.zero_y
|
163
|
-
while start_y -
|
164
|
-
start_y -=
|
162
|
+
while start_y - dy > self.min_y:
|
163
|
+
start_y -= dy
|
165
164
|
# But we could be way too low, too
|
166
165
|
while start_x < self.min_x:
|
167
|
-
start_x +=
|
166
|
+
start_x += dx
|
168
167
|
while start_y < self.min_y:
|
169
|
-
start_y +=
|
168
|
+
start_y += dy
|
170
169
|
|
171
170
|
x = start_x
|
172
171
|
while x <= self.max_x:
|
173
172
|
starts.append((x, self.min_y))
|
174
173
|
ends.append((x, self.max_y))
|
175
|
-
x +=
|
174
|
+
x += dx
|
176
175
|
|
177
176
|
y = start_y
|
178
177
|
while y <= self.max_y:
|
179
178
|
starts.append((self.min_x, y))
|
180
179
|
ends.append((self.max_x, y))
|
181
|
-
y +=
|
180
|
+
y += dy
|
182
181
|
self.primary_grid_lines = starts, ends
|
183
182
|
|
184
183
|
def _calc_secondary_grid_lines(self):
|
@@ -188,28 +187,30 @@ class GridWidget(Widget):
|
|
188
187
|
# Secondary grid
|
189
188
|
# We could be way too high
|
190
189
|
start_x = self.zero_x
|
191
|
-
|
192
|
-
|
190
|
+
dx = abs(self.secondary_tick_length_x)
|
191
|
+
dy = abs(self.secondary_tick_length_y)
|
192
|
+
while start_x - dx > self.min_x:
|
193
|
+
start_x -= dx
|
193
194
|
start_y = self.zero_y
|
194
|
-
while start_y -
|
195
|
-
start_y -=
|
195
|
+
while start_y - dy > self.min_y:
|
196
|
+
start_y -= dy
|
196
197
|
# But we could be way too low, too
|
197
198
|
while start_x < self.min_x:
|
198
|
-
start_x +=
|
199
|
+
start_x += dx
|
199
200
|
while start_y < self.min_y:
|
200
|
-
start_y +=
|
201
|
+
start_y += dy
|
201
202
|
|
202
203
|
x = start_x
|
203
204
|
while x <= self.max_x:
|
204
205
|
starts2.append((x, self.min_y))
|
205
206
|
ends2.append((x, self.max_y))
|
206
|
-
x +=
|
207
|
+
x += dx
|
207
208
|
|
208
209
|
y = start_y
|
209
210
|
while y <= self.max_y:
|
210
211
|
starts2.append((self.min_x, y))
|
211
212
|
ends2.append((self.max_x, y))
|
212
|
-
y +=
|
213
|
+
y += dy
|
213
214
|
self.secondary_grid_lines = starts2, ends2
|
214
215
|
|
215
216
|
def calculate_grid_lines(self):
|
@@ -346,7 +347,7 @@ class GridWidget(Widget):
|
|
346
347
|
(self.min_x, self.circular_grid_center_y),
|
347
348
|
(self.max_x, self.circular_grid_center_y),
|
348
349
|
)
|
349
|
-
for
|
350
|
+
for pt in test_points:
|
350
351
|
dx = pt[0] - self.circular_grid_center_x
|
351
352
|
dy = pt[1] - self.circular_grid_center_y
|
352
353
|
r = sqrt(dx * dx + dy * dy)
|
@@ -525,10 +526,7 @@ class GridWidget(Widget):
|
|
525
526
|
c_angle = r_angle
|
526
527
|
while c_angle > tau:
|
527
528
|
c_angle -= tau
|
528
|
-
if i % 2 == 0
|
529
|
-
r = 0
|
530
|
-
else:
|
531
|
-
r = r_fourth
|
529
|
+
r = 0 if i % 2 == 0 else r_fourth
|
532
530
|
while r < self.min_radius:
|
533
531
|
r += tick_length
|
534
532
|
|
@@ -634,8 +632,8 @@ class GridWidget(Widget):
|
|
634
632
|
def _draw_grid_primary(self, gc):
|
635
633
|
starts, ends = self.primary_grid_lines
|
636
634
|
gc.SetPen(self.primary_grid_line_pen)
|
637
|
-
grid_path = gc.CreatePath()
|
638
635
|
if starts and ends:
|
636
|
+
grid_path = gc.CreatePath()
|
639
637
|
for i in range(len(starts)):
|
640
638
|
sx = starts[i][0]
|
641
639
|
sy = starts[i][1]
|
@@ -648,8 +646,8 @@ class GridWidget(Widget):
|
|
648
646
|
def _draw_grid_secondary(self, gc):
|
649
647
|
starts2, ends2 = self.secondary_grid_lines
|
650
648
|
gc.SetPen(self.secondary_grid_line_pen)
|
651
|
-
grid_path = gc.CreatePath()
|
652
649
|
if starts2 and ends2:
|
650
|
+
grid_path = gc.CreatePath()
|
653
651
|
for i in range(len(starts2)):
|
654
652
|
sx = starts2[i][0]
|
655
653
|
sy = starts2[i][1]
|
@@ -667,8 +665,8 @@ class GridWidget(Widget):
|
|
667
665
|
u_height = float(self.scene.context.device.view.unit_height)
|
668
666
|
gc.Clip(0, 0, u_width, u_height)
|
669
667
|
# siz = sqrt(u_width * u_width + u_height * u_height)
|
670
|
-
sox = self.circular_grid_center_x / u_width
|
671
|
-
soy = self.circular_grid_center_y / u_height
|
668
|
+
# sox = self.circular_grid_center_x / u_width
|
669
|
+
# soy = self.circular_grid_center_y / u_height
|
672
670
|
step = self.primary_tick_length_x
|
673
671
|
# factor = max(2 * (1 - sox), 2 * (1 - soy))
|
674
672
|
# Initially I drew a complete circle, which is a waste in most situations,
|
@@ -699,8 +697,7 @@ class GridWidget(Widget):
|
|
699
697
|
radials_start = []
|
700
698
|
radials_end = []
|
701
699
|
fsize = 10 / self.scene.widget_root.scene_widget.matrix.value_scale_x()
|
702
|
-
|
703
|
-
fsize = 1.0 # Mac does not allow values lower than 1.
|
700
|
+
fsize = max(fsize, 1.0) # Mac does not allow values lower than 1.
|
704
701
|
try:
|
705
702
|
font = wx.Font(
|
706
703
|
fsize,
|
@@ -771,7 +768,7 @@ class GridWidget(Widget):
|
|
771
768
|
)
|
772
769
|
r_angle += tau / segments
|
773
770
|
i += 1
|
774
|
-
if
|
771
|
+
if radials_start:
|
775
772
|
gc.StrokeLineSegments(radials_start, radials_end)
|
776
773
|
gc.ResetClip()
|
777
774
|
|
@@ -16,7 +16,7 @@ from meerk40t.gui.scene.scene import (
|
|
16
16
|
RESPONSE_DROP,
|
17
17
|
)
|
18
18
|
from meerk40t.gui.scene.widget import Widget
|
19
|
-
from meerk40t.gui.wxutils import
|
19
|
+
from meerk40t.gui.wxutils import dip_size, get_gc_full_scale, get_matrix_scale
|
20
20
|
from meerk40t.tools.geomstr import NON_GEOMETRY_TYPES
|
21
21
|
|
22
22
|
|
@@ -80,6 +80,7 @@ class RectSelectWidget(Widget):
|
|
80
80
|
self.scene.context.setting(bool, "delayed_move", True)
|
81
81
|
self.mode = "select"
|
82
82
|
self.can_drag_move = False
|
83
|
+
self.magnification = dip_size(scene.gui, 100, 100)[1] / 100
|
83
84
|
|
84
85
|
def hit(self):
|
85
86
|
return HITCHAIN_HIT
|
@@ -93,15 +94,9 @@ class RectSelectWidget(Widget):
|
|
93
94
|
ex = self.end_location[0]
|
94
95
|
ey = self.end_location[1]
|
95
96
|
if sx <= ex:
|
96
|
-
if sy <= ey
|
97
|
-
return 0
|
98
|
-
else:
|
99
|
-
return 1
|
97
|
+
return 0 if sy <= ey else 1
|
100
98
|
else:
|
101
|
-
if sy <= ey
|
102
|
-
return 3
|
103
|
-
else:
|
104
|
-
return 2
|
99
|
+
return 3 if sy <= ey else 2
|
105
100
|
|
106
101
|
def rect_select(self, elements, sx, sy, ex, ey):
|
107
102
|
sector = self.sector
|
@@ -190,6 +185,30 @@ class RectSelectWidget(Widget):
|
|
190
185
|
x = x[0]
|
191
186
|
return box[0] <= x <= box[2] and box[1] <= y <= box[3]
|
192
187
|
|
188
|
+
def shortest_distance(p1, p2, tuplemode):
|
189
|
+
"""
|
190
|
+
Calculates the shortest distance between two arrays of 2-dimensional points.
|
191
|
+
"""
|
192
|
+
try:
|
193
|
+
# Calculate the Euclidean distance between each point in p1 and p2
|
194
|
+
if tuplemode:
|
195
|
+
# For an array of tuples:
|
196
|
+
dist = np.sqrt(np.sum((p1[:, np.newaxis] - p2) ** 2, axis=2))
|
197
|
+
else:
|
198
|
+
# For an array of complex numbers
|
199
|
+
dist = np.abs(p1[:, np.newaxis] - p2[np.newaxis, :])
|
200
|
+
|
201
|
+
# Find the minimum distance and its corresponding indices
|
202
|
+
min_dist = np.min(dist)
|
203
|
+
if np.isnan(min_dist):
|
204
|
+
return None, 0, 0
|
205
|
+
min_indices = np.argwhere(dist == min_dist)
|
206
|
+
|
207
|
+
# Return the coordinates of the two points
|
208
|
+
return min_dist, p1[min_indices[0][0]], p2[min_indices[0][1]]
|
209
|
+
except Exception: # out of memory eg
|
210
|
+
return None, None, None
|
211
|
+
|
193
212
|
def move_to(dx, dy):
|
194
213
|
if dx == 0 and dy == 0:
|
195
214
|
return
|
@@ -217,192 +236,21 @@ class RectSelectWidget(Widget):
|
|
217
236
|
)
|
218
237
|
self.scene.request_refresh()
|
219
238
|
|
220
|
-
|
221
|
-
self.modifiers = modifiers
|
222
|
-
|
223
|
-
elements = self.scene.context.elements
|
224
|
-
if event_type == "leftdown":
|
239
|
+
def check_leftdown(space_pos):
|
225
240
|
self.mouse_down_time = perf_counter()
|
226
241
|
self.mode = "unclear"
|
227
242
|
self.start_location = space_pos
|
228
243
|
self.end_location = space_pos
|
229
244
|
if contains(self.scene.context.elements._emphasized_bounds, space_pos):
|
230
245
|
self.can_drag_move = True
|
231
|
-
|
232
|
-
|
233
|
-
elif event_type == "leftclick":
|
246
|
+
|
247
|
+
def check_click(space_pos):
|
234
248
|
# That's too fast
|
235
249
|
# still chaining though
|
236
250
|
self.scene.request_refresh()
|
237
251
|
self.reset()
|
238
|
-
return RESPONSE_CHAIN
|
239
|
-
elif event_type == "leftup":
|
240
|
-
if self.mode == "select":
|
241
|
-
if self.start_location is None:
|
242
|
-
return RESPONSE_CHAIN
|
243
|
-
_ = self.scene.context._
|
244
|
-
self.update_statusmsg(_("Status"))
|
245
|
-
elements.validate_selected_area()
|
246
|
-
sx = min(self.start_location[0], self.end_location[0])
|
247
|
-
sy = min(self.start_location[1], self.end_location[1])
|
248
|
-
ex = max(self.start_location[0], self.end_location[0])
|
249
|
-
ey = max(self.start_location[1], self.end_location[1])
|
250
|
-
self.rect_select(elements, sx, sy, ex, ey)
|
251
|
-
|
252
|
-
self.scene.request_refresh()
|
253
|
-
self.scene.context.signal("select_emphasized_tree", 0)
|
254
|
-
else:
|
255
|
-
|
256
|
-
def shortest_distance(p1, p2, tuplemode):
|
257
|
-
"""
|
258
|
-
Calculates the shortest distance between two arrays of 2-dimensional points.
|
259
|
-
"""
|
260
|
-
try:
|
261
|
-
# Calculate the Euclidean distance between each point in p1 and p2
|
262
|
-
if tuplemode:
|
263
|
-
# For an array of tuples:
|
264
|
-
dist = np.sqrt(np.sum((p1[:, np.newaxis] - p2) ** 2, axis=2))
|
265
|
-
else:
|
266
|
-
# For an array of complex numbers
|
267
|
-
dist = np.abs(p1[:, np.newaxis] - p2[np.newaxis, :])
|
268
|
-
|
269
|
-
# Find the minimum distance and its corresponding indices
|
270
|
-
min_dist = np.min(dist)
|
271
|
-
if np.isnan(min_dist):
|
272
|
-
return None, 0, 0
|
273
|
-
min_indices = np.argwhere(dist == min_dist)
|
274
|
-
|
275
|
-
# Return the coordinates of the two points
|
276
|
-
return min_dist, p1[min_indices[0][0]], p2[min_indices[0][1]]
|
277
|
-
except Exception: # out of memory eg
|
278
|
-
return None, None, None
|
279
|
-
|
280
|
-
b = self.scene.context.elements._emphasized_bounds
|
281
|
-
if b is None:
|
282
|
-
b = self.scene.context.elements.selected_area()
|
283
|
-
matrix = self.scene.widget_root.scene_widget.matrix
|
284
|
-
did_snap_to_point = False
|
285
|
-
if (
|
286
|
-
self.scene.context.snap_points
|
287
|
-
and "shift" not in modifiers
|
288
|
-
and b is not None
|
289
|
-
):
|
290
|
-
gap = self.scene.context.action_attract_len / get_matrix_scale(matrix)
|
291
|
-
# We gather all points of non-selected elements,
|
292
|
-
# but only those that lie within the boundaries
|
293
|
-
# of the selected area
|
294
|
-
# We compare every point of the selected elements
|
295
|
-
# with the points of the non-selected elements (provided they
|
296
|
-
# lie within the selection area plus boundary) and look for
|
297
|
-
# the closest distance.
|
298
|
-
|
299
|
-
# t1 = perf_counter()
|
300
|
-
other_points = []
|
301
|
-
selected_points = []
|
302
|
-
for e in self.scene.context.elements.elems():
|
303
|
-
if e.emphasized:
|
304
|
-
target = selected_points
|
305
|
-
else:
|
306
|
-
target = other_points
|
307
|
-
if not hasattr(e, "as_geometry"):
|
308
|
-
continue
|
309
|
-
geom = e.as_geometry()
|
310
|
-
last = None
|
311
|
-
for seg in geom.segments[: geom.index]:
|
312
|
-
start = seg[0]
|
313
|
-
seg_type = geom._segtype(seg)
|
314
|
-
end = seg[4]
|
315
|
-
if seg_type in NON_GEOMETRY_TYPES:
|
316
|
-
continue
|
317
|
-
if np.isnan(start) or np.isnan(end):
|
318
|
-
print (f"Strange, encountered within rectselect a segment with type: {seg_type} and start={start}, end={end} - coming from element type {e.type}\nPlease inform the developers")
|
319
|
-
continue
|
320
|
-
if start != last:
|
321
|
-
xx = start.real
|
322
|
-
yy = start.imag
|
323
|
-
ignore = (
|
324
|
-
xx < b[0] - gap
|
325
|
-
or xx > b[2] + gap
|
326
|
-
or yy < b[1] - gap
|
327
|
-
or yy > b[3] + gap
|
328
|
-
)
|
329
|
-
if not ignore:
|
330
|
-
target.append(start)
|
331
|
-
xx = end.real
|
332
|
-
yy = end.imag
|
333
|
-
ignore = (
|
334
|
-
xx < b[0] - gap
|
335
|
-
or xx > b[2] + gap
|
336
|
-
or yy < b[1] - gap
|
337
|
-
or yy > b[3] + gap
|
338
|
-
)
|
339
|
-
if not ignore:
|
340
|
-
target.append(end)
|
341
|
-
last = end
|
342
|
-
# t2 = perf_counter()
|
343
|
-
if (
|
344
|
-
other_points is not None
|
345
|
-
and selected_points is not None
|
346
|
-
and len(other_points) > 0
|
347
|
-
and len(selected_points) > 0
|
348
|
-
):
|
349
|
-
np_other = np.asarray(other_points)
|
350
|
-
np_selected = np.asarray(selected_points)
|
351
|
-
dist, pt1, pt2 = shortest_distance(np_other, np_selected, False)
|
352
|
-
|
353
|
-
if dist is not None and dist < gap:
|
354
|
-
did_snap_to_point = True
|
355
|
-
dx = pt1.real - pt2.real
|
356
|
-
dy = pt1.imag - pt2.imag
|
357
|
-
move_to(dx, dy)
|
358
|
-
# Get new value
|
359
|
-
b = self.scene.context.elements._emphasized_bounds
|
360
|
-
# t3 = perf_counter()
|
361
|
-
# print (f"Snap, compared {len(selected_points)} pts to {len(other_points)} pts. Total time: {t3-t1:.2f}sec, Generation: {t2-t1:.2f}sec, shortest: {t3-t2:.2f}sec")
|
362
|
-
if (
|
363
|
-
self.scene.context.snap_grid
|
364
|
-
and "shift" not in modifiers
|
365
|
-
and b is not None
|
366
|
-
and not did_snap_to_point
|
367
|
-
):
|
368
|
-
# t1 = perf_counter()
|
369
|
-
gap = self.scene.context.grid_attract_len / get_matrix_scale(matrix)
|
370
|
-
# Check for corner points + center:
|
371
|
-
selected_points = (
|
372
|
-
(b[0], b[1]),
|
373
|
-
(b[2], b[1]),
|
374
|
-
(b[0], b[3]),
|
375
|
-
(b[2], b[3]),
|
376
|
-
((b[0] + b[2]) / 2, (b[1] + b[3]) / 2),
|
377
|
-
)
|
378
|
-
other_points = self.scene.pane.grid.grid_points
|
379
|
-
if (
|
380
|
-
other_points is not None
|
381
|
-
and selected_points is not None
|
382
|
-
and len(other_points) > 0
|
383
|
-
and len(selected_points) > 0
|
384
|
-
):
|
385
|
-
np_other = np.asarray(other_points)
|
386
|
-
np_selected = np.asarray(selected_points)
|
387
|
-
dist, pt1, pt2 = shortest_distance(np_other, np_selected, True)
|
388
|
-
if dist is not None and dist < gap:
|
389
|
-
# did_snap_to_point = True
|
390
|
-
dx = pt1[0] - pt2[0]
|
391
|
-
dy = pt1[1] - pt2[1]
|
392
|
-
move_to(dx, dy)
|
393
|
-
# Get new value
|
394
|
-
b = self.scene.context.elements._emphasized_bounds
|
395
|
-
|
396
|
-
# t2 = perf_counter()
|
397
|
-
# print (f"Corner-points, compared {len(selected_points)} pts to {len(other_points)} pts. Total time: {t2-t1:.2f}sec")
|
398
|
-
# Even then magnets win!
|
399
|
-
dx, dy = self.scene.pane.revised_magnet_bound(b)
|
400
|
-
move_to(dx, dy)
|
401
|
-
|
402
|
-
self.reset()
|
403
252
|
|
404
|
-
|
405
|
-
elif event_type == "move":
|
253
|
+
def check_move(space_pos):
|
406
254
|
if self.mode == "unclear":
|
407
255
|
current_time = perf_counter()
|
408
256
|
# print (f"{current_time - self.mouse_down_time:.2f}sec.")
|
@@ -421,6 +269,155 @@ class RectSelectWidget(Widget):
|
|
421
269
|
dy = space_pos[5]
|
422
270
|
move_to(dx, dy)
|
423
271
|
|
272
|
+
def check_leftup_select(space_pos):
|
273
|
+
_ = self.scene.context._
|
274
|
+
self.update_statusmsg(_("Status"))
|
275
|
+
elements.validate_selected_area()
|
276
|
+
sx = min(self.start_location[0], self.end_location[0])
|
277
|
+
sy = min(self.start_location[1], self.end_location[1])
|
278
|
+
ex = max(self.start_location[0], self.end_location[0])
|
279
|
+
ey = max(self.start_location[1], self.end_location[1])
|
280
|
+
self.rect_select(elements, sx, sy, ex, ey)
|
281
|
+
|
282
|
+
self.scene.request_refresh()
|
283
|
+
self.scene.context.signal("select_emphasized_tree", 0)
|
284
|
+
|
285
|
+
def check_leftup_move(space_pos):
|
286
|
+
b = self.scene.context.elements._emphasized_bounds
|
287
|
+
if b is None:
|
288
|
+
b = self.scene.context.elements.selected_area()
|
289
|
+
matrix = self.scene.widget_root.scene_widget.matrix
|
290
|
+
did_snap_to_point = False
|
291
|
+
if (
|
292
|
+
self.scene.context.snap_points
|
293
|
+
and "shift" not in modifiers
|
294
|
+
and b is not None
|
295
|
+
):
|
296
|
+
gap = self.scene.context.action_attract_len / get_matrix_scale(matrix)
|
297
|
+
# We gather all points of non-selected elements,
|
298
|
+
# but only those that lie within the boundaries
|
299
|
+
# of the selected area
|
300
|
+
# We compare every point of the selected elements
|
301
|
+
# with the points of the non-selected elements (provided they
|
302
|
+
# lie within the selection area plus boundary) and look for
|
303
|
+
# the closest distance.
|
304
|
+
|
305
|
+
# t1 = perf_counter()
|
306
|
+
other_points = []
|
307
|
+
selected_points = []
|
308
|
+
for e in self.scene.context.elements.elems():
|
309
|
+
target = selected_points if e.emphasized else other_points
|
310
|
+
if not hasattr(e, "as_geometry"):
|
311
|
+
continue
|
312
|
+
geom = e.as_geometry()
|
313
|
+
last = None
|
314
|
+
for seg in geom.segments[: geom.index]:
|
315
|
+
start = seg[0]
|
316
|
+
seg_type = geom._segtype(seg)
|
317
|
+
end = seg[4]
|
318
|
+
if seg_type in NON_GEOMETRY_TYPES:
|
319
|
+
continue
|
320
|
+
if np.isnan(start) or np.isnan(end):
|
321
|
+
print(
|
322
|
+
f"Strange, encountered within rectselect a segment with type: {seg_type} and start={start}, end={end} - coming from element type {e.type}\nPlease inform the developers"
|
323
|
+
)
|
324
|
+
continue
|
325
|
+
if start != last:
|
326
|
+
xx = start.real
|
327
|
+
yy = start.imag
|
328
|
+
ignore = (
|
329
|
+
xx < b[0] - gap
|
330
|
+
or xx > b[2] + gap
|
331
|
+
or yy < b[1] - gap
|
332
|
+
or yy > b[3] + gap
|
333
|
+
)
|
334
|
+
if not ignore:
|
335
|
+
target.append(start)
|
336
|
+
xx = end.real
|
337
|
+
yy = end.imag
|
338
|
+
ignore = (
|
339
|
+
xx < b[0] - gap
|
340
|
+
or xx > b[2] + gap
|
341
|
+
or yy < b[1] - gap
|
342
|
+
or yy > b[3] + gap
|
343
|
+
)
|
344
|
+
if not ignore:
|
345
|
+
target.append(end)
|
346
|
+
last = end
|
347
|
+
# t2 = perf_counter()
|
348
|
+
if other_points and selected_points:
|
349
|
+
np_other = np.asarray(other_points)
|
350
|
+
np_selected = np.asarray(selected_points)
|
351
|
+
dist, pt1, pt2 = shortest_distance(np_other, np_selected, False)
|
352
|
+
|
353
|
+
if dist is not None and dist < gap:
|
354
|
+
did_snap_to_point = True
|
355
|
+
dx = pt1.real - pt2.real
|
356
|
+
dy = pt1.imag - pt2.imag
|
357
|
+
move_to(dx, dy)
|
358
|
+
# Get new value
|
359
|
+
b = self.scene.context.elements._emphasized_bounds
|
360
|
+
# t3 = perf_counter()
|
361
|
+
# print (f"Snap, compared {len(selected_points)} pts to {len(other_points)} pts. Total time: {t3-t1:.2f}sec, Generation: {t2-t1:.2f}sec, shortest: {t3-t2:.2f}sec")
|
362
|
+
if (
|
363
|
+
self.scene.context.snap_grid
|
364
|
+
and "shift" not in modifiers
|
365
|
+
and b is not None
|
366
|
+
and not did_snap_to_point
|
367
|
+
):
|
368
|
+
# t1 = perf_counter()
|
369
|
+
gap = self.scene.context.grid_attract_len / get_matrix_scale(matrix)
|
370
|
+
# Check for corner points + center:
|
371
|
+
selected_points = (
|
372
|
+
(b[0], b[1]),
|
373
|
+
(b[2], b[1]),
|
374
|
+
(b[0], b[3]),
|
375
|
+
(b[2], b[3]),
|
376
|
+
((b[0] + b[2]) / 2, (b[1] + b[3]) / 2),
|
377
|
+
)
|
378
|
+
other_points = self.scene.pane.grid.grid_points
|
379
|
+
if other_points and selected_points:
|
380
|
+
np_other = np.asarray(other_points)
|
381
|
+
np_selected = np.asarray(selected_points)
|
382
|
+
dist, pt1, pt2 = shortest_distance(np_other, np_selected, True)
|
383
|
+
if dist is not None and dist < gap:
|
384
|
+
# did_snap_to_point = True
|
385
|
+
dx = pt1[0] - pt2[0]
|
386
|
+
dy = pt1[1] - pt2[1]
|
387
|
+
move_to(dx, dy)
|
388
|
+
# Get new value
|
389
|
+
b = self.scene.context.elements._emphasized_bounds
|
390
|
+
|
391
|
+
# t2 = perf_counter()
|
392
|
+
# print (f"Corner-points, compared {len(selected_points)} pts to {len(other_points)} pts. Total time: {t2-t1:.2f}sec")
|
393
|
+
# Even then magnets win!
|
394
|
+
dx, dy = self.scene.pane.revised_magnet_bound(b)
|
395
|
+
move_to(dx, dy)
|
396
|
+
|
397
|
+
if modifiers is not None:
|
398
|
+
self.modifiers = modifiers
|
399
|
+
|
400
|
+
elements = self.scene.context.elements
|
401
|
+
if event_type == "leftdown":
|
402
|
+
check_leftdown(space_pos)
|
403
|
+
# print ("RectSelect consumed leftdown")
|
404
|
+
return RESPONSE_CONSUME
|
405
|
+
elif event_type == "leftclick":
|
406
|
+
check_click(space_pos)
|
407
|
+
return RESPONSE_CHAIN
|
408
|
+
elif event_type == "leftup":
|
409
|
+
if self.mode == "select":
|
410
|
+
if self.start_location is None:
|
411
|
+
return RESPONSE_CHAIN
|
412
|
+
check_leftup_select(space_pos)
|
413
|
+
else:
|
414
|
+
check_leftup_move(space_pos)
|
415
|
+
|
416
|
+
self.reset()
|
417
|
+
|
418
|
+
return RESPONSE_CONSUME
|
419
|
+
elif event_type == "move":
|
420
|
+
check_move(space_pos)
|
424
421
|
return RESPONSE_CONSUME
|
425
422
|
elif event_type == "lost":
|
426
423
|
self.reset()
|
@@ -476,25 +473,26 @@ class RectSelectWidget(Widget):
|
|
476
473
|
except TypeError:
|
477
474
|
self.selection_pen.SetWidth(int(linewidth))
|
478
475
|
gc.SetPen(self.selection_pen)
|
479
|
-
delta_X = 15.0
|
480
|
-
delta_Y = 15.0
|
476
|
+
delta_X = 15.0 * self.magnification
|
477
|
+
delta_Y = 15.0 * self.magnification
|
481
478
|
x0 *= sx
|
482
479
|
x1 *= sx
|
483
480
|
y0 *= sx
|
484
481
|
y1 *= sx
|
485
|
-
if abs(x1 - x0) > delta_X and abs(y1 - y0)
|
482
|
+
if abs(x1 - x0) > delta_X and abs(y1 - y0) > delta_Y: # Don't draw if too tiny
|
486
483
|
# Draw tiny '+' in corner of pointer
|
487
484
|
x_signum = +1 * delta_X if x0 < x1 else -1 * delta_X
|
488
|
-
y_signum = +1 * delta_Y if y0 < y1 else -1 *
|
485
|
+
y_signum = +1 * delta_Y if y0 < y1 else -1 * delta_Y
|
489
486
|
ax1 = x1 - x_signum
|
490
487
|
ay1 = y1 - y_signum
|
491
488
|
|
492
489
|
gc.SetPen(self.selection_pen)
|
493
490
|
gc.StrokeLine(ax1, y1, ax1, ay1)
|
494
491
|
gc.StrokeLine(ax1, ay1, x1, ay1)
|
495
|
-
font_size = 10.0
|
496
|
-
|
497
|
-
font_size
|
492
|
+
font_size = 10.0 * self.magnification
|
493
|
+
font_size = max(
|
494
|
+
font_size, 1.0
|
495
|
+
) # Darwin issues a TypeError if font size is smaller than 1
|
498
496
|
try:
|
499
497
|
font = wx.Font(
|
500
498
|
font_size,
|
@@ -515,7 +513,7 @@ class RectSelectWidget(Widget):
|
|
515
513
|
symbol, (ax1 + x1) / 2 - t_width / 2, (ay1 + y1) / 2 - t_height / 2
|
516
514
|
)
|
517
515
|
if (
|
518
|
-
abs(x1 - x0) > 2 * delta_X and abs(y1 - y0)
|
516
|
+
abs(x1 - x0) > 2 * delta_X and abs(y1 - y0) > 2 * delta_Y
|
519
517
|
): # Don't draw if too tiny
|
520
518
|
# Draw second symbol at origin
|
521
519
|
ax1 = x0 + x_signum
|