meerk40t 0.9.7020__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.
- meerk40t/core/cutcode/cutcode.py +1 -1
- meerk40t/core/cutplan.py +70 -2
- meerk40t/core/elements/element_treeops.py +9 -7
- meerk40t/core/elements/grid.py +8 -1
- meerk40t/core/elements/offset_mk.py +2 -1
- meerk40t/core/elements/shapes.py +378 -259
- meerk40t/core/node/node.py +6 -3
- meerk40t/core/planner.py +23 -0
- meerk40t/core/undos.py +1 -1
- meerk40t/core/wordlist.py +1 -0
- meerk40t/dxf/dxf_io.py +6 -0
- meerk40t/extra/mk_potrace.py +1959 -0
- meerk40t/extra/param_functions.py +1 -1
- meerk40t/extra/potrace.py +14 -10
- meerk40t/grbl/interpreter.py +1 -1
- meerk40t/gui/about.py +3 -5
- meerk40t/gui/basicops.py +3 -3
- meerk40t/gui/choicepropertypanel.py +1 -4
- meerk40t/gui/gui_mixins.py +4 -1
- meerk40t/gui/spoolerpanel.py +6 -9
- meerk40t/gui/themes.py +7 -1
- meerk40t/gui/wxmeerk40t.py +26 -0
- meerk40t/gui/wxmscene.py +93 -0
- meerk40t/image/imagetools.py +1 -1
- meerk40t/kernel/kernel.py +10 -4
- meerk40t/kernel/settings.py +2 -0
- meerk40t/lihuiyu/device.py +9 -3
- meerk40t/main.py +22 -5
- meerk40t/ruida/gui/gui.py +6 -6
- meerk40t/ruida/gui/ruidaoperationproperties.py +1 -10
- meerk40t/ruida/rdjob.py +3 -3
- meerk40t/tools/geomstr.py +88 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/RECORD +39 -38
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/zip-safe +0 -0
@@ -435,7 +435,7 @@ def plugin(kernel, lifecycle):
|
|
435
435
|
@self.console_argument("inversions", nargs="*", type=int)
|
436
436
|
@context.console_command(
|
437
437
|
"ffractal",
|
438
|
-
help=_("
|
438
|
+
help=_("fractal iterations"),
|
439
439
|
output_type="geometry",
|
440
440
|
hidden=True,
|
441
441
|
)
|
meerk40t/extra/potrace.py
CHANGED
@@ -48,21 +48,25 @@ potracer: https://github.com/tatarize/potrace
|
|
48
48
|
|
49
49
|
def plugin(kernel, lifecycle=None):
|
50
50
|
if lifecycle == "invalidate":
|
51
|
+
invalid = False
|
52
|
+
return invalid
|
53
|
+
|
54
|
+
if lifecycle == "register":
|
55
|
+
_ = kernel.translation
|
56
|
+
import numpy
|
57
|
+
valid = False
|
51
58
|
try:
|
52
|
-
import numpy
|
53
59
|
import potrace
|
54
|
-
if
|
60
|
+
if hasattr(potrace, "Bitmap"):
|
61
|
+
valid = True
|
62
|
+
else:
|
55
63
|
# This is a strange variant, that we do not support!
|
56
64
|
print ("The version of potrace that is installed on your machine is incompatible. Please report this to the developers.")
|
57
|
-
return True
|
58
65
|
except ImportError:
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
_ = kernel.translation
|
64
|
-
import numpy
|
65
|
-
import potrace
|
66
|
+
valid = False
|
67
|
+
|
68
|
+
if not valid:
|
69
|
+
from . import mk_potrace as potrace
|
66
70
|
|
67
71
|
def make_vector(
|
68
72
|
image,
|
meerk40t/grbl/interpreter.py
CHANGED
@@ -12,7 +12,7 @@ from meerk40t.kernel import Module
|
|
12
12
|
class GRBLInterpreter(Module):
|
13
13
|
def __init__(self, service, path):
|
14
14
|
Module.__init__(self, service, path)
|
15
|
-
self.emulator = GRBLEmulator(self, service.space.display.matrix
|
15
|
+
self.emulator = GRBLEmulator(self, service.space.display.matrix)
|
16
16
|
self._attached_device = None
|
17
17
|
|
18
18
|
def __repr__(self):
|
meerk40t/gui/about.py
CHANGED
@@ -1770,6 +1770,8 @@ class ComponentPanel(ScrolledPanel):
|
|
1770
1770
|
|
1771
1771
|
def get_potrace():
|
1772
1772
|
entry = ["potracer", "", "", "https://pypi.org/project/potracer/"]
|
1773
|
+
status = _("Present (slow)")
|
1774
|
+
info = "0.05 (internal)"
|
1773
1775
|
try:
|
1774
1776
|
import potrace
|
1775
1777
|
|
@@ -1780,14 +1782,10 @@ class ComponentPanel(ScrolledPanel):
|
|
1780
1782
|
entry[0] = "pypotrace"
|
1781
1783
|
entry[3] = "https://pypi.org/project/pypotrace/"
|
1782
1784
|
info = potrace.potracelib_version()
|
1783
|
-
else:
|
1784
|
-
status = _("Present (slow)")
|
1785
|
-
info = "??"
|
1786
1785
|
if not hasattr(potrace, "Bitmap"):
|
1787
1786
|
status = _("Faulty, please report")
|
1788
1787
|
except ImportError:
|
1789
|
-
|
1790
|
-
status = _("Missing")
|
1788
|
+
pass
|
1791
1789
|
entry[1] = info
|
1792
1790
|
entry[2] = status
|
1793
1791
|
self.content.append(entry)
|
meerk40t/gui/basicops.py
CHANGED
@@ -459,21 +459,21 @@ class BasicOpPanel(wx.Panel):
|
|
459
459
|
self.context.themes.set_window_colors(header)
|
460
460
|
header.SetMinSize(dip_size(self, 20, -1))
|
461
461
|
header.SetMaxSize(dip_size(self, 20, -1))
|
462
|
-
header.SetToolTip(_("Active"))
|
462
|
+
header.SetToolTip(_("A: Active = toggle whether the elements assigned to this operation will be burned or not"))
|
463
463
|
info_sizer.Add(header, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
464
464
|
|
465
465
|
header = wxStaticText(self.op_panel, wx.ID_ANY, label="S")
|
466
466
|
self.context.themes.set_window_colors(header)
|
467
467
|
header.SetMinSize(dip_size(self, 20, -1))
|
468
468
|
header.SetMaxSize(dip_size(self, 20, -1))
|
469
|
-
header.SetToolTip(_("Show"))
|
469
|
+
header.SetToolTip(_("S: Show = if inactive then you can suppress the drawing of the assigned elements"))
|
470
470
|
info_sizer.Add(header, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
471
471
|
|
472
472
|
header = wxStaticText(self.op_panel, wx.ID_ANY, label="C")
|
473
473
|
self.context.themes.set_window_colors(header)
|
474
474
|
header.SetMinSize(dip_size(self, 20, -1))
|
475
475
|
header.SetMaxSize(dip_size(self, 20, -1))
|
476
|
-
header.SetToolTip(_("Coolant"))
|
476
|
+
header.SetToolTip(_("C: Coolant = determines whether coolant remains / will be turned on / turned off at start of this operation"))
|
477
477
|
info_sizer.Add(header, 1, wx.ALIGN_CENTER_VERTICAL, 0)
|
478
478
|
|
479
479
|
unit = " [%]" if self.use_percent else ""
|
@@ -1117,10 +1117,7 @@ class ChoicePropertyPanel(ScrolledPanel):
|
|
1117
1117
|
control.SetValue(bool((data >> b) & 1))
|
1118
1118
|
if mask:
|
1119
1119
|
control.Enable(bool((mask_bits >> b) & 1))
|
1120
|
-
control.Bind(
|
1121
|
-
wx.EVT_CHECKBOX,
|
1122
|
-
on_checkbox_check(attr, control, obj, b, additional_signal),
|
1123
|
-
)
|
1120
|
+
control.Bind(wx.EVT_CHECKBOX, on_checkbox_bitcheck(attr, control, obj, b, additional_signal), )
|
1124
1121
|
|
1125
1122
|
# mask bit
|
1126
1123
|
if mask:
|
meerk40t/gui/gui_mixins.py
CHANGED
@@ -584,7 +584,10 @@ class Warnings:
|
|
584
584
|
image_node = node.node if hasattr(node, "node") else node
|
585
585
|
if getattr(image_node, "hidden", False):
|
586
586
|
continue
|
587
|
-
|
587
|
+
if hasattr(image_node, "dpi"):
|
588
|
+
opdpi = op.dpi if useop else image_node.dpi
|
589
|
+
else:
|
590
|
+
opdpi = op.dpi
|
588
591
|
step_x, step_y = self.context.device.view.dpi_to_steps(opdpi)
|
589
592
|
step_x *= self.context.device.view.native_scale_x
|
590
593
|
step_y *= self.context.device.view.native_scale_y
|
meerk40t/gui/spoolerpanel.py
CHANGED
@@ -673,15 +673,6 @@ class SpoolerPanel(wx.Panel):
|
|
673
673
|
|
674
674
|
return routine
|
675
675
|
|
676
|
-
def pane_show(self, *args):
|
677
|
-
self.shown = True
|
678
|
-
self.context.schedule(self.timerjob)
|
679
|
-
self.refresh_spooler_list()
|
680
|
-
|
681
|
-
def pane_hide(self, *args):
|
682
|
-
self.context.unschedule(self.timerjob)
|
683
|
-
self.shown = False
|
684
|
-
|
685
676
|
@staticmethod
|
686
677
|
def _name_str(named_obj):
|
687
678
|
try:
|
@@ -1171,10 +1162,16 @@ class SpoolerPanel(wx.Panel):
|
|
1171
1162
|
self.on_device_update(None)
|
1172
1163
|
|
1173
1164
|
def pane_show(self):
|
1165
|
+
self.shown = True
|
1174
1166
|
self.list_job_history.load_column_widths()
|
1175
1167
|
self.list_job_spool.load_column_widths()
|
1168
|
+
self.context.schedule(self.timerjob)
|
1169
|
+
self.refresh_spooler_list()
|
1176
1170
|
|
1177
1171
|
def pane_hide(self):
|
1172
|
+
self.context.unschedule(self.timerjob)
|
1173
|
+
self.shown = False
|
1174
|
+
|
1178
1175
|
self.list_job_history.save_column_widths()
|
1179
1176
|
self.list_job_spool.save_column_widths()
|
1180
1177
|
|
meerk40t/gui/themes.py
CHANGED
@@ -31,6 +31,9 @@ def color_distance(c1:wx.Colour, c2:wx.Colour) -> bool:
|
|
31
31
|
# print (f"Distance from {c1.GetAsString()} to {c2.GetAsString()} = {sqrt(sq_dist)}")
|
32
32
|
return sqrt(sq_dist)
|
33
33
|
|
34
|
+
def inverted_color(c1:wx.Colour) -> wx.Colour:
|
35
|
+
return wx.Colour(255-c1.red, 255-c1.green, 255-c1.blue, c1.alpha)
|
36
|
+
|
34
37
|
def is_a_bright_color(c1):
|
35
38
|
return color_distance(c1, wx.BLACK) > color_distance(c1, wx.WHITE)
|
36
39
|
|
@@ -132,6 +135,10 @@ class Themes(Service):
|
|
132
135
|
tp["inactive_fg"] = wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTIONTEXT)
|
133
136
|
# for key, col in tp.items():
|
134
137
|
# print (f'tp["{key}"] = wx.Colour({col.red}, {col.green}, {col.blue}, {col.alpha})')
|
138
|
+
for p1, p2 in (("label_bg", "label_fg"), ("button_bg", "button_fg"), ("text_bg", "text_fg"), ("list_bg", "list_fg")):
|
139
|
+
inv_col = inverted_color(tp[p2])
|
140
|
+
if color_distance(tp[p2], tp[p1]) < color_distance(inv_col, tp[p1]):
|
141
|
+
tp[p2] = inv_col
|
135
142
|
if system() != "Darwin":
|
136
143
|
# Alas, Darwin does not properly support overloading of colors...
|
137
144
|
if not self.dark and is_a_dark_color(tp["win_bg"]):
|
@@ -166,7 +173,6 @@ class Themes(Service):
|
|
166
173
|
tp["highlight"] = wx.Colour(0, 0, 255)
|
167
174
|
tp["inactive_bg"] = wx.Colour(46, 46, 46)
|
168
175
|
tp["inactive_fg"] = base_fg
|
169
|
-
|
170
176
|
tp["pause_bg"] = (
|
171
177
|
wx.Colour(87, 87, 0) if self._dark else wx.Colour(200, 200, 0)
|
172
178
|
)
|
meerk40t/gui/wxmeerk40t.py
CHANGED
@@ -24,6 +24,7 @@ from meerk40t.gui.wxmscene import SceneWindow
|
|
24
24
|
from meerk40t.gui.wxutils import TextCtrl, wxButton, wxStaticText
|
25
25
|
from meerk40t.kernel import CommandSyntaxError, Module, get_safe_path
|
26
26
|
from meerk40t.kernel.kernel import Job
|
27
|
+
from meerk40t.core.units import Length
|
27
28
|
|
28
29
|
from ..main import APPLICATION_NAME, APPLICATION_VERSION
|
29
30
|
from ..tools.kerftest import KerfTool
|
@@ -835,6 +836,31 @@ class wxMeerK40t(wx.App, Module):
|
|
835
836
|
dialog.cancel_it()
|
836
837
|
dialog.Destroy()
|
837
838
|
|
839
|
+
@kernel.console_argument("info", type=str, help=_("Unit to translate"))
|
840
|
+
@kernel.console_command("unit", help=_("Translate units"))
|
841
|
+
def show_unit_info(command, channel, _, info=None, **kwargs):
|
842
|
+
if info is None:
|
843
|
+
channel(_("You need to provide a value to translate"))
|
844
|
+
device = kernel.root.device
|
845
|
+
try:
|
846
|
+
valuex = Length(info, relative_length=device.view.width, digits=4)
|
847
|
+
except ValueError:
|
848
|
+
channel(f"Invalid value: '{info}'")
|
849
|
+
return
|
850
|
+
channel(f"{info} translates to:")
|
851
|
+
channel(f"tat : {float(valuex):.4f}")
|
852
|
+
channel(f"mil : {valuex.mil}")
|
853
|
+
channel(f"um : {valuex.um}")
|
854
|
+
channel(f"nm : {valuex.nm}")
|
855
|
+
channel(f"mm : {valuex.mm}")
|
856
|
+
channel(f"cm : {valuex.cm}")
|
857
|
+
channel(f"Pixels : {valuex.pixels}")
|
858
|
+
channel(f"Point : {valuex.pt}")
|
859
|
+
channel(f"spx (screen) : {valuex.spx}")
|
860
|
+
channel(f"inch : {valuex.inches}")
|
861
|
+
channel(f"Device units : {float(valuex) / device.view.native_scale_x:.4f}")
|
862
|
+
|
863
|
+
|
838
864
|
def module_open(self, *args, **kwargs):
|
839
865
|
context = self.context
|
840
866
|
kernel = context.kernel
|
meerk40t/gui/wxmscene.py
CHANGED
@@ -868,6 +868,99 @@ class MeerK40tScenePanel(wx.Panel):
|
|
868
868
|
else:
|
869
869
|
channel(_("Target needs to be one of primary, secondary, circular"))
|
870
870
|
|
871
|
+
# Establishes magnet commands
|
872
|
+
@context.console_argument(
|
873
|
+
"action", type=str, help=_("Action: clear or set / delete with coordinate")
|
874
|
+
)
|
875
|
+
@context.console_argument(
|
876
|
+
"axis", type=str, help=_("Axis (X or Y)")
|
877
|
+
)
|
878
|
+
@context.console_argument("pos", type=str, help=_("Position for magnetline"))
|
879
|
+
@context.console_command(
|
880
|
+
"magnet",
|
881
|
+
help=_("magnet <action> <axis> <position>"),
|
882
|
+
input_type="scene",
|
883
|
+
)
|
884
|
+
def magnet_set(
|
885
|
+
command,
|
886
|
+
channel,
|
887
|
+
_,
|
888
|
+
action=None,
|
889
|
+
axis=None,
|
890
|
+
pos=None,
|
891
|
+
**kwarg,
|
892
|
+
):
|
893
|
+
def info(opt_msg):
|
894
|
+
channel(
|
895
|
+
_("You need to provide the intended action:") + "\n" +
|
896
|
+
_("clear x - clear y : will clear all magnets on the given axis") + "\n" +
|
897
|
+
_("set x <pos> - set y <pos>: will set a magnet line on the given axis") + "\n" +
|
898
|
+
_("delete x <pos> - delete y <pos>: will delete the magnet line on the given axis")
|
899
|
+
)
|
900
|
+
if opt_msg:
|
901
|
+
channel(opt_msg)
|
902
|
+
|
903
|
+
if action is None or axis is None or axis.upper() not in ("X", "Y"):
|
904
|
+
info("")
|
905
|
+
return
|
906
|
+
action = action.lower()
|
907
|
+
axis = axis.upper()
|
908
|
+
value = None
|
909
|
+
if pos:
|
910
|
+
try:
|
911
|
+
rel_len = self.context.device.view.width if axis == "X" else self.context.device.view.height
|
912
|
+
value = float(Length(pos, relative_length=rel_len))
|
913
|
+
except ValueError:
|
914
|
+
info (f"Invalid length: {pos}")
|
915
|
+
return
|
916
|
+
|
917
|
+
if action != "clear" and value is None:
|
918
|
+
info(_("You need to provide a position"))
|
919
|
+
return
|
920
|
+
|
921
|
+
if action == "clear":
|
922
|
+
if axis == "X":
|
923
|
+
count = len(self.magnet_x)
|
924
|
+
self.magnet_x.clear()
|
925
|
+
else:
|
926
|
+
count = len(self.magnet_y)
|
927
|
+
self.magnet_y.clear()
|
928
|
+
self.save_magnets()
|
929
|
+
self.context.signal("refresh_scene", "Scene")
|
930
|
+
channel (_("Deleted {count} magnet lines on axis {axis}").format(axis=axis, count=count))
|
931
|
+
elif action == "set":
|
932
|
+
done = False
|
933
|
+
if axis == "X":
|
934
|
+
if not value in self.magnet_x:
|
935
|
+
done = True
|
936
|
+
self.magnet_x.append(value)
|
937
|
+
else:
|
938
|
+
if not value in self.magnet_y:
|
939
|
+
done = True
|
940
|
+
self.magnet_y.append(value)
|
941
|
+
self.save_magnets()
|
942
|
+
self.context.signal("refresh_scene", "Scene")
|
943
|
+
if done:
|
944
|
+
channel(_("Magnetline appended at {pos} on axis {axis}").format(pos=pos, axis=axis))
|
945
|
+
else:
|
946
|
+
channel(_("Magnetline was already present"))
|
947
|
+
elif action.startswith("del"):
|
948
|
+
done = False
|
949
|
+
if axis == "X":
|
950
|
+
if value in self.magnet_x:
|
951
|
+
done = True
|
952
|
+
self.magnet_x.remove(value)
|
953
|
+
else:
|
954
|
+
if value in self.magnet_y:
|
955
|
+
done = True
|
956
|
+
self.magnet_y.remove(value)
|
957
|
+
self.save_magnets()
|
958
|
+
self.context.signal("refresh_scene", "Scene")
|
959
|
+
if done:
|
960
|
+
channel(_("Magnetline removed at {pos} on axis {axis}").format(pos=pos, axis=axis))
|
961
|
+
else:
|
962
|
+
channel(_("Magnetline was not existing"))
|
963
|
+
|
871
964
|
def toggle_ref_obj(self):
|
872
965
|
for e in self.scene.context.elements.flat(types=elem_nodes, emphasized=True):
|
873
966
|
if self.reference_object == e:
|
meerk40t/image/imagetools.py
CHANGED
meerk40t/kernel/kernel.py
CHANGED
@@ -254,15 +254,21 @@ class Kernel(Settings):
|
|
254
254
|
kwargs_repr = [f"{k}={v}" for k, v in kwargs.items()]
|
255
255
|
signature = ", ".join(args_repr + kwargs_repr)
|
256
256
|
start = f"Calling {str(obj)}.{func.__name__}({signature})"
|
257
|
-
|
257
|
+
try:
|
258
|
+
debug_file.write(start + "\n")
|
259
|
+
except (ValueError, OSError):
|
260
|
+
pass
|
258
261
|
print(start)
|
259
262
|
t = time.time()
|
260
263
|
value = func(*args, **kwargs)
|
261
264
|
t = time.time() - t
|
262
265
|
finish = f" {func.__name__} returned {value} after {t * 1000}ms"
|
263
266
|
print(finish)
|
264
|
-
|
265
|
-
|
267
|
+
try:
|
268
|
+
debug_file.write(finish + "\n")
|
269
|
+
debug_file.flush()
|
270
|
+
except (ValueError, OSError):
|
271
|
+
pass
|
266
272
|
return value
|
267
273
|
|
268
274
|
return wrapper_debug
|
@@ -1236,7 +1242,7 @@ class Kernel(Settings):
|
|
1236
1242
|
|
1237
1243
|
line = await loop.run_in_executor(None, sys.stdin.readline)
|
1238
1244
|
line = line.strip()
|
1239
|
-
if line in ("quit", "shutdown", "restart"):
|
1245
|
+
if line in ("quit", "shutdown", "exit", "restart"):
|
1240
1246
|
self._quit = True
|
1241
1247
|
if line == "restart":
|
1242
1248
|
self._restart = True
|
meerk40t/kernel/settings.py
CHANGED
@@ -54,6 +54,8 @@ class Settings:
|
|
54
54
|
FileNotFoundError,
|
55
55
|
):
|
56
56
|
return
|
57
|
+
except UnicodeDecodeError as e:
|
58
|
+
print ("The config file contained unsupported characters, please share the file with the dev team")
|
57
59
|
except (configparser.DuplicateOptionError, configparser.DuplicateSectionError) as e:
|
58
60
|
print (f"We had a duplication error in the config, try to recover from {e}")
|
59
61
|
for section in parser.sections():
|
meerk40t/lihuiyu/device.py
CHANGED
@@ -6,14 +6,16 @@ the given device type.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from hashlib import md5
|
9
|
+
import platform
|
10
|
+
|
9
11
|
import meerk40t.constants as mkconst
|
10
12
|
from meerk40t.core.laserjob import LaserJob
|
11
13
|
from meerk40t.core.spoolers import Spooler
|
12
14
|
from meerk40t.core.view import View
|
13
15
|
from meerk40t.kernel import CommandSyntaxError, Service, signal_listener
|
14
16
|
|
15
|
-
from
|
16
|
-
from
|
17
|
+
from meerk40t.core.units import UNITS_PER_MIL, Length
|
18
|
+
from meerk40t.device.mixins import Status
|
17
19
|
from .controller import LihuiyuController
|
18
20
|
from .driver import LihuiyuDriver
|
19
21
|
from .tcp_connection import TCPOutput
|
@@ -514,7 +516,10 @@ class LihuiyuDevice(Service, Status):
|
|
514
516
|
self.setting(str, "serial", None)
|
515
517
|
self.setting(bool, "serial_enable", False)
|
516
518
|
|
517
|
-
|
519
|
+
# Linux prevents ports below 1024 to be used in an non-root context
|
520
|
+
def_port = 1022 if platform.system() == "Windows" else "1025"
|
521
|
+
|
522
|
+
self.setting(int, "port", def_port)
|
518
523
|
self.setting(str, "address", "localhost")
|
519
524
|
|
520
525
|
self.driver = LihuiyuDriver(self)
|
@@ -978,6 +983,7 @@ class LihuiyuDevice(Service, Status):
|
|
978
983
|
server = self.open_as("module/TCPServer", server_name, port=port)
|
979
984
|
if quit:
|
980
985
|
self.close(server_name)
|
986
|
+
channel(_("TCP Server for lihuiyu has been closed"))
|
981
987
|
return
|
982
988
|
channel(_("TCP Server for lihuiyu on port: {port}").format(port=port))
|
983
989
|
if verbose:
|
meerk40t/main.py
CHANGED
@@ -11,7 +11,7 @@ import os.path
|
|
11
11
|
import sys
|
12
12
|
|
13
13
|
APPLICATION_NAME = "MeerK40t"
|
14
|
-
APPLICATION_VERSION = "0.9.
|
14
|
+
APPLICATION_VERSION = "0.9.7030"
|
15
15
|
|
16
16
|
if not getattr(sys, "frozen", False):
|
17
17
|
# If .git directory does not exist we are running from a package like pypi
|
@@ -151,6 +151,9 @@ parser.add_argument(
|
|
151
151
|
action="store_true",
|
152
152
|
help="start window maximized",
|
153
153
|
)
|
154
|
+
parser.add_argument(
|
155
|
+
"-d", "--daemon", action="store_true", help="keep MeerK40t in background"
|
156
|
+
)
|
154
157
|
|
155
158
|
|
156
159
|
def run():
|
@@ -220,12 +223,26 @@ def _exe(restarted, args):
|
|
220
223
|
kernel.add_plugin(internal_plugins)
|
221
224
|
kernel.add_plugin(external_plugins)
|
222
225
|
auto = hasattr(kernel.args, "auto") and kernel.args.auto
|
226
|
+
command = hasattr(kernel.args, "execute") and kernel.args.execute
|
223
227
|
console = hasattr(kernel.args, "console") and kernel.args.console
|
228
|
+
daemon = hasattr(kernel.args, "daemon") and kernel.args.daemon
|
229
|
+
server_mode = False
|
230
|
+
if command:
|
231
|
+
for c in command:
|
232
|
+
server_mode = server_mode or any(substring in c for substring in ("lhyserver", "grblserver", "ruidacontrol", "grblcontrol", "webserver"))
|
233
|
+
nogui = (
|
234
|
+
(hasattr(kernel.args, "gui_suppress") and kernel.args.gui_suppress) or
|
235
|
+
(hasattr(kernel.args, "no_gui") and kernel.args.no_gui)
|
236
|
+
)
|
224
237
|
for idx, attrib in enumerate(("mktablength", "mktabpositions")):
|
225
238
|
kernel.register(f"registered_mk_svg_parameters/tabs{idx}", attrib)
|
226
239
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
240
|
+
require_partial_mode = False
|
241
|
+
if (
|
242
|
+
(not console or nogui) and
|
243
|
+
(auto or daemon or server_mode)
|
244
|
+
):
|
245
|
+
require_partial_mode = True
|
246
|
+
# print (f"Auto: {auto}, Command: {command}, Console: {console}, daemon: {daemon}, nogui:{nogui}, Server: {server_mode} -> {require_partial_mode}")
|
247
|
+
kernel(partial=require_partial_mode)
|
231
248
|
return hasattr(kernel, "restart") and kernel.restart
|
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("
|
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
|
-
|
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
|