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
@@ -13,6 +13,7 @@ non_structural_nodes = (
|
|
13
13
|
"op engrave",
|
14
14
|
"op dots",
|
15
15
|
"effect hatch",
|
16
|
+
"effect wobble",
|
16
17
|
"util console",
|
17
18
|
"util wait",
|
18
19
|
"util home",
|
@@ -32,6 +33,7 @@ non_structural_nodes = (
|
|
32
33
|
"elem rect",
|
33
34
|
"elem line",
|
34
35
|
"elem text",
|
36
|
+
"image raster",
|
35
37
|
"file",
|
36
38
|
"group",
|
37
39
|
)
|
@@ -61,7 +63,8 @@ place_nodes = (
|
|
61
63
|
"place point",
|
62
64
|
"place current",
|
63
65
|
)
|
64
|
-
effect_nodes = ("effect hatch",)
|
66
|
+
effect_nodes = ("effect hatch", "effect wobble")
|
67
|
+
image_nodes = ("image raster", "image processed", "elem image")
|
65
68
|
elem_nodes = (
|
66
69
|
"elem ellipse",
|
67
70
|
"elem image",
|
@@ -71,7 +74,6 @@ elem_nodes = (
|
|
71
74
|
"elem rect",
|
72
75
|
"elem line",
|
73
76
|
"elem text",
|
74
|
-
"effect hatch",
|
75
77
|
)
|
76
78
|
elem_group_nodes = (
|
77
79
|
"elem ellipse",
|
@@ -82,7 +84,9 @@ elem_group_nodes = (
|
|
82
84
|
"elem rect",
|
83
85
|
"elem line",
|
84
86
|
"elem text",
|
87
|
+
"image raster",
|
85
88
|
"effect hatch",
|
89
|
+
"effect wobble",
|
86
90
|
"group",
|
87
91
|
"file",
|
88
92
|
)
|
@@ -96,5 +100,6 @@ elem_ref_nodes = (
|
|
96
100
|
"elem line",
|
97
101
|
"elem text",
|
98
102
|
"effect hatch",
|
103
|
+
"effect wobble",
|
99
104
|
"reference",
|
100
105
|
)
|
@@ -117,7 +117,11 @@ def plugin(kernel, lifecycle=None):
|
|
117
117
|
kernel.register("format/elem text", "{element_type} {desc} {text}")
|
118
118
|
kernel.register(
|
119
119
|
"format/effect hatch",
|
120
|
-
"{
|
120
|
+
"{element_type} - {distance} {angle} ({children})",
|
121
|
+
)
|
122
|
+
kernel.register(
|
123
|
+
"format/effect wobble",
|
124
|
+
"{element_type} - {type} {radius} ({children})",
|
121
125
|
)
|
122
126
|
kernel.register("format/reference", "*{reference}")
|
123
127
|
kernel.register(
|
@@ -494,7 +498,7 @@ class Elemental(Service):
|
|
494
498
|
self.points = list()
|
495
499
|
self.segments = list()
|
496
500
|
|
497
|
-
self.undo = Undo(self._tree)
|
501
|
+
self.undo = Undo(self, self._tree)
|
498
502
|
self.do_undo = True
|
499
503
|
self.suppress_updates = False
|
500
504
|
|
@@ -522,14 +526,15 @@ class Elemental(Service):
|
|
522
526
|
|
523
527
|
direct = os.path.dirname(self.op_data._config_file)
|
524
528
|
self.mywordlist = Wordlist(self.kernel.version, direct)
|
525
|
-
self.
|
529
|
+
with self.undofree():
|
530
|
+
self.load_persistent_operations("previous")
|
526
531
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
532
|
+
ops = list(self.ops())
|
533
|
+
if len(ops) == 0 and not self.operation_default_empty:
|
534
|
+
self.load_default(performclassify=False)
|
535
|
+
if list(self.ops()):
|
536
|
+
# Something was loaded for default ops. Mark that.
|
537
|
+
self.undo.mark("op-loaded") # Mark defaulted
|
533
538
|
|
534
539
|
self._default_stroke = None
|
535
540
|
self._default_strokewidth = None
|
@@ -677,13 +682,18 @@ class Elemental(Service):
|
|
677
682
|
# pnode.targeted = True
|
678
683
|
# pnode = pnode.parent
|
679
684
|
|
685
|
+
def unassigned_elements(self):
|
686
|
+
for e in self.elems():
|
687
|
+
if (e._references is None or len(e._references) == 0) and e.type not in (
|
688
|
+
"file",
|
689
|
+
"group",
|
690
|
+
):
|
691
|
+
yield e
|
692
|
+
|
680
693
|
def have_unassigned_elements(self):
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
unassigned = True
|
685
|
-
break
|
686
|
-
return unassigned
|
694
|
+
for node in self.unassigned_elements():
|
695
|
+
return True
|
696
|
+
return False
|
687
697
|
|
688
698
|
def have_unburnable_elements(self):
|
689
699
|
unassigned = False
|
@@ -713,17 +723,23 @@ class Elemental(Service):
|
|
713
723
|
return float(Length(v))
|
714
724
|
|
715
725
|
def length_x(self, v):
|
716
|
-
|
726
|
+
try:
|
727
|
+
return float(Length(v, relative_length=self.device.view.width))
|
728
|
+
except AttributeError:
|
729
|
+
return 0.0
|
717
730
|
|
718
731
|
def length_y(self, v):
|
719
|
-
|
732
|
+
try:
|
733
|
+
return float(Length(v, relative_length=self.device.view.height))
|
734
|
+
except AttributeError:
|
735
|
+
return 0.0
|
720
736
|
|
721
737
|
def bounds(self, x0, y0, x1, y1):
|
722
738
|
return (
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
739
|
+
self.length_x(x0),
|
740
|
+
self.length_y(y0),
|
741
|
+
self.length_x(x1),
|
742
|
+
self.length_y(y1),
|
727
743
|
)
|
728
744
|
|
729
745
|
def area(self, v):
|
@@ -1439,6 +1455,7 @@ class Elemental(Service):
|
|
1439
1455
|
# Restore emphasized flags
|
1440
1456
|
for e in emph_data:
|
1441
1457
|
e.emphasized = True
|
1458
|
+
self.signal("element_property_reload", data)
|
1442
1459
|
|
1443
1460
|
def remove_unused_default_copies(self):
|
1444
1461
|
# Let's clean non-used operations that come from defaults...
|
@@ -1617,6 +1634,13 @@ class Elemental(Service):
|
|
1617
1634
|
continue
|
1618
1635
|
yield item
|
1619
1636
|
|
1637
|
+
def op_groups(self, **kwargs):
|
1638
|
+
operations = self._tree.get(type="branch ops")
|
1639
|
+
for item in operations.flat(**kwargs):
|
1640
|
+
if item.type.startswith("branch") or item.type.startswith("ref"):
|
1641
|
+
continue
|
1642
|
+
yield item
|
1643
|
+
|
1620
1644
|
def elems(self, **kwargs):
|
1621
1645
|
elements = self._tree.get(type="branch elems")
|
1622
1646
|
yield from elements.flat(types=elem_nodes, **kwargs)
|
@@ -1826,7 +1850,7 @@ class Elemental(Service):
|
|
1826
1850
|
if drop_node.drop(drag_node, modify=False):
|
1827
1851
|
# Is the drag node coming from the regmarks branch?
|
1828
1852
|
# If yes then we might need to classify.
|
1829
|
-
if drag_node.
|
1853
|
+
if drag_node.has_ancestor("branch reg"):
|
1830
1854
|
if drag_node.type in ("file", "group"):
|
1831
1855
|
for e in drag_node.flat(elem_nodes):
|
1832
1856
|
to_classify.append(e)
|
@@ -3471,6 +3495,7 @@ class Elemental(Service):
|
|
3471
3495
|
# self.unlisten_tree(self)
|
3472
3496
|
elemcount_then = self.count_elems()
|
3473
3497
|
opcount_then = self.count_op()
|
3498
|
+
self._loading_cleared = False
|
3474
3499
|
results = loader.load(
|
3475
3500
|
self, self, filename_to_process, **kwargs
|
3476
3501
|
)
|
@@ -3487,11 +3512,12 @@ class Elemental(Service):
|
|
3487
3512
|
):
|
3488
3513
|
return True
|
3489
3514
|
elif results:
|
3490
|
-
self.
|
3491
|
-
|
3492
|
-
|
3493
|
-
|
3494
|
-
|
3515
|
+
if not self._loading_cleared:
|
3516
|
+
self.signal(
|
3517
|
+
"warning",
|
3518
|
+
_("File is Empty"),
|
3519
|
+
_("File is Malformed"),
|
3520
|
+
)
|
3495
3521
|
return True
|
3496
3522
|
|
3497
3523
|
except FileNotFoundError:
|
@@ -74,6 +74,14 @@ def init_commands(kernel):
|
|
74
74
|
path.append(e)
|
75
75
|
return "geometry", path
|
76
76
|
|
77
|
+
@self.console_command("validate", input_type="geometry", output_type="geometry")
|
78
|
+
def geometry_validate(channel, _, data=None, **kwargs):
|
79
|
+
try:
|
80
|
+
data.validate()
|
81
|
+
channel(_("Geometry is valid."))
|
82
|
+
except AssertionError:
|
83
|
+
channel(_("Geometry was not valid."))
|
84
|
+
|
77
85
|
@self.console_argument("x_pos", type=Length)
|
78
86
|
@self.console_argument("y_pos", type=Length)
|
79
87
|
@self.console_argument("r_pos", type=Length)
|
@@ -473,14 +473,27 @@ def init_commands(kernel):
|
|
473
473
|
pyc_method = pyclipr.ClipType.Xor
|
474
474
|
else:
|
475
475
|
pyc_method = pyclipr.ClipType.Union
|
476
|
+
# Definition of enumerators has changed, so let#s try to be backwards compatible
|
476
477
|
if filltype.startswith("no") or filltype.startswith("z"):
|
477
|
-
|
478
|
+
try:
|
479
|
+
pyc_filltype = pyclipr.FillRule.NonZero
|
480
|
+
except AttributeError:
|
481
|
+
pyc_filltype = pyclipr.FillType.NonZero
|
478
482
|
elif filltype.startswith("p") or filltype.startswith("+"):
|
479
|
-
|
483
|
+
try:
|
484
|
+
pyc_filltype = pyclipr.FillRule.Positive
|
485
|
+
except AttributeError:
|
486
|
+
pyc_filltype = pyclipr.FillType.Positive
|
480
487
|
elif filltype.startswith("ne") or filltype.startswith("-"):
|
481
|
-
|
488
|
+
try:
|
489
|
+
pyc_filltype = pyclipr.FillRule.Negative
|
490
|
+
except AttributeError:
|
491
|
+
pyc_filltype = pyclipr.FillType.Negative
|
482
492
|
else:
|
483
|
-
|
493
|
+
try:
|
494
|
+
pyc_filltype = pyclipr.FillRule.EvenOdd
|
495
|
+
except AttributeError:
|
496
|
+
pyc_filltype = pyclipr.FillType.EvenOdd
|
484
497
|
|
485
498
|
if self.any_open and pyc_method in (pyclipr.ClipType.Union,):
|
486
499
|
self.newpath = self.clipr_clipper.execute(
|
@@ -678,6 +691,118 @@ def init_commands(kernel):
|
|
678
691
|
self.signal("refresh_scene", "Scene")
|
679
692
|
return "elements", data_out
|
680
693
|
|
694
|
+
# Pocketing
|
695
|
+
@self.console_argument(
|
696
|
+
"offset",
|
697
|
+
type=str,
|
698
|
+
help=_(
|
699
|
+
"offset to line mm (negative values to left/outside, positive values to right/inside)"
|
700
|
+
),
|
701
|
+
)
|
702
|
+
@self.console_option(
|
703
|
+
"jointype", "j", type=str, help=_("join type: round, miter, square")
|
704
|
+
)
|
705
|
+
@self.console_option(
|
706
|
+
"separate",
|
707
|
+
"s",
|
708
|
+
action="store_true",
|
709
|
+
type=bool,
|
710
|
+
help=_("deal with subpaths separately"),
|
711
|
+
)
|
712
|
+
@self.console_option(
|
713
|
+
"repeats",
|
714
|
+
"r",
|
715
|
+
type=int,
|
716
|
+
help=_("amount of repetitions, 0=until area is fully filled"),
|
717
|
+
)
|
718
|
+
@self.console_option(
|
719
|
+
"interpolation", "i", type=int, help=_("interpolation points per segment")
|
720
|
+
)
|
721
|
+
@self.console_command(
|
722
|
+
"pocket",
|
723
|
+
help=_("create a pocketing path for any of the given elements"),
|
724
|
+
input_type=(None, "elements"),
|
725
|
+
output_type="elements",
|
726
|
+
)
|
727
|
+
def element_pocket_path(
|
728
|
+
command,
|
729
|
+
channel,
|
730
|
+
_,
|
731
|
+
offset=None,
|
732
|
+
jointype=None,
|
733
|
+
separate=None,
|
734
|
+
repeats=0,
|
735
|
+
interpolation=None,
|
736
|
+
data=None,
|
737
|
+
post=None,
|
738
|
+
**kwargs,
|
739
|
+
):
|
740
|
+
if data is None:
|
741
|
+
data = list(self.elems(emphasized=True))
|
742
|
+
if len(data) == 0:
|
743
|
+
channel(_("No elements selected"))
|
744
|
+
return "elements", data
|
745
|
+
if interpolation is None:
|
746
|
+
interpolation = 500
|
747
|
+
if separate is None:
|
748
|
+
separate = False
|
749
|
+
if offset is None:
|
750
|
+
offset = 0
|
751
|
+
else:
|
752
|
+
try:
|
753
|
+
ll = Length(offset)
|
754
|
+
offset = float(ll)
|
755
|
+
except ValueError:
|
756
|
+
offset = 0
|
757
|
+
if offset == 0.0:
|
758
|
+
channel("Invalid offset, nothing to do")
|
759
|
+
return
|
760
|
+
# Our definition for an offset is different this time
|
761
|
+
offset *= -1
|
762
|
+
if repeats is None or repeats < 0:
|
763
|
+
repeats = 0
|
764
|
+
if offset > 0 and repeats == 0:
|
765
|
+
channel(
|
766
|
+
"You need to provide the -r parameter to set the amount of repetitions"
|
767
|
+
)
|
768
|
+
return
|
769
|
+
|
770
|
+
if jointype is None:
|
771
|
+
jointype = "miter"
|
772
|
+
jointype = jointype.lower()
|
773
|
+
default_stroke = None
|
774
|
+
for node in data:
|
775
|
+
if hasattr(node, "stroke"):
|
776
|
+
default_stroke = node.stroke
|
777
|
+
break
|
778
|
+
if default_stroke is None:
|
779
|
+
default_stroke = self._default_stroke
|
780
|
+
data_out = []
|
781
|
+
rep_count = 0
|
782
|
+
mydata = [e for e in data]
|
783
|
+
while (rep_count < repeats or repeats == 0) and len(mydata) > 0:
|
784
|
+
rep_count += 1
|
785
|
+
c_off = ClipperOffset(interpolation=interpolation)
|
786
|
+
c_off.add_nodes(mydata)
|
787
|
+
c_off.process_data(offset, jointype=jointype, separate=separate)
|
788
|
+
mydata.clear()
|
789
|
+
for geom in c_off.result_geometry():
|
790
|
+
if geom is not None:
|
791
|
+
newnode = self.elem_branch.add(
|
792
|
+
geometry=geom, type="elem path", stroke=default_stroke
|
793
|
+
)
|
794
|
+
newnode.stroke_width = UNITS_PER_PIXEL
|
795
|
+
newnode.linejoin = Linejoin.JOIN_ROUND
|
796
|
+
newnode.label = f"Offset: {Length(offset).length_mm}"
|
797
|
+
mydata.append(newnode)
|
798
|
+
data_out.append(newnode)
|
799
|
+
|
800
|
+
# Newly created! Classification needed?
|
801
|
+
if len(data_out) > 0:
|
802
|
+
post.append(classify_new(data_out))
|
803
|
+
self.signal("refresh_scene", "Scene")
|
804
|
+
return "elements", data_out
|
805
|
+
|
681
806
|
# ---- Let's add some CAG commands....
|
682
807
|
@self.console_argument(
|
683
808
|
"method",
|
@@ -633,7 +633,8 @@ def path_offset(
|
|
633
633
|
# print (f"Subpath {spct}")
|
634
634
|
p = Path(subpath)
|
635
635
|
if not linearize:
|
636
|
-
p.approximate_arcs_with_cubics()
|
636
|
+
# p.approximate_arcs_with_cubics()
|
637
|
+
pass
|
637
638
|
offset = offset_value
|
638
639
|
# # No offset bigger than half the path size, otherwise stuff will get crazy
|
639
640
|
# if offset > 0:
|
@@ -829,6 +830,7 @@ def path_offset(
|
|
829
830
|
result = results[0]
|
830
831
|
for idx in range(1, len(results)):
|
831
832
|
result += results[idx]
|
833
|
+
# result.approximate_arcs_with_cubics()
|
832
834
|
return result
|
833
835
|
|
834
836
|
|
meerk40t/core/elements/shapes.py
CHANGED
@@ -238,37 +238,39 @@ def init_commands(kernel):
|
|
238
238
|
input_type=(None, "elements"),
|
239
239
|
)
|
240
240
|
def effect_hatch(
|
241
|
-
command,
|
241
|
+
command,
|
242
|
+
data=None,
|
243
|
+
angle=None,
|
244
|
+
angle_delta=None,
|
245
|
+
distance=None,
|
246
|
+
post=None,
|
247
|
+
**kwargs,
|
242
248
|
):
|
243
249
|
"""
|
244
250
|
Add an effect hatch object
|
245
251
|
"""
|
246
|
-
|
252
|
+
if data is None:
|
253
|
+
data = list(self.elems(emphasized=True))
|
254
|
+
if len(data) == 0:
|
255
|
+
return
|
256
|
+
first_node = data[0]
|
257
|
+
|
258
|
+
node = first_node.parent.add(
|
247
259
|
type="effect hatch",
|
248
260
|
label="Hatch Effect",
|
249
261
|
hatch_angle=angle.as_radians,
|
250
262
|
hatch_angle_delta=angle_delta.as_radians,
|
251
263
|
hatch_distance=distance,
|
252
264
|
)
|
265
|
+
for n in data:
|
266
|
+
node.append_child(n)
|
267
|
+
|
268
|
+
# Newly created! Classification needed?
|
269
|
+
post.append(classify_new([node]))
|
270
|
+
|
253
271
|
self.set_emphasis([node])
|
254
|
-
if data is not None:
|
255
|
-
for n in data:
|
256
|
-
node.append_child(n)
|
257
272
|
node.focus()
|
258
273
|
|
259
|
-
@self.console_command(
|
260
|
-
"toggle",
|
261
|
-
help=_("Toggles effect from being group to an effect."),
|
262
|
-
input_type="elements",
|
263
|
-
)
|
264
|
-
def effect_toggle(command, data=None, **kwargs):
|
265
|
-
"""
|
266
|
-
Toggles effect hatch object
|
267
|
-
"""
|
268
|
-
for n in data:
|
269
|
-
if n.type.startswith("effect "):
|
270
|
-
n.effect = not n.effect
|
271
|
-
|
272
274
|
@self.console_option(
|
273
275
|
"size", "s", type=float, default=16, help=_("font size to for object")
|
274
276
|
)
|
@@ -732,12 +734,10 @@ def init_commands(kernel):
|
|
732
734
|
def element_pathd_info(command, channel, _, data, real=True, **kwargs):
|
733
735
|
for node in data:
|
734
736
|
try:
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
else:
|
740
|
-
channel(f"{str(node)}: {node.path.d(transformed=not real)}")
|
737
|
+
g = node.as_geometry()
|
738
|
+
path = g.as_path()
|
739
|
+
ident = " (Identity)" if node.matrix.is_identity() else ""
|
740
|
+
channel(f"{str(node)}{ident}: {path.d(transformed=not real)}")
|
741
741
|
except AttributeError:
|
742
742
|
channel(f"{str(node)}: Invalid")
|
743
743
|
|
@@ -2021,7 +2021,10 @@ def init_commands(kernel):
|
|
2021
2021
|
except AttributeError:
|
2022
2022
|
pass
|
2023
2023
|
if e.type == "elem path":
|
2024
|
-
e.
|
2024
|
+
g = e.geometry
|
2025
|
+
path = g.as_path()
|
2026
|
+
path.approximate_bezier_with_circular_arcs()
|
2027
|
+
e.geometry = Geomstr.svg(path)
|
2025
2028
|
e.altered()
|
2026
2029
|
|
2027
2030
|
return "elements", data
|
meerk40t/core/laserjob.py
CHANGED
@@ -183,6 +183,13 @@ class LaserJob:
|
|
183
183
|
self.runtime += time.time() - self.time_started
|
184
184
|
self._stopped = True
|
185
185
|
|
186
|
+
def stop_after_loop(self):
|
187
|
+
self.loops = self.loops_executed + 1
|
188
|
+
|
189
|
+
def add_another_loop(self):
|
190
|
+
if not isinf(self.loops):
|
191
|
+
self.loops += 1
|
192
|
+
|
186
193
|
def elapsed_time(self):
|
187
194
|
"""
|
188
195
|
How long is this job already running...
|
meerk40t/core/node/bootstrap.py
CHANGED
@@ -4,6 +4,7 @@ from meerk40t.core.node.branch_ops import BranchOperationsNode
|
|
4
4
|
from meerk40t.core.node.branch_regmark import BranchRegmarkNode
|
5
5
|
from meerk40t.core.node.cutnode import CutNode
|
6
6
|
from meerk40t.core.node.effect_hatch import HatchEffectNode
|
7
|
+
from meerk40t.core.node.effect_wobble import WobbleEffectNode
|
7
8
|
from meerk40t.core.node.elem_ellipse import EllipseNode
|
8
9
|
from meerk40t.core.node.elem_image import ImageNode
|
9
10
|
from meerk40t.core.node.elem_line import LineNode
|
@@ -14,6 +15,7 @@ from meerk40t.core.node.elem_rect import RectNode
|
|
14
15
|
from meerk40t.core.node.elem_text import TextNode
|
15
16
|
from meerk40t.core.node.filenode import FileNode
|
16
17
|
from meerk40t.core.node.groupnode import GroupNode
|
18
|
+
from meerk40t.core.node.image_raster import ImageRasterNode
|
17
19
|
from meerk40t.core.node.layernode import LayerNode
|
18
20
|
from meerk40t.core.node.op_cut import CutOpNode
|
19
21
|
from meerk40t.core.node.op_dots import DotsOpNode
|
@@ -71,6 +73,7 @@ bootstrap = {
|
|
71
73
|
"op image": ImageOpNode,
|
72
74
|
"op dots": DotsOpNode,
|
73
75
|
"effect hatch": HatchEffectNode,
|
76
|
+
"effect wobble": WobbleEffectNode,
|
74
77
|
"util console": ConsoleOperation,
|
75
78
|
"util wait": WaitOperation,
|
76
79
|
"util home": HomeOperation,
|
@@ -90,6 +93,7 @@ bootstrap = {
|
|
90
93
|
"elem polyline": PolylineNode,
|
91
94
|
"elem image": ImageNode,
|
92
95
|
"elem text": TextNode,
|
96
|
+
"image raster": ImageRasterNode,
|
93
97
|
"reference": ReferenceNode,
|
94
98
|
"cutcode": CutNode,
|
95
99
|
"branch ops": BranchOperationsNode,
|