meerk40t 0.9.7010__py2.py3-none-any.whl → 0.9.7030__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meerk40t/balormk/galvo_commands.py +1 -2
- meerk40t/core/cutcode/cutcode.py +1 -1
- meerk40t/core/cutplan.py +70 -2
- meerk40t/core/elements/branches.py +18 -4
- meerk40t/core/elements/element_treeops.py +43 -7
- meerk40t/core/elements/elements.py +49 -63
- meerk40t/core/elements/grid.py +8 -1
- meerk40t/core/elements/offset_clpr.py +4 -3
- meerk40t/core/elements/offset_mk.py +2 -1
- meerk40t/core/elements/shapes.py +379 -260
- meerk40t/core/elements/testcases.py +105 -0
- meerk40t/core/node/node.py +6 -3
- meerk40t/core/node/op_cut.py +9 -8
- meerk40t/core/node/op_dots.py +8 -8
- meerk40t/core/node/op_engrave.py +7 -7
- meerk40t/core/node/op_raster.py +8 -8
- 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/encode_detect.py +8 -2
- meerk40t/extra/hershey.py +2 -3
- meerk40t/extra/inkscape.py +3 -5
- meerk40t/extra/mk_potrace.py +1959 -0
- meerk40t/extra/outerworld.py +2 -3
- meerk40t/extra/param_functions.py +2 -2
- meerk40t/extra/potrace.py +14 -10
- meerk40t/grbl/device.py +4 -1
- meerk40t/grbl/gui/grblcontroller.py +2 -2
- meerk40t/grbl/interpreter.py +1 -1
- meerk40t/gui/about.py +3 -5
- meerk40t/gui/basicops.py +3 -3
- meerk40t/gui/busy.py +75 -13
- meerk40t/gui/choicepropertypanel.py +365 -379
- meerk40t/gui/consolepanel.py +3 -3
- meerk40t/gui/gui_mixins.py +4 -1
- meerk40t/gui/hersheymanager.py +13 -3
- meerk40t/gui/laserpanel.py +12 -7
- meerk40t/gui/materialmanager.py +33 -6
- meerk40t/gui/plugin.py +9 -3
- meerk40t/gui/propertypanels/operationpropertymain.py +1 -1
- meerk40t/gui/ribbon.py +4 -1
- meerk40t/gui/scene/widget.py +1 -1
- meerk40t/gui/scenewidgets/rectselectwidget.py +19 -16
- meerk40t/gui/scenewidgets/selectionwidget.py +26 -20
- meerk40t/gui/simpleui.py +13 -8
- meerk40t/gui/simulation.py +22 -2
- meerk40t/gui/spoolerpanel.py +8 -11
- meerk40t/gui/themes.py +7 -1
- meerk40t/gui/tips.py +2 -3
- meerk40t/gui/toolwidgets/toolmeasure.py +4 -1
- meerk40t/gui/wxmeerk40t.py +32 -3
- meerk40t/gui/wxmmain.py +72 -6
- meerk40t/gui/wxmscene.py +95 -6
- meerk40t/gui/wxmtree.py +17 -11
- meerk40t/gui/wxutils.py +1 -1
- meerk40t/image/imagetools.py +21 -6
- meerk40t/kernel/kernel.py +31 -6
- meerk40t/kernel/settings.py +2 -0
- meerk40t/lihuiyu/device.py +9 -3
- meerk40t/main.py +22 -5
- meerk40t/network/console_server.py +52 -14
- meerk40t/network/web_server.py +15 -1
- meerk40t/ruida/device.py +5 -1
- 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/tools/polybool.py +2 -1
- meerk40t/tools/shxparser.py +92 -34
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/RECORD +77 -75
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7030.dist-info}/zip-safe +0 -0
@@ -1153,7 +1153,6 @@ def plugin(service, lifecycle):
|
|
1153
1153
|
import platform
|
1154
1154
|
|
1155
1155
|
from meerk40t.balormk.clone_loader import load_sys
|
1156
|
-
from meerk40t.kernel import get_safe_path
|
1157
1156
|
|
1158
1157
|
kernel = service.kernel
|
1159
1158
|
|
@@ -1173,7 +1172,7 @@ def plugin(service, lifecycle):
|
|
1173
1172
|
return
|
1174
1173
|
|
1175
1174
|
# Check for file in the meerk40t directory (safe_path)
|
1176
|
-
directory =
|
1175
|
+
directory = kernel.os_information["WORKDIR"]
|
1177
1176
|
p = os.path.join(directory, service.clone_sys)
|
1178
1177
|
if os.path.exists(p):
|
1179
1178
|
load_sys(p, channel=channel)
|
meerk40t/core/cutcode/cutcode.py
CHANGED
@@ -132,7 +132,7 @@ class CutCode(CutGroup):
|
|
132
132
|
length_of_previous_travel = Point.distance(prev.end, current.start)
|
133
133
|
total_distance_travel += length_of_previous_travel
|
134
134
|
rapid_speed = self._native_speed(cutcode)
|
135
|
-
if rapid_speed is not None:
|
135
|
+
if rapid_speed is not None and rapid_speed != 0:
|
136
136
|
total_duration_travel = total_distance_travel / rapid_speed
|
137
137
|
duration_of_this_travel = length_of_previous_travel / rapid_speed
|
138
138
|
|
meerk40t/core/cutplan.py
CHANGED
@@ -23,7 +23,7 @@ from functools import lru_cache
|
|
23
23
|
import numpy as np
|
24
24
|
|
25
25
|
from ..svgelements import Group, Matrix, Path, Polygon
|
26
|
-
from ..tools.geomstr import Geomstr
|
26
|
+
from ..tools.geomstr import Geomstr, stitch_geometries
|
27
27
|
from ..tools.pathtools import VectorMontonizer
|
28
28
|
from .cutcode.cutcode import CutCode
|
29
29
|
from .cutcode.cutgroup import CutGroup
|
@@ -32,7 +32,6 @@ from .cutcode.rastercut import RasterCut
|
|
32
32
|
from .node.node import Node
|
33
33
|
from .node.util_console import ConsoleOperation
|
34
34
|
from .units import Length, UNITS_PER_MM
|
35
|
-
|
36
35
|
"""
|
37
36
|
The time to compile does outweigh the benefit...
|
38
37
|
try:
|
@@ -187,6 +186,7 @@ class CutPlan:
|
|
187
186
|
placements.append(scene_to_device_matrix)
|
188
187
|
|
189
188
|
original_ops = copy(self.plan)
|
189
|
+
|
190
190
|
if self.context.opt_raster_optimisation and self.context.do_optimization:
|
191
191
|
try:
|
192
192
|
margin = float(Length(self.context.opt_raster_opt_margin, "0"))
|
@@ -244,6 +244,74 @@ class CutPlan:
|
|
244
244
|
op_type = getattr(op, "type", "")
|
245
245
|
if op_type.startswith("place "):
|
246
246
|
continue
|
247
|
+
if op_type == "op cut" and self.context.opt_stitching and self.context.do_optimization:
|
248
|
+
# This isn't a lossless operation: dotted/dashed lines will be treated as solid lines
|
249
|
+
try:
|
250
|
+
stitch_tolerance = float(Length(self.context.opt_stitch_tolerance))
|
251
|
+
except ValueError:
|
252
|
+
stitch_tolerance = 0
|
253
|
+
default_stroke = None
|
254
|
+
default_strokewidth = None
|
255
|
+
|
256
|
+
def stitcheable_nodes(data, tolerance) -> list:
|
257
|
+
out = []
|
258
|
+
geoms = []
|
259
|
+
# Store all geometries together with an indicator, to which node they belong
|
260
|
+
for idx, node in enumerate(data):
|
261
|
+
if not hasattr(node, "as_geometry"):
|
262
|
+
continue
|
263
|
+
for g1 in node.as_geometry().as_contiguous():
|
264
|
+
geoms.append((idx, g1))
|
265
|
+
for idx1, (nodeidx1, g1) in enumerate(geoms):
|
266
|
+
for idx2 in range(idx1 + 1, len(geoms)):
|
267
|
+
nodeidx2 = geoms[idx2][0]
|
268
|
+
g2 = geoms[idx2][1]
|
269
|
+
fp1 = g1.first_point
|
270
|
+
fp2 = g2.first_point
|
271
|
+
lp1 = g1.last_point
|
272
|
+
lp2 = g2.last_point
|
273
|
+
if (
|
274
|
+
abs(lp1 - lp2) <= tolerance or
|
275
|
+
abs(lp1 - fp2) <= tolerance or
|
276
|
+
abs(fp1 - fp2) <= tolerance or
|
277
|
+
abs(fp1 - lp2) <= tolerance
|
278
|
+
):
|
279
|
+
if nodeidx1 not in out:
|
280
|
+
out.append(nodeidx1)
|
281
|
+
if nodeidx2 not in out:
|
282
|
+
out.append(nodeidx2)
|
283
|
+
|
284
|
+
return [data[idx] for idx in out]
|
285
|
+
|
286
|
+
geoms = []
|
287
|
+
to_be_deleted = []
|
288
|
+
data = stitcheable_nodes(list(op.flat()), stitch_tolerance)
|
289
|
+
for node in data:
|
290
|
+
if node is op:
|
291
|
+
continue
|
292
|
+
if hasattr(node, "as_geometry"):
|
293
|
+
geom : Geomstr = node.as_geometry()
|
294
|
+
geoms.extend(iter(geom.as_contiguous()))
|
295
|
+
if default_stroke is None and hasattr(node, "stroke"):
|
296
|
+
default_stroke = node.stroke
|
297
|
+
if default_strokewidth is None and hasattr(node, "stroke_width"):
|
298
|
+
default_strokewidth = node.stroke_width
|
299
|
+
to_be_deleted.append(node)
|
300
|
+
result = stitch_geometries(geoms, stitch_tolerance)
|
301
|
+
if result is not None:
|
302
|
+
# print (f"Paths at start of action: {len(list(op.flat()))}")
|
303
|
+
for node in to_be_deleted:
|
304
|
+
node.remove_node()
|
305
|
+
for idx, g in enumerate(result):
|
306
|
+
node = op.add(
|
307
|
+
label=f"Stitch # {idx + 1}",
|
308
|
+
stroke=default_stroke,
|
309
|
+
stroke_width=default_strokewidth,
|
310
|
+
geometry=g,
|
311
|
+
type="elem path",
|
312
|
+
)
|
313
|
+
# print (f"Paths at start of action: {len(list(op.flat()))}")
|
314
|
+
|
247
315
|
self.plan.append(op)
|
248
316
|
if (op_type.startswith("op") or op_type.startswith("util")) and hasattr(op, "preprocess"):
|
249
317
|
op.preprocess(self.context, placement, self)
|
@@ -187,7 +187,7 @@ def init_commands(kernel):
|
|
187
187
|
return
|
188
188
|
try:
|
189
189
|
channel(_("loading..."))
|
190
|
-
result = self.load(new_file)
|
190
|
+
result = self.load(new_file, svg_ppi=self.svg_ppi)
|
191
191
|
if result:
|
192
192
|
channel(_("Done."))
|
193
193
|
except AttributeError:
|
@@ -1410,6 +1410,20 @@ def init_commands(kernel):
|
|
1410
1410
|
self.remove_operations(data)
|
1411
1411
|
self.signal("update_group_labels")
|
1412
1412
|
|
1413
|
+
@self.console_command(
|
1414
|
+
"clear_all", help=_("Clear all content"), input_type=("elements", "ops")
|
1415
|
+
)
|
1416
|
+
def e_clear(command, channel, _, data=None, data_type=None, **kwargs):
|
1417
|
+
channel(_("Deleting…"))
|
1418
|
+
fast = True
|
1419
|
+
with self.undoscope("Deleting"):
|
1420
|
+
if data_type == "elements":
|
1421
|
+
self.clear_elements(fast=fast)
|
1422
|
+
self.emphasized()
|
1423
|
+
else:
|
1424
|
+
self.clear_operations(fast=fast)
|
1425
|
+
self.signal("rebuild_tree", "all")
|
1426
|
+
|
1413
1427
|
# ==========
|
1414
1428
|
# ELEMENT BASE
|
1415
1429
|
# ==========
|
@@ -1490,7 +1504,7 @@ def init_commands(kernel):
|
|
1490
1504
|
else:
|
1491
1505
|
target = self.reg_branch
|
1492
1506
|
scope = "Elements -> Regmarks"
|
1493
|
-
|
1507
|
+
|
1494
1508
|
with self.undoscope(scope):
|
1495
1509
|
if data is None:
|
1496
1510
|
data = list()
|
@@ -1826,8 +1840,8 @@ def init_commands(kernel):
|
|
1826
1840
|
subpath.ensure_proper_subpaths()
|
1827
1841
|
idx += 1
|
1828
1842
|
subnode = group_node.add(
|
1829
|
-
geometry=subpath,
|
1830
|
-
type="elem path",
|
1843
|
+
geometry=subpath,
|
1844
|
+
type="elem path",
|
1831
1845
|
label=f"{node_label}-{idx}",
|
1832
1846
|
stroke=node_attributes.get("stroke", None),
|
1833
1847
|
fill=node_attributes.get("fill", None),
|
@@ -2866,13 +2866,15 @@ def init_tree(kernel):
|
|
2866
2866
|
dots_per_units = node.dpi / UNITS_PER_INCH
|
2867
2867
|
new_width = width * dots_per_units
|
2868
2868
|
new_height = height * dots_per_units
|
2869
|
-
|
2870
|
-
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
|
2875
|
-
|
2869
|
+
try:
|
2870
|
+
image = make_raster(
|
2871
|
+
data,
|
2872
|
+
bounds=bounds,
|
2873
|
+
width=new_width,
|
2874
|
+
height=new_height,
|
2875
|
+
)
|
2876
|
+
except Exception:
|
2877
|
+
return None, None
|
2876
2878
|
matrix = Matrix.scale(width / new_width, height / new_height)
|
2877
2879
|
matrix.post_translate(bounds[0], bounds[1])
|
2878
2880
|
return image, matrix
|
@@ -3570,6 +3572,40 @@ def init_tree(kernel):
|
|
3570
3572
|
with self.undoscope("Outline"):
|
3571
3573
|
self(f"outline {offset}mm\n")
|
3572
3574
|
self.signal("refresh_tree")
|
3575
|
+
|
3576
|
+
@tree_conditional(
|
3577
|
+
lambda node: not is_regmark(node)
|
3578
|
+
and hasattr(node, "as_geometry")
|
3579
|
+
)
|
3580
|
+
@tree_submenu(_("Offset shapes..."))
|
3581
|
+
@tree_iterate("offset", 1, 5)
|
3582
|
+
@tree_operation(
|
3583
|
+
_("...to outside with {offset}mm distance"),
|
3584
|
+
node_type=elem_nodes,
|
3585
|
+
help=_("Create an outer offset around the selected elements"),
|
3586
|
+
grouping="50_ELEM_MODIFY_ZMISC"
|
3587
|
+
)
|
3588
|
+
def make_positive_offsets(node, offset=1, **kwargs):
|
3589
|
+
with self.undoscope("Offset"):
|
3590
|
+
self(f"offset {offset}mm\n")
|
3591
|
+
self.signal("refresh_tree")
|
3592
|
+
|
3593
|
+
@tree_conditional(
|
3594
|
+
lambda node: not is_regmark(node)
|
3595
|
+
and hasattr(node, "as_geometry")
|
3596
|
+
)
|
3597
|
+
@tree_submenu(_("Offset shapes..."))
|
3598
|
+
@tree_iterate("offset", 1, 5)
|
3599
|
+
@tree_operation(
|
3600
|
+
_("...to inside with {offset}mm distance"),
|
3601
|
+
node_type=elem_nodes,
|
3602
|
+
help=_("Create an inner offset around the selected elements"),
|
3603
|
+
grouping="50_ELEM_MODIFY_ZMISC"
|
3604
|
+
)
|
3605
|
+
def make_negative_offsets(node, offset=1, **kwargs):
|
3606
|
+
with self.undoscope("Offset"):
|
3607
|
+
self(f"offset -{offset}mm\n")
|
3608
|
+
self.signal("refresh_tree")
|
3573
3609
|
|
3574
3610
|
def mergeable(node):
|
3575
3611
|
elems = list(self.elems(emphasized=True))
|
@@ -75,6 +75,7 @@ def plugin(kernel, lifecycle=None):
|
|
75
75
|
tree_commands,
|
76
76
|
undo_redo,
|
77
77
|
wordlist,
|
78
|
+
testcases,
|
78
79
|
)
|
79
80
|
|
80
81
|
return [
|
@@ -96,6 +97,7 @@ def plugin(kernel, lifecycle=None):
|
|
96
97
|
placements.plugin,
|
97
98
|
offset_mk.plugin,
|
98
99
|
offset_clpr.plugin,
|
100
|
+
testcases.plugin,
|
99
101
|
]
|
100
102
|
elif lifecycle == "preregister":
|
101
103
|
kernel.register(
|
@@ -2699,6 +2701,13 @@ class Elemental(Service):
|
|
2699
2701
|
if elements is None:
|
2700
2702
|
return
|
2701
2703
|
new_operations_added = False
|
2704
|
+
debug_set = {}
|
2705
|
+
|
2706
|
+
def update_debug_set(debug_set, opnode):
|
2707
|
+
if opnode.type not in debug_set:
|
2708
|
+
debug_set[opnode.type] = 0
|
2709
|
+
debug_set[opnode.type] = debug_set[opnode.type] + 1
|
2710
|
+
|
2702
2711
|
|
2703
2712
|
if len(list(self.ops())) == 0 and not self.operation_default_empty:
|
2704
2713
|
has_cut = False
|
@@ -2732,6 +2741,13 @@ class Elemental(Service):
|
|
2732
2741
|
add_op_function = self.add_classify_op
|
2733
2742
|
for node in elements:
|
2734
2743
|
node_desc = f"[{node.type}]{'' if node.id is None else node.id + '-'}{'<none>' if node.label is None else node.display_label()}"
|
2744
|
+
if hasattr(node, "stroke") or hasattr(node, "fill"):
|
2745
|
+
info = ""
|
2746
|
+
if hasattr(node, "stroke") and node.stroke is not None:
|
2747
|
+
info += f"S:{node.stroke},"
|
2748
|
+
if hasattr(node, "fill") and node.fill is not None:
|
2749
|
+
info += f"F:{node.fill},"
|
2750
|
+
node_desc += f"({info})"
|
2735
2751
|
# Following lines added to handle 0.7 special ops added to ops list
|
2736
2752
|
if hasattr(node, "operation"):
|
2737
2753
|
add_op_function(node)
|
@@ -2758,7 +2774,7 @@ class Elemental(Service):
|
|
2758
2774
|
if not do_fill and op.type in ("op raster", "op image"):
|
2759
2775
|
continue
|
2760
2776
|
is_black = False
|
2761
|
-
|
2777
|
+
perform_classification = True
|
2762
2778
|
if (
|
2763
2779
|
hasattr(node, "stroke")
|
2764
2780
|
and node.stroke is not None
|
@@ -2780,18 +2796,18 @@ class Elemental(Service):
|
|
2780
2796
|
and is_black
|
2781
2797
|
and isinstance(op, RasterOpNode)
|
2782
2798
|
):
|
2783
|
-
|
2799
|
+
perform_classification = False
|
2784
2800
|
elif (
|
2785
2801
|
self.classify_black_as_raster
|
2786
2802
|
and is_black
|
2787
2803
|
and isinstance(op, EngraveOpNode)
|
2788
2804
|
):
|
2789
|
-
|
2805
|
+
perform_classification = False
|
2790
2806
|
if debug:
|
2791
2807
|
debug(
|
2792
|
-
f"For {op.type}.{op.id}: black={is_black}, perform={
|
2808
|
+
f"For {op.type}.{op.id}: black={is_black}, perform={perform_classification}, flag={self.classify_black_as_raster}"
|
2793
2809
|
)
|
2794
|
-
if hasattr(op, "classify") and
|
2810
|
+
if hasattr(op, "classify") and perform_classification:
|
2795
2811
|
classified, should_break, feedback = op.classify(
|
2796
2812
|
node,
|
2797
2813
|
fuzzy=tempfuzzy,
|
@@ -2801,6 +2817,7 @@ class Elemental(Service):
|
|
2801
2817
|
else:
|
2802
2818
|
continue
|
2803
2819
|
if classified:
|
2820
|
+
update_debug_set(debug_set, op)
|
2804
2821
|
if feedback is not None and "stroke" in feedback:
|
2805
2822
|
classif_info[0] = True
|
2806
2823
|
if feedback is not None and "fill" in feedback:
|
@@ -2869,78 +2886,41 @@ class Elemental(Service):
|
|
2869
2886
|
# let's iterate through the default ops and add them
|
2870
2887
|
if debug:
|
2871
2888
|
debug("Pass 2 (wasn't classified), looking for default ops")
|
2889
|
+
default_candidates = []
|
2872
2890
|
for op in operations:
|
2873
|
-
if classif_info[0] and op.type in (
|
2874
|
-
"op engrave",
|
2875
|
-
"op cut",
|
2876
|
-
"op dots",
|
2877
|
-
):
|
2878
|
-
continue
|
2879
|
-
if classif_info[1] and op.type in ("op raster", "op image"):
|
2880
|
-
continue
|
2881
|
-
is_black = False
|
2882
|
-
whisperer = True
|
2883
2891
|
if (
|
2884
|
-
hasattr(
|
2885
|
-
|
2886
|
-
|
2887
|
-
|
2888
|
-
):
|
2889
|
-
if fuzzy:
|
2890
|
-
is_black = (
|
2891
|
-
Color.distance("black", abs(node.stroke))
|
2892
|
-
<= fuzzydistance
|
2893
|
-
or Color.distance("white", abs(node.stroke))
|
2894
|
-
<= fuzzydistance
|
2895
|
-
)
|
2896
|
-
else:
|
2897
|
-
is_black = Color("black") == abs(node.stroke) or Color(
|
2898
|
-
"white"
|
2899
|
-
) == abs(node.stroke)
|
2900
|
-
if (
|
2901
|
-
not self.classify_black_as_raster
|
2902
|
-
and is_black
|
2903
|
-
and isinstance(op, RasterOpNode)
|
2892
|
+
hasattr(op, "classify") and
|
2893
|
+
getattr(op, "default", False) and
|
2894
|
+
hasattr(op, "valid_node_for_reference") and
|
2895
|
+
op.valid_node_for_reference(node)
|
2904
2896
|
):
|
2905
|
-
|
2906
|
-
|
2907
|
-
|
2908
|
-
|
2909
|
-
|
2910
|
-
|
2911
|
-
|
2912
|
-
|
2913
|
-
|
2914
|
-
|
2915
|
-
f"For {op.type}.{op.id}: black={is_black}, perform={whisperer}, flag={self.classify_black_as_raster}"
|
2916
|
-
)
|
2917
|
-
if hasattr(op, "classify") and whisperer:
|
2918
|
-
classified, should_break, feedback = op.classify(
|
2919
|
-
node,
|
2920
|
-
fuzzy=fuzzy,
|
2921
|
-
fuzzydistance=fuzzydistance,
|
2922
|
-
usedefault=True,
|
2923
|
-
)
|
2924
|
-
else:
|
2925
|
-
continue
|
2897
|
+
default_candidates.append(op)
|
2898
|
+
if len(default_candidates) > 1 and debug:
|
2899
|
+
debug(f"For node {node_desc} there were {len(default_candidates)} default operations available, nb the very first will be taken!")
|
2900
|
+
for op in default_candidates:
|
2901
|
+
classified, should_break, feedback = op.classify(
|
2902
|
+
node,
|
2903
|
+
fuzzy=fuzzy,
|
2904
|
+
fuzzydistance=fuzzydistance,
|
2905
|
+
usedefault=True,
|
2906
|
+
)
|
2926
2907
|
if classified:
|
2927
|
-
|
2928
|
-
|
2929
|
-
|
2930
|
-
|
2908
|
+
update_debug_set(debug_set, op)
|
2909
|
+
# Default ops fulfill stuff by definition
|
2910
|
+
classif_info[0] = True
|
2911
|
+
classif_info[1] = True
|
2931
2912
|
was_classified = True
|
2932
2913
|
if debug:
|
2933
2914
|
debug(
|
2934
|
-
f"Was classified to default operation: {type(op).__name__}
|
2915
|
+
f"Was classified to default operation: {type(op).__name__}"
|
2935
2916
|
)
|
2936
|
-
if should_break:
|
2937
2917
|
break
|
2938
2918
|
# Let's make sure we only consider relevant, i.e. existing attributes...
|
2939
2919
|
if hasattr(node, "stroke"):
|
2940
2920
|
if node.stroke is None or node.stroke.argb is None:
|
2941
2921
|
classif_info[0] = True
|
2942
2922
|
if node.type == "elem text":
|
2943
|
-
# even if it has, we are not going to something with it
|
2923
|
+
# even if it has, we are not going to do something with it
|
2944
2924
|
classif_info[0] = True
|
2945
2925
|
else:
|
2946
2926
|
classif_info[0] = True
|
@@ -3218,8 +3198,14 @@ class Elemental(Service):
|
|
3218
3198
|
|
3219
3199
|
if not existing:
|
3220
3200
|
op.add_reference(node)
|
3201
|
+
update_debug_set(debug_set, op)
|
3202
|
+
|
3221
3203
|
|
3222
3204
|
self.remove_unused_default_copies()
|
3205
|
+
if debug:
|
3206
|
+
debug("Summary:")
|
3207
|
+
for key, count in debug_set.items():
|
3208
|
+
debug(f"{count} items assigned to {key}")
|
3223
3209
|
if new_operations_added:
|
3224
3210
|
self.signal("tree_changed")
|
3225
3211
|
|
meerk40t/core/elements/grid.py
CHANGED
@@ -198,7 +198,14 @@ def init_commands(kernel):
|
|
198
198
|
y_distance += height
|
199
199
|
if origin is None:
|
200
200
|
origin = (1, 1)
|
201
|
-
|
201
|
+
if isinstance(origin, (tuple, list)) and isinstance(origin[0], (tuple, list)):
|
202
|
+
origin = origin[0]
|
203
|
+
try:
|
204
|
+
cx, cy = origin
|
205
|
+
except ValueError:
|
206
|
+
cx = 1
|
207
|
+
cy = 1
|
208
|
+
|
202
209
|
data_out = list(data)
|
203
210
|
if cx is None:
|
204
211
|
cx = 1
|
@@ -876,9 +876,6 @@ def init_commands(kernel):
|
|
876
876
|
if method is None:
|
877
877
|
method = "union"
|
878
878
|
method = method.lower()
|
879
|
-
if filltype is None:
|
880
|
-
filltype = "evenodd"
|
881
|
-
filltype = filltype.lower()
|
882
879
|
if keep is None:
|
883
880
|
keep = False
|
884
881
|
|
@@ -891,6 +888,10 @@ def init_commands(kernel):
|
|
891
888
|
else:
|
892
889
|
long_method = "Union"
|
893
890
|
|
891
|
+
if filltype is None:
|
892
|
+
filltype = "evenodd" if method != "union" else "nonzero"
|
893
|
+
filltype = filltype.lower()
|
894
|
+
|
894
895
|
if filltype.startswith("no") or filltype.startswith("z"):
|
895
896
|
long_filltype = "NonZero"
|
896
897
|
elif filltype.startswith("p") or filltype.startswith("+"):
|
@@ -360,10 +360,11 @@ def offset_path(self, path, offset_value=0):
|
|
360
360
|
# As this oveloading a regular method in a class
|
361
361
|
# it needs to have the very same definition (including the class
|
362
362
|
# reference self)
|
363
|
+
# Radial connectors seem to have issues, so we don't use them for now...
|
363
364
|
p = path_offset(
|
364
365
|
path,
|
365
366
|
offset_value=-offset_value,
|
366
|
-
radial_connector=
|
367
|
+
radial_connector=False,
|
367
368
|
linearize=True,
|
368
369
|
interpolation=500,
|
369
370
|
)
|