meerk40t 0.9.7040__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.
- meerk40t/balormk/controller.py +10 -2
- meerk40t/core/cutplan.py +1 -36
- meerk40t/core/elements/shapes.py +7 -40
- meerk40t/core/node/blobnode.py +19 -4
- meerk40t/core/planner.py +25 -11
- meerk40t/grbl/device.py +15 -1
- meerk40t/grbl/driver.py +15 -5
- meerk40t/gui/laserpanel.py +19 -0
- meerk40t/gui/materialtest.py +474 -405
- meerk40t/gui/propertypanels/wobbleproperty.py +6 -2
- meerk40t/gui/spoolerpanel.py +27 -7
- meerk40t/gui/wxutils.py +226 -0
- meerk40t/kernel/kernel.py +28 -0
- meerk40t/main.py +14 -9
- meerk40t/ruida/loader.py +3 -1
- meerk40t/ruida/rdjob.py +48 -8
- meerk40t/tools/geomstr.py +93 -44
- meerk40t/tools/rasterplotter.py +6 -1
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/RECORD +25 -25
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7040.dist-info → meerk40t-0.9.7050.dist-info}/zip-safe +0 -0
meerk40t/balormk/controller.py
CHANGED
@@ -1003,7 +1003,11 @@ class GalvoController:
|
|
1003
1003
|
def get_scale_from_correction_file(filename):
|
1004
1004
|
with open(filename, "rb") as f:
|
1005
1005
|
label = f.read(0x16)
|
1006
|
-
|
1006
|
+
try:
|
1007
|
+
decoded_label = label.decode("utf-16")
|
1008
|
+
except UnicodeDecodeError:
|
1009
|
+
decoded_label = label.decode("utf-8", errors="ignore")
|
1010
|
+
if decoded_label == "LMC1COR_1.0":
|
1007
1011
|
unk = f.read(2)
|
1008
1012
|
return struct.unpack("63d", f.read(0x1F8))[43]
|
1009
1013
|
else:
|
@@ -1049,7 +1053,11 @@ class GalvoController:
|
|
1049
1053
|
"""
|
1050
1054
|
with open(filename, "rb") as f:
|
1051
1055
|
label = f.read(0x16)
|
1052
|
-
|
1056
|
+
try:
|
1057
|
+
decoded_label = label.decode("utf-16")
|
1058
|
+
except UnicodeDecodeError:
|
1059
|
+
decoded_label = label.decode("utf-8", errors="ignore")
|
1060
|
+
if decoded_label == "LMC1COR_1.0":
|
1053
1061
|
header = f.read(0x1FA)
|
1054
1062
|
return self._read_float_correction_file(f)
|
1055
1063
|
else:
|
meerk40t/core/cutplan.py
CHANGED
@@ -24,7 +24,7 @@ from typing import Optional
|
|
24
24
|
import numpy as np
|
25
25
|
|
26
26
|
from ..svgelements import Group, Matrix, Path, Polygon
|
27
|
-
from ..tools.geomstr import Geomstr, stitch_geometries
|
27
|
+
from ..tools.geomstr import Geomstr, stitch_geometries, stitcheable_nodes
|
28
28
|
from ..tools.pathtools import VectorMontonizer
|
29
29
|
from .cutcode.cutcode import CutCode
|
30
30
|
from .cutcode.cutgroup import CutGroup
|
@@ -265,41 +265,6 @@ class CutPlan:
|
|
265
265
|
stitch_tolerance = 0
|
266
266
|
default_stroke = None
|
267
267
|
default_strokewidth = None
|
268
|
-
|
269
|
-
def stitcheable_nodes(data, tolerance) -> list:
|
270
|
-
out = []
|
271
|
-
geoms = []
|
272
|
-
# Store all geometries together with an indicator, to which node they belong
|
273
|
-
for idx, node in enumerate(data):
|
274
|
-
if not hasattr(node, "as_geometry"):
|
275
|
-
continue
|
276
|
-
for g1 in node.as_geometry().as_contiguous():
|
277
|
-
geoms.append((idx, g1))
|
278
|
-
for idx1, (nodeidx1, g1) in enumerate(geoms):
|
279
|
-
for idx2 in range(idx1 + 1, len(geoms)):
|
280
|
-
nodeidx2 = geoms[idx2][0]
|
281
|
-
g2 = geoms[idx2][1]
|
282
|
-
fp1 = g1.first_point
|
283
|
-
fp2 = g2.first_point
|
284
|
-
lp1 = g1.last_point
|
285
|
-
lp2 = g2.last_point
|
286
|
-
if fp1 is None or fp2 is None:
|
287
|
-
continue
|
288
|
-
if lp1 is None or lp2 is None:
|
289
|
-
continue
|
290
|
-
if (
|
291
|
-
abs(lp1 - lp2) <= tolerance
|
292
|
-
or abs(lp1 - fp2) <= tolerance
|
293
|
-
or abs(fp1 - fp2) <= tolerance
|
294
|
-
or abs(fp1 - lp2) <= tolerance
|
295
|
-
):
|
296
|
-
if nodeidx1 not in out:
|
297
|
-
out.append(nodeidx1)
|
298
|
-
if nodeidx2 not in out:
|
299
|
-
out.append(nodeidx2)
|
300
|
-
|
301
|
-
return [data[idx] for idx in out]
|
302
|
-
|
303
268
|
geoms = []
|
304
269
|
to_be_deleted = []
|
305
270
|
data = stitcheable_nodes(list(op.flat()), stitch_tolerance)
|
meerk40t/core/elements/shapes.py
CHANGED
@@ -66,7 +66,7 @@ from meerk40t.svgelements import (
|
|
66
66
|
Polygon,
|
67
67
|
Polyline,
|
68
68
|
)
|
69
|
-
from meerk40t.tools.geomstr import Geomstr, stitch_geometries
|
69
|
+
from meerk40t.tools.geomstr import Geomstr, stitch_geometries, stitcheable_nodes
|
70
70
|
|
71
71
|
|
72
72
|
def plugin(kernel, lifecycle=None):
|
@@ -2778,38 +2778,6 @@ def init_commands(kernel):
|
|
2778
2778
|
return data, tolerance, keep, False
|
2779
2779
|
return data, tolerance_val, keep, True
|
2780
2780
|
|
2781
|
-
def stitcheable_nodes(data, tolerance) -> list:
|
2782
|
-
out = []
|
2783
|
-
geoms = []
|
2784
|
-
# Store all geometries together with an indicator, to which node they belong
|
2785
|
-
for idx, node in enumerate(data):
|
2786
|
-
if not hasattr(node, "as_geometry"):
|
2787
|
-
continue
|
2788
|
-
for g1 in node.as_geometry().as_contiguous():
|
2789
|
-
geoms.append((idx, g1))
|
2790
|
-
if tolerance == 0:
|
2791
|
-
tolerance = 1e-6
|
2792
|
-
for idx1, (nodeidx1, g1) in enumerate(geoms):
|
2793
|
-
for idx2 in range(idx1 + 1, len(geoms)):
|
2794
|
-
nodeidx2 = geoms[idx2][0]
|
2795
|
-
g2 = geoms[idx2][1]
|
2796
|
-
fp1 = g1.first_point
|
2797
|
-
fp2 = g2.first_point
|
2798
|
-
lp1 = g1.last_point
|
2799
|
-
lp2 = g2.last_point
|
2800
|
-
if (
|
2801
|
-
abs(lp1 - lp2) <= tolerance
|
2802
|
-
or abs(lp1 - fp2) <= tolerance
|
2803
|
-
or abs(fp1 - fp2) <= tolerance
|
2804
|
-
or abs(fp1 - lp2) <= tolerance
|
2805
|
-
):
|
2806
|
-
if nodeidx1 not in out:
|
2807
|
-
out.append(nodeidx1)
|
2808
|
-
if nodeidx2 not in out:
|
2809
|
-
out.append(nodeidx2)
|
2810
|
-
|
2811
|
-
return [data[idx] for idx in out]
|
2812
|
-
|
2813
2781
|
data, tolerance, keep, valid = _prepare_stitching_params(
|
2814
2782
|
channel, data, tolerance, keep
|
2815
2783
|
)
|
@@ -2829,13 +2797,12 @@ def init_commands(kernel):
|
|
2829
2797
|
default_strokewidth = None
|
2830
2798
|
default_fill = None
|
2831
2799
|
for node in s_data:
|
2832
|
-
|
2833
|
-
|
2834
|
-
|
2835
|
-
|
2836
|
-
|
2837
|
-
|
2838
|
-
default_strokewidth = node.stroke_width
|
2800
|
+
geom: Geomstr = node.as_geometry()
|
2801
|
+
geoms.extend(iter(geom.as_contiguous()))
|
2802
|
+
if default_stroke is None and hasattr(node, "stroke"):
|
2803
|
+
default_stroke = node.stroke
|
2804
|
+
if default_strokewidth is None and hasattr(node, "stroke_width"):
|
2805
|
+
default_strokewidth = node.stroke_width
|
2839
2806
|
to_be_deleted.append(node)
|
2840
2807
|
prev_len = len(geoms)
|
2841
2808
|
if geoms:
|
meerk40t/core/node/blobnode.py
CHANGED
@@ -41,8 +41,15 @@ class BlobNode(Node):
|
|
41
41
|
return False
|
42
42
|
|
43
43
|
@staticmethod
|
44
|
-
def hex_view(data, data_type):
|
45
|
-
|
44
|
+
def hex_view(data, data_type, info=''):
|
45
|
+
"""
|
46
|
+
Render a hex dump with an optional info header.
|
47
|
+
|
48
|
+
data: bytes to display
|
49
|
+
data_type: mime type
|
50
|
+
info: an arbitrary string to append to the end of first line of header
|
51
|
+
"""
|
52
|
+
header1 = f"Data-Type: {data_type}, Length={len(data)}{info}\n"
|
46
53
|
header2 = "Offset | Hex | Ascii \n"
|
47
54
|
header2 += "-------+-------------------------------------------------+----------------\n"
|
48
55
|
if isinstance(data, str):
|
@@ -70,8 +77,16 @@ class BlobNode(Node):
|
|
70
77
|
return header1 + header2 + "".join(hex_data)
|
71
78
|
|
72
79
|
@staticmethod
|
73
|
-
def ascii_view(data, data_type):
|
74
|
-
|
80
|
+
def ascii_view(data, data_type, info=''):
|
81
|
+
"""
|
82
|
+
Render an ascii view with an optional info header.
|
83
|
+
|
84
|
+
data: bytes to display
|
85
|
+
data_type: mime type
|
86
|
+
info: an arbitrary string to append to the end of first line of header
|
87
|
+
"""
|
88
|
+
|
89
|
+
header1 = f"Data-Type: {data_type}, Length={len(data)}{info}\n"
|
75
90
|
header2 = "Offset | Hex | Ascii \n"
|
76
91
|
header2 += "-------+-------------------------------------------------+----------------\n"
|
77
92
|
if isinstance(data, str):
|
meerk40t/core/planner.py
CHANGED
@@ -43,7 +43,9 @@ def plugin(kernel, lifecycle=None):
|
|
43
43
|
},
|
44
44
|
]
|
45
45
|
kernel.register_choices("planner", choices)
|
46
|
-
|
46
|
+
INNER_WARNING = _(
|
47
|
+
"Notabene: Reduce Travel Time and Burn Inner First cannot be used at the same time."
|
48
|
+
)
|
47
49
|
choices = [
|
48
50
|
{
|
49
51
|
"attr": "opt_raster_optimisation",
|
@@ -97,7 +99,9 @@ def plugin(kernel, lifecycle=None):
|
|
97
99
|
"When this option IS checked, Meerk40t will burn each subpath "
|
98
100
|
+ "and then move to the nearest remaining subpath instead, "
|
99
101
|
+ "reducing the time taken moving between burn items."
|
100
|
-
)
|
102
|
+
)
|
103
|
+
+ "\n"
|
104
|
+
+ INNER_WARNING,
|
101
105
|
"page": "Optimisations",
|
102
106
|
"section": "_20_Reducing Movements",
|
103
107
|
},
|
@@ -187,9 +191,11 @@ def plugin(kernel, lifecycle=None):
|
|
187
191
|
"default": False,
|
188
192
|
"type": bool,
|
189
193
|
"label": _("Combine path segments"),
|
190
|
-
"tip":
|
191
|
-
|
192
|
-
|
194
|
+
"tip": _(
|
195
|
+
"Stitch segments together that are very close (ideally having joint start/end points)."
|
196
|
+
)
|
197
|
+
+ "\n"
|
198
|
+
+ _("Only inside a single cut/engrave operation."),
|
193
199
|
"page": "Optimisations",
|
194
200
|
"section": "_05_Stitching",
|
195
201
|
},
|
@@ -199,7 +205,9 @@ def plugin(kernel, lifecycle=None):
|
|
199
205
|
"default": "0",
|
200
206
|
"type": Length,
|
201
207
|
"label": _("Tolerance"),
|
202
|
-
"tip": _(
|
208
|
+
"tip": _(
|
209
|
+
"Tolerance to decide whether two path segments should be joined."
|
210
|
+
),
|
203
211
|
"page": "Optimisations",
|
204
212
|
"section": "_05_Stitching",
|
205
213
|
"conditional": (context, "opt_stitching"),
|
@@ -221,7 +229,9 @@ def plugin(kernel, lifecycle=None):
|
|
221
229
|
+ "* Deselecting Cut Inner First if you are not cutting fully through your material \n"
|
222
230
|
+ "* Putting the inner paths into a separate earlier operation(s) and not using Merge Operations or Cut Inner First \n"
|
223
231
|
+ "* If you are using multiple passes, check Merge Passes"
|
224
|
-
)
|
232
|
+
)
|
233
|
+
+ "\n"
|
234
|
+
+ INNER_WARNING,
|
225
235
|
"page": "Optimisations",
|
226
236
|
"section": "_10_Burn sequence",
|
227
237
|
},
|
@@ -285,8 +295,11 @@ def plugin(kernel, lifecycle=None):
|
|
285
295
|
"type": bool,
|
286
296
|
"label": _("Keep effect lines together"),
|
287
297
|
"tip": (
|
288
|
-
_("Active: effects like hatches are dealt with as a bigger shape")
|
289
|
-
|
298
|
+
_("Active: effects like hatches are dealt with as a bigger shape")
|
299
|
+
+ "\n"
|
300
|
+
+ _(
|
301
|
+
"Inactive: every single line segment will be dealt with individually."
|
302
|
+
)
|
290
303
|
),
|
291
304
|
"page": "Optimisations",
|
292
305
|
"section": "_25_Effects",
|
@@ -298,8 +311,9 @@ def plugin(kernel, lifecycle=None):
|
|
298
311
|
"type": bool,
|
299
312
|
"label": _("Optimize internally"),
|
300
313
|
"tip": (
|
301
|
-
_("Active: hatch lines will be optimized internally")
|
302
|
-
|
314
|
+
_("Active: hatch lines will be optimized internally")
|
315
|
+
+ "\n"
|
316
|
+
+ _("Inactive: hatch lines will be burnt sequentially.")
|
303
317
|
),
|
304
318
|
"page": "Optimisations",
|
305
319
|
"section": "_25_Effects",
|
meerk40t/grbl/device.py
CHANGED
@@ -495,6 +495,19 @@ class GRBLDevice(Service, Status):
|
|
495
495
|
"section": "_20_" + _("Maximum speeds"),
|
496
496
|
"subsection": "_10_",
|
497
497
|
},
|
498
|
+
{
|
499
|
+
"attr": "rapid_speed",
|
500
|
+
"object": self,
|
501
|
+
"default": 600,
|
502
|
+
"type": float,
|
503
|
+
"label": _("Travel speed"),
|
504
|
+
"trailer": "mm/s",
|
505
|
+
"tip": _(
|
506
|
+
"What is the travel speed for your device to move from point to another."
|
507
|
+
),
|
508
|
+
"section": "_25_" + _("Travel"),
|
509
|
+
"subsection": "_10_",
|
510
|
+
},
|
498
511
|
{
|
499
512
|
"attr": "limit_buffer",
|
500
513
|
"object": self,
|
@@ -900,7 +913,8 @@ class GRBLDevice(Service, Status):
|
|
900
913
|
# self.redlight_preferred = True
|
901
914
|
# self.driver.set("power", int(self.red_dot_level / 100 * 1000))
|
902
915
|
self.driver._clean()
|
903
|
-
self.
|
916
|
+
rapid_speed = self.setting(float, "rapid_speed", 600.0)
|
917
|
+
self.driver.laser_on(power=int(self.red_dot_level), speed=rapid_speed)
|
904
918
|
# By default, any move is a G0 move which will not activate the laser,
|
905
919
|
# so we need to switch to G1 mode:
|
906
920
|
self.driver.move_mode = 1
|
meerk40t/grbl/driver.py
CHANGED
@@ -47,7 +47,12 @@ class GRBLDriver(Parameters):
|
|
47
47
|
self.stepper_step_size = UNITS_PER_MIL
|
48
48
|
|
49
49
|
self.plot_planner = PlotPlanner(
|
50
|
-
self.settings,
|
50
|
+
self.settings,
|
51
|
+
single=True,
|
52
|
+
ppi=False,
|
53
|
+
shift=False,
|
54
|
+
group=True,
|
55
|
+
require_uniform_movement=False,
|
51
56
|
)
|
52
57
|
self.queue = []
|
53
58
|
self._queue_current = 0
|
@@ -407,10 +412,10 @@ class GRBLDriver(Parameters):
|
|
407
412
|
for q in self.queue:
|
408
413
|
# Are there any custom commands to be executed?
|
409
414
|
# Usecase (as described in issue https://github.com/meerk40t/meerk40t/issues/2764 ):
|
410
|
-
# Switch between M3 and M4 mode for cut / raster
|
415
|
+
# Switch between M3 and M4 mode for cut / raster
|
411
416
|
# M3=used to cut as gantry acceleration doesn't matter on a cut.
|
412
|
-
# M4=used for Raster/Engrave operations, as grblHAL will
|
413
|
-
# adjust power based on gantry speed including acceleration.
|
417
|
+
# M4=used for Raster/Engrave operations, as grblHAL will
|
418
|
+
# adjust power based on gantry speed including acceleration.
|
414
419
|
|
415
420
|
cmd_string = q.settings.get("custom_commands", "")
|
416
421
|
if cmd_string:
|
@@ -437,7 +442,7 @@ class GRBLDriver(Parameters):
|
|
437
442
|
self.on_value = 1.0
|
438
443
|
# Do we have a custom z-Value?
|
439
444
|
# NB: zaxis is not a property inside Parameters like power/or speed
|
440
|
-
# so we need to deal with it more directly
|
445
|
+
# so we need to deal with it more directly
|
441
446
|
# (e.g. self.power is the equivalent to self.settings.["power"]))
|
442
447
|
qzaxis = q.settings.get("zaxis", self.zaxis)
|
443
448
|
if qzaxis != self.zaxis:
|
@@ -534,6 +539,7 @@ class GRBLDriver(Parameters):
|
|
534
539
|
PLOT_RAPID | PLOT_JOG
|
535
540
|
): # Plot planner requests position change.
|
536
541
|
# self.move_mode = 0
|
542
|
+
self.rapid_mode()
|
537
543
|
self._move(x, y)
|
538
544
|
continue
|
539
545
|
# if on == 0:
|
@@ -609,6 +615,10 @@ class GRBLDriver(Parameters):
|
|
609
615
|
@param values:
|
610
616
|
@return:
|
611
617
|
"""
|
618
|
+
speedvalue = self.service.setting(float, "rapid_speed", 600.0)
|
619
|
+
if self.speed != speedvalue:
|
620
|
+
self.speed = speedvalue
|
621
|
+
self.speed_dirty = True
|
612
622
|
|
613
623
|
def finished_mode(self, *values):
|
614
624
|
"""
|
meerk40t/gui/laserpanel.py
CHANGED
@@ -888,6 +888,25 @@ class OptimizePanel(wx.Panel):
|
|
888
888
|
self.checkbox_optimize.SetValue(newvalue)
|
889
889
|
self.optimize_panel.Enable(newvalue)
|
890
890
|
|
891
|
+
def ensure_mutually_exclusive(self, prio: str):
|
892
|
+
# Ensure that opt_inner_first and opt_reduce_travel are mutually exclusive
|
893
|
+
inner_first = self.context.planner.opt_inner_first
|
894
|
+
reduce_travel = self.context.planner.opt_reduce_travel
|
895
|
+
if inner_first and reduce_travel:
|
896
|
+
if prio == "opt_inner_first":
|
897
|
+
self.context.planner.opt_reduce_travel = False
|
898
|
+
else:
|
899
|
+
self.context.planner.opt_inner_first = False
|
900
|
+
self.optimize_panel.reload()
|
901
|
+
|
902
|
+
@signal_listener("opt_inner_first")
|
903
|
+
def opt_inner_update(self, origin, *message):
|
904
|
+
self.ensure_mutually_exclusive("opt_inner_first")
|
905
|
+
|
906
|
+
@signal_listener("opt_reduce_travel")
|
907
|
+
def opt_reduce_travel_update(self, origin, *message):
|
908
|
+
self.ensure_mutually_exclusive("opt_reduce_travel")
|
909
|
+
|
891
910
|
def on_optimize(self, event):
|
892
911
|
newvalue = bool(self.checkbox_optimize.GetValue())
|
893
912
|
if newvalue != self.context.planner.do_optimization:
|