meerk40t 0.9.7030__py2.py3-none-any.whl → 0.9.7050__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.
Files changed (85) hide show
  1. meerk40t/balormk/clone_loader.py +3 -2
  2. meerk40t/balormk/controller.py +38 -13
  3. meerk40t/balormk/cylindermod.py +1 -0
  4. meerk40t/balormk/device.py +13 -9
  5. meerk40t/balormk/driver.py +9 -2
  6. meerk40t/balormk/galvo_commands.py +3 -1
  7. meerk40t/balormk/gui/gui.py +6 -0
  8. meerk40t/balormk/livelightjob.py +338 -321
  9. meerk40t/balormk/mock_connection.py +4 -3
  10. meerk40t/balormk/usb_connection.py +11 -2
  11. meerk40t/camera/camera.py +19 -14
  12. meerk40t/camera/gui/camerapanel.py +6 -0
  13. meerk40t/core/cutplan.py +101 -78
  14. meerk40t/core/elements/element_treeops.py +435 -140
  15. meerk40t/core/elements/elements.py +100 -9
  16. meerk40t/core/elements/shapes.py +259 -72
  17. meerk40t/core/elements/tree_commands.py +10 -5
  18. meerk40t/core/node/blobnode.py +19 -4
  19. meerk40t/core/node/elem_ellipse.py +18 -8
  20. meerk40t/core/node/elem_image.py +51 -19
  21. meerk40t/core/node/elem_line.py +18 -8
  22. meerk40t/core/node/elem_path.py +18 -8
  23. meerk40t/core/node/elem_point.py +10 -4
  24. meerk40t/core/node/elem_polyline.py +19 -11
  25. meerk40t/core/node/elem_rect.py +18 -8
  26. meerk40t/core/node/elem_text.py +11 -5
  27. meerk40t/core/node/filenode.py +2 -8
  28. meerk40t/core/node/groupnode.py +11 -11
  29. meerk40t/core/node/image_processed.py +11 -5
  30. meerk40t/core/node/image_raster.py +11 -5
  31. meerk40t/core/node/node.py +64 -16
  32. meerk40t/core/node/refnode.py +2 -1
  33. meerk40t/core/planner.py +25 -11
  34. meerk40t/core/svg_io.py +91 -34
  35. meerk40t/device/dummydevice.py +7 -1
  36. meerk40t/extra/vtracer.py +222 -0
  37. meerk40t/grbl/device.py +96 -9
  38. meerk40t/grbl/driver.py +15 -5
  39. meerk40t/gui/about.py +20 -0
  40. meerk40t/gui/devicepanel.py +20 -16
  41. meerk40t/gui/gui_mixins.py +4 -0
  42. meerk40t/gui/icons.py +330 -253
  43. meerk40t/gui/laserpanel.py +27 -3
  44. meerk40t/gui/laserrender.py +41 -21
  45. meerk40t/gui/magnetoptions.py +158 -65
  46. meerk40t/gui/materialtest.py +569 -310
  47. meerk40t/gui/navigationpanels.py +229 -24
  48. meerk40t/gui/propertypanels/hatchproperty.py +2 -0
  49. meerk40t/gui/propertypanels/imageproperty.py +160 -106
  50. meerk40t/gui/propertypanels/wobbleproperty.py +6 -2
  51. meerk40t/gui/ribbon.py +6 -1
  52. meerk40t/gui/scenewidgets/gridwidget.py +29 -32
  53. meerk40t/gui/scenewidgets/rectselectwidget.py +190 -192
  54. meerk40t/gui/simulation.py +75 -77
  55. meerk40t/gui/spoolerpanel.py +27 -7
  56. meerk40t/gui/statusbarwidgets/defaultoperations.py +84 -48
  57. meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
  58. meerk40t/gui/tips.py +15 -1
  59. meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
  60. meerk40t/gui/wxmmain.py +242 -114
  61. meerk40t/gui/wxmscene.py +107 -24
  62. meerk40t/gui/wxmtree.py +4 -2
  63. meerk40t/gui/wxutils.py +286 -15
  64. meerk40t/image/imagetools.py +129 -65
  65. meerk40t/internal_plugins.py +4 -0
  66. meerk40t/kernel/kernel.py +67 -18
  67. meerk40t/kernel/settings.py +28 -9
  68. meerk40t/lihuiyu/device.py +24 -12
  69. meerk40t/main.py +14 -9
  70. meerk40t/moshi/device.py +20 -6
  71. meerk40t/network/console_server.py +22 -6
  72. meerk40t/newly/device.py +10 -3
  73. meerk40t/newly/gui/gui.py +10 -0
  74. meerk40t/ruida/device.py +22 -2
  75. meerk40t/ruida/loader.py +9 -4
  76. meerk40t/ruida/rdjob.py +48 -8
  77. meerk40t/tools/geomstr.py +240 -123
  78. meerk40t/tools/rasterplotter.py +185 -94
  79. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/METADATA +1 -1
  80. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/RECORD +85 -84
  81. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/LICENSE +0 -0
  82. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/WHEEL +0 -0
  83. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/entry_points.txt +0 -0
  84. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/top_level.txt +0 -0
  85. {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7050.dist-info}/zip-safe +0 -0
@@ -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 numpy as np
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
- RASTER_R2L,
28
- RASTER_L2R,
29
- RASTER_HATCH,
28
+ RASTER_CROSSOVER,
30
29
  RASTER_GREEDY_H,
31
30
  RASTER_GREEDY_V,
32
- RASTER_CROSSOVER,
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 # 0 Nothing, 1 file creation, 2 file + summary, 3 file + summary + details
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), # top to bottom
102
- RASTER_B2T: (None, False, True, None), # bottom to top
103
- RASTER_R2L: (False, None, False, None), # right to left
104
- RASTER_L2R: (True, None, False, None), # left to right
105
- RASTER_HATCH: (None, None, None, None), # crossraster (one of the two)
106
- RASTER_GREEDY_H: (None, None, None, True), # greedy neighbour horizontal
107
- RASTER_GREEDY_V: (None, None, None, True), # greedy neighbour
108
- RASTER_CROSSOVER: (None, None, None, True), # true crossover
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(direction, (None, None, None, None))
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) # Copy it so it wont be changed
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 = f"Rasterplotter ({self.width}x{self.height}): Unknown {self.direction}"
154
- s_direc = 'Bidirectional' if self.bidirectional else 'Unidirectional'
155
- s_axis = 'horizontal' if self.horizontal else 'vertical'
156
- s_ystart = 'top' if self.start_minimum_y else 'bottom'
157
- s_xstart = 'left' if self.start_minimum_x else 'right'
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:
@@ -456,7 +462,12 @@ class RasterPlotter:
456
462
  of the width and height.
457
463
  @return:
458
464
  """
459
- if self.final_x is None: # image is blank.
465
+ if self.final_x is None or isinf(self.final_x): # image is blank.
466
+ if self.use_integers:
467
+ return int(round(self.offset_x)), int(round(self.offset_y))
468
+ else:
469
+ return self.offset_x, self.offset_y
470
+ if self.use_integers:
460
471
  if self.use_integers:
461
472
  return int(round(self.offset_x)), int(round(self.offset_y))
462
473
  else:
@@ -518,15 +529,20 @@ class RasterPlotter:
518
529
  s_meth = f"Method: {m} ({self.direction})"
519
530
  except IndexError:
520
531
  s_meth = f"Method: Unknown {self.direction}"
521
- print (s_meth)
532
+ print(s_meth)
522
533
  data = list(self._plot_pixels())
523
534
  from platform import system
535
+
524
536
  defaultdir = "c:\\temp\\" if system() == "Windows" else ""
525
537
  has_duplicates = 0
526
538
  tstamp = int(perf_counter() * 100)
527
539
  with open(f"{defaultdir}plot_{tstamp}.txt", mode="w") as f:
528
- f.write(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")
529
- f.write(f"Overscan: {self.overscan:.2f}, Stepx={step_x:.2f}, Stepy={step_y:.2f}\n")
540
+ f.write(
541
+ 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"
542
+ )
543
+ f.write(
544
+ f"Overscan: {self.overscan:.2f}, Stepx={step_x:.2f}, Stepy={step_y:.2f}\n"
545
+ )
530
546
  f.write(f"Image dimensions: {self.width}x{self.height}\n")
531
547
  f.write(f"Startpoint: {self.initial_x}, {self.initial_y}\n")
532
548
  f.write(f"Overlapping pixels to any side: {self.overlap}\n")
@@ -534,7 +550,9 @@ class RasterPlotter:
534
550
  f.write(f"Special instructions:\n")
535
551
  for key, value in self.special.items():
536
552
  f.write(f" {key} = {value}\n")
537
- f.write("----------------------------------------------------------------------\n")
553
+ f.write(
554
+ "----------------------------------------------------------------------\n"
555
+ )
538
556
  test_dict = {}
539
557
  lastx = self.initial_x
540
558
  lasty = self.initial_y
@@ -543,32 +561,48 @@ class RasterPlotter:
543
561
  if lastx is not None:
544
562
  dx = x - lastx
545
563
  dy = y - lasty
546
- if dx != 0 and dy != 0: # and abs(dx) != abs(dy):
547
- f.write (f"You f**ed up! No zigzag movement from line {lineno - 1} to {lineno}: {lastx}, {lasty} -> {x}, {y}\n")
548
- print (f"You f**ed up! No zigzag movement from line {lineno - 1} to {lineno}: {lastx}, {lasty} -> {x}, {y}")
564
+ if dx != 0 and dy != 0: # and abs(dx) != abs(dy):
565
+ f.write(
566
+ f"You f**ed up! No zigzag movement from line {lineno - 1} to {lineno}: {lastx}, {lasty} -> {x}, {y}\n"
567
+ )
568
+ print(
569
+ f"You f**ed up! No zigzag movement from line {lineno - 1} to {lineno}: {lastx}, {lasty} -> {x}, {y}"
570
+ )
549
571
  failed = True
550
572
  lastx = x
551
573
  lasty = y
552
574
  if not failed:
553
575
  f.write("Good news, no zig-zag movements identified!\n")
554
- f.write("----------------------------------------------------------------------\n")
576
+ f.write(
577
+ "----------------------------------------------------------------------\n"
578
+ )
555
579
  for lineno, (x, y, on) in enumerate(data, start=1):
556
580
  if x is None or y is None:
557
581
  continue
558
582
  key = f"{x} - {y}"
559
583
  if key in test_dict:
560
- f.write (f"Duplicate coordinates in list at ({x}, {y})! 1st: #{test_dict[key][0]}, on={test_dict[key][1]}, 2nd: #{lineno}, on={on}\n")
584
+ f.write(
585
+ f"Duplicate coordinates in list at ({x}, {y})! 1st: #{test_dict[key][0]}, on={test_dict[key][1]}, 2nd: #{lineno}, on={on}\n"
586
+ )
561
587
  has_duplicates += 1
562
588
  else:
563
589
  test_dict[key] = (lineno, on)
564
590
  if has_duplicates:
565
- f.write("----------------------------------------------------------------------\n")
591
+ f.write(
592
+ "----------------------------------------------------------------------\n"
593
+ )
566
594
  for lineno, (x, y, on) in enumerate(data, start=1):
567
595
  f.write(f"{lineno}: {x}, {y}, {on}\n")
568
596
  if has_duplicates:
569
- print(f"Attention: the generated plot has {has_duplicates} duplicate coordinate values!")
570
- print(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'}")
571
- print(f"Overscan: {self.overscan:.2f}, Stepx={step_x:.2f}, Stepy={step_y:.2f}")
597
+ print(
598
+ f"Attention: the generated plot has {has_duplicates} duplicate coordinate values!"
599
+ )
600
+ print(
601
+ 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'}"
602
+ )
603
+ print(
604
+ f"Overscan: {self.overscan:.2f}, Stepx={step_x:.2f}, Stepy={step_y:.2f}"
605
+ )
572
606
  print(f"Image dimensions: {self.width}x{self.height}")
573
607
  else:
574
608
  data = list(self._plot_pixels())
@@ -585,8 +619,22 @@ class RasterPlotter:
585
619
  else:
586
620
  nx = int(round(offset_x + step_x * x))
587
621
  ny = int(round(offset_y + y * step_y))
588
- self._distance_burn += 0 if on == 0 else sqrt( (nx - last_x) * (nx-last_x) + (ny - last_y) * (ny - last_y) )
589
- self._distance_travel += 0 if on != 0 else sqrt( (nx - last_x) * (nx-last_x) + (ny - last_y) * (ny - last_y) )
622
+ self._distance_burn += (
623
+ 0
624
+ if on == 0
625
+ else sqrt(
626
+ (nx - last_x) * (nx - last_x)
627
+ + (ny - last_y) * (ny - last_y)
628
+ )
629
+ )
630
+ self._distance_travel += (
631
+ 0
632
+ if on != 0
633
+ else sqrt(
634
+ (nx - last_x) * (nx - last_x)
635
+ + (ny - last_y) * (ny - last_y)
636
+ )
637
+ )
590
638
  yield nx, ny, on
591
639
  last_x = nx
592
640
  last_y = ny
@@ -598,8 +646,22 @@ class RasterPlotter:
598
646
  else:
599
647
  nx = round(offset_x + step_x * x)
600
648
  ny = round(offset_y + y * step_y)
601
- self._distance_burn += 0 if on == 0 else sqrt( (nx - last_x) * (nx-last_x) + (ny - last_y) * (ny - last_y) )
602
- self._distance_travel += 0 if on != 0 else sqrt( (nx - last_x) * (nx-last_x) + (ny - last_y) * (ny - last_y) )
649
+ self._distance_burn += (
650
+ 0
651
+ if on == 0
652
+ else sqrt(
653
+ (nx - last_x) * (nx - last_x)
654
+ + (ny - last_y) * (ny - last_y)
655
+ )
656
+ )
657
+ self._distance_travel += (
658
+ 0
659
+ if on != 0
660
+ else sqrt(
661
+ (nx - last_x) * (nx - last_x)
662
+ + (ny - last_y) * (ny - last_y)
663
+ )
664
+ )
603
665
  yield offset_x + step_x * x, offset_y + y * step_y, on
604
666
  last_x = nx
605
667
  last_y = ny
@@ -632,12 +694,12 @@ class RasterPlotter:
632
694
  return
633
695
  BLANK = 255
634
696
  for y in range(self.height):
635
- msg:str = f"{y:3d}: "
697
+ msg: str = f"{y:3d}: "
636
698
  for x in range(self.width):
637
699
  msg += "." if self.data[x, y] == BLANK else "X"
638
- print (msg)
700
+ print(msg)
639
701
 
640
- def _get_pixel_chains(self, xy:int, is_x : bool) -> list:
702
+ def _get_pixel_chains(self, xy: int, is_x: bool) -> list:
641
703
  last_pixel = None
642
704
  segments = []
643
705
  upper = self.width if is_x else self.height
@@ -648,11 +710,11 @@ class RasterPlotter:
648
710
  if on == last_pixel:
649
711
  segments[-1][1] = idx
650
712
  else:
651
- segments.append ([idx, idx, on])
713
+ segments.append([idx, idx, on])
652
714
  last_pixel = on
653
715
  return segments
654
716
 
655
- def _consume_pixel_chains(self, segments:list, xy:int, is_x : bool):
717
+ def _consume_pixel_chains(self, segments: list, xy: int, is_x: bool):
656
718
  BLANK = 255
657
719
  # for x in range(5):
658
720
  # msg1 = f"{x}: "
@@ -727,7 +789,11 @@ class RasterPlotter:
727
789
  # We consider as well the overscan value
728
790
  overscan_top = 0 if dy >= 0 else self.overscan
729
791
  overscan_bottom = 0 if dy <= 0 else self.overscan
730
- if not first and (segments[0][0] - overscan_top <= last_y <= segments[-1][1] + overscan_bottom):
792
+ if not first and (
793
+ segments[0][0] - overscan_top
794
+ <= last_y
795
+ <= segments[-1][1] + overscan_bottom
796
+ ):
731
797
  # inside the chain!
732
798
  # So lets move a bit to the side
733
799
  if dy > 0:
@@ -814,7 +880,11 @@ class RasterPlotter:
814
880
  # We consider as well the overscan value
815
881
  overscan_left = 0 if dx >= 0 else self.overscan
816
882
  overscan_right = 0 if dx <= 0 else self.overscan
817
- if not first and (segments[0][0] - overscan_left <= last_x <= segments[-1][1] + overscan_right):
883
+ if not first and (
884
+ segments[0][0] - overscan_left
885
+ <= last_x
886
+ <= segments[-1][1] + overscan_right
887
+ ):
818
888
  # inside the chain!
819
889
  # So lets move a bit to the side
820
890
  if dx > 0:
@@ -1021,12 +1091,14 @@ class RasterPlotter:
1021
1091
  """
1022
1092
 
1023
1093
  def walk_segments(segments, horizontal=True, xy_penalty=1, width=1, height=1):
1024
- n:int = len(segments)
1094
+ n: int = len(segments)
1025
1095
  visited = np.zeros(n, dtype=bool)
1026
1096
  path = []
1027
1097
  window_size = 10
1028
1098
  current_point = np.array(segments[0][0], dtype=float)
1029
- segment_points = np.array([point for segment in segments for point in segment], dtype=float)
1099
+ segment_points = np.array(
1100
+ [point for segment in segments for point in segment], dtype=float
1101
+ )
1030
1102
  mask = ~visited.repeat(2)
1031
1103
  while len(path) < n:
1032
1104
  # Find the range of segments within the x- and y-window
@@ -1035,17 +1107,19 @@ class RasterPlotter:
1035
1107
  y_min = current_point[1] - window_size
1036
1108
  y_max = current_point[1] + window_size
1037
1109
  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
1110
+ (segment_points[:, 0] >= x_min)
1111
+ & (segment_points[:, 0] <= x_max)
1112
+ & (segment_points[:, 1] >= y_min)
1113
+ & (segment_points[:, 1] <= y_max)
1114
+ & mask
1043
1115
  )[0]
1044
1116
  if len(unvisited_indices) == 0:
1045
1117
  # If no segments are within the window, expand the window
1046
1118
  window_size *= 2
1047
1119
  # print (f"Did not find points: now window: {window_size}")
1048
- if window_size <= 2* height or window_size <= 2 * width: # Safety belt
1120
+ if (
1121
+ window_size <= 2 * height or window_size <= 2 * width
1122
+ ): # Safety belt
1049
1123
  continue
1050
1124
 
1051
1125
  unvisited_points = segment_points[unvisited_indices]
@@ -1053,11 +1127,11 @@ class RasterPlotter:
1053
1127
  # distances = distance_matrix(unvisited_points, current_point, y_penalty)
1054
1128
  diff = unvisited_points - current_point
1055
1129
  if horizontal:
1056
- diff[:, 1] *= xy_penalty # Apply penalty to y-distances
1130
+ diff[:, 1] *= xy_penalty # Apply penalty to y-distances
1057
1131
  else:
1058
- diff[:, 0] *= xy_penalty # Apply penalty to x-distances
1132
+ diff[:, 0] *= xy_penalty # Apply penalty to x-distances
1059
1133
 
1060
- distances = np.sum(diff ** 2, axis=1) # Return squared distances
1134
+ distances = np.sum(diff**2, axis=1) # Return squared distances
1061
1135
 
1062
1136
  min_distance_idx = np.argmin(distances)
1063
1137
  next_segment = unvisited_indices[min_distance_idx] // 2
@@ -1068,12 +1142,16 @@ class RasterPlotter:
1068
1142
  mask[2 * next_segment] = False
1069
1143
  mask[2 * next_segment + 1] = False
1070
1144
  if min_distance_idx % 2 == 0:
1071
- path.append((next_segment, 'end'))
1072
- current_point = segment_points[next_segment * 2 + 1] # Move to the other endpoint
1145
+ path.append((next_segment, "end"))
1146
+ current_point = segment_points[
1147
+ next_segment * 2 + 1
1148
+ ] # Move to the other endpoint
1073
1149
  else:
1074
- path.append((next_segment, 'start'))
1075
- current_point = segment_points[next_segment * 2] # Move to the other endpoint
1076
- window_size = 10 # Reset window size
1150
+ path.append((next_segment, "start"))
1151
+ current_point = segment_points[
1152
+ next_segment * 2
1153
+ ] # Move to the other endpoint
1154
+ window_size = 10 # Reset window size
1077
1155
 
1078
1156
  return path
1079
1157
 
@@ -1093,14 +1171,16 @@ class RasterPlotter:
1093
1171
  line_parts = []
1094
1172
  on_parts = []
1095
1173
  if self.debug_level > 2:
1096
- print (f"{'horizontal' if horizontal else 'Vertical'} for {self.width}x{self.height} image. {'y' if horizontal else 'x'} from {lower} to {upper}")
1174
+ print(
1175
+ f"{'horizontal' if horizontal else 'Vertical'} for {self.width}x{self.height} image. {'y' if horizontal else 'x'} from {lower} to {upper}"
1176
+ )
1097
1177
  if horizontal:
1098
1178
  while lower <= y <= upper:
1099
1179
  segments = self._get_pixel_chains(y, True)
1100
1180
  self._consume_pixel_chains(segments, y, True)
1101
1181
  for seg in segments:
1102
1182
  # Append (xstart, y), (xend, y), on
1103
- line_parts.append( ( (seg[0], y), (seg[1], y) ) )
1183
+ line_parts.append(((seg[0], y), (seg[1], y)))
1104
1184
  on_parts.append(seg[2])
1105
1185
  y += dy
1106
1186
  else:
@@ -1109,14 +1189,20 @@ class RasterPlotter:
1109
1189
  self._consume_pixel_chains(segments, x, False)
1110
1190
  for seg in segments:
1111
1191
  # Append (xstart, y), (xend, y), on
1112
- line_parts.append( ( (x, seg[0]), (x, seg[1]) ) )
1192
+ line_parts.append(((x, seg[0]), (x, seg[1])))
1113
1193
  on_parts.append(seg[2])
1114
1194
  x += dx
1115
1195
  if self.debug_level > 2:
1116
- print (f"Created {len(line_parts)} segments")
1196
+ print(f"Created {len(line_parts)} segments")
1117
1197
  t1 = perf_counter()
1118
1198
  penalty = 3 if self.special.get("gantry", False) else 1
1119
- path = walk_segments(line_parts, horizontal=horizontal, xy_penalty=penalty, width=self.width, height=self.height)
1199
+ path = walk_segments(
1200
+ line_parts,
1201
+ horizontal=horizontal,
1202
+ xy_penalty=penalty,
1203
+ width=self.width,
1204
+ height=self.height,
1205
+ )
1120
1206
  # print("Order of segments:", path)
1121
1207
  t2 = perf_counter()
1122
1208
  if horizontal:
@@ -1171,14 +1257,16 @@ class RasterPlotter:
1171
1257
  last_y = ey
1172
1258
  t3 = perf_counter()
1173
1259
  if self.debug_level > 1:
1174
- print (f"Overall time for {'horizontal' if horizontal else 'vertical'} consumption: {t3-t0:.2f}s - created: {len(line_parts)} segments")
1175
- print (f"Computation: {t2-t0:.2f}s - Chain creation:{t1 - t0:.2f}s, Walk: {t2 - t1:.2f}s")
1260
+ print(
1261
+ f"Overall time for {'horizontal' if horizontal else 'vertical'} consumption: {t3-t0:.2f}s - created: {len(line_parts)} segments"
1262
+ )
1263
+ print(
1264
+ f"Computation: {t2-t0:.2f}s - Chain creation:{t1 - t0:.2f}s, Walk: {t2 - t1:.2f}s"
1265
+ )
1176
1266
  self.final_x = last_x
1177
1267
  self.final_y = last_y
1178
1268
 
1179
1269
  def _plot_spiral(self):
1180
-
1181
-
1182
1270
  rows = self.height
1183
1271
  cols = self.width
1184
1272
  center_row, center_col = rows // 2, cols // 2
@@ -1223,7 +1311,7 @@ class RasterPlotter:
1223
1311
  if on == last_pixel and len(segments):
1224
1312
  segments[-1][1] = (col, row)
1225
1313
  else:
1226
- segments.append ([(col, row), (col, row), on])
1314
+ segments.append([(col, row), (col, row), on])
1227
1315
 
1228
1316
  last_pixel = on
1229
1317
  count += 1
@@ -1255,7 +1343,7 @@ class RasterPlotter:
1255
1343
  sy = min(start_y, end_y)
1256
1344
  ey = max(start_y, end_y)
1257
1345
 
1258
- if direction_index in (0, 2): # horizontal
1346
+ if direction_index in (0, 2): # horizontal
1259
1347
  for y_idx in range(-self.overlap, self.overlap + 1):
1260
1348
  ny = sy + y_idx
1261
1349
  for nx in range(sx, ex + 1):
@@ -1268,11 +1356,9 @@ class RasterPlotter:
1268
1356
  if 0 <= nx < self.width and 0 <= ny < self.height:
1269
1357
  self.data[nx, ny] = BLANK
1270
1358
 
1271
-
1272
1359
  direction_index = (direction_index + 1) % 4
1273
1360
  steps += 1
1274
1361
 
1275
-
1276
1362
  def _plot_crossover(self):
1277
1363
  """
1278
1364
  This algorithm scans through the image looking for the row or the column with the most pixels.
@@ -1289,8 +1375,8 @@ class RasterPlotter:
1289
1375
  Yields:
1290
1376
  list of tuples with (x, y, on)
1291
1377
  """
1292
- ROW=0
1293
- COL=1
1378
+ ROW = 0
1379
+ COL = 1
1294
1380
 
1295
1381
  def process_image(image):
1296
1382
  # We will modify the image to keep track of deleted rows and columns
@@ -1373,28 +1459,30 @@ class RasterPlotter:
1373
1459
  # msg = f"{msg}{'X' if on else '.'}"
1374
1460
  if on:
1375
1461
  if not covered_col[idx]:
1376
- covered_col[idx] = None # needs recalc
1462
+ covered_col[idx] = None # needs recalc
1377
1463
  if on == last_pixel:
1378
1464
  segments[-1][1] = idx
1379
1465
  else:
1380
- segments.append ([idx, idx, on])
1466
+ segments.append([idx, idx, on])
1381
1467
  last_pixel = on
1382
- results.append((COL, rowidx, segments)) # Intentionally so, as the numpy array has x and y exchanged
1468
+ results.append(
1469
+ (COL, rowidx, segments)
1470
+ ) # Intentionally so, as the numpy array has x and y exchanged
1383
1471
  # print (f"Col #{rowidx}: {msg} -> {segments}")
1384
1472
 
1385
1473
  # Clear the column
1386
- image[rowidx,:] = 0
1474
+ image[rowidx, :] = 0
1387
1475
  covered_row[rowidx] = True
1388
1476
  stored_row[rowidx] = 0
1389
1477
  for rc in range(self.overlap):
1390
1478
  r = rowidx - rc
1391
1479
  if 0 <= r < rows:
1392
- image[r,:] = 0
1480
+ image[r, :] = 0
1393
1481
  covered_row[r] = True
1394
1482
  stored_row[r] = 0
1395
1483
  r = rowidx + rc
1396
1484
  if 0 <= r < rows:
1397
- image[r,:] = 0
1485
+ image[r, :] = 0
1398
1486
  covered_row[r] = True
1399
1487
  stored_row[r] = 0
1400
1488
  recalc_col = True
@@ -1407,11 +1495,11 @@ class RasterPlotter:
1407
1495
  # msg = f"{msg}{'X' if on else '.'}"
1408
1496
  if on:
1409
1497
  if not covered_row[idx]:
1410
- covered_row[idx] = None # needs recalc
1498
+ covered_row[idx] = None # needs recalc
1411
1499
  if on == last_pixel:
1412
1500
  segments[-1][1] = idx
1413
1501
  else:
1414
- segments.append ([idx, idx, on])
1502
+ segments.append([idx, idx, on])
1415
1503
  last_pixel = on
1416
1504
  results.append((ROW, colidx, segments))
1417
1505
  # print (f"Row #{colidx}: {msg} -> {segments}")
@@ -1437,7 +1525,7 @@ class RasterPlotter:
1437
1525
  for ridx in range(rows):
1438
1526
  on = image[ridx, cidx]
1439
1527
  msg = f"{msg}{'X' if on else '.'}"
1440
- print (f"{cidx:3d}: {msg}")
1528
+ print(f"{cidx:3d}: {msg}")
1441
1529
 
1442
1530
  return results
1443
1531
 
@@ -1448,7 +1536,7 @@ class RasterPlotter:
1448
1536
  for x in range(self.width):
1449
1537
  for y in range(self.height):
1450
1538
  px = self.px(x, y)
1451
- if px==self.skip_pixel:
1539
+ if px == self.skip_pixel:
1452
1540
  px = 0
1453
1541
  image[x, y] = px
1454
1542
  t1 = perf_counter()
@@ -1528,7 +1616,7 @@ class RasterPlotter:
1528
1616
  if self.bidirectional:
1529
1617
  if mode == ROW:
1530
1618
  dx = -dx
1531
- else: # column
1619
+ else: # column
1532
1620
  dy = -dy
1533
1621
 
1534
1622
  # We need to set the final values so that the rastercut is able to carry on
@@ -1536,8 +1624,11 @@ class RasterPlotter:
1536
1624
  self.final_y = last_y
1537
1625
  t3 = perf_counter()
1538
1626
  if self.debug_level > 1:
1539
- print (f"Overall time for crossover consumption: {t3-t0:.2f}s")
1540
- print (f"Computation: {t2 - t0:.2f}s - Array creation:{t1 - t0:.2f}s, Algorithm: {t2 - t1:.2f}s")
1627
+ print(f"Overall time for crossover consumption: {t3-t0:.2f}s")
1628
+ print(
1629
+ f"Computation: {t2 - t0:.2f}s - Array creation:{t1 - t0:.2f}s, Algorithm: {t2 - t1:.2f}s"
1630
+ )
1631
+
1541
1632
  """
1542
1633
  # Testpattern generation
1543
1634
  def testpattern_generator(self):
@@ -1657,4 +1748,4 @@ class RasterPlotter:
1657
1748
  yield from methods[method]()
1658
1749
  except IndexError:
1659
1750
  print (f"Unknown testgenerator for {self.direction}")
1660
- """
1751
+ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerk40t
3
- Version: 0.9.7030
3
+ Version: 0.9.7050
4
4
  Summary: MeerK40t LaserCutter Software
5
5
  Home-page: https://github.com/meerk40t/meerk40t
6
6
  Author: Tatarize