meerk40t 0.9.7051__py2.py3-none-any.whl → 0.9.7910__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 +3 -3
- meerk40t/balormk/device.py +7 -0
- meerk40t/balormk/driver.py +23 -14
- meerk40t/balormk/galvo_commands.py +18 -3
- meerk40t/balormk/gui/balorconfig.py +6 -0
- meerk40t/balormk/livelightjob.py +36 -14
- meerk40t/camera/camera.py +1 -0
- meerk40t/camera/gui/camerapanel.py +154 -58
- meerk40t/camera/plugin.py +46 -5
- meerk40t/core/elements/branches.py +90 -20
- meerk40t/core/elements/elements.py +59 -37
- meerk40t/core/elements/trace.py +10 -6
- meerk40t/core/node/node.py +2 -0
- meerk40t/core/plotplanner.py +7 -4
- meerk40t/device/gui/defaultactions.py +78 -14
- meerk40t/dxf/dxf_io.py +42 -0
- meerk40t/grbl/controller.py +245 -35
- meerk40t/grbl/device.py +102 -26
- meerk40t/grbl/driver.py +8 -2
- meerk40t/grbl/gui/grblconfiguration.py +6 -0
- meerk40t/grbl/gui/grblcontroller.py +1 -1
- meerk40t/gui/about.py +7 -0
- meerk40t/gui/choicepropertypanel.py +20 -30
- meerk40t/gui/devicepanel.py +27 -16
- meerk40t/gui/help_assets/help_assets.py +126 -2
- meerk40t/gui/icons.py +15 -0
- meerk40t/gui/laserpanel.py +102 -54
- meerk40t/gui/materialtest.py +10 -0
- meerk40t/gui/mkdebug.py +268 -9
- meerk40t/gui/navigationpanels.py +74 -8
- meerk40t/gui/propertypanels/operationpropertymain.py +185 -91
- meerk40t/gui/scenewidgets/elementswidget.py +7 -1
- meerk40t/gui/scenewidgets/selectionwidget.py +24 -9
- meerk40t/gui/simulation.py +1 -1
- meerk40t/gui/statusbarwidgets/shapepropwidget.py +50 -40
- meerk40t/gui/statusbarwidgets/statusbar.py +2 -2
- meerk40t/gui/toolwidgets/toolmeasure.py +1 -1
- meerk40t/gui/toolwidgets/toolnodeedit.py +4 -1
- meerk40t/gui/toolwidgets/tooltabedit.py +9 -7
- meerk40t/gui/wxmeerk40t.py +45 -15
- meerk40t/gui/wxmmain.py +23 -9
- meerk40t/gui/wxmribbon.py +36 -0
- meerk40t/gui/wxutils.py +66 -42
- meerk40t/kernel/inhibitor.py +120 -0
- meerk40t/kernel/kernel.py +38 -0
- meerk40t/lihuiyu/controller.py +33 -3
- meerk40t/lihuiyu/device.py +99 -4
- meerk40t/lihuiyu/driver.py +65 -5
- meerk40t/lihuiyu/gui/lhycontrollergui.py +69 -24
- meerk40t/lihuiyu/gui/lhydrivergui.py +6 -0
- meerk40t/lihuiyu/laserspeed.py +17 -10
- meerk40t/lihuiyu/parser.py +23 -0
- meerk40t/main.py +2 -2
- meerk40t/moshi/gui/moshidrivergui.py +7 -0
- meerk40t/newly/controller.py +3 -2
- meerk40t/newly/device.py +23 -2
- meerk40t/newly/driver.py +8 -3
- meerk40t/newly/gui/newlyconfig.py +7 -0
- meerk40t/ruida/gui/ruidaconfig.py +7 -0
- meerk40t/tools/geomstr.py +142 -49
- meerk40t/tools/rasterplotter.py +0 -5
- meerk40t/tools/ttfparser.py +921 -168
- {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/RECORD +69 -68
- {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7051.dist-info → meerk40t-0.9.7910.dist-info}/zip-safe +0 -0
meerk40t/camera/plugin.py
CHANGED
@@ -15,13 +15,13 @@ def plugin(kernel, lifecycle=None):
|
|
15
15
|
kernel.set_feature("camera")
|
16
16
|
if lifecycle == "invalidate":
|
17
17
|
try:
|
18
|
-
import cv2
|
18
|
+
import cv2 # pylint: disable=unused-import
|
19
19
|
except ImportError:
|
20
20
|
print("OpenCV is not installed. Disabling Camera. Install with:")
|
21
21
|
print("\tpip install opencv-python-headless")
|
22
22
|
return True
|
23
23
|
try:
|
24
|
-
import numpy as np
|
24
|
+
import numpy as np # pylint: disable=unused-import
|
25
25
|
except ImportError:
|
26
26
|
print("Numpy is not installed. Disabling Camera.")
|
27
27
|
return True
|
@@ -32,6 +32,12 @@ def plugin(kernel, lifecycle=None):
|
|
32
32
|
kernel.register("camera-enabled", True)
|
33
33
|
_ = kernel.translation
|
34
34
|
|
35
|
+
def get_camera_attribute(camera, attribute, default=None):
|
36
|
+
if isinstance(camera, int):
|
37
|
+
camera = f"camera/{camera}"
|
38
|
+
return kernel.read_persistent(str, camera, attribute, default) or default
|
39
|
+
|
40
|
+
|
35
41
|
@kernel.console_option("width", "w", type=int, help="force the camera width")
|
36
42
|
@kernel.console_option("height", "h", type=int, help="force the camera height")
|
37
43
|
@kernel.console_option(
|
@@ -100,6 +106,32 @@ def plugin(kernel, lifecycle=None):
|
|
100
106
|
data.set_uri(uri)
|
101
107
|
return "camera", data
|
102
108
|
|
109
|
+
@kernel.console_argument("label", type=str)
|
110
|
+
@kernel.console_command(
|
111
|
+
"label", help="Set camera label", output_type="camera", input_type="camera"
|
112
|
+
)
|
113
|
+
def camera_label(
|
114
|
+
_,
|
115
|
+
channel,
|
116
|
+
data=None,
|
117
|
+
label=None,
|
118
|
+
**kwargs,
|
119
|
+
):
|
120
|
+
if label is None:
|
121
|
+
channel(_("Current labels:"))
|
122
|
+
for d in kernel.section_startswith("camera/"):
|
123
|
+
# We read the persistent description instead of the context,
|
124
|
+
# as this might not be set.
|
125
|
+
desc = get_camera_attribute(d, "desc", "No description set")
|
126
|
+
channel(f"{d}: {desc}")
|
127
|
+
else:
|
128
|
+
data.desc = label
|
129
|
+
kernel.write_persistent(f"camera/{data.uri}", "desc", label)
|
130
|
+
# Alert UI to the change
|
131
|
+
kernel.signal("pane", "/", "")
|
132
|
+
kernel.signal("icon;label", "/", f"cam{data.uri}", label)
|
133
|
+
return "camera", data
|
134
|
+
|
103
135
|
@kernel.console_command(
|
104
136
|
"info", help="list camera info", output_type="camera", input_type="camera"
|
105
137
|
)
|
@@ -110,9 +142,14 @@ def plugin(kernel, lifecycle=None):
|
|
110
142
|
**kwargs,
|
111
143
|
):
|
112
144
|
channel(_("Camera Information:"))
|
145
|
+
channel("Camera-Path\turi\tDescription")
|
146
|
+
channel("----\t---\t-----------")
|
113
147
|
for d in kernel.section_startswith("camera/"):
|
114
|
-
context = kernel.get_context(d)
|
115
|
-
channel(f"{d}: {getattr(context, 'uri', '---')}")
|
148
|
+
# context = kernel.get_context(d)
|
149
|
+
# channel(f"{d}: {getattr(context, 'uri', '---')}")
|
150
|
+
camera_uri = get_camera_attribute(d, "uri", "No URI set")
|
151
|
+
camera_lbl = get_camera_attribute(d, "desc", "No description set")
|
152
|
+
channel(f"{d}:\t{camera_uri}\t{camera_lbl}")
|
116
153
|
return "camera", data
|
117
154
|
|
118
155
|
@kernel.console_command(
|
@@ -277,7 +314,11 @@ def plugin(kernel, lifecycle=None):
|
|
277
314
|
input_type="camera",
|
278
315
|
)
|
279
316
|
def list_camera_resolutions(_, channel, data=None, **kwargs):
|
280
|
-
|
317
|
+
if data is None:
|
318
|
+
channel(_("No camera selected."))
|
319
|
+
return
|
320
|
+
lbl = f" ({data.desc})" if data.desc else ""
|
321
|
+
channel(f"Available resolutions for camera #{data.uri}{lbl}")
|
281
322
|
info_array = data.guess_supported_resolutions()
|
282
323
|
for width, height, description in info_array:
|
283
324
|
channel (f"{width}x{height} - {description}")
|
@@ -144,6 +144,7 @@ Functions:
|
|
144
144
|
import re
|
145
145
|
from copy import copy
|
146
146
|
|
147
|
+
from meerk40t.core.elements.element_types import op_nodes
|
147
148
|
from meerk40t.core.node.effect_hatch import HatchEffectNode
|
148
149
|
from meerk40t.core.node.op_cut import CutOpNode
|
149
150
|
from meerk40t.core.node.op_dots import DotsOpNode
|
@@ -153,8 +154,9 @@ from meerk40t.core.node.op_raster import RasterOpNode
|
|
153
154
|
from meerk40t.core.units import Angle, Length
|
154
155
|
from meerk40t.kernel import CommandSyntaxError
|
155
156
|
from meerk40t.svgelements import Color, Matrix
|
156
|
-
from meerk40t.core.elements.element_types import op_nodes
|
157
157
|
from meerk40t.tools.geomstr import NON_GEOMETRY_TYPES
|
158
|
+
|
159
|
+
|
158
160
|
def plugin(kernel, lifecycle=None):
|
159
161
|
_ = kernel.translation
|
160
162
|
if lifecycle == "postboot":
|
@@ -576,7 +578,6 @@ def init_commands(kernel):
|
|
576
578
|
self.signal("refresh_scene", "Scene")
|
577
579
|
return data_type, data
|
578
580
|
|
579
|
-
|
580
581
|
@self.console_command(
|
581
582
|
"empty",
|
582
583
|
help=_("Remove all elements from provided operations"),
|
@@ -1336,10 +1337,28 @@ def init_commands(kernel):
|
|
1336
1337
|
@self.console_command(
|
1337
1338
|
"copy",
|
1338
1339
|
help=_("Duplicate elements"),
|
1339
|
-
input_type=("elements", "ops"),
|
1340
|
+
input_type=("elements", "ops", None),
|
1340
1341
|
output_type=("elements", "ops"),
|
1341
1342
|
)
|
1342
|
-
def e_copy(
|
1343
|
+
def e_copy(
|
1344
|
+
data=None, data_type=None, post=None, dx=None, dy=None, copies=None, **kwargs
|
1345
|
+
):
|
1346
|
+
if data_type is None:
|
1347
|
+
if data is None:
|
1348
|
+
# Take tree selection for ops, scene selection for elements
|
1349
|
+
elemlist = list(self.elems(emphasized=True))
|
1350
|
+
if elemlist:
|
1351
|
+
data_type = "elements"
|
1352
|
+
data = list(self.elems(emphasized=True))
|
1353
|
+
else:
|
1354
|
+
data_type = "ops"
|
1355
|
+
data = list(self.ops(selected=True))
|
1356
|
+
else:
|
1357
|
+
# If data is given, we assume it is ops or elements
|
1358
|
+
if data[0].type.startswith("op ", "util "):
|
1359
|
+
data_type = "ops"
|
1360
|
+
else:
|
1361
|
+
data_type = "elements"
|
1343
1362
|
if data is None:
|
1344
1363
|
# Take tree selection for ops, scene selection for elements
|
1345
1364
|
if data_type == "ops":
|
@@ -1646,19 +1665,44 @@ def init_commands(kernel):
|
|
1646
1665
|
channel("----------")
|
1647
1666
|
return "elements", data
|
1648
1667
|
|
1649
|
-
@kernel.console_option(
|
1650
|
-
|
1668
|
+
@kernel.console_option(
|
1669
|
+
"stitchtolerance",
|
1670
|
+
"s",
|
1671
|
+
type=Length,
|
1672
|
+
help=_(
|
1673
|
+
"By default elements will be stitched together if they have common end/start points, this option allows to set a tolerance"
|
1674
|
+
),
|
1675
|
+
)
|
1676
|
+
@kernel.console_option(
|
1677
|
+
"nostitch",
|
1678
|
+
"n",
|
1679
|
+
type=bool,
|
1680
|
+
action="store_true",
|
1681
|
+
help=_(
|
1682
|
+
"By default elements will be stitched together if they have a common end/start point, this option prevents that and real subpaths will be created"
|
1683
|
+
),
|
1684
|
+
)
|
1651
1685
|
@self.console_command(
|
1652
1686
|
"merge",
|
1653
1687
|
help=_("merge elements"),
|
1654
1688
|
input_type="elements",
|
1655
1689
|
output_type="elements",
|
1656
1690
|
)
|
1657
|
-
def element_merge(
|
1691
|
+
def element_merge(
|
1692
|
+
command,
|
1693
|
+
channel,
|
1694
|
+
_,
|
1695
|
+
data=None,
|
1696
|
+
post=None,
|
1697
|
+
nostitch=None,
|
1698
|
+
stitchtolerance=None,
|
1699
|
+
**kwargs,
|
1700
|
+
):
|
1658
1701
|
"""
|
1659
1702
|
Merge combines the geometries of the inputs. This matters in some cases where fills are used. Such that two
|
1660
1703
|
nested circles forms a toroid rather two independent circles.
|
1661
1704
|
"""
|
1705
|
+
|
1662
1706
|
def set_nonset_attributes(node, e):
|
1663
1707
|
try:
|
1664
1708
|
if node.stroke is None:
|
@@ -1681,16 +1725,18 @@ def init_commands(kernel):
|
|
1681
1725
|
def segtype(info):
|
1682
1726
|
return int(info[2].real) & 0xFF
|
1683
1727
|
|
1684
|
-
if
|
1728
|
+
if (
|
1729
|
+
segtype(aseg) not in NON_GEOMETRY_TYPES
|
1730
|
+
and segtype(bseg) not in NON_GEOMETRY_TYPES
|
1731
|
+
):
|
1685
1732
|
s1, _dummy2, _dummy3, _dummy4, e1 = aseg
|
1686
1733
|
s2, _dummy2, _dummy3, _dummy4, e2 = bseg
|
1687
1734
|
c1 = s1 if starta else e1
|
1688
1735
|
c2 = s2 if startb else e2
|
1689
|
-
if abs(c1 - c2) <= tolerance +
|
1736
|
+
if abs(c1 - c2) <= tolerance + 1e-6:
|
1690
1737
|
return True
|
1691
1738
|
return False
|
1692
1739
|
|
1693
|
-
|
1694
1740
|
seg1_start = other.segments[0]
|
1695
1741
|
seg1_end = other.segments[other.index - 1]
|
1696
1742
|
seg2_start = path.segments[0]
|
@@ -1726,7 +1772,12 @@ def init_commands(kernel):
|
|
1726
1772
|
orientation = False
|
1727
1773
|
path_before = False
|
1728
1774
|
separate = False
|
1729
|
-
to_set_seg, to_set_idx, from_seg, from_idx =
|
1775
|
+
to_set_seg, to_set_idx, from_seg, from_idx = (
|
1776
|
+
path.index - 1,
|
1777
|
+
4,
|
1778
|
+
other.index - 1,
|
1779
|
+
4,
|
1780
|
+
)
|
1730
1781
|
else:
|
1731
1782
|
# ignore, path after other, proper orientation, disjoint
|
1732
1783
|
separate = True
|
@@ -1734,8 +1785,15 @@ def init_commands(kernel):
|
|
1734
1785
|
path_before = False
|
1735
1786
|
to_set_seg, to_set_idx, from_seg, from_idx = None, None, None, None
|
1736
1787
|
|
1737
|
-
return
|
1738
|
-
|
1788
|
+
return (
|
1789
|
+
separate,
|
1790
|
+
orientation,
|
1791
|
+
path_before,
|
1792
|
+
to_set_seg,
|
1793
|
+
to_set_idx,
|
1794
|
+
from_seg,
|
1795
|
+
from_idx,
|
1796
|
+
)
|
1739
1797
|
|
1740
1798
|
if nostitch is None:
|
1741
1799
|
nostitch = False
|
@@ -1779,16 +1837,26 @@ def init_commands(kernel):
|
|
1779
1837
|
else:
|
1780
1838
|
other = node.geometry
|
1781
1839
|
|
1782
|
-
|
1840
|
+
(
|
1841
|
+
separate,
|
1842
|
+
orientation,
|
1843
|
+
path_before,
|
1844
|
+
to_set_seg,
|
1845
|
+
to_set_idx,
|
1846
|
+
from_seg,
|
1847
|
+
from_idx,
|
1848
|
+
) = merge_paths(other, path, nostitch, tolerance)
|
1783
1849
|
if to_set_seg is not None:
|
1784
|
-
path.segments[to_set_seg, to_set_idx] = other.segments[
|
1785
|
-
|
1786
|
-
|
1850
|
+
path.segments[to_set_seg, to_set_idx] = other.segments[
|
1851
|
+
from_seg, from_idx
|
1852
|
+
]
|
1853
|
+
actionstr = "Insert" if path_before else "Append"
|
1854
|
+
typestr = "regular" if orientation else "reversed"
|
1787
1855
|
channel(f"{actionstr} a {typestr} path - separate: {separate}")
|
1788
1856
|
if not orientation:
|
1789
1857
|
path.reverse()
|
1790
1858
|
if path_before:
|
1791
|
-
node.geometry.insert(0, path.segments[:path.index])
|
1859
|
+
node.geometry.insert(0, path.segments[: path.index])
|
1792
1860
|
else:
|
1793
1861
|
node.geometry.append(path, end=separate)
|
1794
1862
|
|
@@ -1815,7 +1883,7 @@ def init_commands(kernel):
|
|
1815
1883
|
return
|
1816
1884
|
elements_nodes = []
|
1817
1885
|
elems = []
|
1818
|
-
groups= []
|
1886
|
+
groups = []
|
1819
1887
|
# _("Break elements")
|
1820
1888
|
with self.undoscope("Break elements"):
|
1821
1889
|
for node in data:
|
@@ -1825,7 +1893,9 @@ def init_commands(kernel):
|
|
1825
1893
|
if hasattr(node, attrib):
|
1826
1894
|
oldval = getattr(node, attrib, None)
|
1827
1895
|
node_attributes[attrib] = oldval
|
1828
|
-
group_node = node.replace_node(
|
1896
|
+
group_node = node.replace_node(
|
1897
|
+
type="group", label=node_label, expanded=True
|
1898
|
+
)
|
1829
1899
|
groups.append(group_node)
|
1830
1900
|
try:
|
1831
1901
|
if hasattr(node, "final_geometry"):
|
@@ -71,11 +71,11 @@ def plugin(kernel, lifecycle=None):
|
|
71
71
|
placements,
|
72
72
|
render,
|
73
73
|
shapes,
|
74
|
+
testcases,
|
74
75
|
trace,
|
75
76
|
tree_commands,
|
76
77
|
undo_redo,
|
77
78
|
wordlist,
|
78
|
-
testcases,
|
79
79
|
)
|
80
80
|
|
81
81
|
return [
|
@@ -218,9 +218,9 @@ def plugin(kernel, lifecycle=None):
|
|
218
218
|
"default": True,
|
219
219
|
"type": bool,
|
220
220
|
"label": _("Track changes and allow undo"),
|
221
|
-
"tip": _(
|
222
|
-
|
223
|
-
|
221
|
+
"tip": _("MK will save intermediate states to undo/redo changes")
|
222
|
+
+ "\n"
|
223
|
+
+ _("This may consume a significant amount of memory"),
|
224
224
|
"page": "Start",
|
225
225
|
"section": "_60_Undo",
|
226
226
|
"signals": "restart",
|
@@ -645,6 +645,7 @@ class Elemental(Service):
|
|
645
645
|
self.remembered_keyhole_nodes = []
|
646
646
|
self.setting(bool, "use_undo", True)
|
647
647
|
self.setting(int, "undo_levels", 20)
|
648
|
+
self.setting(bool, "filenode_selection", False)
|
648
649
|
undo_active = self.use_undo
|
649
650
|
undo_levels = self.undo_levels
|
650
651
|
self.undo = Undo(self, self._tree, active=undo_active, levels=undo_levels)
|
@@ -751,7 +752,7 @@ class Elemental(Service):
|
|
751
752
|
self.signal(source)
|
752
753
|
|
753
754
|
@contextlib.contextmanager
|
754
|
-
def static(self, source:str):
|
755
|
+
def static(self, source: str):
|
755
756
|
try:
|
756
757
|
self.stop_updates(source, False)
|
757
758
|
yield self
|
@@ -767,7 +768,7 @@ class Elemental(Service):
|
|
767
768
|
self.do_undo = True
|
768
769
|
|
769
770
|
@contextlib.contextmanager
|
770
|
-
def undoscope(self, message:str, static:bool = True):
|
771
|
+
def undoscope(self, message: str, static: bool = True):
|
771
772
|
busy = self.kernel.busyinfo
|
772
773
|
busy.start(msg=self.kernel.translation(message))
|
773
774
|
undo_active = self.do_undo
|
@@ -903,7 +904,10 @@ class Elemental(Service):
|
|
903
904
|
child = child.node
|
904
905
|
if getattr(child, "hidden", False):
|
905
906
|
continue
|
906
|
-
if
|
907
|
+
if (
|
908
|
+
hasattr(child, "affected_children")
|
909
|
+
and len(child.affected_children()) == 0
|
910
|
+
):
|
907
911
|
continue
|
908
912
|
canburn = True
|
909
913
|
break
|
@@ -1094,7 +1098,11 @@ class Elemental(Service):
|
|
1094
1098
|
for ref in list(n._references):
|
1095
1099
|
ref.remove_node()
|
1096
1100
|
op_assign.drop(n, modify=True)
|
1097
|
-
if
|
1101
|
+
if (
|
1102
|
+
impose == "to_elem"
|
1103
|
+
and target_color is not None
|
1104
|
+
and hasattr(n, attrib)
|
1105
|
+
):
|
1098
1106
|
setattr(n, attrib, target_color)
|
1099
1107
|
if set_fill_to_none and hasattr(n, "fill"):
|
1100
1108
|
n.fill = None
|
@@ -2316,10 +2324,11 @@ class Elemental(Service):
|
|
2316
2324
|
with self.undoscope("Drag and drop"):
|
2317
2325
|
for drag_node in data:
|
2318
2326
|
to_be_refreshed.extend(drag_node.flat())
|
2319
|
-
op_treatment = (
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2327
|
+
op_treatment = drop_node.type in op_parent_nodes and (
|
2328
|
+
not drag_node.has_ancestor("branch reg")
|
2329
|
+
or (
|
2330
|
+
drag_node.has_ancestor("branch reg")
|
2331
|
+
and self.allow_reg_to_op_dragging
|
2323
2332
|
)
|
2324
2333
|
)
|
2325
2334
|
if drop_node is drag_node:
|
@@ -2585,6 +2594,7 @@ class Elemental(Service):
|
|
2585
2594
|
keep_old_selection=False,
|
2586
2595
|
use_smallest=False,
|
2587
2596
|
exit_over_selection=False,
|
2597
|
+
force_filenodes_too=False,
|
2588
2598
|
):
|
2589
2599
|
def contains(box, x, y=None):
|
2590
2600
|
if y is None:
|
@@ -2607,6 +2617,8 @@ class Elemental(Service):
|
|
2607
2617
|
for node in self.elems(emphasized=True):
|
2608
2618
|
e_list.append(node)
|
2609
2619
|
for node in self.elems_nodes(emphasized=False):
|
2620
|
+
if not force_filenodes_too and node.type == "file":
|
2621
|
+
continue
|
2610
2622
|
try:
|
2611
2623
|
bounds = node.bounds
|
2612
2624
|
except AttributeError:
|
@@ -2614,9 +2626,8 @@ class Elemental(Service):
|
|
2614
2626
|
if hasattr(node, "hidden") and node.hidden:
|
2615
2627
|
continue
|
2616
2628
|
# Empty group / files may cause problems
|
2617
|
-
if node.type in ("
|
2618
|
-
|
2619
|
-
bounds = None
|
2629
|
+
if node.type in ("group", "file") and not node._children:
|
2630
|
+
bounds = None
|
2620
2631
|
if bounds is None:
|
2621
2632
|
continue
|
2622
2633
|
if contains(bounds, position):
|
@@ -2715,7 +2726,11 @@ class Elemental(Service):
|
|
2715
2726
|
def _get_next_auto_raster_count(operations):
|
2716
2727
|
auto_raster_count = 0
|
2717
2728
|
for op in operations:
|
2718
|
-
if
|
2729
|
+
if (
|
2730
|
+
op.type == "op raster"
|
2731
|
+
and op.id is not None
|
2732
|
+
and op.id.startswith("AR#")
|
2733
|
+
):
|
2719
2734
|
try:
|
2720
2735
|
used_id = int(op.id[3:])
|
2721
2736
|
auto_raster_count = max(auto_raster_count, used_id)
|
@@ -2750,7 +2765,6 @@ class Elemental(Service):
|
|
2750
2765
|
debug_set[opnode.type] = 0
|
2751
2766
|
debug_set[opnode.type] = debug_set[opnode.type] + 1
|
2752
2767
|
|
2753
|
-
|
2754
2768
|
if len(list(self.ops())) == 0 and not self.operation_default_empty:
|
2755
2769
|
has_cut = False
|
2756
2770
|
has_engrave = False
|
@@ -2796,7 +2810,7 @@ class Elemental(Service):
|
|
2796
2810
|
continue
|
2797
2811
|
classif_info = [False, False]
|
2798
2812
|
# Even for fuzzy we check first a direct hit
|
2799
|
-
fuzzy_param = (False, True) if fuzzy else (False,
|
2813
|
+
fuzzy_param = (False, True) if fuzzy else (False,)
|
2800
2814
|
do_stroke = True
|
2801
2815
|
do_fill = True
|
2802
2816
|
for tempfuzzy in fuzzy_param:
|
@@ -2854,24 +2868,27 @@ class Elemental(Service):
|
|
2854
2868
|
classified = False
|
2855
2869
|
classifying_op = None
|
2856
2870
|
if (
|
2857
|
-
self.classify_fill
|
2858
|
-
op.type=="op raster"
|
2859
|
-
hasattr(node, "fill")
|
2871
|
+
self.classify_fill
|
2872
|
+
and op.type == "op raster"
|
2873
|
+
and hasattr(node, "fill")
|
2874
|
+
and node.fill is not None
|
2860
2875
|
):
|
2861
2876
|
# This is a special use case:
|
2862
2877
|
# Usually we don't distinguish a fill color - all non-transparent objects
|
2863
2878
|
# are assigned to a single raster operation.
|
2864
2879
|
# If the classify_fill flag is set, then we will use the fill attribute
|
2865
2880
|
# to look for / create a matching raster operation
|
2866
|
-
raster_candidate = _select_raster_candidate(
|
2881
|
+
raster_candidate = _select_raster_candidate(
|
2882
|
+
operations, node, fuzzydistance
|
2883
|
+
)
|
2867
2884
|
if raster_candidate is None and self.classify_autogenerate:
|
2868
2885
|
# We need to create one...
|
2869
2886
|
auto_raster_count = _get_next_auto_raster_count(operations)
|
2870
2887
|
raster_candidate = RasterOpNode(
|
2871
|
-
id
|
2872
|
-
label
|
2873
|
-
color
|
2874
|
-
output
|
2888
|
+
id=f"AR#{auto_raster_count}",
|
2889
|
+
label=f"Auto-Raster #{auto_raster_count}",
|
2890
|
+
color=abs(node.fill),
|
2891
|
+
output=True,
|
2875
2892
|
)
|
2876
2893
|
add_op_function(raster_candidate)
|
2877
2894
|
new_operations_added = True
|
@@ -2972,14 +2989,16 @@ class Elemental(Service):
|
|
2972
2989
|
default_candidates = []
|
2973
2990
|
for op in operations:
|
2974
2991
|
if (
|
2975
|
-
hasattr(op, "classify")
|
2976
|
-
getattr(op, "default", False)
|
2977
|
-
hasattr(op, "valid_node_for_reference")
|
2978
|
-
op.valid_node_for_reference(node)
|
2992
|
+
hasattr(op, "classify")
|
2993
|
+
and getattr(op, "default", False)
|
2994
|
+
and hasattr(op, "valid_node_for_reference")
|
2995
|
+
and op.valid_node_for_reference(node)
|
2979
2996
|
):
|
2980
2997
|
default_candidates.append(op)
|
2981
2998
|
if len(default_candidates) > 1 and debug:
|
2982
|
-
debug(
|
2999
|
+
debug(
|
3000
|
+
f"For node {node_desc} there were {len(default_candidates)} default operations available, nb the very first will be taken!"
|
3001
|
+
)
|
2983
3002
|
for op in default_candidates:
|
2984
3003
|
classified, should_break, feedback = op.classify(
|
2985
3004
|
node,
|
@@ -3097,7 +3116,7 @@ class Elemental(Service):
|
|
3097
3116
|
and node.stroke is not None
|
3098
3117
|
and node.stroke.argb is not None
|
3099
3118
|
):
|
3100
|
-
fuzzy_param = (False, True) if fuzzy else (False,
|
3119
|
+
fuzzy_param = (False, True) if fuzzy else (False,)
|
3101
3120
|
was_classified = False
|
3102
3121
|
for tempfuzzy in fuzzy_param:
|
3103
3122
|
if debug:
|
@@ -3179,7 +3198,7 @@ class Elemental(Service):
|
|
3179
3198
|
"white"
|
3180
3199
|
) == abs(node.fill)
|
3181
3200
|
node_fill = Color("black") if is_black else abs(node.fill)
|
3182
|
-
fuzzy_param = (False, True) if fuzzy else (False,
|
3201
|
+
fuzzy_param = (False, True) if fuzzy else (False,)
|
3183
3202
|
was_classified = False
|
3184
3203
|
for tempfuzzy in fuzzy_param:
|
3185
3204
|
if debug:
|
@@ -3215,14 +3234,18 @@ class Elemental(Service):
|
|
3215
3234
|
and node.fill is not None
|
3216
3235
|
and node.fill.argb is not None
|
3217
3236
|
):
|
3218
|
-
default_color =
|
3237
|
+
default_color = (
|
3238
|
+
abs(node.fill) if self.classify_fill else Color("black")
|
3239
|
+
)
|
3219
3240
|
default_id = "AR#1" if self.classify_fill else "R1"
|
3220
|
-
default_label =
|
3241
|
+
default_label = (
|
3242
|
+
"Auto-Raster #1" if self.classify_fill else "Standard-Raster"
|
3243
|
+
)
|
3221
3244
|
op = RasterOpNode(
|
3222
3245
|
id=default_id,
|
3223
3246
|
label=default_label,
|
3224
3247
|
color=default_color,
|
3225
|
-
output
|
3248
|
+
output=True,
|
3226
3249
|
)
|
3227
3250
|
stdops.append(op)
|
3228
3251
|
if debug:
|
@@ -3291,7 +3314,6 @@ class Elemental(Service):
|
|
3291
3314
|
op.add_reference(node)
|
3292
3315
|
update_debug_set(debug_set, op)
|
3293
3316
|
|
3294
|
-
|
3295
3317
|
self.remove_unused_default_copies()
|
3296
3318
|
if debug:
|
3297
3319
|
debug("Summary:")
|
meerk40t/core/elements/trace.py
CHANGED
@@ -31,6 +31,7 @@ from meerk40t.core.units import Length
|
|
31
31
|
from meerk40t.svgelements import Circle, Path, Point, Polyline
|
32
32
|
from meerk40t.tools.geomstr import Geomstr
|
33
33
|
|
34
|
+
|
34
35
|
def plugin(kernel, lifecycle=None):
|
35
36
|
_ = kernel.translation
|
36
37
|
if lifecycle == "postboot":
|
@@ -317,6 +318,7 @@ def generate_hull_shape_hull(data):
|
|
317
318
|
pts.append(pts[0]) # loop
|
318
319
|
return pts
|
319
320
|
|
321
|
+
|
320
322
|
"""
|
321
323
|
There is no need for shape_complex any more as the regular hull routine already uses interpolation
|
322
324
|
def generate_hull_shape_complex(data, resolution=None):
|
@@ -356,6 +358,7 @@ def generate_hull_shape_complex(data, resolution=None):
|
|
356
358
|
return hull
|
357
359
|
"""
|
358
360
|
|
361
|
+
|
359
362
|
def generate_hull_shape_circle_data(data):
|
360
363
|
pts = []
|
361
364
|
for node in data:
|
@@ -476,9 +479,7 @@ def init_commands(kernel):
|
|
476
479
|
method = method.lower()
|
477
480
|
if method not in ("segment", "quick", "hull", "circle"):
|
478
481
|
channel(
|
479
|
-
_(
|
480
|
-
"Invalid method, please use one of quick, hull, segment, circle."
|
481
|
-
)
|
482
|
+
_("Invalid method, please use one of quick, hull, segment, circle.")
|
482
483
|
)
|
483
484
|
return
|
484
485
|
|
@@ -553,6 +554,9 @@ def init_commands(kernel):
|
|
553
554
|
# Wait for some seconds
|
554
555
|
yield "wait", 5000
|
555
556
|
|
557
|
+
if hasattr(_spooler.context, "pre_outline"):
|
558
|
+
yield from _spooler.context.pre_outline()
|
559
|
+
|
556
560
|
yield "wait_finish"
|
557
561
|
yield "rapid_mode"
|
558
562
|
idx = 0
|
@@ -563,6 +567,8 @@ def init_commands(kernel):
|
|
563
567
|
Length(amount=p[0]).length_mm,
|
564
568
|
Length(amount=p[1]).length_mm,
|
565
569
|
)
|
570
|
+
if hasattr(_spooler.context, "post_outline"):
|
571
|
+
yield from _spooler.context.post_outline()
|
566
572
|
|
567
573
|
_spooler.laserjob(
|
568
574
|
list(trace_hull(startmethod)), label=f"Trace Job: {method}", helper=True
|
@@ -598,9 +604,7 @@ def init_commands(kernel):
|
|
598
604
|
method = method.lower()
|
599
605
|
if not method in ("segment", "quick", "hull", "circle"):
|
600
606
|
channel(
|
601
|
-
_(
|
602
|
-
"Invalid method, please use one of quick, hull, segment, circle."
|
603
|
-
)
|
607
|
+
_("Invalid method, please use one of quick, hull, segment, circle.")
|
604
608
|
)
|
605
609
|
return
|
606
610
|
|
meerk40t/core/node/node.py
CHANGED
@@ -1282,6 +1282,8 @@ class Node:
|
|
1282
1282
|
if keep_children is None:
|
1283
1283
|
keep_children = False
|
1284
1284
|
parent = self._parent
|
1285
|
+
if parent is None:
|
1286
|
+
raise ValueError(f"Cannot replace {self.type}-node without parent.")
|
1285
1287
|
index = parent._children.index(self)
|
1286
1288
|
parent._children.remove(self)
|
1287
1289
|
self.notify_detached(self)
|
meerk40t/core/plotplanner.py
CHANGED
@@ -47,7 +47,7 @@ class PlotPlanner(Parameters):
|
|
47
47
|
ppi=True,
|
48
48
|
shift=True,
|
49
49
|
group=True,
|
50
|
-
require_uniform_movement
|
50
|
+
require_uniform_movement=True,
|
51
51
|
**kwargs,
|
52
52
|
):
|
53
53
|
super().__init__(settings, **kwargs)
|
@@ -69,17 +69,21 @@ class PlotPlanner(Parameters):
|
|
69
69
|
|
70
70
|
if single:
|
71
71
|
self.single = Single(self)
|
72
|
-
if ppi:
|
73
|
-
self.ppi = PPI(self)
|
74
72
|
if shift:
|
75
73
|
self.shift = Shift(self)
|
76
74
|
if group:
|
77
75
|
self.group = Group(self)
|
76
|
+
self.set_ppi(ppi)
|
78
77
|
|
79
78
|
self.pos_x = None
|
80
79
|
self.pos_y = None
|
81
80
|
self.settings_then_jog = False
|
82
81
|
|
82
|
+
def set_ppi(self, ppi):
|
83
|
+
self.ppi = None
|
84
|
+
if ppi:
|
85
|
+
self.ppi = PPI(self)
|
86
|
+
|
83
87
|
def push(self, plot):
|
84
88
|
self.abort = False
|
85
89
|
self.queue.append(plot)
|
@@ -653,4 +657,3 @@ def grouped(plot):
|
|
653
657
|
group_y = y
|
654
658
|
# There are no more plots.
|
655
659
|
yield group_x, group_y
|
656
|
-
|