meerk40t 0.9.3001__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/__init__.py +1 -1
- meerk40t/balormk/balor_params.py +167 -167
- meerk40t/balormk/clone_loader.py +457 -457
- meerk40t/balormk/controller.py +1566 -1512
- meerk40t/balormk/cylindermod.py +64 -0
- meerk40t/balormk/device.py +966 -1959
- meerk40t/balormk/driver.py +778 -591
- meerk40t/balormk/galvo_commands.py +1194 -0
- meerk40t/balormk/gui/balorconfig.py +237 -111
- meerk40t/balormk/gui/balorcontroller.py +191 -184
- meerk40t/balormk/gui/baloroperationproperties.py +116 -115
- meerk40t/balormk/gui/corscene.py +845 -0
- meerk40t/balormk/gui/gui.py +179 -147
- meerk40t/balormk/livelightjob.py +466 -382
- meerk40t/balormk/mock_connection.py +131 -109
- meerk40t/balormk/plugin.py +133 -135
- meerk40t/balormk/usb_connection.py +306 -301
- meerk40t/camera/__init__.py +1 -1
- meerk40t/camera/camera.py +514 -397
- meerk40t/camera/gui/camerapanel.py +1241 -1095
- meerk40t/camera/gui/gui.py +58 -58
- meerk40t/camera/plugin.py +441 -399
- meerk40t/ch341/__init__.py +27 -27
- meerk40t/ch341/ch341device.py +628 -628
- meerk40t/ch341/libusb.py +595 -589
- meerk40t/ch341/mock.py +171 -171
- meerk40t/ch341/windriver.py +157 -157
- meerk40t/constants.py +13 -0
- meerk40t/core/__init__.py +1 -1
- meerk40t/core/bindalias.py +550 -539
- meerk40t/core/core.py +47 -47
- meerk40t/core/cutcode/cubiccut.py +73 -73
- meerk40t/core/cutcode/cutcode.py +315 -312
- meerk40t/core/cutcode/cutgroup.py +141 -137
- meerk40t/core/cutcode/cutobject.py +192 -185
- meerk40t/core/cutcode/dwellcut.py +37 -37
- meerk40t/core/cutcode/gotocut.py +29 -29
- meerk40t/core/cutcode/homecut.py +29 -29
- meerk40t/core/cutcode/inputcut.py +34 -34
- meerk40t/core/cutcode/linecut.py +33 -33
- meerk40t/core/cutcode/outputcut.py +34 -34
- meerk40t/core/cutcode/plotcut.py +335 -335
- meerk40t/core/cutcode/quadcut.py +61 -61
- meerk40t/core/cutcode/rastercut.py +168 -148
- meerk40t/core/cutcode/waitcut.py +34 -34
- meerk40t/core/cutplan.py +1843 -1316
- meerk40t/core/drivers.py +330 -329
- meerk40t/core/elements/align.py +801 -669
- meerk40t/core/elements/branches.py +1858 -1507
- meerk40t/core/elements/clipboard.py +229 -219
- meerk40t/core/elements/element_treeops.py +4595 -2837
- meerk40t/core/elements/element_types.py +125 -105
- meerk40t/core/elements/elements.py +4315 -3617
- meerk40t/core/elements/files.py +117 -64
- meerk40t/core/elements/geometry.py +473 -224
- meerk40t/core/elements/grid.py +467 -316
- meerk40t/core/elements/materials.py +158 -94
- meerk40t/core/elements/notes.py +50 -38
- meerk40t/core/elements/offset_clpr.py +934 -912
- meerk40t/core/elements/offset_mk.py +963 -955
- meerk40t/core/elements/penbox.py +339 -267
- meerk40t/core/elements/placements.py +300 -83
- meerk40t/core/elements/render.py +785 -687
- meerk40t/core/elements/shapes.py +2618 -2092
- meerk40t/core/elements/testcases.py +105 -0
- meerk40t/core/elements/trace.py +651 -563
- meerk40t/core/elements/tree_commands.py +415 -409
- meerk40t/core/elements/undo_redo.py +116 -58
- meerk40t/core/elements/wordlist.py +319 -200
- meerk40t/core/exceptions.py +9 -9
- meerk40t/core/laserjob.py +220 -220
- meerk40t/core/logging.py +63 -63
- meerk40t/core/node/blobnode.py +83 -86
- meerk40t/core/node/bootstrap.py +105 -103
- meerk40t/core/node/branch_elems.py +40 -31
- meerk40t/core/node/branch_ops.py +45 -38
- meerk40t/core/node/branch_regmark.py +48 -41
- meerk40t/core/node/cutnode.py +29 -32
- meerk40t/core/node/effect_hatch.py +375 -257
- meerk40t/core/node/effect_warp.py +398 -0
- meerk40t/core/node/effect_wobble.py +441 -309
- meerk40t/core/node/elem_ellipse.py +404 -309
- meerk40t/core/node/elem_image.py +1082 -801
- meerk40t/core/node/elem_line.py +358 -292
- meerk40t/core/node/elem_path.py +259 -201
- meerk40t/core/node/elem_point.py +129 -102
- meerk40t/core/node/elem_polyline.py +310 -246
- meerk40t/core/node/elem_rect.py +376 -286
- meerk40t/core/node/elem_text.py +445 -418
- meerk40t/core/node/filenode.py +59 -40
- meerk40t/core/node/groupnode.py +138 -74
- meerk40t/core/node/image_processed.py +777 -766
- meerk40t/core/node/image_raster.py +156 -113
- meerk40t/core/node/layernode.py +31 -31
- meerk40t/core/node/mixins.py +135 -107
- meerk40t/core/node/node.py +1427 -1304
- meerk40t/core/node/nutils.py +117 -114
- meerk40t/core/node/op_cut.py +463 -335
- meerk40t/core/node/op_dots.py +296 -251
- meerk40t/core/node/op_engrave.py +414 -311
- meerk40t/core/node/op_image.py +755 -369
- meerk40t/core/node/op_raster.py +787 -522
- meerk40t/core/node/place_current.py +37 -40
- meerk40t/core/node/place_point.py +329 -126
- meerk40t/core/node/refnode.py +58 -47
- meerk40t/core/node/rootnode.py +225 -219
- meerk40t/core/node/util_console.py +48 -48
- meerk40t/core/node/util_goto.py +84 -65
- meerk40t/core/node/util_home.py +61 -61
- meerk40t/core/node/util_input.py +102 -102
- meerk40t/core/node/util_output.py +102 -102
- meerk40t/core/node/util_wait.py +65 -65
- meerk40t/core/parameters.py +709 -707
- meerk40t/core/planner.py +875 -785
- meerk40t/core/plotplanner.py +656 -652
- meerk40t/core/space.py +120 -113
- meerk40t/core/spoolers.py +706 -705
- meerk40t/core/svg_io.py +1836 -1549
- meerk40t/core/treeop.py +534 -445
- meerk40t/core/undos.py +278 -124
- meerk40t/core/units.py +784 -680
- meerk40t/core/view.py +393 -322
- meerk40t/core/webhelp.py +62 -62
- meerk40t/core/wordlist.py +513 -504
- meerk40t/cylinder/cylinder.py +247 -0
- meerk40t/cylinder/gui/cylindersettings.py +41 -0
- meerk40t/cylinder/gui/gui.py +24 -0
- meerk40t/device/__init__.py +1 -1
- meerk40t/device/basedevice.py +322 -123
- meerk40t/device/devicechoices.py +50 -0
- meerk40t/device/dummydevice.py +163 -128
- meerk40t/device/gui/defaultactions.py +618 -602
- meerk40t/device/gui/effectspanel.py +114 -0
- meerk40t/device/gui/formatterpanel.py +253 -290
- meerk40t/device/gui/warningpanel.py +337 -260
- meerk40t/device/mixins.py +13 -13
- meerk40t/dxf/__init__.py +1 -1
- meerk40t/dxf/dxf_io.py +766 -554
- meerk40t/dxf/plugin.py +47 -35
- meerk40t/external_plugins.py +79 -79
- meerk40t/external_plugins_build.py +28 -28
- meerk40t/extra/cag.py +112 -116
- meerk40t/extra/coolant.py +403 -0
- meerk40t/extra/encode_detect.py +204 -0
- meerk40t/extra/ezd.py +1165 -1165
- meerk40t/extra/hershey.py +834 -340
- meerk40t/extra/imageactions.py +322 -316
- meerk40t/extra/inkscape.py +628 -622
- meerk40t/extra/lbrn.py +424 -424
- meerk40t/extra/outerworld.py +283 -0
- meerk40t/extra/param_functions.py +1542 -1556
- meerk40t/extra/potrace.py +257 -253
- meerk40t/extra/serial_exchange.py +118 -0
- meerk40t/extra/updater.py +602 -453
- meerk40t/extra/vectrace.py +147 -146
- meerk40t/extra/winsleep.py +83 -83
- meerk40t/extra/xcs_reader.py +597 -0
- meerk40t/fill/fills.py +781 -335
- meerk40t/fill/patternfill.py +1061 -1061
- meerk40t/fill/patterns.py +614 -567
- meerk40t/grbl/control.py +87 -87
- meerk40t/grbl/controller.py +990 -903
- meerk40t/grbl/device.py +1084 -768
- meerk40t/grbl/driver.py +989 -771
- meerk40t/grbl/emulator.py +532 -497
- meerk40t/grbl/gcodejob.py +783 -767
- meerk40t/grbl/gui/grblconfiguration.py +373 -298
- meerk40t/grbl/gui/grblcontroller.py +485 -271
- meerk40t/grbl/gui/grblhardwareconfig.py +269 -153
- meerk40t/grbl/gui/grbloperationconfig.py +105 -0
- meerk40t/grbl/gui/gui.py +147 -116
- meerk40t/grbl/interpreter.py +44 -44
- meerk40t/grbl/loader.py +22 -22
- meerk40t/grbl/mock_connection.py +56 -56
- meerk40t/grbl/plugin.py +294 -264
- meerk40t/grbl/serial_connection.py +93 -88
- meerk40t/grbl/tcp_connection.py +81 -79
- meerk40t/grbl/ws_connection.py +112 -0
- meerk40t/gui/__init__.py +1 -1
- meerk40t/gui/about.py +2042 -296
- meerk40t/gui/alignment.py +1644 -1608
- meerk40t/gui/autoexec.py +199 -0
- meerk40t/gui/basicops.py +791 -670
- meerk40t/gui/bufferview.py +77 -71
- meerk40t/gui/busy.py +232 -133
- meerk40t/gui/choicepropertypanel.py +1662 -1469
- meerk40t/gui/consolepanel.py +706 -542
- meerk40t/gui/devicepanel.py +687 -581
- meerk40t/gui/dialogoptions.py +110 -107
- meerk40t/gui/executejob.py +316 -306
- meerk40t/gui/fonts.py +90 -90
- meerk40t/gui/functionwrapper.py +252 -0
- meerk40t/gui/gui_mixins.py +729 -0
- meerk40t/gui/guicolors.py +205 -182
- meerk40t/gui/help_assets/help_assets.py +218 -201
- meerk40t/gui/helper.py +154 -0
- meerk40t/gui/hersheymanager.py +1440 -846
- meerk40t/gui/icons.py +3422 -2747
- meerk40t/gui/imagesplitter.py +555 -508
- meerk40t/gui/keymap.py +354 -344
- meerk40t/gui/laserpanel.py +897 -806
- meerk40t/gui/laserrender.py +1470 -1232
- meerk40t/gui/lasertoolpanel.py +805 -793
- meerk40t/gui/magnetoptions.py +436 -0
- meerk40t/gui/materialmanager.py +2944 -0
- meerk40t/gui/materialtest.py +1722 -1694
- meerk40t/gui/mkdebug.py +646 -359
- meerk40t/gui/mwindow.py +163 -140
- meerk40t/gui/navigationpanels.py +2605 -2467
- meerk40t/gui/notes.py +143 -142
- meerk40t/gui/opassignment.py +414 -410
- meerk40t/gui/operation_info.py +310 -299
- meerk40t/gui/plugin.py +500 -328
- meerk40t/gui/position.py +714 -669
- meerk40t/gui/preferences.py +901 -650
- meerk40t/gui/propertypanels/attributes.py +1461 -1131
- meerk40t/gui/propertypanels/blobproperty.py +117 -114
- meerk40t/gui/propertypanels/consoleproperty.py +83 -80
- meerk40t/gui/propertypanels/gotoproperty.py +77 -0
- meerk40t/gui/propertypanels/groupproperties.py +223 -217
- meerk40t/gui/propertypanels/hatchproperty.py +489 -469
- meerk40t/gui/propertypanels/imageproperty.py +2244 -1384
- meerk40t/gui/propertypanels/inputproperty.py +59 -58
- meerk40t/gui/propertypanels/opbranchproperties.py +82 -80
- meerk40t/gui/propertypanels/operationpropertymain.py +1890 -1638
- meerk40t/gui/propertypanels/outputproperty.py +59 -58
- meerk40t/gui/propertypanels/pathproperty.py +389 -380
- meerk40t/gui/propertypanels/placementproperty.py +1214 -383
- meerk40t/gui/propertypanels/pointproperty.py +140 -136
- meerk40t/gui/propertypanels/propertywindow.py +313 -181
- meerk40t/gui/propertypanels/rasterwizardpanels.py +996 -912
- meerk40t/gui/propertypanels/regbranchproperties.py +76 -0
- meerk40t/gui/propertypanels/textproperty.py +770 -755
- meerk40t/gui/propertypanels/waitproperty.py +56 -55
- meerk40t/gui/propertypanels/warpproperty.py +121 -0
- meerk40t/gui/propertypanels/wobbleproperty.py +255 -204
- meerk40t/gui/ribbon.py +2471 -2210
- meerk40t/gui/scene/scene.py +1100 -1051
- meerk40t/gui/scene/sceneconst.py +22 -22
- meerk40t/gui/scene/scenepanel.py +439 -349
- meerk40t/gui/scene/scenespacewidget.py +365 -365
- meerk40t/gui/scene/widget.py +518 -505
- meerk40t/gui/scenewidgets/affinemover.py +215 -215
- meerk40t/gui/scenewidgets/attractionwidget.py +315 -309
- meerk40t/gui/scenewidgets/bedwidget.py +120 -97
- meerk40t/gui/scenewidgets/elementswidget.py +137 -107
- meerk40t/gui/scenewidgets/gridwidget.py +785 -745
- meerk40t/gui/scenewidgets/guidewidget.py +765 -765
- meerk40t/gui/scenewidgets/laserpathwidget.py +66 -66
- meerk40t/gui/scenewidgets/machineoriginwidget.py +86 -86
- meerk40t/gui/scenewidgets/nodeselector.py +28 -28
- meerk40t/gui/scenewidgets/rectselectwidget.py +592 -346
- meerk40t/gui/scenewidgets/relocatewidget.py +33 -33
- meerk40t/gui/scenewidgets/reticlewidget.py +83 -83
- meerk40t/gui/scenewidgets/selectionwidget.py +2958 -2756
- meerk40t/gui/simpleui.py +362 -333
- meerk40t/gui/simulation.py +2451 -2094
- meerk40t/gui/snapoptions.py +208 -203
- meerk40t/gui/spoolerpanel.py +1227 -1180
- meerk40t/gui/statusbarwidgets/defaultoperations.py +480 -353
- meerk40t/gui/statusbarwidgets/infowidget.py +520 -483
- meerk40t/gui/statusbarwidgets/opassignwidget.py +356 -355
- meerk40t/gui/statusbarwidgets/selectionwidget.py +172 -171
- meerk40t/gui/statusbarwidgets/shapepropwidget.py +754 -236
- meerk40t/gui/statusbarwidgets/statusbar.py +272 -260
- meerk40t/gui/statusbarwidgets/statusbarwidget.py +268 -270
- meerk40t/gui/statusbarwidgets/strokewidget.py +267 -251
- meerk40t/gui/themes.py +200 -78
- meerk40t/gui/tips.py +590 -0
- meerk40t/gui/toolwidgets/circlebrush.py +35 -35
- meerk40t/gui/toolwidgets/toolcircle.py +248 -242
- meerk40t/gui/toolwidgets/toolcontainer.py +82 -77
- meerk40t/gui/toolwidgets/tooldraw.py +97 -90
- meerk40t/gui/toolwidgets/toolellipse.py +219 -212
- meerk40t/gui/toolwidgets/toolimagecut.py +25 -132
- meerk40t/gui/toolwidgets/toolline.py +39 -144
- meerk40t/gui/toolwidgets/toollinetext.py +79 -236
- meerk40t/gui/toolwidgets/toollinetext_inline.py +296 -0
- meerk40t/gui/toolwidgets/toolmeasure.py +163 -216
- meerk40t/gui/toolwidgets/toolnodeedit.py +2088 -2074
- meerk40t/gui/toolwidgets/toolnodemove.py +92 -94
- meerk40t/gui/toolwidgets/toolparameter.py +754 -668
- meerk40t/gui/toolwidgets/toolplacement.py +108 -108
- meerk40t/gui/toolwidgets/toolpoint.py +68 -59
- meerk40t/gui/toolwidgets/toolpointlistbuilder.py +294 -0
- meerk40t/gui/toolwidgets/toolpointmove.py +183 -0
- meerk40t/gui/toolwidgets/toolpolygon.py +288 -403
- meerk40t/gui/toolwidgets/toolpolyline.py +38 -196
- meerk40t/gui/toolwidgets/toolrect.py +211 -207
- meerk40t/gui/toolwidgets/toolrelocate.py +72 -72
- meerk40t/gui/toolwidgets/toolribbon.py +598 -113
- meerk40t/gui/toolwidgets/tooltabedit.py +546 -0
- meerk40t/gui/toolwidgets/tooltext.py +98 -89
- meerk40t/gui/toolwidgets/toolvector.py +213 -204
- meerk40t/gui/toolwidgets/toolwidget.py +39 -39
- meerk40t/gui/usbconnect.py +98 -91
- meerk40t/gui/utilitywidgets/buttonwidget.py +18 -18
- meerk40t/gui/utilitywidgets/checkboxwidget.py +90 -90
- meerk40t/gui/utilitywidgets/controlwidget.py +14 -14
- meerk40t/gui/utilitywidgets/cyclocycloidwidget.py +343 -340
- meerk40t/gui/utilitywidgets/debugwidgets.py +148 -0
- meerk40t/gui/utilitywidgets/handlewidget.py +27 -27
- meerk40t/gui/utilitywidgets/harmonograph.py +450 -447
- meerk40t/gui/utilitywidgets/openclosewidget.py +40 -40
- meerk40t/gui/utilitywidgets/rotationwidget.py +54 -54
- meerk40t/gui/utilitywidgets/scalewidget.py +75 -75
- meerk40t/gui/utilitywidgets/seekbarwidget.py +183 -183
- meerk40t/gui/utilitywidgets/togglewidget.py +142 -142
- meerk40t/gui/utilitywidgets/toolbarwidget.py +8 -8
- meerk40t/gui/wordlisteditor.py +985 -931
- meerk40t/gui/wxmeerk40t.py +1447 -1169
- meerk40t/gui/wxmmain.py +5644 -4112
- meerk40t/gui/wxmribbon.py +1591 -1076
- meerk40t/gui/wxmscene.py +1631 -1453
- meerk40t/gui/wxmtree.py +2416 -2089
- meerk40t/gui/wxutils.py +1769 -1099
- meerk40t/gui/zmatrix.py +102 -102
- meerk40t/image/__init__.py +1 -1
- meerk40t/image/dither.py +429 -0
- meerk40t/image/imagetools.py +2793 -2269
- meerk40t/internal_plugins.py +150 -130
- meerk40t/kernel/__init__.py +63 -12
- meerk40t/kernel/channel.py +259 -212
- meerk40t/kernel/context.py +538 -538
- meerk40t/kernel/exceptions.py +41 -41
- meerk40t/kernel/functions.py +463 -414
- meerk40t/kernel/jobs.py +100 -100
- meerk40t/kernel/kernel.py +3828 -3571
- meerk40t/kernel/lifecycles.py +71 -71
- meerk40t/kernel/module.py +49 -49
- meerk40t/kernel/service.py +147 -147
- meerk40t/kernel/settings.py +383 -343
- meerk40t/lihuiyu/controller.py +883 -876
- meerk40t/lihuiyu/device.py +1181 -1069
- meerk40t/lihuiyu/driver.py +1466 -1372
- meerk40t/lihuiyu/gui/gui.py +127 -106
- meerk40t/lihuiyu/gui/lhyaccelgui.py +377 -363
- meerk40t/lihuiyu/gui/lhycontrollergui.py +741 -651
- meerk40t/lihuiyu/gui/lhydrivergui.py +470 -446
- meerk40t/lihuiyu/gui/lhyoperationproperties.py +238 -237
- meerk40t/lihuiyu/gui/tcpcontroller.py +226 -190
- meerk40t/lihuiyu/interpreter.py +53 -53
- meerk40t/lihuiyu/laserspeed.py +450 -450
- meerk40t/lihuiyu/loader.py +90 -90
- meerk40t/lihuiyu/parser.py +404 -404
- meerk40t/lihuiyu/plugin.py +101 -102
- meerk40t/lihuiyu/tcp_connection.py +111 -109
- meerk40t/main.py +231 -165
- meerk40t/moshi/builder.py +788 -781
- meerk40t/moshi/controller.py +505 -499
- meerk40t/moshi/device.py +495 -442
- meerk40t/moshi/driver.py +862 -696
- meerk40t/moshi/gui/gui.py +78 -76
- meerk40t/moshi/gui/moshicontrollergui.py +538 -522
- meerk40t/moshi/gui/moshidrivergui.py +87 -75
- meerk40t/moshi/plugin.py +43 -43
- meerk40t/network/console_server.py +140 -57
- meerk40t/network/kernelserver.py +10 -9
- meerk40t/network/tcp_server.py +142 -140
- meerk40t/network/udp_server.py +103 -77
- meerk40t/network/web_server.py +404 -0
- meerk40t/newly/controller.py +1158 -1144
- meerk40t/newly/device.py +874 -732
- meerk40t/newly/driver.py +540 -412
- meerk40t/newly/gui/gui.py +219 -188
- meerk40t/newly/gui/newlyconfig.py +116 -101
- meerk40t/newly/gui/newlycontroller.py +193 -186
- meerk40t/newly/gui/operationproperties.py +51 -51
- meerk40t/newly/mock_connection.py +82 -82
- meerk40t/newly/newly_params.py +56 -56
- meerk40t/newly/plugin.py +1214 -1246
- meerk40t/newly/usb_connection.py +322 -322
- meerk40t/rotary/gui/gui.py +52 -46
- meerk40t/rotary/gui/rotarysettings.py +240 -232
- meerk40t/rotary/rotary.py +202 -98
- meerk40t/ruida/control.py +291 -91
- meerk40t/ruida/controller.py +138 -1088
- meerk40t/ruida/device.py +676 -231
- meerk40t/ruida/driver.py +534 -472
- meerk40t/ruida/emulator.py +1494 -1491
- meerk40t/ruida/exceptions.py +4 -4
- meerk40t/ruida/gui/gui.py +71 -76
- meerk40t/ruida/gui/ruidaconfig.py +239 -72
- meerk40t/ruida/gui/ruidacontroller.py +187 -184
- meerk40t/ruida/gui/ruidaoperationproperties.py +48 -47
- meerk40t/ruida/loader.py +54 -52
- meerk40t/ruida/mock_connection.py +57 -109
- meerk40t/ruida/plugin.py +124 -87
- meerk40t/ruida/rdjob.py +2084 -945
- meerk40t/ruida/serial_connection.py +116 -0
- meerk40t/ruida/tcp_connection.py +146 -0
- meerk40t/ruida/udp_connection.py +73 -0
- meerk40t/svgelements.py +9671 -9669
- meerk40t/tools/driver_to_path.py +584 -579
- meerk40t/tools/geomstr.py +5583 -4680
- meerk40t/tools/jhfparser.py +357 -292
- meerk40t/tools/kerftest.py +904 -890
- meerk40t/tools/livinghinges.py +1168 -1033
- meerk40t/tools/pathtools.py +987 -949
- meerk40t/tools/pmatrix.py +234 -0
- meerk40t/tools/pointfinder.py +942 -942
- meerk40t/tools/polybool.py +941 -940
- meerk40t/tools/rasterplotter.py +1660 -547
- meerk40t/tools/shxparser.py +1047 -901
- meerk40t/tools/ttfparser.py +726 -446
- meerk40t/tools/zinglplotter.py +595 -593
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/LICENSE +21 -21
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/METADATA +150 -139
- meerk40t-0.9.7020.dist-info/RECORD +446 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/top_level.txt +0 -1
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/zip-safe +1 -1
- meerk40t/balormk/elementlightjob.py +0 -159
- meerk40t-0.9.3001.dist-info/RECORD +0 -437
- test/bootstrap.py +0 -63
- test/test_cli.py +0 -12
- test/test_core_cutcode.py +0 -418
- test/test_core_elements.py +0 -144
- test/test_core_plotplanner.py +0 -397
- test/test_core_viewports.py +0 -312
- test/test_drivers_grbl.py +0 -108
- test/test_drivers_lihuiyu.py +0 -443
- test/test_drivers_newly.py +0 -113
- test/test_element_degenerate_points.py +0 -43
- test/test_elements_classify.py +0 -97
- test/test_elements_penbox.py +0 -22
- test/test_file_svg.py +0 -176
- test/test_fill.py +0 -155
- test/test_geomstr.py +0 -1523
- test/test_geomstr_nodes.py +0 -18
- test/test_imagetools_actualize.py +0 -306
- test/test_imagetools_wizard.py +0 -258
- test/test_kernel.py +0 -200
- test/test_laser_speeds.py +0 -3303
- test/test_length.py +0 -57
- test/test_lifecycle.py +0 -66
- test/test_operations.py +0 -251
- test/test_operations_hatch.py +0 -57
- test/test_ruida.py +0 -19
- test/test_spooler.py +0 -22
- test/test_tools_rasterplotter.py +0 -29
- test/test_wobble.py +0 -133
- test/test_zingl.py +0 -124
- {test → meerk40t/cylinder}/__init__.py +0 -0
- /meerk40t/{core/element_commands.py → cylinder/gui/__init__.py} +0 -0
- {meerk40t-0.9.3001.dist-info → meerk40t-0.9.7020.dist-info}/entry_points.txt +0 -0
meerk40t/core/planner.py
CHANGED
@@ -1,785 +1,875 @@
|
|
1
|
-
from copy import copy
|
2
|
-
|
3
|
-
from meerk40t.kernel import Service
|
4
|
-
|
5
|
-
from ..core.cutcode.cutcode import CutCode
|
6
|
-
from .cutplan import CutPlan, CutPlanningFailedError
|
7
|
-
from .node.op_cut import CutOpNode
|
8
|
-
from .node.op_dots import DotsOpNode
|
9
|
-
from .node.op_engrave import EngraveOpNode
|
10
|
-
from .node.op_image import ImageOpNode
|
11
|
-
from .node.op_raster import RasterOpNode
|
12
|
-
from .node.util_console import ConsoleOperation
|
13
|
-
from .node.util_goto import GotoOperation
|
14
|
-
from .node.util_home import HomeOperation
|
15
|
-
from .node.util_output import OutputOperation
|
16
|
-
from .node.util_wait import WaitOperation
|
17
|
-
from .units import Length
|
18
|
-
|
19
|
-
"""
|
20
|
-
The planner module provides cut planning services. This provides a method of going from operations + elements into
|
21
|
-
cutcode which is then put inside a laserjob and sent to a spooler. Most of these operations are called on the
|
22
|
-
individual CutPlan objects.
|
23
|
-
"""
|
24
|
-
|
25
|
-
|
26
|
-
def plugin(kernel, lifecycle=None):
|
27
|
-
if lifecycle == "register":
|
28
|
-
kernel.add_service("planner", Planner(kernel))
|
29
|
-
|
30
|
-
elif lifecycle == "boot":
|
31
|
-
context = kernel.get_context("planner") # specifically get this planner context
|
32
|
-
_ = context._
|
33
|
-
choices = [
|
34
|
-
{
|
35
|
-
"attr": "auto_spooler",
|
36
|
-
"object": context,
|
37
|
-
"default": True,
|
38
|
-
"type": bool,
|
39
|
-
"label": _("Launch Spooler on Job Start"),
|
40
|
-
"tip": _(
|
41
|
-
"Open the Spooler window automatically when you Execute a Job"
|
42
|
-
),
|
43
|
-
},
|
44
|
-
]
|
45
|
-
kernel.register_choices("planner", choices)
|
46
|
-
|
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 (
|
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
|
-
},
|
78
|
-
{
|
79
|
-
"attr": "opt_reduce_travel",
|
80
|
-
"object": context,
|
81
|
-
"default": True,
|
82
|
-
"type": bool,
|
83
|
-
"label": _("Reduce Travel Time"),
|
84
|
-
"tip": _(
|
85
|
-
"Using this option can significantly reduce the time spent "
|
86
|
-
+ "moving between elements with the laser off "
|
87
|
-
+ "by optimizing the sequence that elements are burned. "
|
88
|
-
)
|
89
|
-
+ "\n\n"
|
90
|
-
+ _(
|
91
|
-
"When this option is NOT checked, elements are burned strictly "
|
92
|
-
+ "in the order they appear in the Operation tree, "
|
93
|
-
+ "and the Merge options will have no effect on the burn time. "
|
94
|
-
)
|
95
|
-
+ "\n\n"
|
96
|
-
+ _(
|
97
|
-
"When this option IS checked, Meerk40t will burn each subpath "
|
98
|
-
+ "and then move to the nearest remaining subpath instead, "
|
99
|
-
+ "reducing the time taken moving between burn items."
|
100
|
-
),
|
101
|
-
"page": "Optimisations",
|
102
|
-
"section": "_20_Reducing Movements",
|
103
|
-
},
|
104
|
-
{
|
105
|
-
"attr": "opt_complete_subpaths",
|
106
|
-
"object": context,
|
107
|
-
"default": True,
|
108
|
-
"type": bool,
|
109
|
-
"label": _("Burn Complete Subpaths"),
|
110
|
-
"tip": _(
|
111
|
-
"By default Reduce Travel Time optimises using SVG individual path segments, "
|
112
|
-
+ "which means that non-closed subpaths can be burned in several shorter separate burns "
|
113
|
-
+ "rather than one continuous burn from start to end. "
|
114
|
-
)
|
115
|
-
+ "\n\n"
|
116
|
-
+ _(
|
117
|
-
"This option only affects non-closed paths. "
|
118
|
-
+ "When this option is checked, non-closed subpaths are always burned in one continuous burn "
|
119
|
-
+ "from start to end rather than having burns start in the middle. "
|
120
|
-
+ "Whilst this may create a longer travel move to the end of the subpath,"
|
121
|
-
+ "it also avoids later travel moves to or from the intermediate point. "
|
122
|
-
+ "The total travel time may therefore be shorter or longer. "
|
123
|
-
+ "It may also avoid minor differences in total burn depth "
|
124
|
-
+ "at the point the burns join. "
|
125
|
-
),
|
126
|
-
"page": "Optimisations",
|
127
|
-
"section": "_20_Reducing Movements",
|
128
|
-
"conditional": (context, "opt_reduce_travel"),
|
129
|
-
},
|
130
|
-
{
|
131
|
-
"attr": "opt_merge_passes",
|
132
|
-
"object": context,
|
133
|
-
"default": False,
|
134
|
-
"type": bool,
|
135
|
-
"label": _("Merge Passes"),
|
136
|
-
"tip": _(
|
137
|
-
"Combine multiple passes into the same optimization. "
|
138
|
-
+ "This will typically result in each subpath being burned multiple times in succession, "
|
139
|
-
+ "burning closed paths round-and-round "
|
140
|
-
+ "and non-closed paths back-and-forth, "
|
141
|
-
+ "before Meerk40t moves to the next path. "
|
142
|
-
)
|
143
|
-
+ "\n\n"
|
144
|
-
+ _(
|
145
|
-
"If you have a complex design with many paths and are burning with multiple passes, "
|
146
|
-
+ "using this option can significantly REDUCE the optimisation time. "
|
147
|
-
)
|
148
|
-
+ "\n\n"
|
149
|
-
+ _(
|
150
|
-
"NOTE: Where you burn very short paths multiple times in quick succession, "
|
151
|
-
+ "this does not allow time for the material to cool down between burns, "
|
152
|
-
+ "and this can result in greater charring "
|
153
|
-
+ "or even an increased risk of the material catching fire."
|
154
|
-
),
|
155
|
-
"page": "Optimisations",
|
156
|
-
"section": "_20_Reducing Movements",
|
157
|
-
"conditional": (context, "opt_reduce_travel"),
|
158
|
-
},
|
159
|
-
{
|
160
|
-
"attr": "opt_merge_ops",
|
161
|
-
"object": context,
|
162
|
-
"default": False,
|
163
|
-
"type": bool,
|
164
|
-
"label": _("Merge Operations"),
|
165
|
-
"tip": _(
|
166
|
-
"Combine multiple consecutive burn operations and optimise across them globally. "
|
167
|
-
+ "Operations of different types will be optimised together to reduce travel time, "
|
168
|
-
+ "so vector and raster burns will be mixed. "
|
169
|
-
)
|
170
|
-
+ "\n\n"
|
171
|
-
+ _(
|
172
|
-
"If Merge Passes is not checked, Operations with >1 passes will only have the same passes merged. "
|
173
|
-
+ "If Merge Passes is also checked, then all burns will be optimised globally."
|
174
|
-
)
|
175
|
-
+ "\n\n"
|
176
|
-
+ _(
|
177
|
-
"If you have a complex design with many paths across multiple consecutive burn operations, "
|
178
|
-
+ "using this option can significantly INCREASE the optimisation time. "
|
179
|
-
),
|
180
|
-
"page": "Optimisations",
|
181
|
-
"section": "_20_Reducing Movements",
|
182
|
-
"conditional": (context, "opt_reduce_travel"),
|
183
|
-
},
|
184
|
-
{
|
185
|
-
"attr": "opt_inner_first",
|
186
|
-
"object": context,
|
187
|
-
"default": True,
|
188
|
-
"type": bool,
|
189
|
-
"label": _("Burn Inner First"),
|
190
|
-
"tip": _(
|
191
|
-
"Ensure that inside burns are done before an outside cut in order to ensure that burns inside "
|
192
|
-
+ "a cut-out piece are done before the cut piece shifts or drops out of the material."
|
193
|
-
)
|
194
|
-
+ "\n\n"
|
195
|
-
+ _(
|
196
|
-
"If you find that using this option significantly increases the optimisation time, "
|
197
|
-
+ "alternatives are: \n"
|
198
|
-
+ "* Deselecting Cut Inner First if you are not cutting fully through your material \n"
|
199
|
-
+ "* Putting the inner paths into a separate earlier operation(s) and not using Merge Operations or Cut Inner First \n"
|
200
|
-
+ "* If you are using multiple passes, check Merge Passes"
|
201
|
-
),
|
202
|
-
"page": "Optimisations",
|
203
|
-
"section": "_10_Burn sequence",
|
204
|
-
},
|
205
|
-
{
|
206
|
-
"attr": "opt_inner_tolerance",
|
207
|
-
"object": context,
|
208
|
-
"default": "0",
|
209
|
-
"type": Length,
|
210
|
-
"label": _("Tolerance"),
|
211
|
-
"tip": _("Tolerance to decide if a shape is truly inside another one."),
|
212
|
-
"page": "Optimisations",
|
213
|
-
"section": "_10_Burn sequence",
|
214
|
-
"conditional": (context, "opt_inner_first"),
|
215
|
-
},
|
216
|
-
{
|
217
|
-
"attr": "opt_inners_grouped",
|
218
|
-
"object": context,
|
219
|
-
"default": False,
|
220
|
-
"type": bool,
|
221
|
-
"label": _("Group Inner Burns"),
|
222
|
-
"tip": _(
|
223
|
-
"Try to complete a set of inner burns and the associated outer cut before moving onto other elements.\n"
|
224
|
-
+ "This option only does something if Burn Inner First is also selected. "
|
225
|
-
+ "If your design has multiple separate pieces on it, "
|
226
|
-
+ "this should mostly cause each piece to be burned in entirety "
|
227
|
-
+ "before moving on to burn another piece. "
|
228
|
-
+ "This can reduce the risk of e.g. a shift ruining an entire piece of material "
|
229
|
-
+ "by trying to ensure that one piece is finished before starting on another."
|
230
|
-
)
|
231
|
-
+ "\n\n"
|
232
|
-
+ _(
|
233
|
-
"This optimization works best with Merge Operations also checked though this is not a requirement. "
|
234
|
-
)
|
235
|
-
+ "\n\n"
|
236
|
-
+ _(
|
237
|
-
"Because this optimisation is done once rasters have been turned into images, "
|
238
|
-
+ "inner elements may span multiple design pieces, "
|
239
|
-
+ "in which case they may be optimised together."
|
240
|
-
),
|
241
|
-
"page": "Optimisations",
|
242
|
-
"section": "_10_Burn sequence",
|
243
|
-
"conditional": (context, "opt_inner_first"),
|
244
|
-
},
|
245
|
-
{
|
246
|
-
"attr": "opt_closed_distance",
|
247
|
-
"object": context,
|
248
|
-
"default": 15,
|
249
|
-
"type": int,
|
250
|
-
"label": _("Closed Distance"),
|
251
|
-
"tip": _(
|
252
|
-
"How close in device specific natural units do endpoints need to be to count as closed?"
|
253
|
-
),
|
254
|
-
"page": "Optimisations",
|
255
|
-
"section": "_20_Reducing Movements",
|
256
|
-
"hidden": True,
|
257
|
-
},
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
)
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
"
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
)
|
630
|
-
def
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
return data_type, data
|
657
|
-
|
658
|
-
@self.console_command(
|
659
|
-
"
|
660
|
-
help=_("plan<?>
|
661
|
-
input_type="plan",
|
662
|
-
output_type="plan",
|
663
|
-
)
|
664
|
-
def
|
665
|
-
# Update Info-panel if displayed
|
666
|
-
busy = self.kernel.busyinfo
|
667
|
-
if busy.shown:
|
668
|
-
busy.change(msg=_("
|
669
|
-
busy.show()
|
670
|
-
|
671
|
-
data.
|
672
|
-
self.signal("plan", data.name,
|
673
|
-
return data_type, data
|
674
|
-
|
675
|
-
@self.console_command(
|
676
|
-
"
|
677
|
-
help=_("plan<?>
|
678
|
-
input_type="plan",
|
679
|
-
output_type="plan",
|
680
|
-
)
|
681
|
-
def
|
682
|
-
# Update Info-panel if displayed
|
683
|
-
busy = self.kernel.busyinfo
|
684
|
-
if busy.shown:
|
685
|
-
busy.change(msg=_("
|
686
|
-
busy.show()
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
"
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
1
|
+
from copy import copy
|
2
|
+
|
3
|
+
from meerk40t.kernel import Service
|
4
|
+
|
5
|
+
from ..core.cutcode.cutcode import CutCode
|
6
|
+
from .cutplan import CutPlan, CutPlanningFailedError
|
7
|
+
from .node.op_cut import CutOpNode
|
8
|
+
from .node.op_dots import DotsOpNode
|
9
|
+
from .node.op_engrave import EngraveOpNode
|
10
|
+
from .node.op_image import ImageOpNode
|
11
|
+
from .node.op_raster import RasterOpNode
|
12
|
+
from .node.util_console import ConsoleOperation
|
13
|
+
from .node.util_goto import GotoOperation
|
14
|
+
from .node.util_home import HomeOperation
|
15
|
+
from .node.util_output import OutputOperation
|
16
|
+
from .node.util_wait import WaitOperation
|
17
|
+
from .units import Length
|
18
|
+
|
19
|
+
"""
|
20
|
+
The planner module provides cut planning services. This provides a method of going from operations + elements into
|
21
|
+
cutcode which is then put inside a laserjob and sent to a spooler. Most of these operations are called on the
|
22
|
+
individual CutPlan objects.
|
23
|
+
"""
|
24
|
+
|
25
|
+
|
26
|
+
def plugin(kernel, lifecycle=None):
|
27
|
+
if lifecycle == "register":
|
28
|
+
kernel.add_service("planner", Planner(kernel))
|
29
|
+
|
30
|
+
elif lifecycle == "boot":
|
31
|
+
context = kernel.get_context("planner") # specifically get this planner context
|
32
|
+
_ = context._
|
33
|
+
choices = [
|
34
|
+
{
|
35
|
+
"attr": "auto_spooler",
|
36
|
+
"object": context,
|
37
|
+
"default": True,
|
38
|
+
"type": bool,
|
39
|
+
"label": _("Launch Spooler on Job Start"),
|
40
|
+
"tip": _(
|
41
|
+
"Open the Spooler window automatically when you Execute a Job"
|
42
|
+
),
|
43
|
+
},
|
44
|
+
]
|
45
|
+
kernel.register_choices("planner", choices)
|
46
|
+
|
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 (i.e. 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
|
+
},
|
78
|
+
{
|
79
|
+
"attr": "opt_reduce_travel",
|
80
|
+
"object": context,
|
81
|
+
"default": True,
|
82
|
+
"type": bool,
|
83
|
+
"label": _("Reduce Travel Time"),
|
84
|
+
"tip": _(
|
85
|
+
"Using this option can significantly reduce the time spent "
|
86
|
+
+ "moving between elements with the laser off "
|
87
|
+
+ "by optimizing the sequence that elements are burned. "
|
88
|
+
)
|
89
|
+
+ "\n\n"
|
90
|
+
+ _(
|
91
|
+
"When this option is NOT checked, elements are burned strictly "
|
92
|
+
+ "in the order they appear in the Operation tree, "
|
93
|
+
+ "and the Merge options will have no effect on the burn time. "
|
94
|
+
)
|
95
|
+
+ "\n\n"
|
96
|
+
+ _(
|
97
|
+
"When this option IS checked, Meerk40t will burn each subpath "
|
98
|
+
+ "and then move to the nearest remaining subpath instead, "
|
99
|
+
+ "reducing the time taken moving between burn items."
|
100
|
+
),
|
101
|
+
"page": "Optimisations",
|
102
|
+
"section": "_20_Reducing Movements",
|
103
|
+
},
|
104
|
+
{
|
105
|
+
"attr": "opt_complete_subpaths",
|
106
|
+
"object": context,
|
107
|
+
"default": True,
|
108
|
+
"type": bool,
|
109
|
+
"label": _("Burn Complete Subpaths"),
|
110
|
+
"tip": _(
|
111
|
+
"By default Reduce Travel Time optimises using SVG individual path segments, "
|
112
|
+
+ "which means that non-closed subpaths can be burned in several shorter separate burns "
|
113
|
+
+ "rather than one continuous burn from start to end. "
|
114
|
+
)
|
115
|
+
+ "\n\n"
|
116
|
+
+ _(
|
117
|
+
"This option only affects non-closed paths. "
|
118
|
+
+ "When this option is checked, non-closed subpaths are always burned in one continuous burn "
|
119
|
+
+ "from start to end rather than having burns start in the middle. "
|
120
|
+
+ "Whilst this may create a longer travel move to the end of the subpath,"
|
121
|
+
+ "it also avoids later travel moves to or from the intermediate point. "
|
122
|
+
+ "The total travel time may therefore be shorter or longer. "
|
123
|
+
+ "It may also avoid minor differences in total burn depth "
|
124
|
+
+ "at the point the burns join. "
|
125
|
+
),
|
126
|
+
"page": "Optimisations",
|
127
|
+
"section": "_20_Reducing Movements",
|
128
|
+
"conditional": (context, "opt_reduce_travel"),
|
129
|
+
},
|
130
|
+
{
|
131
|
+
"attr": "opt_merge_passes",
|
132
|
+
"object": context,
|
133
|
+
"default": False,
|
134
|
+
"type": bool,
|
135
|
+
"label": _("Merge Passes"),
|
136
|
+
"tip": _(
|
137
|
+
"Combine multiple passes into the same optimization. "
|
138
|
+
+ "This will typically result in each subpath being burned multiple times in succession, "
|
139
|
+
+ "burning closed paths round-and-round "
|
140
|
+
+ "and non-closed paths back-and-forth, "
|
141
|
+
+ "before Meerk40t moves to the next path. "
|
142
|
+
)
|
143
|
+
+ "\n\n"
|
144
|
+
+ _(
|
145
|
+
"If you have a complex design with many paths and are burning with multiple passes, "
|
146
|
+
+ "using this option can significantly REDUCE the optimisation time. "
|
147
|
+
)
|
148
|
+
+ "\n\n"
|
149
|
+
+ _(
|
150
|
+
"NOTE: Where you burn very short paths multiple times in quick succession, "
|
151
|
+
+ "this does not allow time for the material to cool down between burns, "
|
152
|
+
+ "and this can result in greater charring "
|
153
|
+
+ "or even an increased risk of the material catching fire."
|
154
|
+
),
|
155
|
+
"page": "Optimisations",
|
156
|
+
"section": "_20_Reducing Movements",
|
157
|
+
"conditional": (context, "opt_reduce_travel"),
|
158
|
+
},
|
159
|
+
{
|
160
|
+
"attr": "opt_merge_ops",
|
161
|
+
"object": context,
|
162
|
+
"default": False,
|
163
|
+
"type": bool,
|
164
|
+
"label": _("Merge Operations"),
|
165
|
+
"tip": _(
|
166
|
+
"Combine multiple consecutive burn operations and optimise across them globally. "
|
167
|
+
+ "Operations of different types will be optimised together to reduce travel time, "
|
168
|
+
+ "so vector and raster burns will be mixed. "
|
169
|
+
)
|
170
|
+
+ "\n\n"
|
171
|
+
+ _(
|
172
|
+
"If Merge Passes is not checked, Operations with >1 passes will only have the same passes merged. "
|
173
|
+
+ "If Merge Passes is also checked, then all burns will be optimised globally."
|
174
|
+
)
|
175
|
+
+ "\n\n"
|
176
|
+
+ _(
|
177
|
+
"If you have a complex design with many paths across multiple consecutive burn operations, "
|
178
|
+
+ "using this option can significantly INCREASE the optimisation time. "
|
179
|
+
),
|
180
|
+
"page": "Optimisations",
|
181
|
+
"section": "_20_Reducing Movements",
|
182
|
+
"conditional": (context, "opt_reduce_travel"),
|
183
|
+
},
|
184
|
+
{
|
185
|
+
"attr": "opt_inner_first",
|
186
|
+
"object": context,
|
187
|
+
"default": True,
|
188
|
+
"type": bool,
|
189
|
+
"label": _("Burn Inner First"),
|
190
|
+
"tip": _(
|
191
|
+
"Ensure that inside burns are done before an outside cut in order to ensure that burns inside "
|
192
|
+
+ "a cut-out piece are done before the cut piece shifts or drops out of the material."
|
193
|
+
)
|
194
|
+
+ "\n\n"
|
195
|
+
+ _(
|
196
|
+
"If you find that using this option significantly increases the optimisation time, "
|
197
|
+
+ "alternatives are: \n"
|
198
|
+
+ "* Deselecting Cut Inner First if you are not cutting fully through your material \n"
|
199
|
+
+ "* Putting the inner paths into a separate earlier operation(s) and not using Merge Operations or Cut Inner First \n"
|
200
|
+
+ "* If you are using multiple passes, check Merge Passes"
|
201
|
+
),
|
202
|
+
"page": "Optimisations",
|
203
|
+
"section": "_10_Burn sequence",
|
204
|
+
},
|
205
|
+
{
|
206
|
+
"attr": "opt_inner_tolerance",
|
207
|
+
"object": context,
|
208
|
+
"default": "0",
|
209
|
+
"type": Length,
|
210
|
+
"label": _("Tolerance"),
|
211
|
+
"tip": _("Tolerance to decide if a shape is truly inside another one."),
|
212
|
+
"page": "Optimisations",
|
213
|
+
"section": "_10_Burn sequence",
|
214
|
+
"conditional": (context, "opt_inner_first"),
|
215
|
+
},
|
216
|
+
{
|
217
|
+
"attr": "opt_inners_grouped",
|
218
|
+
"object": context,
|
219
|
+
"default": False,
|
220
|
+
"type": bool,
|
221
|
+
"label": _("Group Inner Burns"),
|
222
|
+
"tip": _(
|
223
|
+
"Try to complete a set of inner burns and the associated outer cut before moving onto other elements.\n"
|
224
|
+
+ "This option only does something if Burn Inner First is also selected. "
|
225
|
+
+ "If your design has multiple separate pieces on it, "
|
226
|
+
+ "this should mostly cause each piece to be burned in entirety "
|
227
|
+
+ "before moving on to burn another piece. "
|
228
|
+
+ "This can reduce the risk of e.g. a shift ruining an entire piece of material "
|
229
|
+
+ "by trying to ensure that one piece is finished before starting on another."
|
230
|
+
)
|
231
|
+
+ "\n\n"
|
232
|
+
+ _(
|
233
|
+
"This optimization works best with Merge Operations also checked though this is not a requirement. "
|
234
|
+
)
|
235
|
+
+ "\n\n"
|
236
|
+
+ _(
|
237
|
+
"Because this optimisation is done once rasters have been turned into images, "
|
238
|
+
+ "inner elements may span multiple design pieces, "
|
239
|
+
+ "in which case they may be optimised together."
|
240
|
+
),
|
241
|
+
"page": "Optimisations",
|
242
|
+
"section": "_10_Burn sequence",
|
243
|
+
"conditional": (context, "opt_inner_first"),
|
244
|
+
},
|
245
|
+
{
|
246
|
+
"attr": "opt_closed_distance",
|
247
|
+
"object": context,
|
248
|
+
"default": 15,
|
249
|
+
"type": int,
|
250
|
+
"label": _("Closed Distance"),
|
251
|
+
"tip": _(
|
252
|
+
"How close in device specific natural units do endpoints need to be to count as closed?"
|
253
|
+
),
|
254
|
+
"page": "Optimisations",
|
255
|
+
"section": "_20_Reducing Movements",
|
256
|
+
"hidden": True,
|
257
|
+
},
|
258
|
+
{
|
259
|
+
"attr": "opt_effect_combine",
|
260
|
+
"object": context,
|
261
|
+
"default": True,
|
262
|
+
"type": bool,
|
263
|
+
"label": _("Keep effect lines together"),
|
264
|
+
"tip": (
|
265
|
+
_("Active: effects like hatches are dealt with as a bigger shape") + "\n" +
|
266
|
+
_("Inactive: every single line segment will be dealt with individually.")
|
267
|
+
),
|
268
|
+
"page": "Optimisations",
|
269
|
+
"section": "_25_Effects",
|
270
|
+
},
|
271
|
+
{
|
272
|
+
"attr": "opt_effect_optimize",
|
273
|
+
"object": context,
|
274
|
+
"default": False,
|
275
|
+
"type": bool,
|
276
|
+
"label": _("Optimize internally"),
|
277
|
+
"tip": (
|
278
|
+
_("Active: hatch lines will be optimized internally") + "\n" +
|
279
|
+
_("Inactive: hatch lines will be burnt sequentially.")
|
280
|
+
),
|
281
|
+
"page": "Optimisations",
|
282
|
+
"section": "_25_Effects",
|
283
|
+
"conditional": (context, "opt_effect_combine"),
|
284
|
+
},
|
285
|
+
{
|
286
|
+
"attr": "opt_reduce_details",
|
287
|
+
"object": context,
|
288
|
+
"default": False,
|
289
|
+
"type": bool,
|
290
|
+
"label": _("Reduce polyline details"),
|
291
|
+
"tip": _(
|
292
|
+
"Active: reduce the details of polyline elements,\n"
|
293
|
+
+ "so that less information needs to be sent to the laser."
|
294
|
+
)
|
295
|
+
+ "\n"
|
296
|
+
+ _(
|
297
|
+
"This can reduce the processing and laser time but can as well\n"
|
298
|
+
+ "compromise the quality at higher levels, so use with care and preview in simulation."
|
299
|
+
),
|
300
|
+
"page": "Optimisations",
|
301
|
+
"section": "_30_Details",
|
302
|
+
"subsection": "_10_",
|
303
|
+
},
|
304
|
+
{
|
305
|
+
"attr": "opt_reduce_tolerance",
|
306
|
+
"object": context,
|
307
|
+
"default": 10,
|
308
|
+
"type": int,
|
309
|
+
"label": _("Level"),
|
310
|
+
"style": "option",
|
311
|
+
"choices": (1, 10, 50, 100),
|
312
|
+
"display": (_("Minimal"), _("Fine"), _("Medium"), _("Coarse")),
|
313
|
+
"tip": _(
|
314
|
+
"This can reduce the processing and laser time but can as well\n"
|
315
|
+
+ "compromise the quality at higher levels, so use with care and preview in simulation."
|
316
|
+
),
|
317
|
+
"page": "Optimisations",
|
318
|
+
"section": "_30_Details",
|
319
|
+
"subsection": "_10_",
|
320
|
+
"conditional": (context, "opt_reduce_details"),
|
321
|
+
},
|
322
|
+
]
|
323
|
+
for c in choices:
|
324
|
+
c["help"] = "optimisation"
|
325
|
+
kernel.register_choices("optimize", choices)
|
326
|
+
context.setting(bool, "opt_2opt", False)
|
327
|
+
context.setting(bool, "opt_nearest_neighbor", True)
|
328
|
+
context.setting(bool, "opt_reduce_directions", False)
|
329
|
+
context.setting(bool, "opt_remove_overlap", False)
|
330
|
+
context.setting(bool, "opt_start_from_position", False)
|
331
|
+
|
332
|
+
# context.setting(int, "opt_closed_distance", 15)
|
333
|
+
# context.setting(bool, "opt_merge_passes", False)
|
334
|
+
# context.setting(bool, "opt_merge_ops", False)
|
335
|
+
# context.setting(bool, "opt_inner_first", True)
|
336
|
+
|
337
|
+
elif lifecycle == "poststart":
|
338
|
+
planner = kernel.planner
|
339
|
+
auto = hasattr(kernel.args, "auto") and kernel.args.auto
|
340
|
+
console = hasattr(kernel.args, "console") and kernel.args.console
|
341
|
+
quit = hasattr(kernel.args, "quit") and kernel.args.quit
|
342
|
+
if auto:
|
343
|
+
planner("plan copy preprocess validate blob preopt optimize\n")
|
344
|
+
if quit or not console:
|
345
|
+
planner("plan console quit\n")
|
346
|
+
planner("plan spool\n")
|
347
|
+
|
348
|
+
|
349
|
+
class Planner(Service):
|
350
|
+
"""
|
351
|
+
Planner is a service that adds 'plan' commands to the kernel. These are text based versions of the job preview and
|
352
|
+
should be permitted to control the job creation process.
|
353
|
+
"""
|
354
|
+
|
355
|
+
def __init__(self, kernel, *args, **kwargs):
|
356
|
+
Service.__init__(self, kernel, "planner")
|
357
|
+
self._plan = dict()
|
358
|
+
self._default_plan = "0"
|
359
|
+
self.do_optimization = True
|
360
|
+
|
361
|
+
def length(self, v):
|
362
|
+
return float(Length(v))
|
363
|
+
|
364
|
+
def length_x(self, v):
|
365
|
+
return float(Length(v, relative_length=self.device.view.width))
|
366
|
+
|
367
|
+
def length_y(self, v):
|
368
|
+
return float(Length(v, relative_length=self.device.view.height))
|
369
|
+
|
370
|
+
def get_or_make_plan(self, plan_name):
|
371
|
+
"""
|
372
|
+
Plans are a tuple of 3 lists and the name. Plan, Original, Commands, and Plan-Name
|
373
|
+
"""
|
374
|
+
try:
|
375
|
+
return self._plan[plan_name]
|
376
|
+
except KeyError:
|
377
|
+
self._plan[plan_name] = CutPlan(plan_name, self)
|
378
|
+
return self._plan[plan_name]
|
379
|
+
|
380
|
+
@property
|
381
|
+
def default_plan(self):
|
382
|
+
return self.get_or_make_plan(self._default_plan)
|
383
|
+
|
384
|
+
def service_attach(self, *args, **kwargs):
|
385
|
+
_ = self.kernel.translation
|
386
|
+
|
387
|
+
@self.console_command(
|
388
|
+
"plan",
|
389
|
+
help=_("plan<?> <command>"),
|
390
|
+
regex=True,
|
391
|
+
input_type=(None, "ops"),
|
392
|
+
output_type="plan",
|
393
|
+
)
|
394
|
+
def plan_base(command, channel, _, data=None, remainder=None, **kwgs):
|
395
|
+
if len(command) > 4:
|
396
|
+
self._default_plan = command[4:]
|
397
|
+
self.signal("plan", self._default_plan, None)
|
398
|
+
|
399
|
+
cutplan = self.default_plan
|
400
|
+
if data is not None:
|
401
|
+
# If ops data is in data, then we copy that and move on to next step.
|
402
|
+
for c in data:
|
403
|
+
if not c.output:
|
404
|
+
continue
|
405
|
+
try:
|
406
|
+
if len(c.children) == 0:
|
407
|
+
continue
|
408
|
+
except TypeError:
|
409
|
+
pass
|
410
|
+
copy_c = copy(c)
|
411
|
+
try:
|
412
|
+
copy_c.copy_children_as_real(c)
|
413
|
+
except AttributeError:
|
414
|
+
pass
|
415
|
+
cutplan.plan.append(copy_c)
|
416
|
+
self.signal("plan", self._default_plan, 1)
|
417
|
+
return "plan", cutplan
|
418
|
+
if remainder is None:
|
419
|
+
channel(_("----------"))
|
420
|
+
channel(_("Plan:"))
|
421
|
+
for i, plan_name in enumerate(cutplan.name):
|
422
|
+
channel(f"{i}: {plan_name}")
|
423
|
+
channel(_("----------"))
|
424
|
+
channel(_("Plan {plan}:").format(plan=self._default_plan))
|
425
|
+
for i, op_name in enumerate(cutplan.plan):
|
426
|
+
channel(f"{i}: {op_name}")
|
427
|
+
channel(_("Commands {plan}:").format(plan=self._default_plan))
|
428
|
+
for i, cmd_name in enumerate(cutplan.commands):
|
429
|
+
channel(f"{i}: {cmd_name}")
|
430
|
+
channel(_("----------"))
|
431
|
+
|
432
|
+
return "plan", cutplan
|
433
|
+
|
434
|
+
@self.console_command(
|
435
|
+
("copy", "copy-selected"),
|
436
|
+
help=_("plan(-selected)<?> copy"),
|
437
|
+
input_type="plan",
|
438
|
+
output_type="plan",
|
439
|
+
)
|
440
|
+
def plan_copy(command, channel, _, data_type=None, data=None, **kwgs):
|
441
|
+
# Update Info-panel if displayed
|
442
|
+
busy = self.kernel.busyinfo
|
443
|
+
if busy.shown:
|
444
|
+
busy.change(msg=_("Copy data"), keep=1)
|
445
|
+
busy.show()
|
446
|
+
|
447
|
+
operations = data # unused.
|
448
|
+
if command == "copy-selected":
|
449
|
+
operations = list(self.elements.ops(emphasized=True))
|
450
|
+
copy_selected = True
|
451
|
+
else:
|
452
|
+
operations = list(self.elements.ops())
|
453
|
+
copy_selected = False
|
454
|
+
|
455
|
+
def init_settings():
|
456
|
+
for prefix in ("prepend", "append"):
|
457
|
+
str_count = f"{prefix}_op_count"
|
458
|
+
self.device.setting(int, str_count, 0)
|
459
|
+
value = getattr(self.device, str_count, 0)
|
460
|
+
if value > 0:
|
461
|
+
for idx in range(value):
|
462
|
+
attr1 = f"{prefix}_op_{idx:02d}"
|
463
|
+
attr2 = f"{prefix}_op_param_{idx:02d}"
|
464
|
+
self.device.setting(str, attr1, "")
|
465
|
+
self.device.setting(str, attr2, "")
|
466
|
+
|
467
|
+
def add_ops(is_prepend):
|
468
|
+
# Do we have any default actions to include first?
|
469
|
+
if is_prepend:
|
470
|
+
prefix = "prepend"
|
471
|
+
else:
|
472
|
+
prefix = "append"
|
473
|
+
try:
|
474
|
+
if is_prepend:
|
475
|
+
count = self.device.prepend_op_count
|
476
|
+
else:
|
477
|
+
count = self.device.append_op_count
|
478
|
+
except AttributeError:
|
479
|
+
count = 0
|
480
|
+
idx = 0
|
481
|
+
while idx <= count - 1:
|
482
|
+
addop = None
|
483
|
+
attr1 = f"{prefix}_op_{idx:02d}"
|
484
|
+
attr2 = f"{prefix}_op_param_{idx:02d}"
|
485
|
+
if hasattr(self.device, attr1):
|
486
|
+
optype = getattr(self.device, attr1, None)
|
487
|
+
opparam = getattr(self.device, attr2, None)
|
488
|
+
if optype is not None:
|
489
|
+
if optype == "util console":
|
490
|
+
addop = ConsoleOperation(command=opparam)
|
491
|
+
elif optype == "util home":
|
492
|
+
addop = HomeOperation()
|
493
|
+
elif optype == "util output":
|
494
|
+
if opparam is not None:
|
495
|
+
params = opparam.split(",")
|
496
|
+
mask = 0
|
497
|
+
setvalue = 0
|
498
|
+
if len(params) > 0:
|
499
|
+
try:
|
500
|
+
mask = int(params[0])
|
501
|
+
except ValueError:
|
502
|
+
mask = 0
|
503
|
+
if len(params) > 1:
|
504
|
+
try:
|
505
|
+
setvalue = int(params[1])
|
506
|
+
except ValueError:
|
507
|
+
setvalue = 0
|
508
|
+
if mask != 0 or setvalue != 0:
|
509
|
+
addop = OutputOperation(
|
510
|
+
output_mask=mask, output_value=setvalue
|
511
|
+
)
|
512
|
+
elif optype == "util goto":
|
513
|
+
if opparam is not None:
|
514
|
+
params = opparam.split(",")
|
515
|
+
x = 0
|
516
|
+
y = 0
|
517
|
+
if len(params) > 0:
|
518
|
+
try:
|
519
|
+
x = float(Length(params[0]))
|
520
|
+
except ValueError:
|
521
|
+
x = 0
|
522
|
+
if len(params) > 1:
|
523
|
+
try:
|
524
|
+
y = float(Length(params[1]))
|
525
|
+
except ValueError:
|
526
|
+
y = 0
|
527
|
+
absolute = False
|
528
|
+
if len(params) > 2:
|
529
|
+
absolute = params[2] not in ("False", "0")
|
530
|
+
addop = GotoOperation(x=x, y=y, absolute=absolute)
|
531
|
+
elif optype == "util wait":
|
532
|
+
if opparam is not None:
|
533
|
+
try:
|
534
|
+
opparam = float(opparam)
|
535
|
+
except ValueError:
|
536
|
+
opparam = None
|
537
|
+
if opparam is not None:
|
538
|
+
addop = WaitOperation(wait=opparam)
|
539
|
+
if addop is not None:
|
540
|
+
try:
|
541
|
+
if not addop.output:
|
542
|
+
continue
|
543
|
+
except AttributeError:
|
544
|
+
pass
|
545
|
+
try:
|
546
|
+
if len(addop) == 0:
|
547
|
+
continue
|
548
|
+
except TypeError:
|
549
|
+
pass
|
550
|
+
if addop.type == "cutcode":
|
551
|
+
# CutNodes are denuded into normal objects.
|
552
|
+
addop = addop.cutcode
|
553
|
+
copy_c = copy(addop)
|
554
|
+
try:
|
555
|
+
copy_c.copy_children_as_real(addop)
|
556
|
+
except AttributeError:
|
557
|
+
pass
|
558
|
+
data.plan.append(copy_c)
|
559
|
+
|
560
|
+
idx += 1
|
561
|
+
|
562
|
+
init_settings()
|
563
|
+
|
564
|
+
# Add default start ops
|
565
|
+
add_ops(True)
|
566
|
+
# types = (
|
567
|
+
# "op cut",
|
568
|
+
# "op raster",
|
569
|
+
# "op image",
|
570
|
+
# "op engrave",
|
571
|
+
# "op dots",
|
572
|
+
# "cutcode",
|
573
|
+
# "util console",
|
574
|
+
# "util wait",
|
575
|
+
# "util home",
|
576
|
+
# "util goto",
|
577
|
+
# "util input",
|
578
|
+
# "util output",
|
579
|
+
# "place point"
|
580
|
+
# "blob",
|
581
|
+
# )
|
582
|
+
for c in operations:
|
583
|
+
isactive = True
|
584
|
+
try:
|
585
|
+
if not c.output:
|
586
|
+
isactive = False
|
587
|
+
except AttributeError:
|
588
|
+
pass
|
589
|
+
if not isactive and copy_selected and len(operations) == 1:
|
590
|
+
# If it's the only one we make an exception
|
591
|
+
isactive = True
|
592
|
+
if not isactive:
|
593
|
+
continue
|
594
|
+
if not hasattr(c, "type") or c.type is None:
|
595
|
+
# Node must be a type of node.
|
596
|
+
continue
|
597
|
+
if c.type.startswith("op ") and len(c.children) == 0:
|
598
|
+
# We don't need empty operations.
|
599
|
+
continue
|
600
|
+
if c.type == "cutcode":
|
601
|
+
# CutNodes are denuded into normal objects.
|
602
|
+
c = c.cutcode
|
603
|
+
|
604
|
+
# Make copy of node.
|
605
|
+
copy_c = copy(c)
|
606
|
+
try:
|
607
|
+
# Make copy of real (non-referenced) children if that is permitted.
|
608
|
+
copy_c.copy_children_as_real(c)
|
609
|
+
except AttributeError:
|
610
|
+
pass
|
611
|
+
data.plan.append(copy_c)
|
612
|
+
|
613
|
+
# Add default trailing ops
|
614
|
+
add_ops(False)
|
615
|
+
channel(_("Copied Operations."))
|
616
|
+
self.signal("plan", data.name, 1)
|
617
|
+
return data_type, data
|
618
|
+
|
619
|
+
@self.console_option(
|
620
|
+
"index", "i", type=int, help=_("index of location to insert command")
|
621
|
+
)
|
622
|
+
@self.console_argument("console", type=str, help=_("console command to append"))
|
623
|
+
@self.console_command(
|
624
|
+
"console",
|
625
|
+
help=_("plan<?> command"),
|
626
|
+
input_type="plan",
|
627
|
+
output_type="plan",
|
628
|
+
all_arguments_required=True,
|
629
|
+
)
|
630
|
+
def plan_command(
|
631
|
+
command,
|
632
|
+
channel,
|
633
|
+
_,
|
634
|
+
data_type=None,
|
635
|
+
data=None,
|
636
|
+
console=None,
|
637
|
+
index=None,
|
638
|
+
**kwgs,
|
639
|
+
):
|
640
|
+
if not console:
|
641
|
+
channel(
|
642
|
+
_(
|
643
|
+
"plan console... requires a console command to inject into the current plan"
|
644
|
+
)
|
645
|
+
)
|
646
|
+
else:
|
647
|
+
cmd = ConsoleOperation(command=console)
|
648
|
+
if index is None:
|
649
|
+
data.plan.append(cmd)
|
650
|
+
else:
|
651
|
+
try:
|
652
|
+
data.plan.insert(index, cmd)
|
653
|
+
except ValueError:
|
654
|
+
channel(_("Invalid index for command insert."))
|
655
|
+
self.signal("plan", data.name, None)
|
656
|
+
return data_type, data
|
657
|
+
|
658
|
+
@self.console_command(
|
659
|
+
"preprocess",
|
660
|
+
help=_("plan<?> preprocess"),
|
661
|
+
input_type="plan",
|
662
|
+
output_type="plan",
|
663
|
+
)
|
664
|
+
def plan_preprocess(command, channel, _, data_type=None, data=None, **kwgs):
|
665
|
+
# Update Info-panel if displayed
|
666
|
+
busy = self.kernel.busyinfo
|
667
|
+
if busy.shown:
|
668
|
+
busy.change(msg=_("Preprocessing"), keep=1)
|
669
|
+
busy.show()
|
670
|
+
|
671
|
+
data.preprocess()
|
672
|
+
self.signal("plan", data.name, 2)
|
673
|
+
return data_type, data
|
674
|
+
|
675
|
+
@self.console_command(
|
676
|
+
"validate",
|
677
|
+
help=_("plan<?> validate"),
|
678
|
+
input_type="plan",
|
679
|
+
output_type="plan",
|
680
|
+
)
|
681
|
+
def plan_validate(command, channel, _, data_type=None, data=None, **kwgs):
|
682
|
+
# Update Info-panel if displayed
|
683
|
+
busy = self.kernel.busyinfo
|
684
|
+
if busy.shown:
|
685
|
+
busy.change(msg=_("Validating"), keep=1)
|
686
|
+
busy.show()
|
687
|
+
|
688
|
+
try:
|
689
|
+
data.execute()
|
690
|
+
except CutPlanningFailedError as e:
|
691
|
+
self.signal("cutplanning;failed", str(e))
|
692
|
+
data.clear()
|
693
|
+
return
|
694
|
+
self.signal("plan", data.name, 3)
|
695
|
+
return data_type, data
|
696
|
+
|
697
|
+
@self.console_command(
|
698
|
+
"geometry",
|
699
|
+
help=_("plan<?> geometry"),
|
700
|
+
input_type="plan",
|
701
|
+
output_type="plan",
|
702
|
+
)
|
703
|
+
def plan_geometry(data_type=None, data=None, **kwgs):
|
704
|
+
# Update Info-panel if displayed
|
705
|
+
busy = self.kernel.busyinfo
|
706
|
+
if busy.shown:
|
707
|
+
busy.change(msg=_("Converting data"), keep=1)
|
708
|
+
busy.show()
|
709
|
+
|
710
|
+
data.geometry()
|
711
|
+
self.signal("plan", data.name, 4)
|
712
|
+
return data_type, data
|
713
|
+
|
714
|
+
@self.console_command(
|
715
|
+
"blob",
|
716
|
+
help=_("plan<?> blob"),
|
717
|
+
input_type="plan",
|
718
|
+
output_type="plan",
|
719
|
+
)
|
720
|
+
def plan_blob(data_type=None, data=None, **kwgs):
|
721
|
+
# Update Info-panel if displayed
|
722
|
+
busy = self.kernel.busyinfo
|
723
|
+
if busy.shown:
|
724
|
+
busy.change(msg=_("Converting data"), keep=1)
|
725
|
+
busy.show()
|
726
|
+
|
727
|
+
data.blob()
|
728
|
+
self.signal("plan", data.name, 4)
|
729
|
+
return data_type, data
|
730
|
+
|
731
|
+
@self.console_command(
|
732
|
+
"preopt",
|
733
|
+
help=_("plan<?> preopt"),
|
734
|
+
input_type="plan",
|
735
|
+
output_type="plan",
|
736
|
+
)
|
737
|
+
def plan_preopt(data_type=None, data=None, **kwgs):
|
738
|
+
# Update Info-panel if displayed
|
739
|
+
busy = self.kernel.busyinfo
|
740
|
+
if busy.shown:
|
741
|
+
busy.change(msg=_("Preparing optimisation"), keep=1)
|
742
|
+
busy.show()
|
743
|
+
|
744
|
+
data.preopt()
|
745
|
+
self.signal("plan", data.name, 5)
|
746
|
+
return data_type, data
|
747
|
+
|
748
|
+
@self.console_command(
|
749
|
+
"optimize",
|
750
|
+
help=_("plan<?> optimize"),
|
751
|
+
input_type="plan",
|
752
|
+
output_type="plan",
|
753
|
+
)
|
754
|
+
def plan_optimize(data_type=None, data=None, **kwgs):
|
755
|
+
# Update Info-panel if displayed
|
756
|
+
busy = self.kernel.busyinfo
|
757
|
+
if busy.shown:
|
758
|
+
busy.change(msg=_("Optimising"), keep=1)
|
759
|
+
busy.show()
|
760
|
+
|
761
|
+
data.execute()
|
762
|
+
self.signal("plan", data.name, 6)
|
763
|
+
return data_type, data
|
764
|
+
|
765
|
+
@self.console_command(
|
766
|
+
"clear",
|
767
|
+
help=_("plan<?> clear"),
|
768
|
+
input_type="plan",
|
769
|
+
output_type="plan",
|
770
|
+
)
|
771
|
+
def plan_clear(data_type=None, data=None, **kwgs):
|
772
|
+
# Update Info-panel if displayed
|
773
|
+
busy = self.kernel.busyinfo
|
774
|
+
if busy.shown:
|
775
|
+
busy.change(msg=_("Clearing data"), keep=1)
|
776
|
+
busy.show()
|
777
|
+
|
778
|
+
data.clear()
|
779
|
+
self.signal("plan", data.name, 0)
|
780
|
+
return data_type, data
|
781
|
+
|
782
|
+
@self.console_command(
|
783
|
+
"return",
|
784
|
+
help=_("plan<?> return"),
|
785
|
+
input_type="plan",
|
786
|
+
output_type="plan",
|
787
|
+
)
|
788
|
+
def plan_return(command, channel, _, data_type=None, data=None, **kwgs):
|
789
|
+
operations = self.elements.get(type="branch ops")
|
790
|
+
operations.remove_all_children()
|
791
|
+
|
792
|
+
for c in data.plan:
|
793
|
+
if isinstance(c, CutCode):
|
794
|
+
operations.add(type="cutcode", cutcode=c)
|
795
|
+
if isinstance(
|
796
|
+
c,
|
797
|
+
(
|
798
|
+
RasterOpNode,
|
799
|
+
ImageOpNode,
|
800
|
+
CutOpNode,
|
801
|
+
EngraveOpNode,
|
802
|
+
DotsOpNode,
|
803
|
+
),
|
804
|
+
):
|
805
|
+
copy_c = copy(c)
|
806
|
+
operations.add_node(copy_c)
|
807
|
+
channel(_("Returned Operations."))
|
808
|
+
self.signal("plan", data.name, None)
|
809
|
+
return data_type, data
|
810
|
+
|
811
|
+
@self.console_argument(
|
812
|
+
"start", help="start index for cutcode", type=int, default=0
|
813
|
+
)
|
814
|
+
@self.console_argument(
|
815
|
+
"end", help="end index for cutcode (-1 is last value)", type=int, default=-1
|
816
|
+
)
|
817
|
+
@self.console_command(
|
818
|
+
"sublist",
|
819
|
+
help=_("plan<?> sublist"),
|
820
|
+
input_type="plan",
|
821
|
+
output_type="plan",
|
822
|
+
)
|
823
|
+
def plan_sublist(
|
824
|
+
command, channel, _, start=None, end=None, data_type=None, data=None, **kwgs
|
825
|
+
):
|
826
|
+
if end == -1:
|
827
|
+
end = float("inf")
|
828
|
+
pos = 0
|
829
|
+
index = 0
|
830
|
+
size = 0
|
831
|
+
plan = list(data.plan)
|
832
|
+
data.plan.clear()
|
833
|
+
c = None
|
834
|
+
while pos < start:
|
835
|
+
# Process prestart elements.
|
836
|
+
try:
|
837
|
+
c = plan[index]
|
838
|
+
except IndexError:
|
839
|
+
break
|
840
|
+
index += 1
|
841
|
+
if isinstance(c, CutCode):
|
842
|
+
c = CutCode(c.flat())
|
843
|
+
size = len(c)
|
844
|
+
else:
|
845
|
+
size = 0
|
846
|
+
if (pos + size) > start:
|
847
|
+
break
|
848
|
+
pos += size
|
849
|
+
size = 0
|
850
|
+
if (pos + size) > start:
|
851
|
+
# We overshot the start
|
852
|
+
c = CutCode(c[start - pos :])
|
853
|
+
pos = start
|
854
|
+
data.plan.append(c)
|
855
|
+
while end > pos:
|
856
|
+
try:
|
857
|
+
c = plan[index]
|
858
|
+
except IndexError:
|
859
|
+
break
|
860
|
+
index += 1
|
861
|
+
if isinstance(c, CutCode):
|
862
|
+
c = CutCode(c.flat())
|
863
|
+
size = len(c)
|
864
|
+
else:
|
865
|
+
size = 0
|
866
|
+
pos += size
|
867
|
+
if pos > end:
|
868
|
+
c = CutCode(c[: end - pos])
|
869
|
+
data.plan.append(c)
|
870
|
+
|
871
|
+
self.signal("plan", data.name, None)
|
872
|
+
return data_type, data
|
873
|
+
|
874
|
+
def plan(self, **kwargs):
|
875
|
+
yield from self._plan
|