meerk40t 0.9.2000__py2.py3-none-any.whl → 0.9.3001__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/balor_params.py +1 -43
- meerk40t/balormk/controller.py +1 -41
- meerk40t/balormk/device.py +16 -22
- meerk40t/balormk/driver.py +4 -4
- meerk40t/balormk/gui/balorconfig.py +2 -2
- meerk40t/balormk/gui/balorcontroller.py +13 -5
- meerk40t/balormk/gui/baloroperationproperties.py +0 -46
- meerk40t/balormk/gui/gui.py +17 -17
- meerk40t/camera/gui/camerapanel.py +18 -11
- meerk40t/core/cutcode/rastercut.py +3 -1
- meerk40t/core/cutplan.py +145 -14
- meerk40t/core/elements/clipboard.py +18 -9
- meerk40t/core/elements/element_treeops.py +320 -180
- meerk40t/core/elements/element_types.py +7 -2
- meerk40t/core/elements/elements.py +53 -27
- meerk40t/core/elements/geometry.py +8 -0
- meerk40t/core/elements/offset_clpr.py +129 -4
- meerk40t/core/elements/offset_mk.py +3 -1
- meerk40t/core/elements/shapes.py +28 -25
- meerk40t/core/laserjob.py +7 -0
- meerk40t/core/node/bootstrap.py +4 -0
- meerk40t/core/node/effect_hatch.py +85 -96
- meerk40t/core/node/effect_wobble.py +309 -0
- meerk40t/core/node/elem_image.py +49 -19
- meerk40t/core/node/elem_line.py +60 -0
- meerk40t/core/node/elem_rect.py +5 -3
- meerk40t/core/node/image_processed.py +766 -0
- meerk40t/core/node/image_raster.py +113 -0
- meerk40t/core/node/node.py +120 -1
- meerk40t/core/node/op_cut.py +2 -8
- meerk40t/core/node/op_dots.py +0 -8
- meerk40t/core/node/op_engrave.py +2 -18
- meerk40t/core/node/op_image.py +22 -35
- meerk40t/core/node/op_raster.py +0 -9
- meerk40t/core/planner.py +32 -2
- meerk40t/core/svg_io.py +699 -461
- meerk40t/core/treeop.py +191 -0
- meerk40t/core/undos.py +15 -1
- meerk40t/core/units.py +14 -4
- meerk40t/device/dummydevice.py +3 -2
- meerk40t/device/gui/defaultactions.py +43 -55
- meerk40t/device/gui/formatterpanel.py +58 -49
- meerk40t/device/gui/warningpanel.py +12 -12
- meerk40t/device/mixins.py +13 -0
- meerk40t/dxf/dxf_io.py +9 -5
- meerk40t/extra/ezd.py +28 -26
- meerk40t/extra/imageactions.py +300 -308
- meerk40t/extra/lbrn.py +19 -2
- meerk40t/fill/fills.py +6 -6
- meerk40t/fill/patternfill.py +1061 -1061
- meerk40t/fill/patterns.py +2 -6
- meerk40t/grbl/controller.py +168 -52
- meerk40t/grbl/device.py +23 -18
- meerk40t/grbl/driver.py +39 -0
- meerk40t/grbl/emulator.py +79 -19
- meerk40t/grbl/gcodejob.py +10 -0
- meerk40t/grbl/gui/grblconfiguration.py +2 -2
- meerk40t/grbl/gui/grblcontroller.py +24 -8
- meerk40t/grbl/gui/grblhardwareconfig.py +153 -0
- meerk40t/grbl/gui/gui.py +17 -14
- meerk40t/grbl/mock_connection.py +15 -34
- meerk40t/grbl/plugin.py +0 -4
- meerk40t/grbl/serial_connection.py +2 -1
- meerk40t/gui/about.py +8 -5
- meerk40t/gui/alignment.py +10 -6
- meerk40t/gui/basicops.py +27 -17
- meerk40t/gui/bufferview.py +2 -2
- meerk40t/gui/choicepropertypanel.py +101 -13
- meerk40t/gui/consolepanel.py +12 -9
- meerk40t/gui/devicepanel.py +38 -25
- meerk40t/gui/executejob.py +6 -4
- meerk40t/gui/help_assets/help_assets.py +13 -10
- meerk40t/gui/hersheymanager.py +8 -6
- meerk40t/gui/icons.py +1951 -3065
- meerk40t/gui/imagesplitter.py +14 -7
- meerk40t/gui/keymap.py +3 -3
- meerk40t/gui/laserpanel.py +151 -84
- meerk40t/gui/laserrender.py +61 -70
- meerk40t/gui/lasertoolpanel.py +8 -7
- meerk40t/gui/materialtest.py +3 -3
- meerk40t/gui/mkdebug.py +254 -1
- meerk40t/gui/navigationpanels.py +321 -180
- meerk40t/gui/notes.py +3 -3
- meerk40t/gui/opassignment.py +12 -12
- meerk40t/gui/operation_info.py +13 -13
- meerk40t/gui/plugin.py +5 -0
- meerk40t/gui/position.py +20 -18
- meerk40t/gui/preferences.py +21 -6
- meerk40t/gui/propertypanels/attributes.py +70 -22
- meerk40t/gui/propertypanels/blobproperty.py +2 -2
- meerk40t/gui/propertypanels/consoleproperty.py +2 -2
- meerk40t/gui/propertypanels/groupproperties.py +3 -3
- meerk40t/gui/propertypanels/hatchproperty.py +11 -18
- meerk40t/gui/propertypanels/imageproperty.py +4 -3
- meerk40t/gui/propertypanels/opbranchproperties.py +1 -1
- meerk40t/gui/propertypanels/pathproperty.py +2 -2
- meerk40t/gui/propertypanels/pointproperty.py +2 -2
- meerk40t/gui/propertypanels/propertywindow.py +4 -4
- meerk40t/gui/propertypanels/textproperty.py +3 -3
- meerk40t/gui/propertypanels/wobbleproperty.py +204 -0
- meerk40t/gui/ribbon.py +367 -259
- meerk40t/gui/scene/scene.py +31 -5
- meerk40t/gui/scenewidgets/elementswidget.py +12 -4
- meerk40t/gui/scenewidgets/gridwidget.py +2 -2
- meerk40t/gui/scenewidgets/laserpathwidget.py +7 -2
- meerk40t/gui/scenewidgets/machineoriginwidget.py +6 -2
- meerk40t/gui/scenewidgets/relocatewidget.py +1 -1
- meerk40t/gui/scenewidgets/reticlewidget.py +9 -0
- meerk40t/gui/scenewidgets/selectionwidget.py +12 -7
- meerk40t/gui/simpleui.py +95 -8
- meerk40t/gui/simulation.py +44 -36
- meerk40t/gui/spoolerpanel.py +124 -26
- meerk40t/gui/statusbarwidgets/defaultoperations.py +18 -6
- meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
- meerk40t/gui/statusbarwidgets/opassignwidget.py +12 -12
- meerk40t/gui/statusbarwidgets/shapepropwidget.py +45 -18
- meerk40t/gui/statusbarwidgets/statusbar.py +11 -4
- meerk40t/gui/themes.py +78 -0
- meerk40t/gui/toolwidgets/toolcircle.py +2 -1
- meerk40t/gui/toolwidgets/toolellipse.py +2 -1
- meerk40t/gui/toolwidgets/toolimagecut.py +132 -0
- meerk40t/gui/toolwidgets/toolline.py +144 -0
- meerk40t/gui/toolwidgets/toolnodeedit.py +72 -145
- meerk40t/gui/toolwidgets/toolpoint.py +1 -1
- meerk40t/gui/toolwidgets/toolpolygon.py +8 -55
- meerk40t/gui/toolwidgets/toolrect.py +2 -1
- meerk40t/gui/usbconnect.py +2 -2
- meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +2 -2
- meerk40t/gui/utilitywidgets/harmonograph.py +7 -7
- meerk40t/gui/utilitywidgets/scalewidget.py +1 -1
- meerk40t/gui/wordlisteditor.py +33 -18
- meerk40t/gui/wxmeerk40t.py +166 -66
- meerk40t/gui/wxmmain.py +236 -157
- meerk40t/gui/wxmribbon.py +49 -25
- meerk40t/gui/wxmscene.py +49 -38
- meerk40t/gui/wxmtree.py +216 -85
- meerk40t/gui/wxutils.py +62 -4
- meerk40t/image/imagetools.py +443 -15
- meerk40t/internal_plugins.py +2 -10
- meerk40t/kernel/kernel.py +12 -4
- meerk40t/lihuiyu/controller.py +7 -7
- meerk40t/lihuiyu/device.py +3 -1
- meerk40t/lihuiyu/driver.py +3 -0
- meerk40t/lihuiyu/gui/gui.py +8 -8
- meerk40t/lihuiyu/gui/lhyaccelgui.py +2 -2
- meerk40t/lihuiyu/gui/lhycontrollergui.py +73 -27
- meerk40t/lihuiyu/gui/lhydrivergui.py +2 -2
- meerk40t/lihuiyu/gui/tcpcontroller.py +22 -9
- meerk40t/main.py +6 -1
- meerk40t/moshi/controller.py +5 -5
- meerk40t/moshi/device.py +5 -2
- meerk40t/moshi/driver.py +4 -0
- meerk40t/moshi/gui/gui.py +8 -8
- meerk40t/moshi/gui/moshicontrollergui.py +24 -8
- meerk40t/moshi/gui/moshidrivergui.py +2 -2
- meerk40t/newly/controller.py +2 -0
- meerk40t/newly/device.py +9 -2
- meerk40t/newly/driver.py +4 -0
- meerk40t/newly/gui/gui.py +16 -17
- meerk40t/newly/gui/newlyconfig.py +2 -2
- meerk40t/newly/gui/newlycontroller.py +13 -5
- meerk40t/rotary/gui/gui.py +2 -2
- meerk40t/rotary/gui/rotarysettings.py +2 -2
- meerk40t/ruida/device.py +3 -0
- meerk40t/ruida/driver.py +4 -0
- meerk40t/ruida/gui/gui.py +6 -6
- meerk40t/ruida/gui/ruidaconfig.py +2 -2
- meerk40t/ruida/gui/ruidacontroller.py +13 -5
- meerk40t/svgelements.py +9 -9
- meerk40t/tools/geomstr.py +849 -153
- meerk40t/tools/kerftest.py +8 -4
- meerk40t/tools/livinghinges.py +15 -8
- {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/METADATA +21 -16
- {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/RECORD +185 -177
- {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/entry_points.txt +0 -1
- test/test_core_elements.py +8 -24
- test/test_file_svg.py +88 -0
- test/test_fill.py +9 -9
- test/test_geomstr.py +258 -8
- test/test_kernel.py +4 -0
- test/test_tools_rasterplotter.py +29 -0
- meerk40t/extra/embroider.py +0 -56
- meerk40t/extra/pathoptimize.py +0 -249
- {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.2000.dist-info → meerk40t-0.9.3001.dist-info}/zip-safe +0 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
from copy import copy
|
2
|
+
|
3
|
+
from meerk40t.core.node.node import Node
|
4
|
+
from meerk40t.svgelements import Matrix
|
5
|
+
|
6
|
+
|
7
|
+
class ImageRasterNode(Node):
|
8
|
+
"""
|
9
|
+
ImageRasterNode is a basic image type. Its information is backed by a raster.
|
10
|
+
"""
|
11
|
+
|
12
|
+
def __init__(self, **kwargs):
|
13
|
+
self.image = None
|
14
|
+
self.matrix = None
|
15
|
+
super().__init__(type="image raster", **kwargs)
|
16
|
+
self.__formatter = "{element_type} {id} {width}x{height}"
|
17
|
+
if self.matrix is None:
|
18
|
+
self.matrix = Matrix()
|
19
|
+
self._can_rotate = False
|
20
|
+
self._can_skew = False
|
21
|
+
|
22
|
+
def __copy__(self):
|
23
|
+
nd = self.node_dict
|
24
|
+
nd["matrix"] = copy(self.matrix)
|
25
|
+
nd["image"] = copy(self.image)
|
26
|
+
return ImageRasterNode(**nd)
|
27
|
+
|
28
|
+
def __repr__(self):
|
29
|
+
return f"{self.__class__.__name__}('{self.type}', {str(self.image)}, {str(self._parent)})"
|
30
|
+
|
31
|
+
def as_image(self):
|
32
|
+
return self.image, self.bbox()
|
33
|
+
|
34
|
+
def preprocess(self, context, matrix, plan):
|
35
|
+
"""
|
36
|
+
Preprocess step during the cut planning stages.
|
37
|
+
|
38
|
+
We require a context to calculate the correct step values relative to the device
|
39
|
+
"""
|
40
|
+
self.matrix *= matrix
|
41
|
+
self.set_dirty_bounds()
|
42
|
+
|
43
|
+
def bbox(self, transformed=True, with_stroke=False):
|
44
|
+
image_width, image_height = self.image.size
|
45
|
+
matrix = self.matrix
|
46
|
+
x0, y0 = matrix.point_in_matrix_space((0, 0))
|
47
|
+
x1, y1 = matrix.point_in_matrix_space((image_width, image_height))
|
48
|
+
x2, y2 = matrix.point_in_matrix_space((0, image_height))
|
49
|
+
x3, y3 = matrix.point_in_matrix_space((image_width, 0))
|
50
|
+
return (
|
51
|
+
min(x0, x1, x2, x3),
|
52
|
+
min(y0, y1, y2, y3),
|
53
|
+
max(x0, x1, x2, x3),
|
54
|
+
max(y0, y1, y2, y3),
|
55
|
+
)
|
56
|
+
|
57
|
+
def default_map(self, default_map=None):
|
58
|
+
default_map = super().default_map(default_map=default_map)
|
59
|
+
default_map.update(self.__dict__)
|
60
|
+
image = self.image
|
61
|
+
default_map["width"] = image.width
|
62
|
+
default_map["height"] = image.height
|
63
|
+
default_map["element_type"] = "Image"
|
64
|
+
return default_map
|
65
|
+
|
66
|
+
def drop(self, drag_node, modify=True):
|
67
|
+
# Dragging element into element.
|
68
|
+
if drag_node.type.startswith("elem"):
|
69
|
+
if modify:
|
70
|
+
self.insert_sibling(drag_node)
|
71
|
+
return True
|
72
|
+
elif drag_node.type.startswith("op"):
|
73
|
+
# If we drag an operation to this node,
|
74
|
+
# then we will reverse the game
|
75
|
+
return drag_node.drop(self, modify=modify)
|
76
|
+
return False
|
77
|
+
|
78
|
+
def revalidate_points(self):
|
79
|
+
bounds = self.bounds
|
80
|
+
if bounds is None:
|
81
|
+
return
|
82
|
+
if len(self._points) < 9:
|
83
|
+
self._points.extend([None] * (9 - len(self._points)))
|
84
|
+
self._points[0] = [bounds[0], bounds[1], "bounds top_left"]
|
85
|
+
self._points[1] = [bounds[2], bounds[1], "bounds top_right"]
|
86
|
+
self._points[2] = [bounds[0], bounds[3], "bounds bottom_left"]
|
87
|
+
self._points[3] = [bounds[2], bounds[3], "bounds bottom_right"]
|
88
|
+
cx = (bounds[0] + bounds[2]) / 2
|
89
|
+
cy = (bounds[1] + bounds[3]) / 2
|
90
|
+
self._points[4] = [cx, cy, "bounds center_center"]
|
91
|
+
self._points[5] = [cx, bounds[1], "bounds top_center"]
|
92
|
+
self._points[6] = [cx, bounds[3], "bounds bottom_center"]
|
93
|
+
self._points[7] = [bounds[0], cy, "bounds center_left"]
|
94
|
+
self._points[8] = [bounds[2], cy, "bounds center_right"]
|
95
|
+
|
96
|
+
def update_point(self, index, point):
|
97
|
+
return False
|
98
|
+
|
99
|
+
def add_point(self, point, index=None):
|
100
|
+
return False
|
101
|
+
|
102
|
+
@property
|
103
|
+
def opaque_image(self):
|
104
|
+
from PIL import Image
|
105
|
+
|
106
|
+
img = self.image
|
107
|
+
if img is not None:
|
108
|
+
if img.mode == "RGBA":
|
109
|
+
r, g, b, a = img.split()
|
110
|
+
background = Image.new("RGB", img.size, "white")
|
111
|
+
background.paste(img, mask=a)
|
112
|
+
img = background
|
113
|
+
return img
|
meerk40t/core/node/node.py
CHANGED
@@ -512,6 +512,38 @@ class Node:
|
|
512
512
|
def valid_node_for_reference(self, node):
|
513
513
|
return True
|
514
514
|
|
515
|
+
def copy_children_as_references(self, obj):
|
516
|
+
"""
|
517
|
+
Copy the children of the given object as direct references to those children.
|
518
|
+
@param obj:
|
519
|
+
@return:
|
520
|
+
"""
|
521
|
+
for element in obj.children:
|
522
|
+
self.add_reference(element)
|
523
|
+
|
524
|
+
def copy_with_reified_tree(self):
|
525
|
+
"""
|
526
|
+
Make a copy of the current node, and a copy of the sub-nodes dereferencing any reference nodes
|
527
|
+
@return:
|
528
|
+
"""
|
529
|
+
copy_c = copy(self)
|
530
|
+
copy_c.copy_children_as_real(self)
|
531
|
+
return copy_c
|
532
|
+
|
533
|
+
def copy_children_as_real(self, copy_node):
|
534
|
+
"""
|
535
|
+
Copy the children of copy_node to the current node, dereferencing any reference nodes.
|
536
|
+
@param copy_node:
|
537
|
+
@return:
|
538
|
+
"""
|
539
|
+
for child in copy_node.children:
|
540
|
+
child = child
|
541
|
+
if child.type == "reference":
|
542
|
+
child = child.node
|
543
|
+
copy_child = copy(child)
|
544
|
+
self.add_node(copy_child)
|
545
|
+
copy_child.copy_children_as_real(child)
|
546
|
+
|
515
547
|
def is_draggable(self):
|
516
548
|
return True
|
517
549
|
|
@@ -912,7 +944,7 @@ class Node:
|
|
912
944
|
if node._parent is not None:
|
913
945
|
raise ValueError("Cannot reparent node on add.")
|
914
946
|
node._parent = self
|
915
|
-
node.
|
947
|
+
node.set_root(self._root)
|
916
948
|
if pos is None:
|
917
949
|
self._children.append(node)
|
918
950
|
else:
|
@@ -957,6 +989,17 @@ class Node:
|
|
957
989
|
print(f"Did not produce a valid node for type '{type}'")
|
958
990
|
return node
|
959
991
|
|
992
|
+
def set_root(self, root):
|
993
|
+
"""
|
994
|
+
Set the root for this and all descendant to the provided root
|
995
|
+
|
996
|
+
@param root:
|
997
|
+
@return:
|
998
|
+
"""
|
999
|
+
self._root = root
|
1000
|
+
for c in self._children:
|
1001
|
+
c.set_root(root)
|
1002
|
+
|
960
1003
|
def _flatten(self, node):
|
961
1004
|
"""
|
962
1005
|
Yield this node and all descendants in a flat generation.
|
@@ -1097,6 +1140,63 @@ class Node:
|
|
1097
1140
|
self.unregister()
|
1098
1141
|
return node
|
1099
1142
|
|
1143
|
+
def swap_node(self, node):
|
1144
|
+
"""
|
1145
|
+
Swap nodes swaps the current node with the provided node in the other position in the same tree. All children
|
1146
|
+
during a swap are kept in place structurally. This permits swapping nodes between two positions that may be
|
1147
|
+
nested, without creating a loop.
|
1148
|
+
|
1149
|
+
Special care is taken for both swaps being children of the same parent.
|
1150
|
+
|
1151
|
+
@param node: Node already in the tree that should be swapped with the current node.
|
1152
|
+
@return:
|
1153
|
+
"""
|
1154
|
+
# Remove self from tree.
|
1155
|
+
parent = self._parent
|
1156
|
+
n_parent = node._parent
|
1157
|
+
|
1158
|
+
index = parent._children.index(self)
|
1159
|
+
n_index = n_parent._children.index(node)
|
1160
|
+
|
1161
|
+
if index < n_index:
|
1162
|
+
# N_index is greater.
|
1163
|
+
del n_parent._children[n_index]
|
1164
|
+
del parent._children[index]
|
1165
|
+
|
1166
|
+
parent._children.insert(index, node)
|
1167
|
+
n_parent._children.insert(n_index, self)
|
1168
|
+
else:
|
1169
|
+
# N_index is lesser, equal
|
1170
|
+
del parent._children[index]
|
1171
|
+
del n_parent._children[n_index]
|
1172
|
+
|
1173
|
+
n_parent._children.insert(n_index, self)
|
1174
|
+
parent._children.insert(index, node)
|
1175
|
+
|
1176
|
+
node._parent = parent
|
1177
|
+
self._parent = n_parent
|
1178
|
+
|
1179
|
+
# Make a copy of children
|
1180
|
+
n_children = list(node._children)
|
1181
|
+
children = list(self._children)
|
1182
|
+
|
1183
|
+
# Delete children.
|
1184
|
+
node._children.clear()
|
1185
|
+
self._children.clear()
|
1186
|
+
|
1187
|
+
# Move children without call attach / detach.
|
1188
|
+
node._children.extend(children)
|
1189
|
+
self._children.extend(n_children)
|
1190
|
+
|
1191
|
+
# Correct parent for all children.
|
1192
|
+
for n in list(n_children):
|
1193
|
+
n._parent = self
|
1194
|
+
for n in list(children):
|
1195
|
+
n._parent = node
|
1196
|
+
|
1197
|
+
# self._root._validate_tree()
|
1198
|
+
self._root.notify_reorder()
|
1199
|
+
|
1100
1200
|
def remove_node(self, children=True, references=True, fast=False, destroy=True):
|
1101
1201
|
"""
|
1102
1202
|
Remove the current node from the tree.
|
@@ -1132,6 +1232,25 @@ class Node:
|
|
1132
1232
|
child.remove_all_children(fast=fast, destroy=destroy)
|
1133
1233
|
child.remove_node(fast=fast, destroy=destroy)
|
1134
1234
|
|
1235
|
+
def has_ancestor(self, type):
|
1236
|
+
"""
|
1237
|
+
Return whether this node has an ancestor node that matches the given type, or matches the major type.
|
1238
|
+
|
1239
|
+
@param type:
|
1240
|
+
@return:
|
1241
|
+
"""
|
1242
|
+
if self.parent is None:
|
1243
|
+
return False
|
1244
|
+
|
1245
|
+
if self.parent.type == type:
|
1246
|
+
return True
|
1247
|
+
|
1248
|
+
if " " not in type:
|
1249
|
+
if self.parent.type.startswith(type):
|
1250
|
+
return True
|
1251
|
+
|
1252
|
+
return self.parent.has_ancestor(type=type)
|
1253
|
+
|
1135
1254
|
def get(self, type=None):
|
1136
1255
|
"""
|
1137
1256
|
Recursive call for get to find first sub-nodes with the given type.
|
meerk40t/core/node/op_cut.py
CHANGED
@@ -35,6 +35,7 @@ class CutOpNode(Node, Parameters):
|
|
35
35
|
"elem rect",
|
36
36
|
"elem line",
|
37
37
|
"effect hatch",
|
38
|
+
"effect wobble",
|
38
39
|
)
|
39
40
|
# Which elements do we consider for automatic classification?
|
40
41
|
self._allowed_elements = (
|
@@ -44,6 +45,7 @@ class CutOpNode(Node, Parameters):
|
|
44
45
|
"elem rect",
|
45
46
|
"elem line",
|
46
47
|
"effect hatch",
|
48
|
+
"effect wobble",
|
47
49
|
)
|
48
50
|
# To which attributes responds the classification color check
|
49
51
|
self.allowed_attributes = [
|
@@ -235,14 +237,6 @@ class CutOpNode(Node, Parameters):
|
|
235
237
|
settings.write_persistent(section, "hex_color", self.color.hexa)
|
236
238
|
settings.write_persistent_dict(section, self.settings)
|
237
239
|
|
238
|
-
def copy_children(self, obj):
|
239
|
-
for element in obj.children:
|
240
|
-
self.add_reference(element)
|
241
|
-
|
242
|
-
def copy_children_as_real(self, copy_node):
|
243
|
-
for node in copy_node.children:
|
244
|
-
self.add_node(copy(node.node))
|
245
|
-
|
246
240
|
def time_estimate(self):
|
247
241
|
estimate = 0
|
248
242
|
for node in self.children:
|
meerk40t/core/node/op_dots.py
CHANGED
@@ -198,14 +198,6 @@ class DotsOpNode(Node, Parameters):
|
|
198
198
|
settings.write_persistent(section, "hex_color", self.color.hexa)
|
199
199
|
settings.write_persistent_dict(section, self.settings)
|
200
200
|
|
201
|
-
def copy_children(self, obj):
|
202
|
-
for element in obj.children:
|
203
|
-
self.add_reference(element)
|
204
|
-
|
205
|
-
def copy_children_as_real(self, copy_node):
|
206
|
-
for node in copy_node.children:
|
207
|
-
self.add_node(copy(node.node))
|
208
|
-
|
209
201
|
def time_estimate(self):
|
210
202
|
estimate = 0
|
211
203
|
for e in self.children:
|
meerk40t/core/node/op_engrave.py
CHANGED
@@ -34,6 +34,7 @@ class EngraveOpNode(Node, Parameters):
|
|
34
34
|
"elem rect",
|
35
35
|
"elem line",
|
36
36
|
"effect hatch",
|
37
|
+
"effect wobble",
|
37
38
|
)
|
38
39
|
# Which elements do we consider for automatic classification?
|
39
40
|
self._allowed_elements = (
|
@@ -43,6 +44,7 @@ class EngraveOpNode(Node, Parameters):
|
|
43
44
|
"elem rect",
|
44
45
|
"elem line",
|
45
46
|
"effect hatch",
|
47
|
+
"effect wobble",
|
46
48
|
)
|
47
49
|
|
48
50
|
# To which attributes does the classification color check respond
|
@@ -224,24 +226,6 @@ class EngraveOpNode(Node, Parameters):
|
|
224
226
|
settings.write_persistent(section, "hex_color", self.color.hexa)
|
225
227
|
settings.write_persistent_dict(section, self.settings)
|
226
228
|
|
227
|
-
def copy_children(self, obj):
|
228
|
-
for element in obj.children:
|
229
|
-
self.add_reference(element)
|
230
|
-
|
231
|
-
def copy_children_as_real(self, copy_node):
|
232
|
-
context = self
|
233
|
-
for node in copy_node.children:
|
234
|
-
if node.type.startswith("effect"):
|
235
|
-
n = copy(node)
|
236
|
-
context.add_node(n)
|
237
|
-
context = n
|
238
|
-
for node in copy_node.children:
|
239
|
-
if node.type == "reference":
|
240
|
-
context.add_node(copy(node.node))
|
241
|
-
for node in self.children:
|
242
|
-
if node.type.startswith("effect"):
|
243
|
-
node.effect = True
|
244
|
-
|
245
229
|
def time_estimate(self):
|
246
230
|
estimate = 0
|
247
231
|
for node in self.children:
|
meerk40t/core/node/op_image.py
CHANGED
@@ -21,11 +21,6 @@ class ImageOpNode(Node, Parameters):
|
|
21
21
|
settings = dict(settings)
|
22
22
|
Parameters.__init__(self, settings, **kwargs)
|
23
23
|
|
24
|
-
# Which elements can be added to an operation (manually via DND)?
|
25
|
-
self._allowed_elements_dnd = ("elem image",)
|
26
|
-
# Which elements do we consider for automatic classification?
|
27
|
-
self._allowed_elements = ("elem image",)
|
28
|
-
|
29
24
|
# Is this op out of useful bounds?
|
30
25
|
self.dangerous = False
|
31
26
|
self.stopop = True
|
@@ -90,34 +85,32 @@ class ImageOpNode(Node, Parameters):
|
|
90
85
|
|
91
86
|
def drop(self, drag_node, modify=True):
|
92
87
|
# Default routine for drag + drop for an op node - irrelevant for others...
|
93
|
-
if drag_node
|
94
|
-
if
|
95
|
-
|
96
|
-
or drag_node._parent.type == "branch reg"
|
97
|
-
):
|
88
|
+
if hasattr(drag_node, "as_image"):
|
89
|
+
if drag_node._parent.type == "branch reg":
|
90
|
+
# We do not accept reg nodes.
|
98
91
|
return False
|
99
92
|
# Dragging element onto operation adds that element to the op.
|
100
93
|
if modify:
|
101
94
|
self.add_reference(drag_node, pos=0)
|
102
95
|
return True
|
103
|
-
|
96
|
+
if drag_node.type == "reference":
|
104
97
|
# Disallow drop of image refelems onto a Dot op.
|
105
|
-
if not drag_node.node
|
98
|
+
if not hasattr(drag_node.node, "as_image"):
|
106
99
|
return False
|
107
100
|
# Move a refelem to end of op.
|
108
101
|
if modify:
|
109
102
|
self.append_child(drag_node)
|
110
103
|
return True
|
111
|
-
|
104
|
+
if drag_node.type in op_nodes:
|
112
105
|
# Move operation to a different position.
|
113
106
|
if modify:
|
114
107
|
self.insert_sibling(drag_node)
|
115
108
|
return True
|
116
|
-
|
109
|
+
if drag_node.type in ("file", "group"):
|
117
110
|
some_nodes = False
|
118
111
|
for e in drag_node.flat(elem_nodes):
|
119
112
|
# Add element to operation
|
120
|
-
if e
|
113
|
+
if hasattr(e, "as_image"):
|
121
114
|
if modify:
|
122
115
|
self.add_reference(e)
|
123
116
|
some_nodes = True
|
@@ -125,14 +118,14 @@ class ImageOpNode(Node, Parameters):
|
|
125
118
|
return False
|
126
119
|
|
127
120
|
def valid_node_for_reference(self, node):
|
128
|
-
if node
|
121
|
+
if hasattr(node, "as_image"):
|
129
122
|
return True
|
130
123
|
else:
|
131
124
|
return False
|
132
125
|
|
133
126
|
def classify(self, node, fuzzy=False, fuzzydistance=100, usedefault=False):
|
134
127
|
feedback = []
|
135
|
-
if node
|
128
|
+
if hasattr(node, "as_image"):
|
136
129
|
self.add_reference(node)
|
137
130
|
# Have classified and no more classification are needed
|
138
131
|
feedback.append("stroke")
|
@@ -159,14 +152,6 @@ class ImageOpNode(Node, Parameters):
|
|
159
152
|
settings.write_persistent(section, "hex_color", self.color.hexa)
|
160
153
|
settings.write_persistent_dict(section, self.settings)
|
161
154
|
|
162
|
-
def copy_children(self, obj):
|
163
|
-
for element in obj.children:
|
164
|
-
self.add_reference(element)
|
165
|
-
|
166
|
-
def copy_children_as_real(self, copy_node):
|
167
|
-
for node in copy_node.children:
|
168
|
-
self.add_node(copy(node.node))
|
169
|
-
|
170
155
|
def time_estimate(self):
|
171
156
|
"""
|
172
157
|
The scanlines would equal "(e.height * 1000) / dpi" but our images are pre-actualized.
|
@@ -267,7 +252,7 @@ class ImageOpNode(Node, Parameters):
|
|
267
252
|
for image_node in self.children:
|
268
253
|
# Process each child. All settings are different for each child.
|
269
254
|
|
270
|
-
if image_node
|
255
|
+
if not hasattr(image_node, "as_image"):
|
271
256
|
continue
|
272
257
|
settings = self.derive()
|
273
258
|
|
@@ -277,7 +262,7 @@ class ImageOpNode(Node, Parameters):
|
|
277
262
|
overscan = float(Length(overscan))
|
278
263
|
|
279
264
|
# Set variables by direction
|
280
|
-
if image_node.direction is not None:
|
265
|
+
if hasattr(image_node, "direction") and image_node.direction is not None:
|
281
266
|
direction = image_node.direction
|
282
267
|
else:
|
283
268
|
direction = self.raster_direction
|
@@ -298,9 +283,17 @@ class ImageOpNode(Node, Parameters):
|
|
298
283
|
start_on_left = True
|
299
284
|
bidirectional = self.bidirectional
|
300
285
|
|
286
|
+
# Set variables
|
287
|
+
pil_image, bounds = image_node.as_image()
|
288
|
+
offset_x = bounds[0]
|
289
|
+
offset_y = bounds[1]
|
290
|
+
|
301
291
|
# Get steps from individual images
|
302
|
-
|
303
|
-
|
292
|
+
image_width, image_height = pil_image.size
|
293
|
+
expected_width = bounds[2] - bounds[0]
|
294
|
+
expected_height = bounds[3] - bounds[1]
|
295
|
+
step_x = expected_width / image_width
|
296
|
+
step_y = expected_height / image_height
|
304
297
|
|
305
298
|
if horizontal:
|
306
299
|
# Raster step is only along y for horizontal raster
|
@@ -311,12 +304,6 @@ class ImageOpNode(Node, Parameters):
|
|
311
304
|
settings["raster_step_x"] = step_x
|
312
305
|
settings["raster_step_y"] = 0
|
313
306
|
|
314
|
-
# Set variables
|
315
|
-
matrix = image_node.active_matrix
|
316
|
-
pil_image = image_node.active_image
|
317
|
-
offset_x = matrix.value_trans_x()
|
318
|
-
offset_y = matrix.value_trans_y()
|
319
|
-
|
320
307
|
# Establish path
|
321
308
|
min_x = offset_x
|
322
309
|
min_y = offset_y
|
meerk40t/core/node/op_raster.py
CHANGED
@@ -40,7 +40,6 @@ class RasterOpNode(Node, Parameters):
|
|
40
40
|
"elem rect",
|
41
41
|
"elem line",
|
42
42
|
"elem text",
|
43
|
-
# "elem image",
|
44
43
|
)
|
45
44
|
|
46
45
|
# self.allowed_attributes.append("fill")
|
@@ -276,14 +275,6 @@ class RasterOpNode(Node, Parameters):
|
|
276
275
|
settings.write_persistent(section, "hex_color", self.color.hexa)
|
277
276
|
settings.write_persistent_dict(section, self.settings)
|
278
277
|
|
279
|
-
def copy_children(self, obj):
|
280
|
-
for element in obj.children:
|
281
|
-
self.add_reference(element)
|
282
|
-
|
283
|
-
def copy_children_as_real(self, copy_node):
|
284
|
-
for node in copy_node.children:
|
285
|
-
self.add_node(copy(node.node))
|
286
|
-
|
287
278
|
def time_estimate(self):
|
288
279
|
estimate = 0
|
289
280
|
dpi = self.dpi
|
meerk40t/core/planner.py
CHANGED
@@ -45,6 +45,36 @@ def plugin(kernel, lifecycle=None):
|
|
45
45
|
kernel.register_choices("planner", choices)
|
46
46
|
|
47
47
|
choices = [
|
48
|
+
{
|
49
|
+
"attr": "opt_raster_optimisation",
|
50
|
+
"object": context,
|
51
|
+
"default": True,
|
52
|
+
"type": bool,
|
53
|
+
"label": _("Cluster raster objects"),
|
54
|
+
"tip": _(
|
55
|
+
"Separate non-overlapping raster objects.\n"
|
56
|
+
"Active: this will raster close (ie overlapping) objects as one,\n"
|
57
|
+
"but will separately process objects lying apart from each other.\n"
|
58
|
+
"Inactive: all objects will be lasered as one single unit."
|
59
|
+
),
|
60
|
+
"page": "Optimisations",
|
61
|
+
"section": "_20_Reducing Movements",
|
62
|
+
"subsection": "Splitting rasters",
|
63
|
+
},
|
64
|
+
{
|
65
|
+
"attr": "opt_raster_opt_margin",
|
66
|
+
"object": context,
|
67
|
+
"default": "1mm",
|
68
|
+
"type": Length,
|
69
|
+
"label": _("Margin:"),
|
70
|
+
"tip": _(
|
71
|
+
"Allowed gap between rasterable objects, to still be counted as one."
|
72
|
+
),
|
73
|
+
"page": "Optimisations",
|
74
|
+
"section": "_20_Reducing Movements",
|
75
|
+
"subsection": "Splitting rasters",
|
76
|
+
"conditional": (context, "opt_raster_optimisation"),
|
77
|
+
},
|
48
78
|
{
|
49
79
|
"attr": "opt_reduce_travel",
|
50
80
|
"object": context,
|
@@ -190,7 +220,7 @@ def plugin(kernel, lifecycle=None):
|
|
190
220
|
"type": bool,
|
191
221
|
"label": _("Group Inner Burns"),
|
192
222
|
"tip": _(
|
193
|
-
"Try to complete a set of inner burns and the associated outer cut before moving onto other elements
|
223
|
+
"Try to complete a set of inner burns and the associated outer cut before moving onto other elements.\n"
|
194
224
|
+ "This option only does something if Burn Inner First is also selected. "
|
195
225
|
+ "If your design has multiple separate pieces on it, "
|
196
226
|
+ "this should mostly cause each piece to be burned in entirety "
|
@@ -227,7 +257,6 @@ def plugin(kernel, lifecycle=None):
|
|
227
257
|
},
|
228
258
|
]
|
229
259
|
kernel.register_choices("optimize", choices)
|
230
|
-
|
231
260
|
context.setting(bool, "opt_2opt", False)
|
232
261
|
context.setting(bool, "opt_nearest_neighbor", True)
|
233
262
|
context.setting(bool, "opt_reduce_directions", False)
|
@@ -259,6 +288,7 @@ class Planner(Service):
|
|
259
288
|
Service.__init__(self, kernel, "planner")
|
260
289
|
self._plan = dict()
|
261
290
|
self._default_plan = "0"
|
291
|
+
self.do_optimization = True
|
262
292
|
|
263
293
|
def length(self, v):
|
264
294
|
return float(Length(v))
|