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
meerk40t/tools/rasterplotter.py
CHANGED
@@ -18,19 +18,21 @@ The rasters can either be BIDIRECTIONAL or UNIDIRECTIONAL meaning they raster on
|
|
18
18
|
or only on forward swing.
|
19
19
|
"""
|
20
20
|
|
21
|
-
import
|
22
|
-
from math import sqrt
|
21
|
+
from math import isinf, sqrt
|
23
22
|
from time import perf_counter, sleep
|
23
|
+
|
24
|
+
import numpy as np
|
25
|
+
|
24
26
|
from meerk40t.constants import (
|
25
|
-
RASTER_T2B,
|
26
27
|
RASTER_B2T,
|
27
|
-
|
28
|
-
RASTER_L2R,
|
29
|
-
RASTER_HATCH,
|
28
|
+
RASTER_CROSSOVER,
|
30
29
|
RASTER_GREEDY_H,
|
31
30
|
RASTER_GREEDY_V,
|
32
|
-
|
31
|
+
RASTER_HATCH,
|
32
|
+
RASTER_L2R,
|
33
|
+
RASTER_R2L,
|
33
34
|
RASTER_SPIRAL,
|
35
|
+
RASTER_T2B,
|
34
36
|
)
|
35
37
|
|
36
38
|
|
@@ -90,7 +92,7 @@ class RasterPlotter:
|
|
90
92
|
|
91
93
|
if special is None:
|
92
94
|
special = {}
|
93
|
-
self.debug_level = 0
|
95
|
+
self.debug_level = 0 # 0 Nothing, 1 file creation, 2 file + summary, 3 file + summary + details
|
94
96
|
self.data = data
|
95
97
|
self.width = width
|
96
98
|
self.height = height
|
@@ -98,16 +100,18 @@ class RasterPlotter:
|
|
98
100
|
self._cache = None
|
99
101
|
parameters = {
|
100
102
|
# Provide an override for the minimumx / minimumy / horizontal / bidirectional
|
101
|
-
RASTER_T2B: (None, True, True, None),
|
102
|
-
RASTER_B2T: (None, False, True, None),
|
103
|
-
RASTER_R2L: (False, None, False, None),
|
104
|
-
RASTER_L2R: (True, None, False, None),
|
105
|
-
RASTER_HATCH: (None, None, None, None),
|
106
|
-
RASTER_GREEDY_H: (None, None, None, True),
|
107
|
-
RASTER_GREEDY_V: (None, None, None, True),
|
108
|
-
RASTER_CROSSOVER: (None, None, None, True),
|
103
|
+
RASTER_T2B: (None, True, True, None), # top to bottom
|
104
|
+
RASTER_B2T: (None, False, True, None), # bottom to top
|
105
|
+
RASTER_R2L: (False, None, False, None), # right to left
|
106
|
+
RASTER_L2R: (True, None, False, None), # left to right
|
107
|
+
RASTER_HATCH: (None, None, None, None), # crossraster (one of the two)
|
108
|
+
RASTER_GREEDY_H: (None, None, None, True), # greedy neighbour horizontal
|
109
|
+
RASTER_GREEDY_V: (None, None, None, True), # greedy neighbour
|
110
|
+
RASTER_CROSSOVER: (None, None, None, True), # true crossover
|
109
111
|
}
|
110
|
-
def_x, def_y, def_hor, def_bidir = parameters.get(
|
112
|
+
def_x, def_y, def_hor, def_bidir = parameters.get(
|
113
|
+
direction, (None, None, None, None)
|
114
|
+
)
|
111
115
|
self.start_minimum_x = start_minimum_x if def_x is None else def_x
|
112
116
|
self.start_minimum_y = start_minimum_y if def_y is None else def_y
|
113
117
|
self.horizontal = horizontal if def_hor is None else def_hor
|
@@ -120,7 +124,7 @@ class RasterPlotter:
|
|
120
124
|
# and calculate the overlap in pixels to the left / to the right
|
121
125
|
self.overlap = int(laserspot / sqrt(2) / 2)
|
122
126
|
# self.overlap = 1
|
123
|
-
self.special = dict(special)
|
127
|
+
self.special = dict(special) # Copy it so it wont be changed
|
124
128
|
if horizontal:
|
125
129
|
self.overscan = round(overscan / float(step_x))
|
126
130
|
else:
|
@@ -150,11 +154,13 @@ class RasterPlotter:
|
|
150
154
|
if 0 <= self.direction < len(methods):
|
151
155
|
s_meth = f"Rasterplotter ({self.width}x{self.height}): {methods[self.direction]} ({self.direction})"
|
152
156
|
else:
|
153
|
-
s_meth =
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
157
|
+
s_meth = (
|
158
|
+
f"Rasterplotter ({self.width}x{self.height}): Unknown {self.direction}"
|
159
|
+
)
|
160
|
+
s_direc = "Bidirectional" if self.bidirectional else "Unidirectional"
|
161
|
+
s_axis = "horizontal" if self.horizontal else "vertical"
|
162
|
+
s_ystart = "top" if self.start_minimum_y else "bottom"
|
163
|
+
s_xstart = "left" if self.start_minimum_x else "right"
|
158
164
|
return f"{s_meth}, {s_direc} {s_axis} plot starting at {s_ystart}-{s_xstart}"
|
159
165
|
|
160
166
|
def reset(self):
|
@@ -434,7 +440,7 @@ class RasterPlotter:
|
|
434
440
|
Returns the initial position for this within the scene. Taking into account start corner, and step size.
|
435
441
|
@return: initial position within scene. The first plot location.
|
436
442
|
"""
|
437
|
-
if self.initial_x is None: # image is blank.
|
443
|
+
if self.initial_x is None or isinf(self.initial_x): # image is blank.
|
438
444
|
if self.use_integers:
|
439
445
|
return int(round(self.offset_x)), int(round(self.offset_y))
|
440
446
|
else:
|
@@ -518,15 +524,20 @@ class RasterPlotter:
|
|
518
524
|
s_meth = f"Method: {m} ({self.direction})"
|
519
525
|
except IndexError:
|
520
526
|
s_meth = f"Method: Unknown {self.direction}"
|
521
|
-
print
|
527
|
+
print(s_meth)
|
522
528
|
data = list(self._plot_pixels())
|
523
529
|
from platform import system
|
530
|
+
|
524
531
|
defaultdir = "c:\\temp\\" if system() == "Windows" else ""
|
525
532
|
has_duplicates = 0
|
526
533
|
tstamp = int(perf_counter() * 100)
|
527
534
|
with open(f"{defaultdir}plot_{tstamp}.txt", mode="w") as f:
|
528
|
-
f.write(
|
529
|
-
|
535
|
+
f.write(
|
536
|
+
f"0.9.7\n{s_meth}\n{'Bidirectional' if self.bidirectional else 'Unidirectional'} {'horizontal' if self.horizontal else 'vertical'} plot starting at {'top' if self.start_minimum_y else 'bottom'}-{'left' if self.start_minimum_x else 'right'}\n"
|
537
|
+
)
|
538
|
+
f.write(
|
539
|
+
f"Overscan: {self.overscan:.2f}, Stepx={step_x:.2f}, Stepy={step_y:.2f}\n"
|
540
|
+
)
|
530
541
|
f.write(f"Image dimensions: {self.width}x{self.height}\n")
|
531
542
|
f.write(f"Startpoint: {self.initial_x}, {self.initial_y}\n")
|
532
543
|
f.write(f"Overlapping pixels to any side: {self.overlap}\n")
|
@@ -534,7 +545,9 @@ class RasterPlotter:
|
|
534
545
|
f.write(f"Special instructions:\n")
|
535
546
|
for key, value in self.special.items():
|
536
547
|
f.write(f" {key} = {value}\n")
|
537
|
-
f.write(
|
548
|
+
f.write(
|
549
|
+
"----------------------------------------------------------------------\n"
|
550
|
+
)
|
538
551
|
test_dict = {}
|
539
552
|
lastx = self.initial_x
|
540
553
|
lasty = self.initial_y
|
@@ -543,32 +556,48 @@ class RasterPlotter:
|
|
543
556
|
if lastx is not None:
|
544
557
|
dx = x - lastx
|
545
558
|
dy = y - lasty
|
546
|
-
if dx != 0 and dy != 0:
|
547
|
-
f.write
|
548
|
-
|
559
|
+
if dx != 0 and dy != 0: # and abs(dx) != abs(dy):
|
560
|
+
f.write(
|
561
|
+
f"You f**ed up! No zigzag movement from line {lineno - 1} to {lineno}: {lastx}, {lasty} -> {x}, {y}\n"
|
562
|
+
)
|
563
|
+
print(
|
564
|
+
f"You f**ed up! No zigzag movement from line {lineno - 1} to {lineno}: {lastx}, {lasty} -> {x}, {y}"
|
565
|
+
)
|
549
566
|
failed = True
|
550
567
|
lastx = x
|
551
568
|
lasty = y
|
552
569
|
if not failed:
|
553
570
|
f.write("Good news, no zig-zag movements identified!\n")
|
554
|
-
f.write(
|
571
|
+
f.write(
|
572
|
+
"----------------------------------------------------------------------\n"
|
573
|
+
)
|
555
574
|
for lineno, (x, y, on) in enumerate(data, start=1):
|
556
575
|
if x is None or y is None:
|
557
576
|
continue
|
558
577
|
key = f"{x} - {y}"
|
559
578
|
if key in test_dict:
|
560
|
-
f.write
|
579
|
+
f.write(
|
580
|
+
f"Duplicate coordinates in list at ({x}, {y})! 1st: #{test_dict[key][0]}, on={test_dict[key][1]}, 2nd: #{lineno}, on={on}\n"
|
581
|
+
)
|
561
582
|
has_duplicates += 1
|
562
583
|
else:
|
563
584
|
test_dict[key] = (lineno, on)
|
564
585
|
if has_duplicates:
|
565
|
-
f.write(
|
586
|
+
f.write(
|
587
|
+
"----------------------------------------------------------------------\n"
|
588
|
+
)
|
566
589
|
for lineno, (x, y, on) in enumerate(data, start=1):
|
567
590
|
f.write(f"{lineno}: {x}, {y}, {on}\n")
|
568
591
|
if has_duplicates:
|
569
|
-
print(
|
570
|
-
|
571
|
-
|
592
|
+
print(
|
593
|
+
f"Attention: the generated plot has {has_duplicates} duplicate coordinate values!"
|
594
|
+
)
|
595
|
+
print(
|
596
|
+
f"{'Bidirectional' if self.bidirectional else 'Unidirectional'} {'horizontal' if self.horizontal else 'vertical'} plot starting at {'top' if self.start_minimum_y else 'bottom'}-{'left' if self.start_minimum_x else 'right'}"
|
597
|
+
)
|
598
|
+
print(
|
599
|
+
f"Overscan: {self.overscan:.2f}, Stepx={step_x:.2f}, Stepy={step_y:.2f}"
|
600
|
+
)
|
572
601
|
print(f"Image dimensions: {self.width}x{self.height}")
|
573
602
|
else:
|
574
603
|
data = list(self._plot_pixels())
|
@@ -585,8 +614,22 @@ class RasterPlotter:
|
|
585
614
|
else:
|
586
615
|
nx = int(round(offset_x + step_x * x))
|
587
616
|
ny = int(round(offset_y + y * step_y))
|
588
|
-
self._distance_burn +=
|
589
|
-
|
617
|
+
self._distance_burn += (
|
618
|
+
0
|
619
|
+
if on == 0
|
620
|
+
else sqrt(
|
621
|
+
(nx - last_x) * (nx - last_x)
|
622
|
+
+ (ny - last_y) * (ny - last_y)
|
623
|
+
)
|
624
|
+
)
|
625
|
+
self._distance_travel += (
|
626
|
+
0
|
627
|
+
if on != 0
|
628
|
+
else sqrt(
|
629
|
+
(nx - last_x) * (nx - last_x)
|
630
|
+
+ (ny - last_y) * (ny - last_y)
|
631
|
+
)
|
632
|
+
)
|
590
633
|
yield nx, ny, on
|
591
634
|
last_x = nx
|
592
635
|
last_y = ny
|
@@ -598,8 +641,22 @@ class RasterPlotter:
|
|
598
641
|
else:
|
599
642
|
nx = round(offset_x + step_x * x)
|
600
643
|
ny = round(offset_y + y * step_y)
|
601
|
-
self._distance_burn +=
|
602
|
-
|
644
|
+
self._distance_burn += (
|
645
|
+
0
|
646
|
+
if on == 0
|
647
|
+
else sqrt(
|
648
|
+
(nx - last_x) * (nx - last_x)
|
649
|
+
+ (ny - last_y) * (ny - last_y)
|
650
|
+
)
|
651
|
+
)
|
652
|
+
self._distance_travel += (
|
653
|
+
0
|
654
|
+
if on != 0
|
655
|
+
else sqrt(
|
656
|
+
(nx - last_x) * (nx - last_x)
|
657
|
+
+ (ny - last_y) * (ny - last_y)
|
658
|
+
)
|
659
|
+
)
|
603
660
|
yield offset_x + step_x * x, offset_y + y * step_y, on
|
604
661
|
last_x = nx
|
605
662
|
last_y = ny
|
@@ -632,12 +689,12 @@ class RasterPlotter:
|
|
632
689
|
return
|
633
690
|
BLANK = 255
|
634
691
|
for y in range(self.height):
|
635
|
-
msg:str = f"{y:3d}: "
|
692
|
+
msg: str = f"{y:3d}: "
|
636
693
|
for x in range(self.width):
|
637
694
|
msg += "." if self.data[x, y] == BLANK else "X"
|
638
|
-
print
|
695
|
+
print(msg)
|
639
696
|
|
640
|
-
def _get_pixel_chains(self, xy:int, is_x
|
697
|
+
def _get_pixel_chains(self, xy: int, is_x: bool) -> list:
|
641
698
|
last_pixel = None
|
642
699
|
segments = []
|
643
700
|
upper = self.width if is_x else self.height
|
@@ -648,11 +705,11 @@ class RasterPlotter:
|
|
648
705
|
if on == last_pixel:
|
649
706
|
segments[-1][1] = idx
|
650
707
|
else:
|
651
|
-
segments.append
|
708
|
+
segments.append([idx, idx, on])
|
652
709
|
last_pixel = on
|
653
710
|
return segments
|
654
711
|
|
655
|
-
def _consume_pixel_chains(self, segments:list, xy:int, is_x
|
712
|
+
def _consume_pixel_chains(self, segments: list, xy: int, is_x: bool):
|
656
713
|
BLANK = 255
|
657
714
|
# for x in range(5):
|
658
715
|
# msg1 = f"{x}: "
|
@@ -727,7 +784,11 @@ class RasterPlotter:
|
|
727
784
|
# We consider as well the overscan value
|
728
785
|
overscan_top = 0 if dy >= 0 else self.overscan
|
729
786
|
overscan_bottom = 0 if dy <= 0 else self.overscan
|
730
|
-
if not first and (
|
787
|
+
if not first and (
|
788
|
+
segments[0][0] - overscan_top
|
789
|
+
<= last_y
|
790
|
+
<= segments[-1][1] + overscan_bottom
|
791
|
+
):
|
731
792
|
# inside the chain!
|
732
793
|
# So lets move a bit to the side
|
733
794
|
if dy > 0:
|
@@ -814,7 +875,11 @@ class RasterPlotter:
|
|
814
875
|
# We consider as well the overscan value
|
815
876
|
overscan_left = 0 if dx >= 0 else self.overscan
|
816
877
|
overscan_right = 0 if dx <= 0 else self.overscan
|
817
|
-
if not first and (
|
878
|
+
if not first and (
|
879
|
+
segments[0][0] - overscan_left
|
880
|
+
<= last_x
|
881
|
+
<= segments[-1][1] + overscan_right
|
882
|
+
):
|
818
883
|
# inside the chain!
|
819
884
|
# So lets move a bit to the side
|
820
885
|
if dx > 0:
|
@@ -1021,12 +1086,14 @@ class RasterPlotter:
|
|
1021
1086
|
"""
|
1022
1087
|
|
1023
1088
|
def walk_segments(segments, horizontal=True, xy_penalty=1, width=1, height=1):
|
1024
|
-
n:int = len(segments)
|
1089
|
+
n: int = len(segments)
|
1025
1090
|
visited = np.zeros(n, dtype=bool)
|
1026
1091
|
path = []
|
1027
1092
|
window_size = 10
|
1028
1093
|
current_point = np.array(segments[0][0], dtype=float)
|
1029
|
-
segment_points = np.array(
|
1094
|
+
segment_points = np.array(
|
1095
|
+
[point for segment in segments for point in segment], dtype=float
|
1096
|
+
)
|
1030
1097
|
mask = ~visited.repeat(2)
|
1031
1098
|
while len(path) < n:
|
1032
1099
|
# Find the range of segments within the x- and y-window
|
@@ -1035,17 +1102,19 @@ class RasterPlotter:
|
|
1035
1102
|
y_min = current_point[1] - window_size
|
1036
1103
|
y_max = current_point[1] + window_size
|
1037
1104
|
unvisited_indices = np.where(
|
1038
|
-
(segment_points[:, 0] >= x_min)
|
1039
|
-
(segment_points[:, 0] <= x_max)
|
1040
|
-
(segment_points[:, 1] >= y_min)
|
1041
|
-
(segment_points[:, 1] <= y_max)
|
1042
|
-
mask
|
1105
|
+
(segment_points[:, 0] >= x_min)
|
1106
|
+
& (segment_points[:, 0] <= x_max)
|
1107
|
+
& (segment_points[:, 1] >= y_min)
|
1108
|
+
& (segment_points[:, 1] <= y_max)
|
1109
|
+
& mask
|
1043
1110
|
)[0]
|
1044
1111
|
if len(unvisited_indices) == 0:
|
1045
1112
|
# If no segments are within the window, expand the window
|
1046
1113
|
window_size *= 2
|
1047
1114
|
# print (f"Did not find points: now window: {window_size}")
|
1048
|
-
if
|
1115
|
+
if (
|
1116
|
+
window_size <= 2 * height or window_size <= 2 * width
|
1117
|
+
): # Safety belt
|
1049
1118
|
continue
|
1050
1119
|
|
1051
1120
|
unvisited_points = segment_points[unvisited_indices]
|
@@ -1053,11 +1122,11 @@ class RasterPlotter:
|
|
1053
1122
|
# distances = distance_matrix(unvisited_points, current_point, y_penalty)
|
1054
1123
|
diff = unvisited_points - current_point
|
1055
1124
|
if horizontal:
|
1056
|
-
diff[:, 1] *= xy_penalty
|
1125
|
+
diff[:, 1] *= xy_penalty # Apply penalty to y-distances
|
1057
1126
|
else:
|
1058
|
-
diff[:, 0] *= xy_penalty
|
1127
|
+
diff[:, 0] *= xy_penalty # Apply penalty to x-distances
|
1059
1128
|
|
1060
|
-
distances = np.sum(diff
|
1129
|
+
distances = np.sum(diff**2, axis=1) # Return squared distances
|
1061
1130
|
|
1062
1131
|
min_distance_idx = np.argmin(distances)
|
1063
1132
|
next_segment = unvisited_indices[min_distance_idx] // 2
|
@@ -1068,12 +1137,16 @@ class RasterPlotter:
|
|
1068
1137
|
mask[2 * next_segment] = False
|
1069
1138
|
mask[2 * next_segment + 1] = False
|
1070
1139
|
if min_distance_idx % 2 == 0:
|
1071
|
-
path.append((next_segment,
|
1072
|
-
current_point = segment_points[
|
1140
|
+
path.append((next_segment, "end"))
|
1141
|
+
current_point = segment_points[
|
1142
|
+
next_segment * 2 + 1
|
1143
|
+
] # Move to the other endpoint
|
1073
1144
|
else:
|
1074
|
-
path.append((next_segment,
|
1075
|
-
current_point = segment_points[
|
1076
|
-
|
1145
|
+
path.append((next_segment, "start"))
|
1146
|
+
current_point = segment_points[
|
1147
|
+
next_segment * 2
|
1148
|
+
] # Move to the other endpoint
|
1149
|
+
window_size = 10 # Reset window size
|
1077
1150
|
|
1078
1151
|
return path
|
1079
1152
|
|
@@ -1093,14 +1166,16 @@ class RasterPlotter:
|
|
1093
1166
|
line_parts = []
|
1094
1167
|
on_parts = []
|
1095
1168
|
if self.debug_level > 2:
|
1096
|
-
print
|
1169
|
+
print(
|
1170
|
+
f"{'horizontal' if horizontal else 'Vertical'} for {self.width}x{self.height} image. {'y' if horizontal else 'x'} from {lower} to {upper}"
|
1171
|
+
)
|
1097
1172
|
if horizontal:
|
1098
1173
|
while lower <= y <= upper:
|
1099
1174
|
segments = self._get_pixel_chains(y, True)
|
1100
1175
|
self._consume_pixel_chains(segments, y, True)
|
1101
1176
|
for seg in segments:
|
1102
1177
|
# Append (xstart, y), (xend, y), on
|
1103
|
-
line_parts.append(
|
1178
|
+
line_parts.append(((seg[0], y), (seg[1], y)))
|
1104
1179
|
on_parts.append(seg[2])
|
1105
1180
|
y += dy
|
1106
1181
|
else:
|
@@ -1109,14 +1184,20 @@ class RasterPlotter:
|
|
1109
1184
|
self._consume_pixel_chains(segments, x, False)
|
1110
1185
|
for seg in segments:
|
1111
1186
|
# Append (xstart, y), (xend, y), on
|
1112
|
-
line_parts.append(
|
1187
|
+
line_parts.append(((x, seg[0]), (x, seg[1])))
|
1113
1188
|
on_parts.append(seg[2])
|
1114
1189
|
x += dx
|
1115
1190
|
if self.debug_level > 2:
|
1116
|
-
print
|
1191
|
+
print(f"Created {len(line_parts)} segments")
|
1117
1192
|
t1 = perf_counter()
|
1118
1193
|
penalty = 3 if self.special.get("gantry", False) else 1
|
1119
|
-
path = walk_segments(
|
1194
|
+
path = walk_segments(
|
1195
|
+
line_parts,
|
1196
|
+
horizontal=horizontal,
|
1197
|
+
xy_penalty=penalty,
|
1198
|
+
width=self.width,
|
1199
|
+
height=self.height,
|
1200
|
+
)
|
1120
1201
|
# print("Order of segments:", path)
|
1121
1202
|
t2 = perf_counter()
|
1122
1203
|
if horizontal:
|
@@ -1171,14 +1252,16 @@ class RasterPlotter:
|
|
1171
1252
|
last_y = ey
|
1172
1253
|
t3 = perf_counter()
|
1173
1254
|
if self.debug_level > 1:
|
1174
|
-
print
|
1175
|
-
|
1255
|
+
print(
|
1256
|
+
f"Overall time for {'horizontal' if horizontal else 'vertical'} consumption: {t3-t0:.2f}s - created: {len(line_parts)} segments"
|
1257
|
+
)
|
1258
|
+
print(
|
1259
|
+
f"Computation: {t2-t0:.2f}s - Chain creation:{t1 - t0:.2f}s, Walk: {t2 - t1:.2f}s"
|
1260
|
+
)
|
1176
1261
|
self.final_x = last_x
|
1177
1262
|
self.final_y = last_y
|
1178
1263
|
|
1179
1264
|
def _plot_spiral(self):
|
1180
|
-
|
1181
|
-
|
1182
1265
|
rows = self.height
|
1183
1266
|
cols = self.width
|
1184
1267
|
center_row, center_col = rows // 2, cols // 2
|
@@ -1223,7 +1306,7 @@ class RasterPlotter:
|
|
1223
1306
|
if on == last_pixel and len(segments):
|
1224
1307
|
segments[-1][1] = (col, row)
|
1225
1308
|
else:
|
1226
|
-
segments.append
|
1309
|
+
segments.append([(col, row), (col, row), on])
|
1227
1310
|
|
1228
1311
|
last_pixel = on
|
1229
1312
|
count += 1
|
@@ -1255,7 +1338,7 @@ class RasterPlotter:
|
|
1255
1338
|
sy = min(start_y, end_y)
|
1256
1339
|
ey = max(start_y, end_y)
|
1257
1340
|
|
1258
|
-
if direction_index in (0, 2):
|
1341
|
+
if direction_index in (0, 2): # horizontal
|
1259
1342
|
for y_idx in range(-self.overlap, self.overlap + 1):
|
1260
1343
|
ny = sy + y_idx
|
1261
1344
|
for nx in range(sx, ex + 1):
|
@@ -1268,11 +1351,9 @@ class RasterPlotter:
|
|
1268
1351
|
if 0 <= nx < self.width and 0 <= ny < self.height:
|
1269
1352
|
self.data[nx, ny] = BLANK
|
1270
1353
|
|
1271
|
-
|
1272
1354
|
direction_index = (direction_index + 1) % 4
|
1273
1355
|
steps += 1
|
1274
1356
|
|
1275
|
-
|
1276
1357
|
def _plot_crossover(self):
|
1277
1358
|
"""
|
1278
1359
|
This algorithm scans through the image looking for the row or the column with the most pixels.
|
@@ -1289,8 +1370,8 @@ class RasterPlotter:
|
|
1289
1370
|
Yields:
|
1290
1371
|
list of tuples with (x, y, on)
|
1291
1372
|
"""
|
1292
|
-
ROW=0
|
1293
|
-
COL=1
|
1373
|
+
ROW = 0
|
1374
|
+
COL = 1
|
1294
1375
|
|
1295
1376
|
def process_image(image):
|
1296
1377
|
# We will modify the image to keep track of deleted rows and columns
|
@@ -1373,28 +1454,30 @@ class RasterPlotter:
|
|
1373
1454
|
# msg = f"{msg}{'X' if on else '.'}"
|
1374
1455
|
if on:
|
1375
1456
|
if not covered_col[idx]:
|
1376
|
-
covered_col[idx] = None
|
1457
|
+
covered_col[idx] = None # needs recalc
|
1377
1458
|
if on == last_pixel:
|
1378
1459
|
segments[-1][1] = idx
|
1379
1460
|
else:
|
1380
|
-
segments.append
|
1461
|
+
segments.append([idx, idx, on])
|
1381
1462
|
last_pixel = on
|
1382
|
-
results.append(
|
1463
|
+
results.append(
|
1464
|
+
(COL, rowidx, segments)
|
1465
|
+
) # Intentionally so, as the numpy array has x and y exchanged
|
1383
1466
|
# print (f"Col #{rowidx}: {msg} -> {segments}")
|
1384
1467
|
|
1385
1468
|
# Clear the column
|
1386
|
-
image[rowidx
|
1469
|
+
image[rowidx, :] = 0
|
1387
1470
|
covered_row[rowidx] = True
|
1388
1471
|
stored_row[rowidx] = 0
|
1389
1472
|
for rc in range(self.overlap):
|
1390
1473
|
r = rowidx - rc
|
1391
1474
|
if 0 <= r < rows:
|
1392
|
-
image[r
|
1475
|
+
image[r, :] = 0
|
1393
1476
|
covered_row[r] = True
|
1394
1477
|
stored_row[r] = 0
|
1395
1478
|
r = rowidx + rc
|
1396
1479
|
if 0 <= r < rows:
|
1397
|
-
image[r
|
1480
|
+
image[r, :] = 0
|
1398
1481
|
covered_row[r] = True
|
1399
1482
|
stored_row[r] = 0
|
1400
1483
|
recalc_col = True
|
@@ -1407,11 +1490,11 @@ class RasterPlotter:
|
|
1407
1490
|
# msg = f"{msg}{'X' if on else '.'}"
|
1408
1491
|
if on:
|
1409
1492
|
if not covered_row[idx]:
|
1410
|
-
covered_row[idx] = None
|
1493
|
+
covered_row[idx] = None # needs recalc
|
1411
1494
|
if on == last_pixel:
|
1412
1495
|
segments[-1][1] = idx
|
1413
1496
|
else:
|
1414
|
-
segments.append
|
1497
|
+
segments.append([idx, idx, on])
|
1415
1498
|
last_pixel = on
|
1416
1499
|
results.append((ROW, colidx, segments))
|
1417
1500
|
# print (f"Row #{colidx}: {msg} -> {segments}")
|
@@ -1437,7 +1520,7 @@ class RasterPlotter:
|
|
1437
1520
|
for ridx in range(rows):
|
1438
1521
|
on = image[ridx, cidx]
|
1439
1522
|
msg = f"{msg}{'X' if on else '.'}"
|
1440
|
-
print
|
1523
|
+
print(f"{cidx:3d}: {msg}")
|
1441
1524
|
|
1442
1525
|
return results
|
1443
1526
|
|
@@ -1448,7 +1531,7 @@ class RasterPlotter:
|
|
1448
1531
|
for x in range(self.width):
|
1449
1532
|
for y in range(self.height):
|
1450
1533
|
px = self.px(x, y)
|
1451
|
-
if px==self.skip_pixel:
|
1534
|
+
if px == self.skip_pixel:
|
1452
1535
|
px = 0
|
1453
1536
|
image[x, y] = px
|
1454
1537
|
t1 = perf_counter()
|
@@ -1528,7 +1611,7 @@ class RasterPlotter:
|
|
1528
1611
|
if self.bidirectional:
|
1529
1612
|
if mode == ROW:
|
1530
1613
|
dx = -dx
|
1531
|
-
else:
|
1614
|
+
else: # column
|
1532
1615
|
dy = -dy
|
1533
1616
|
|
1534
1617
|
# We need to set the final values so that the rastercut is able to carry on
|
@@ -1536,8 +1619,11 @@ class RasterPlotter:
|
|
1536
1619
|
self.final_y = last_y
|
1537
1620
|
t3 = perf_counter()
|
1538
1621
|
if self.debug_level > 1:
|
1539
|
-
print
|
1540
|
-
print
|
1622
|
+
print(f"Overall time for crossover consumption: {t3-t0:.2f}s")
|
1623
|
+
print(
|
1624
|
+
f"Computation: {t2 - t0:.2f}s - Array creation:{t1 - t0:.2f}s, Algorithm: {t2 - t1:.2f}s"
|
1625
|
+
)
|
1626
|
+
|
1541
1627
|
"""
|
1542
1628
|
# Testpattern generation
|
1543
1629
|
def testpattern_generator(self):
|
@@ -1657,4 +1743,4 @@ class RasterPlotter:
|
|
1657
1743
|
yield from methods[method]()
|
1658
1744
|
except IndexError:
|
1659
1745
|
print (f"Unknown testgenerator for {self.direction}")
|
1660
|
-
"""
|
1746
|
+
"""
|