meerk40t 0.9.7010__py2.py3-none-any.whl → 0.9.7020__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/elements/branches.py +18 -4
- meerk40t/core/elements/element_treeops.py +34 -0
- meerk40t/core/elements/elements.py +49 -63
- meerk40t/core/elements/offset_clpr.py +4 -3
- meerk40t/core/elements/shapes.py +1 -1
- meerk40t/core/elements/testcases.py +105 -0
- 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/extra/encode_detect.py +8 -2
- meerk40t/extra/hershey.py +2 -3
- meerk40t/extra/inkscape.py +3 -5
- meerk40t/extra/outerworld.py +2 -3
- meerk40t/extra/param_functions.py +1 -1
- meerk40t/grbl/device.py +4 -1
- meerk40t/grbl/gui/grblcontroller.py +2 -2
- meerk40t/gui/busy.py +75 -13
- meerk40t/gui/choicepropertypanel.py +364 -375
- meerk40t/gui/consolepanel.py +3 -3
- 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 +2 -2
- meerk40t/gui/tips.py +2 -3
- meerk40t/gui/toolwidgets/toolmeasure.py +4 -1
- meerk40t/gui/wxmeerk40t.py +6 -3
- meerk40t/gui/wxmmain.py +72 -6
- meerk40t/gui/wxmscene.py +2 -6
- meerk40t/gui/wxmtree.py +17 -11
- meerk40t/gui/wxutils.py +1 -1
- meerk40t/image/imagetools.py +20 -5
- meerk40t/kernel/kernel.py +21 -2
- meerk40t/main.py +1 -1
- meerk40t/network/console_server.py +52 -14
- meerk40t/network/web_server.py +15 -1
- meerk40t/ruida/device.py +5 -1
- meerk40t/tools/polybool.py +2 -1
- meerk40t/tools/shxparser.py +92 -34
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7020.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7020.dist-info}/RECORD +55 -54
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7020.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7020.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7020.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7020.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7010.dist-info → meerk40t-0.9.7020.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)
|
@@ -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),
|
@@ -3570,6 +3570,40 @@ def init_tree(kernel):
|
|
3570
3570
|
with self.undoscope("Outline"):
|
3571
3571
|
self(f"outline {offset}mm\n")
|
3572
3572
|
self.signal("refresh_tree")
|
3573
|
+
|
3574
|
+
@tree_conditional(
|
3575
|
+
lambda node: not is_regmark(node)
|
3576
|
+
and hasattr(node, "as_geometry")
|
3577
|
+
)
|
3578
|
+
@tree_submenu(_("Offset shapes..."))
|
3579
|
+
@tree_iterate("offset", 1, 5)
|
3580
|
+
@tree_operation(
|
3581
|
+
_("...to outside with {offset}mm distance"),
|
3582
|
+
node_type=elem_nodes,
|
3583
|
+
help=_("Create an outer offset around the selected elements"),
|
3584
|
+
grouping="50_ELEM_MODIFY_ZMISC"
|
3585
|
+
)
|
3586
|
+
def make_positive_offsets(node, offset=1, **kwargs):
|
3587
|
+
with self.undoscope("Offset"):
|
3588
|
+
self(f"offset {offset}mm\n")
|
3589
|
+
self.signal("refresh_tree")
|
3590
|
+
|
3591
|
+
@tree_conditional(
|
3592
|
+
lambda node: not is_regmark(node)
|
3593
|
+
and hasattr(node, "as_geometry")
|
3594
|
+
)
|
3595
|
+
@tree_submenu(_("Offset shapes..."))
|
3596
|
+
@tree_iterate("offset", 1, 5)
|
3597
|
+
@tree_operation(
|
3598
|
+
_("...to inside with {offset}mm distance"),
|
3599
|
+
node_type=elem_nodes,
|
3600
|
+
help=_("Create an inner offset around the selected elements"),
|
3601
|
+
grouping="50_ELEM_MODIFY_ZMISC"
|
3602
|
+
)
|
3603
|
+
def make_negative_offsets(node, offset=1, **kwargs):
|
3604
|
+
with self.undoscope("Offset"):
|
3605
|
+
self(f"offset -{offset}mm\n")
|
3606
|
+
self.signal("refresh_tree")
|
3573
3607
|
|
3574
3608
|
def mergeable(node):
|
3575
3609
|
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
|
|
@@ -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("+"):
|
meerk40t/core/elements/shapes.py
CHANGED
@@ -1729,7 +1729,7 @@ def init_commands(kernel):
|
|
1729
1729
|
# self.signal("rebuild_tree")
|
1730
1730
|
self.signal("refresh_tree", apply)
|
1731
1731
|
else:
|
1732
|
-
self.signal("
|
1732
|
+
self.signal("element_property_reload", apply)
|
1733
1733
|
self.signal("refresh_scene", "Scene")
|
1734
1734
|
return "elements", data
|
1735
1735
|
|
@@ -0,0 +1,105 @@
|
|
1
|
+
from math import sqrt
|
2
|
+
|
3
|
+
from meerk40t.core.node.node import Fillrule, Linecap, Linejoin, Node
|
4
|
+
from meerk40t.core.units import (
|
5
|
+
UNITS_PER_MM,
|
6
|
+
UNITS_PER_PIXEL,
|
7
|
+
UNITS_PER_POINT,
|
8
|
+
Angle,
|
9
|
+
Length,
|
10
|
+
)
|
11
|
+
from meerk40t.kernel import CommandSyntaxError
|
12
|
+
from meerk40t.svgelements import (
|
13
|
+
SVG_RULE_EVENODD,
|
14
|
+
SVG_RULE_NONZERO,
|
15
|
+
Color,
|
16
|
+
Matrix,
|
17
|
+
Path,
|
18
|
+
Polygon,
|
19
|
+
Polyline,
|
20
|
+
)
|
21
|
+
from meerk40t.tools.geomstr import Geomstr
|
22
|
+
|
23
|
+
|
24
|
+
def plugin(kernel, lifecycle=None):
|
25
|
+
_ = kernel.translation
|
26
|
+
if lifecycle == "postboot":
|
27
|
+
init_commands(kernel)
|
28
|
+
|
29
|
+
|
30
|
+
def init_commands(kernel):
|
31
|
+
self = kernel.elements
|
32
|
+
|
33
|
+
_ = kernel.translation
|
34
|
+
|
35
|
+
classify_new = self.post_classify
|
36
|
+
|
37
|
+
def polybool_crash_test(channel, _):
|
38
|
+
# rect_info = "M 30961.4173228,10320.4724409 L 474741.732283,10320.4724409 L 474741.732283,392177.952756 L 30961.4173228,392177.952756 L 30961.4173228,10320.4724409"
|
39
|
+
# geom = Geomstr().svg(rect_info)
|
40
|
+
# Testcase: polybool crash AttributeError: 'NoneType' object has no attribute 'next' for element difference
|
41
|
+
data = []
|
42
|
+
x_pos = 30961.4173228
|
43
|
+
y_pos = 10320.4724409
|
44
|
+
width = 474741.732283 - x_pos
|
45
|
+
height = 392177.952756 - y_pos
|
46
|
+
node1 = self.elem_branch.add(
|
47
|
+
label = "Shape 1",
|
48
|
+
x=x_pos,
|
49
|
+
y=y_pos,
|
50
|
+
width=width,
|
51
|
+
height=height,
|
52
|
+
stroke=self.default_stroke,
|
53
|
+
stroke_width=self.default_strokewidth,
|
54
|
+
fill=self.default_fill,
|
55
|
+
type="elem rect",
|
56
|
+
)
|
57
|
+
data.append(node1)
|
58
|
+
geom = Geomstr()
|
59
|
+
definition = (
|
60
|
+
((30961.417322839014,10320.472440944883),
|
61
|
+
(72243.30708661533,10320.472440944883)),
|
62
|
+
((72243.30708661533,10320.472440944883),
|
63
|
+
(72243.30708661678,20640.944881889765)),
|
64
|
+
((72243.30708661533,10320.472440944883),
|
65
|
+
(113525.19685039311,10320.472440944883)),
|
66
|
+
((113525.19685039311,10320.472440944883),
|
67
|
+
(113525.19685039311,20640.944881889765)),
|
68
|
+
((72243.30708661678,20640.944881889765),
|
69
|
+
(113525.19685039311,20640.944881889765)),
|
70
|
+
((113525.19685039311,10320.472440944883),
|
71
|
+
(154807.08661416644,10320.472440944883)),
|
72
|
+
((154807.08661416644,10320.472440944883),
|
73
|
+
(154807.08661417232,20640.944881889765)),
|
74
|
+
((154807.08661417232,20640.944881889765),
|
75
|
+
(196088.97637794417,20640.944881889765)),
|
76
|
+
((154807.08661416644,10320.472440944883),
|
77
|
+
(196088.97637794568,10320.472440944883)),
|
78
|
+
((196088.97637794417,20640.944881889765),
|
79
|
+
(196088.97637794568,10320.472440944883)),
|
80
|
+
)
|
81
|
+
for s, e in definition:
|
82
|
+
geom.line(complex(s[0], s[1]), complex(e[0], e[1]))
|
83
|
+
node2 = self.elem_branch.add(
|
84
|
+
label = "Shape 2",
|
85
|
+
geometry=geom,
|
86
|
+
stroke=self.default_stroke,
|
87
|
+
stroke_width=self.default_strokewidth,
|
88
|
+
fill=self.default_fill,
|
89
|
+
type="elem path",
|
90
|
+
)
|
91
|
+
|
92
|
+
data.append(node2)
|
93
|
+
return "elements", data
|
94
|
+
|
95
|
+
@self.console_command(
|
96
|
+
"test",
|
97
|
+
output_type="elements",
|
98
|
+
)
|
99
|
+
def element_test(command, channel, _, data=None, post=None, **kwargs):
|
100
|
+
# rect_info = "M 30961.4173228,10320.4724409 L 474741.732283,10320.4724409 L 474741.732283,392177.952756 L 30961.4173228,392177.952756 L 30961.4173228,10320.4724409"
|
101
|
+
# geom = Geomstr().svg(rect_info)
|
102
|
+
# Testcase: polybool crash AttributeError: 'NoneType' object has no attribute 'next' for element difference
|
103
|
+
info, data = polybool_crash_test(channel, _)
|
104
|
+
post.append(classify_new(data))
|
105
|
+
return info, data
|
meerk40t/core/node/op_cut.py
CHANGED
@@ -246,7 +246,15 @@ class CutOpNode(Node, Parameters):
|
|
246
246
|
return False, False, None
|
247
247
|
feedback = []
|
248
248
|
if node.type in self._allowed_elements:
|
249
|
-
if
|
249
|
+
if self.default and usedefault:
|
250
|
+
# Have classified but more classification might be needed
|
251
|
+
if self.valid_node_for_reference(node):
|
252
|
+
self.add_reference(node)
|
253
|
+
feedback.append("stroke")
|
254
|
+
feedback.append("fill")
|
255
|
+
return True, self.stopop, feedback
|
256
|
+
else:
|
257
|
+
# Even if the default attribute set that would be a valid thing
|
250
258
|
if self.has_attributes():
|
251
259
|
result = False
|
252
260
|
for attribute in self.allowed_attributes:
|
@@ -271,13 +279,6 @@ class CutOpNode(Node, Parameters):
|
|
271
279
|
feedback.append("stroke")
|
272
280
|
feedback.append("fill")
|
273
281
|
return True, self.stopop, feedback
|
274
|
-
elif self.default and usedefault:
|
275
|
-
# Have classified but more classification might be needed
|
276
|
-
if self.valid_node_for_reference(node):
|
277
|
-
self.add_reference(node)
|
278
|
-
feedback.append("stroke")
|
279
|
-
feedback.append("fill")
|
280
|
-
return True, self.stopop, feedback
|
281
282
|
return False, False, None
|
282
283
|
|
283
284
|
def add_reference(self, node=None, pos=None, **kwargs):
|
meerk40t/core/node/op_dots.py
CHANGED
@@ -174,7 +174,14 @@ class DotsOpNode(Node, Parameters):
|
|
174
174
|
return False, False, None
|
175
175
|
feedback = []
|
176
176
|
if node.type in self._allowed_elements:
|
177
|
-
if
|
177
|
+
if self.default and usedefault:
|
178
|
+
# Have classified but more classification might be needed
|
179
|
+
if self.valid_node_for_reference(node):
|
180
|
+
self.add_reference(node)
|
181
|
+
feedback.append("stroke")
|
182
|
+
feedback.append("fill")
|
183
|
+
return True, self.stopop, feedback
|
184
|
+
else:
|
178
185
|
if self.has_attributes():
|
179
186
|
result = False
|
180
187
|
for attribute in self.allowed_attributes:
|
@@ -199,13 +206,6 @@ class DotsOpNode(Node, Parameters):
|
|
199
206
|
feedback.append("stroke")
|
200
207
|
feedback.append("fill")
|
201
208
|
return True, self.stopop, feedback
|
202
|
-
elif self.default and usedefault:
|
203
|
-
# Have classified but more classification might be needed
|
204
|
-
if self.valid_node_for_reference(node):
|
205
|
-
self.add_reference(node)
|
206
|
-
feedback.append("stroke")
|
207
|
-
feedback.append("fill")
|
208
|
-
return True, self.stopop, feedback
|
209
209
|
return False, False, None
|
210
210
|
|
211
211
|
def load(self, settings, section):
|
meerk40t/core/node/op_engrave.py
CHANGED
@@ -211,7 +211,13 @@ class EngraveOpNode(Node, Parameters):
|
|
211
211
|
return False, False, None
|
212
212
|
feedback = []
|
213
213
|
if node.type in self._allowed_elements:
|
214
|
-
if
|
214
|
+
if self.default and usedefault:
|
215
|
+
# Have classified but more classification might be needed
|
216
|
+
if self.valid_node_for_reference(node):
|
217
|
+
feedback.append("stroke")
|
218
|
+
feedback.append("fill")
|
219
|
+
return True, self.stopop, feedback
|
220
|
+
else:
|
215
221
|
if self.has_attributes():
|
216
222
|
result = False
|
217
223
|
for attribute in self.allowed_attributes:
|
@@ -236,12 +242,6 @@ class EngraveOpNode(Node, Parameters):
|
|
236
242
|
feedback.append("stroke")
|
237
243
|
feedback.append("fill")
|
238
244
|
return True, self.stopop, feedback
|
239
|
-
elif self.default and usedefault:
|
240
|
-
# Have classified but more classification might be needed
|
241
|
-
if self.valid_node_for_reference(node):
|
242
|
-
feedback.append("stroke")
|
243
|
-
feedback.append("fill")
|
244
|
-
return True, self.stopop, feedback
|
245
245
|
return False, False, None
|
246
246
|
|
247
247
|
def add_reference(self, node=None, pos=None, **kwargs):
|
meerk40t/core/node/op_raster.py
CHANGED
@@ -268,7 +268,14 @@ class RasterOpNode(Node, Parameters):
|
|
268
268
|
|
269
269
|
feedback = []
|
270
270
|
if node.type in self._allowed_elements:
|
271
|
-
if
|
271
|
+
if self.default and usedefault:
|
272
|
+
# Have classified but more classification might be needed
|
273
|
+
if self.valid_node_for_reference(node):
|
274
|
+
self.add_reference(node)
|
275
|
+
feedback.append("stroke")
|
276
|
+
feedback.append("fill")
|
277
|
+
return True, self.stopop, feedback
|
278
|
+
else:
|
272
279
|
if self.has_attributes():
|
273
280
|
result = False
|
274
281
|
for attribute in self.allowed_attributes:
|
@@ -311,13 +318,6 @@ class RasterOpNode(Node, Parameters):
|
|
311
318
|
self.add_reference(node)
|
312
319
|
# Have classified but more classification might be needed
|
313
320
|
return True, self.stopop, feedback
|
314
|
-
elif self.default and usedefault:
|
315
|
-
# Have classified but more classification might be needed
|
316
|
-
if self.valid_node_for_reference(node):
|
317
|
-
self.add_reference(node)
|
318
|
-
feedback.append("stroke")
|
319
|
-
feedback.append("fill")
|
320
|
-
return True, self.stopop, feedback
|
321
321
|
return False, False, None
|
322
322
|
|
323
323
|
def load(self, settings, section):
|
meerk40t/extra/encode_detect.py
CHANGED
@@ -165,13 +165,19 @@ class EncodingDetectFile:
|
|
165
165
|
|
166
166
|
def load(self, file_path):
|
167
167
|
# open file
|
168
|
-
|
168
|
+
try:
|
169
|
+
fh = open(file_path, "rb")
|
170
|
+
except Exception:
|
171
|
+
return False
|
169
172
|
|
170
173
|
# detect a byte order mark (BOM)
|
171
174
|
file_encoding, bom_marker, file_data = self._detect_bom(fh)
|
172
175
|
if file_encoding:
|
173
176
|
# file has a BOM - decode everything past it
|
174
|
-
|
177
|
+
try:
|
178
|
+
decode = fh.read().decode(file_encoding)
|
179
|
+
except UnicodeDecodeError:
|
180
|
+
return False
|
175
181
|
# print(f"decoded: {decode}")
|
176
182
|
fh.close()
|
177
183
|
|
meerk40t/extra/hershey.py
CHANGED
@@ -7,7 +7,6 @@ from os.path import basename, exists, join, realpath, splitext
|
|
7
7
|
from meerk40t.core.node.elem_path import PathNode
|
8
8
|
from meerk40t.core.node.node import Fillrule, Linejoin
|
9
9
|
from meerk40t.core.units import UNITS_PER_INCH, Length
|
10
|
-
from meerk40t.kernel import get_safe_path
|
11
10
|
from meerk40t.tools.geomstr import BeamTable, Geomstr
|
12
11
|
from meerk40t.tools.jhfparser import JhfFont
|
13
12
|
from meerk40t.tools.shxparser import ShxFont, ShxFontParseError
|
@@ -116,7 +115,7 @@ class Meerk40tFonts:
|
|
116
115
|
|
117
116
|
@property
|
118
117
|
def font_directory(self):
|
119
|
-
safe_dir =
|
118
|
+
safe_dir = self.context.kernel.os_information["WORKDIR"]
|
120
119
|
self.context.setting(str, "font_directory", safe_dir)
|
121
120
|
fontdir = self.context.font_directory
|
122
121
|
if not exists(fontdir):
|
@@ -129,7 +128,7 @@ class Meerk40tFonts:
|
|
129
128
|
def font_directory(self, value):
|
130
129
|
if not exists(value):
|
131
130
|
# We cant allow a non-valid directory
|
132
|
-
value =
|
131
|
+
value = self.context.kernel.os_information["WORKDIR"]
|
133
132
|
self.context.setting(str, "font_directory", value)
|
134
133
|
self.context.font_directory = value
|
135
134
|
self._available_fonts = None
|
meerk40t/extra/inkscape.py
CHANGED
@@ -5,8 +5,6 @@ from subprocess import PIPE, TimeoutExpired, run
|
|
5
5
|
from time import time
|
6
6
|
|
7
7
|
from meerk40t.core.exceptions import BadFileError
|
8
|
-
from meerk40t.kernel.kernel import get_safe_path
|
9
|
-
|
10
8
|
|
11
9
|
def get_inkscape(context, manual_candidate=None):
|
12
10
|
root_context = context
|
@@ -143,7 +141,7 @@ class MultiLoader:
|
|
143
141
|
break
|
144
142
|
|
145
143
|
context_root = kernel.root
|
146
|
-
safe_dir =
|
144
|
+
safe_dir = kernel.os_information["WORKDIR"]
|
147
145
|
logfile = os.path.join(safe_dir, "inkscape.log")
|
148
146
|
|
149
147
|
inkscape = get_inkscape(context_root)
|
@@ -228,7 +226,7 @@ def plugin(kernel, lifecycle):
|
|
228
226
|
inkscape_path, filename = data
|
229
227
|
channel(_("inkscape load - loading the previous conversion..."))
|
230
228
|
try:
|
231
|
-
kernel.elements.load(filename)
|
229
|
+
kernel.elements.load(filename, svg_ppi=kernel.elements.svg_ppi)
|
232
230
|
except BadFileError as e:
|
233
231
|
channel(_("File is Malformed."))
|
234
232
|
channel(str(e))
|
@@ -423,7 +421,7 @@ def plugin(kernel, lifecycle):
|
|
423
421
|
],
|
424
422
|
"pattern": [False, ("<pattern",), METHOD_CONVERT_TO_PNG],
|
425
423
|
}
|
426
|
-
safe_dir =
|
424
|
+
safe_dir = kernel.os_information["WORKDIR"]
|
427
425
|
svg_temp_file = os.path.join(safe_dir, "temp.svg")
|
428
426
|
png_temp_file = os.path.join(safe_dir, "temp.png")
|
429
427
|
needs_conversion = 0
|