meerk40t 0.9.7010__py2.py3-none-any.whl → 0.9.7030__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 (77) hide show
  1. meerk40t/balormk/galvo_commands.py +1 -2
  2. meerk40t/core/cutcode/cutcode.py +1 -1
  3. meerk40t/core/cutplan.py +70 -2
  4. meerk40t/core/elements/branches.py +18 -4
  5. meerk40t/core/elements/element_treeops.py +43 -7
  6. meerk40t/core/elements/elements.py +49 -63
  7. meerk40t/core/elements/grid.py +8 -1
  8. meerk40t/core/elements/offset_clpr.py +4 -3
  9. meerk40t/core/elements/offset_mk.py +2 -1
  10. meerk40t/core/elements/shapes.py +379 -260
  11. meerk40t/core/elements/testcases.py +105 -0
  12. meerk40t/core/node/node.py +6 -3
  13. meerk40t/core/node/op_cut.py +9 -8
  14. meerk40t/core/node/op_dots.py +8 -8
  15. meerk40t/core/node/op_engrave.py +7 -7
  16. meerk40t/core/node/op_raster.py +8 -8
  17. meerk40t/core/planner.py +23 -0
  18. meerk40t/core/undos.py +1 -1
  19. meerk40t/core/wordlist.py +1 -0
  20. meerk40t/dxf/dxf_io.py +6 -0
  21. meerk40t/extra/encode_detect.py +8 -2
  22. meerk40t/extra/hershey.py +2 -3
  23. meerk40t/extra/inkscape.py +3 -5
  24. meerk40t/extra/mk_potrace.py +1959 -0
  25. meerk40t/extra/outerworld.py +2 -3
  26. meerk40t/extra/param_functions.py +2 -2
  27. meerk40t/extra/potrace.py +14 -10
  28. meerk40t/grbl/device.py +4 -1
  29. meerk40t/grbl/gui/grblcontroller.py +2 -2
  30. meerk40t/grbl/interpreter.py +1 -1
  31. meerk40t/gui/about.py +3 -5
  32. meerk40t/gui/basicops.py +3 -3
  33. meerk40t/gui/busy.py +75 -13
  34. meerk40t/gui/choicepropertypanel.py +365 -379
  35. meerk40t/gui/consolepanel.py +3 -3
  36. meerk40t/gui/gui_mixins.py +4 -1
  37. meerk40t/gui/hersheymanager.py +13 -3
  38. meerk40t/gui/laserpanel.py +12 -7
  39. meerk40t/gui/materialmanager.py +33 -6
  40. meerk40t/gui/plugin.py +9 -3
  41. meerk40t/gui/propertypanels/operationpropertymain.py +1 -1
  42. meerk40t/gui/ribbon.py +4 -1
  43. meerk40t/gui/scene/widget.py +1 -1
  44. meerk40t/gui/scenewidgets/rectselectwidget.py +19 -16
  45. meerk40t/gui/scenewidgets/selectionwidget.py +26 -20
  46. meerk40t/gui/simpleui.py +13 -8
  47. meerk40t/gui/simulation.py +22 -2
  48. meerk40t/gui/spoolerpanel.py +8 -11
  49. meerk40t/gui/themes.py +7 -1
  50. meerk40t/gui/tips.py +2 -3
  51. meerk40t/gui/toolwidgets/toolmeasure.py +4 -1
  52. meerk40t/gui/wxmeerk40t.py +32 -3
  53. meerk40t/gui/wxmmain.py +72 -6
  54. meerk40t/gui/wxmscene.py +95 -6
  55. meerk40t/gui/wxmtree.py +17 -11
  56. meerk40t/gui/wxutils.py +1 -1
  57. meerk40t/image/imagetools.py +21 -6
  58. meerk40t/kernel/kernel.py +31 -6
  59. meerk40t/kernel/settings.py +2 -0
  60. meerk40t/lihuiyu/device.py +9 -3
  61. meerk40t/main.py +22 -5
  62. meerk40t/network/console_server.py +52 -14
  63. meerk40t/network/web_server.py +15 -1
  64. meerk40t/ruida/device.py +5 -1
  65. meerk40t/ruida/gui/gui.py +6 -6
  66. meerk40t/ruida/gui/ruidaoperationproperties.py +1 -10
  67. meerk40t/ruida/rdjob.py +3 -3
  68. meerk40t/tools/geomstr.py +88 -0
  69. meerk40t/tools/polybool.py +2 -1
  70. meerk40t/tools/shxparser.py +92 -34
  71. {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/METADATA +1 -1
  72. {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/RECORD +77 -75
  73. {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/WHEEL +1 -1
  74. {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/LICENSE +0 -0
  75. {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/entry_points.txt +0 -0
  76. {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/top_level.txt +0 -0
  77. {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/zip-safe +0 -0
@@ -26,6 +26,8 @@ def plugin(kernel, lifecycle=None):
26
26
  command, channel, _, port=23, silent=False, quit=False, **kwargs
27
27
  ):
28
28
  root = kernel.root
29
+ # Variable to store input
30
+ root.__console_buffer = ""
29
31
  try:
30
32
  server = root.open_as("module/TCPServer", "console-server", port=port)
31
33
  if quit:
@@ -36,25 +38,61 @@ def plugin(kernel, lifecycle=None):
36
38
  "{kernel_name} {kernel_version} Telnet Console.\r\n"
37
39
  ).format(kernel_name=kernel.name, kernel_version=kernel.version)
38
40
  send.line_end = "\r\n"
39
-
40
41
  recv = root.channel("console-server/recv")
41
- recv.watch(root.console)
42
- channel(
43
- _(
44
- "{name} {version} console server on port: {port}".format(
45
- name=kernel.name, version=kernel.version, port=port
46
- )
42
+ except (OSError, ValueError):
43
+ channel(_("Server failed on port: {port}").format(port=port))
44
+ return
45
+
46
+ def exec_command(data: str) -> None:
47
+ # We are in a different thread, so let's hand over stuff to the gui
48
+ if isinstance(data, bytes):
49
+ try:
50
+ data = data.decode()
51
+ except UnicodeDecodeError as e:
52
+ return
53
+ start = 0
54
+ while True:
55
+ idx = data.find("|", start)
56
+ if idx < 0:
57
+ break
58
+ # Is the amount of quotation marks odd (ie non-even)?
59
+ # Yes: we are in the middle of a str
60
+ # No: we can split the command
61
+ quotations = data.count('"', 0, idx)
62
+ if quotations % 2 == 0:
63
+ data = data[:idx].rstrip() + "\n" + data[idx+1:].lstrip()
64
+ start = idx + 1
65
+ root.__console_buffer += data
66
+ while "\n" in root.__console_buffer:
67
+ pos = root.__console_buffer.find("\n")
68
+ command = root.__console_buffer[0:pos].strip("\r")
69
+ root.__console_buffer = root.__console_buffer[pos + 1 :]
70
+ if handover is None:
71
+ root.console(command + "\n")
72
+ else:
73
+ handover(command)
74
+
75
+ handover = None
76
+ for result in root.find("gui/handover"):
77
+ # Do we have a thread handover routine?
78
+ if result is not None:
79
+ handover, _path, suffix_path = result
80
+ break
81
+ recv.watch(exec_command)
82
+
83
+ channel(
84
+ _(
85
+ "{name} {version} console server on port: {port}".format(
86
+ name=kernel.name, version=kernel.version, port=port
47
87
  )
48
88
  )
89
+ )
49
90
 
50
- if not silent:
51
- console = root.channel("console")
52
- console.watch(send)
53
- server.events_channel.watch(console)
91
+ if not silent:
92
+ console = root.channel("console")
93
+ console.watch(send)
94
+ server.events_channel.watch(console)
54
95
 
55
- except (OSError, ValueError):
56
- channel(_("Server failed on port: {port}").format(port=port))
57
- return
58
96
 
59
97
  @kernel.console_option(
60
98
  "port", "p", type=int, default=2080, help=_("port to listen on.")
@@ -34,6 +34,13 @@ class WebServer(Module):
34
34
  )
35
35
  self.server_headers = dict()
36
36
  self.client_headers = dict()
37
+ self.handover = None
38
+ root = self.context.root
39
+ for result in root.find("gui/handover"):
40
+ # Do we have a thread handover routine?
41
+ if result is not None:
42
+ self.handover, _path, suffix_path = result
43
+ break
37
44
 
38
45
  def stop(self):
39
46
  self.state = "terminate"
@@ -45,6 +52,13 @@ class WebServer(Module):
45
52
  if self.socket is not None:
46
53
  self.socket.close()
47
54
  self.socket = None
55
+
56
+ def send(self, command):
57
+ if self.handover is None:
58
+ self.context(f"{command}\n")
59
+ else:
60
+ self.handover(command)
61
+
48
62
 
49
63
  def receive(self, data):
50
64
  def parse_received_data():
@@ -92,7 +106,7 @@ class WebServer(Module):
92
106
  content = f"Received command: '{command}'"
93
107
  elif self.client_headers["TYPE"] == "POST" and "post_cmd" in self.client_headers:
94
108
  command = self.client_headers["post_cmd"]
95
- self.context(command + "\n")
109
+ self.send(command)
96
110
  content = f"Received command: '{command}'"
97
111
  return content_type, content
98
112
 
meerk40t/ruida/device.py CHANGED
@@ -263,18 +263,22 @@ class RuidaDevice(Service):
263
263
  choice_dict["choices"] = ["UNCONFIGURED"]
264
264
  choice_dict["display"] = ["pyserial-not-installed"]
265
265
 
266
+ from platform import system
267
+ is_linux = system() == "Linux"
268
+
266
269
  choices = [
267
270
  {
268
271
  "attr": "serial_port",
269
272
  "object": self,
270
273
  "default": "UNCONFIGURED",
271
274
  "type": str,
272
- "style": "option",
275
+ "style": "combosmall" if is_linux else "option",
273
276
  "label": "",
274
277
  "tip": _("What serial interface does this device connect to?"),
275
278
  "section": "_10_Serial Interface",
276
279
  "subsection": "_00_",
277
280
  "dynamic": update,
281
+ "exclusive": not is_linux,
278
282
  },
279
283
  {
280
284
  "attr": "baud_rate",
meerk40t/ruida/gui/gui.py CHANGED
@@ -48,7 +48,7 @@ def plugin(service, lifecycle):
48
48
 
49
49
  from meerk40t.ruida.gui.ruidaconfig import RuidaConfiguration
50
50
  from meerk40t.ruida.gui.ruidacontroller import RuidaController
51
- from meerk40t.ruida.gui.ruidaoperationproperties import RuidaOperationPanel
51
+ # from meerk40t.ruida.gui.ruidaoperationproperties import RuidaOperationPanel
52
52
 
53
53
  service.register("window/Controller", RuidaController)
54
54
  service.register("window/Configuration", RuidaConfiguration)
@@ -56,11 +56,11 @@ def plugin(service, lifecycle):
56
56
  service.register("winpath/Controller", service)
57
57
  service.register("winpath/Configuration", service)
58
58
 
59
- service.register("property/RasterOpNode/Ruida", RuidaOperationPanel)
60
- service.register("property/CutOpNode/Ruida", RuidaOperationPanel)
61
- service.register("property/EngraveOpNode/Ruida", RuidaOperationPanel)
62
- service.register("property/ImageOpNode/Ruida", RuidaOperationPanel)
63
- service.register("property/DotsOpNode/Ruida", RuidaOperationPanel)
59
+ # service.register("property/RasterOpNode/Ruida", RuidaOperationPanel)
60
+ # service.register("property/CutOpNode/Ruida", RuidaOperationPanel)
61
+ # service.register("property/EngraveOpNode/Ruida", RuidaOperationPanel)
62
+ # service.register("property/ImageOpNode/Ruida", RuidaOperationPanel)
63
+ # service.register("property/DotsOpNode/Ruida", RuidaOperationPanel)
64
64
 
65
65
  service.add_service_delegate(RuidaGui(service))
66
66
 
@@ -17,16 +17,7 @@ class RuidaOperationPanel(ScrolledPanel):
17
17
  self.parent = args[0]
18
18
  self.operation = node
19
19
 
20
- choices = [
21
- {
22
- "attr": "air_assist",
23
- "object": node,
24
- "default": True,
25
- "type": bool,
26
- "label": _("Air Assist"),
27
- "tip": _("Trigger the per element air assist"),
28
- },
29
- ]
20
+ choices = []
30
21
 
31
22
  self.panel = ChoicePropertyPanel(
32
23
  self, wx.ID_ANY, context=self.context, choices=choices, scrolling=False
meerk40t/ruida/rdjob.py CHANGED
@@ -1376,13 +1376,13 @@ class RDJob:
1376
1376
  part = current_settings.get("part", 0)
1377
1377
  speed = current_settings.get("speed", 0)
1378
1378
  power = current_settings.get("power", 0) / 10.0
1379
- air = current_settings.get("air_assist", True)
1379
+ air = current_settings.get("coolant", 0)
1380
1380
  self.layer_end()
1381
1381
  self.layer_number_part(part)
1382
1382
  self.laser_device_0()
1383
- if air:
1383
+ if air == 1:
1384
1384
  self.air_assist_on()
1385
- else:
1385
+ elif air==2:
1386
1386
  self.air_assist_off()
1387
1387
  self.speed_laser_1(speed)
1388
1388
  self.laser_on_delay(0)
meerk40t/tools/geomstr.py CHANGED
@@ -179,6 +179,94 @@ def remove(s, i):
179
179
  """
180
180
  s[i:-1] = s[i + 1 :]
181
181
 
182
+ def stitch_geometries(geometry_list:list, tolerance:float=0.0) -> list:
183
+ action_list = list(geometry_list)
184
+ result_list = []
185
+ start_points = []
186
+ end_points = []
187
+ anychanges = True
188
+ were_stitches = False
189
+ iteration_loop = 0
190
+ while anychanges:
191
+ iteration_loop += 1
192
+ # print (f"Loop {iteration_loop}")
193
+ anychanges = False
194
+ for g1 in action_list:
195
+ if g1 is None:
196
+ continue
197
+ fp1 = g1.first_point
198
+ lp1 = g1.last_point
199
+ if fp1 is None or lp1 is None:
200
+ continue
201
+ was_stitched = False
202
+ for idx, g2 in enumerate(result_list):
203
+ fp2 = start_points[idx]
204
+ lp2 = end_points[idx]
205
+ # end - start: append
206
+ # end - end : append reverse
207
+ # start - start: insert reverse
208
+ # start - end: insert
209
+ dist_e_s = abs(lp2 - fp1)
210
+ dist_e_e = abs(lp2 - lp1)
211
+ dist_s_s = abs(fp2 - fp1)
212
+ dist_s_e = abs(fp2 - lp1)
213
+ # print (f"test #{idx} ({fp1.real:.2f},{fp1.imag:.2f})->({lp1.real:.2f},{lp1.imag:.2f}) versus ({fp2.real:.2f},{fp2.imag:.2f})->({lp2.real:.2f},{lp2.imag:.2f})")
214
+ # print (f"Gaps: e -> s: {dist_e_s:.3f}, e -> e: {dist_e_e:.3f}, s -> s: {dist_s_s:.3f},s -> e: {dist_s_e:.3f},")
215
+ if dist_e_s <= tolerance:
216
+ # append
217
+ if dist_e_s > 0:
218
+ g2.line(lp2, fp1)
219
+ g2.append(g1, end=False)
220
+ was_stitched = True
221
+ elif dist_e_e <= tolerance:
222
+ # append reverse
223
+ g1.reverse()
224
+ if dist_e_e > 0:
225
+ g2.line(lp2, lp1)
226
+ g2.append(g1, end=False)
227
+ was_stitched = True
228
+ elif dist_s_s <= tolerance:
229
+ # insert reverse
230
+ g1.reverse()
231
+ if dist_s_s > 0:
232
+ g1.line(fp1, fp2)
233
+ g2.insert(0, g1.segments[:g1.index])
234
+ was_stitched = True
235
+ elif dist_s_e <= tolerance:
236
+ # insert
237
+ if dist_s_e > 0:
238
+ g1.line(lp1, fp2)
239
+ g2.insert(0, g1.segments[:g1.index])
240
+ was_stitched = True
241
+ if was_stitched:
242
+ # print ("stitched")
243
+ # g2.debug_me()
244
+ anychanges = True
245
+ start_points[idx] = g2.first_point
246
+ end_points[idx] = g2.last_point
247
+ result_list[idx] = g2
248
+ were_stitches = True
249
+ break
250
+
251
+ if not was_stitched:
252
+ # print ("Unchanged")
253
+ result_list.append(g1)
254
+ start_points.append(fp1)
255
+ end_points.append(lp1)
256
+ if anychanges:
257
+ action_list = list(result_list)
258
+ result_list.clear()
259
+ start_points.clear()
260
+ end_points.clear()
261
+ if were_stitches:
262
+ for g1 in result_list:
263
+ fp1 = g1.first_point
264
+ lp1 = g1.last_point
265
+ dist_e_s = abs(lp1 - fp1)
266
+ if 0 < dist_e_s <= tolerance:
267
+ g1.line(lp1, fp1)
268
+ return result_list
269
+ return None
182
270
 
183
271
  class Simplifier:
184
272
  # Copyright (c) 2014 Elliot Hallmark
@@ -275,7 +275,8 @@ class LinkedList:
275
275
  data.next = None
276
276
 
277
277
  def remove_func():
278
- data.previous.next = data.next
278
+ if data.previous is not None:
279
+ data.previous.next = data.next
279
280
  if data.next is not None:
280
281
  data.next.previous = data.previous
281
282
  data.previous = None
@@ -229,6 +229,22 @@ class ShxFont:
229
229
  self._parse_unifont(f)
230
230
  else:
231
231
  raise ShxFontParseError(f"{self.type} is not a valid shx file type.")
232
+ self.translate_names_to_codes()
233
+
234
+ def translate_names_to_codes(self):
235
+ # We can't properly deal with long names,
236
+ # so we translate them a virtual character
237
+ gdict = list(self.glyphs.items())
238
+ virtual_char = len(self.glyphs)
239
+ for key, data in gdict:
240
+ if isinstance(key, str) and len(key) > 1:
241
+ while True:
242
+ newkey = chr(virtual_char)
243
+ if newkey not in self.glyphs:
244
+ break
245
+ virtual_char += 1
246
+ self.glyphs[newkey] = data
247
+ del self.glyphs[key]
232
248
 
233
249
  def _parse_header(self, f):
234
250
  header = read_string(f)
@@ -351,6 +367,7 @@ class ShxFont:
351
367
  try:
352
368
  return self._code.pop()
353
369
  except IndexError as e:
370
+ print (f"Error in {self.font_name}: no codes to pop")
354
371
  raise ShxFontParseError("No codes to pop()") from e
355
372
 
356
373
  def render(
@@ -471,7 +488,10 @@ class ShxFont:
471
488
  line_lengths = _do_render(vtext, offsets)
472
489
 
473
490
  def _parse_code(self):
474
- b = self.pop()
491
+ try:
492
+ b = self.pop()
493
+ except ShxFontParseError:
494
+ return
475
495
  direction = b & 0x0F
476
496
  length = (b & 0xF0) >> 4
477
497
  if length == 0:
@@ -608,7 +628,10 @@ class ShxFont:
608
628
 
609
629
  :return:
610
630
  """
611
- factor = self.pop()
631
+ try:
632
+ factor = self.pop()
633
+ except ShxFontParseError:
634
+ return
612
635
  if self._debug:
613
636
  print(
614
637
  f"DIVIDE_VECTOR {self._scale}/{factor} {'(Skipped)' if self._skip else ''}"
@@ -679,7 +702,10 @@ class ShxFont:
679
702
  self._last_x, self._last_y = self._x, self._y
680
703
 
681
704
  def _draw_subshape_shapes(self):
682
- subshape = self.pop()
705
+ try:
706
+ subshape = self.pop()
707
+ except ShxFontParseError:
708
+ return
683
709
  if self._debug:
684
710
  print(
685
711
  f"Appending glyph {subshape} (Type={self.type}). {'(Skipped)' if self._skip else ''}"
@@ -694,21 +720,28 @@ class ShxFont:
694
720
  self._code += bytearray(reversed(shape))
695
721
 
696
722
  def _draw_subshape_bigfont(self):
697
- subshape = self.pop()
723
+ try:
724
+ subshape = self.pop()
725
+ except ShxFontParseError:
726
+ return
698
727
  if self._debug:
699
728
  print(
700
729
  f"Appending glyph {subshape} (Type={self.type}). {'(Skipped)' if self._skip else ''}"
701
730
  )
702
731
  if subshape == 0:
703
- subshape = int_16le([self.pop(), self.pop()])
704
- origin_x = self.pop() * self._scale
705
- origin_y = self.pop() * self._scale
706
- width = self.pop() * self._scale
707
- height = self.pop() * self._scale
708
- if self._debug:
709
- print(
710
- f"Extended Bigfont Glyph: {subshape}, origin_x = {origin_x}, origin_y = {origin_y}. {width}x{height}"
711
- )
732
+ try:
733
+ subshape = int_16le([self.pop(), self.pop()])
734
+
735
+ origin_x = self.pop() * self._scale
736
+ origin_y = self.pop() * self._scale
737
+ width = self.pop() * self._scale
738
+ height = self.pop() * self._scale
739
+ if self._debug:
740
+ print(
741
+ f"Extended Bigfont Glyph: {subshape}, origin_x = {origin_x}, origin_y = {origin_y}. {width}x{height}"
742
+ )
743
+ except ShxFontParseError:
744
+ return
712
745
  if self._skip:
713
746
  self._skip = False
714
747
  return
@@ -719,7 +752,11 @@ class ShxFont:
719
752
  self._code += bytearray(reversed(shape))
720
753
 
721
754
  def _draw_subshape_unifont(self):
722
- subshape = int_16le([self.pop(), self.pop()])
755
+ try:
756
+ subshape = int_16le([self.pop(), self.pop()])
757
+ except ShxFontParseError:
758
+ return
759
+
723
760
  if self._debug:
724
761
  print(
725
762
  f"Appending glyph {subshape} (Type={self.type}). {'(Skipped)' if self._skip else ''}"
@@ -755,8 +792,12 @@ class ShxFont:
755
792
  ranges from -128 to +127.
756
793
  :return:
757
794
  """
758
- dx = signed8(self.pop()) * self._scale
759
- dy = signed8(self.pop()) * self._scale
795
+ try:
796
+ dx = signed8(self.pop()) * self._scale
797
+ dy = signed8(self.pop()) * self._scale
798
+ except ShxFontParseError:
799
+ return
800
+
760
801
  if self._debug:
761
802
  print(f"XY_DISPLACEMENT {dx} {dy} {'(Skipped)' if self._skip else ''}")
762
803
  if self._skip:
@@ -777,8 +818,11 @@ class ShxFont:
777
818
  :return:
778
819
  """
779
820
  while True:
780
- dx = signed8(self.pop()) * self._scale
781
- dy = signed8(self.pop()) * self._scale
821
+ try:
822
+ dx = signed8(self.pop()) * self._scale
823
+ dy = signed8(self.pop()) * self._scale
824
+ except ShxFontParseError:
825
+ return
782
826
  if self._debug:
783
827
  print(
784
828
  f"POLY_XY_DISPLACEMENT {dx} {dy} {'(Skipped)' if self._skip else ''}"
@@ -816,8 +860,11 @@ class ShxFont:
816
860
  and the span.
817
861
  :return:
818
862
  """
819
- radius = self.pop() * self._scale
820
- sc = signed8(self.pop())
863
+ try:
864
+ radius = self.pop() * self._scale
865
+ sc = signed8(self.pop())
866
+ except ShxFontParseError:
867
+ return
821
868
  s = (sc >> 4) & 0x7
822
869
  c = sc & 0x7
823
870
  if self._debug:
@@ -858,13 +905,15 @@ class ShxFont:
858
905
  90° + (28/256 * 45°) = 95°
859
906
  """
860
907
  octant = tau / 8.0
861
- start_offset = octant * self.pop() / 256.0
862
- end_offset = octant * self.pop() / 256.0
863
- radius = (256 * self.pop() + self.pop()) * self._scale
864
- sc = signed8(self.pop())
865
- s = (sc >> 4) & 0x7
866
- c = sc & 0x7
867
-
908
+ try:
909
+ start_offset = octant * self.pop() / 256.0
910
+ end_offset = octant * self.pop() / 256.0
911
+ radius = (256 * self.pop() + self.pop()) * self._scale
912
+ sc = signed8(self.pop())
913
+ s = (sc >> 4) & 0x7
914
+ c = sc & 0x7
915
+ except ShxFontParseError:
916
+ return
868
917
  if self._debug:
869
918
  print(
870
919
  f"FRACTION_ARC {start_offset}, {end_offset}, {radius}, {s}, {c} {'(Skipped)' if self._skip else ''}"
@@ -903,10 +952,12 @@ class ShxFont:
903
952
 
904
953
  :return:
905
954
  """
906
-
907
- dx = signed8(self.pop()) * self._scale
908
- dy = signed8(self.pop()) * self._scale
909
- h = signed8(self.pop())
955
+ try:
956
+ dx = signed8(self.pop()) * self._scale
957
+ dy = signed8(self.pop()) * self._scale
958
+ h = signed8(self.pop())
959
+ except ShxFontParseError:
960
+ return
910
961
 
911
962
  if self._debug:
912
963
  print(f"BULGE_ARC {dx}, {dy}, {h} {'(Skipped)' if self._skip else ''}")
@@ -939,8 +990,12 @@ class ShxFont:
939
990
  """
940
991
  h = 0
941
992
  while True:
942
- dx = signed8(self.pop()) * self._scale
943
- dy = signed8(self.pop()) * self._scale
993
+ try:
994
+ dx = signed8(self.pop()) * self._scale
995
+ dy = signed8(self.pop()) * self._scale
996
+ except ShxFontParseError:
997
+ return
998
+
944
999
  if self._debug:
945
1000
  print(
946
1001
  f"POLY_BULGE_ARC {dx}, {dy}, {h} {'(Skipped)' if self._skip else ''}"
@@ -949,7 +1004,10 @@ class ShxFont:
949
1004
  if self._debug:
950
1005
  print(f"POLY_BULGE_ARC (TERMINATED)")
951
1006
  break
952
- h = signed8(self.pop())
1007
+ try:
1008
+ h = signed8(self.pop())
1009
+ except ShxFontParseError:
1010
+ return
953
1011
  if self._skip:
954
1012
  continue
955
1013
  r = abs(complex(dx, dy)) / 2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerk40t
3
- Version: 0.9.7010
3
+ Version: 0.9.7030
4
4
  Summary: MeerK40t LaserCutter Software
5
5
  Home-page: https://github.com/meerk40t/meerk40t
6
6
  Author: Tatarize