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/units.py
CHANGED
@@ -1,680 +1,784 @@
|
|
1
|
-
"""
|
2
|
-
Device Specific Unit Conversion Objects
|
3
|
-
|
4
|
-
This defines a Viewport which all .device services are expected to implement. This provides the core functionality for
|
5
|
-
establishing the scene and mapping points from scene locations to device locations. This also provides functionality
|
6
|
-
for converting different length or angle units into other length or angle units.
|
7
|
-
|
8
|
-
The fundamental unit used for all the elements objects is that 1 inch is equal to 65535 native units called a Tat for
|
9
|
-
Tiger and Tatarize. This is basically a solid middle ground for providing significant rendering detail while not
|
10
|
-
overflowing the buffer in linux which starts react poorly for values greater than 16,777,216 (2^24). This should provide
|
11
|
-
enough detail for even the smallest lensed galvo laser while also allowing us to define objects as large as a football
|
12
|
-
stadium.
|
13
|
-
"""
|
14
|
-
|
15
|
-
|
16
|
-
import re
|
17
|
-
from copy import copy
|
18
|
-
from math import tau
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
"",
|
72
|
-
"
|
73
|
-
"
|
74
|
-
"
|
75
|
-
"
|
76
|
-
"
|
77
|
-
"
|
78
|
-
"
|
79
|
-
"
|
80
|
-
"
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
""
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
if
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
def
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
def
|
196
|
-
if not isinstance(other, Length):
|
197
|
-
other = Length(other)
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
return
|
205
|
-
|
206
|
-
def
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
c
|
234
|
-
c
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
return
|
247
|
-
|
248
|
-
def
|
249
|
-
s = self.__copy__()
|
250
|
-
s
|
251
|
-
return s
|
252
|
-
|
253
|
-
def
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
return
|
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
|
-
return self.
|
319
|
-
elif self._preferred_units == "
|
320
|
-
return self.
|
321
|
-
elif self._preferred_units == "
|
322
|
-
return self.
|
323
|
-
elif self._preferred_units == "
|
324
|
-
return self.
|
325
|
-
|
326
|
-
return self.
|
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
|
-
return
|
420
|
-
|
421
|
-
@property
|
422
|
-
def
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
amount
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
amount
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
amount
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
amount
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
amount
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
return f"{
|
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
|
-
self.angle
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
if
|
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
|
-
def
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
return
|
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
|
-
def
|
571
|
-
return
|
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
|
-
|
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
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
1
|
+
"""
|
2
|
+
Device Specific Unit Conversion Objects
|
3
|
+
|
4
|
+
This defines a Viewport which all .device services are expected to implement. This provides the core functionality for
|
5
|
+
establishing the scene and mapping points from scene locations to device locations. This also provides functionality
|
6
|
+
for converting different length or angle units into other length or angle units.
|
7
|
+
|
8
|
+
The fundamental unit used for all the elements objects is that 1 inch is equal to 65535 native units called a Tat for
|
9
|
+
Tiger and Tatarize. This is basically a solid middle ground for providing significant rendering detail while not
|
10
|
+
overflowing the buffer in linux which starts react poorly for values greater than 16,777,216 (2^24). This should provide
|
11
|
+
enough detail for even the smallest lensed galvo laser while also allowing us to define objects as large as a football
|
12
|
+
stadium.
|
13
|
+
"""
|
14
|
+
|
15
|
+
|
16
|
+
import re
|
17
|
+
from copy import copy
|
18
|
+
from math import tau
|
19
|
+
|
20
|
+
PATTERN_FLOAT = r"[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?"
|
21
|
+
REGEX_LENGTH = re.compile(r"(%s)\.?([A-Za-z%%]*)" % PATTERN_FLOAT)
|
22
|
+
ERROR = 1e-11
|
23
|
+
DEFAULT_PPI = 96.0
|
24
|
+
NATIVE_UNIT_PER_INCH = 65535
|
25
|
+
|
26
|
+
NM_PER_INCH = 25400000
|
27
|
+
NM_PER_MIL = 25400
|
28
|
+
NM_PER_NM = 1
|
29
|
+
NM_PER_uM = 1000
|
30
|
+
NM_PER_MM = 1000000
|
31
|
+
NM_PER_CM = 10000000
|
32
|
+
NM_PER_PIXEL = NM_PER_INCH / DEFAULT_PPI
|
33
|
+
|
34
|
+
MIL_PER_INCH = 1000
|
35
|
+
NM_PER_INCH = 2.54e7
|
36
|
+
uM_PER_INCH = 25400
|
37
|
+
MM_PER_INCH = 25.4
|
38
|
+
CM_PER_INCH = 2.54
|
39
|
+
|
40
|
+
PX_PER_INCH = DEFAULT_PPI
|
41
|
+
PX_PER_MIL = DEFAULT_PPI / MIL_PER_INCH
|
42
|
+
PX_PER_NM = DEFAULT_PPI / NM_PER_INCH
|
43
|
+
PX_PER_uM = DEFAULT_PPI / uM_PER_INCH
|
44
|
+
PX_PER_MM = DEFAULT_PPI / MM_PER_INCH
|
45
|
+
PX_PER_CM = DEFAULT_PPI / CM_PER_INCH
|
46
|
+
PX_PER_PIXEL = 1
|
47
|
+
|
48
|
+
|
49
|
+
UNITS_PER_TAT = 1
|
50
|
+
UNITS_PER_INCH = NATIVE_UNIT_PER_INCH
|
51
|
+
UNITS_PER_MIL = NATIVE_UNIT_PER_INCH / MIL_PER_INCH
|
52
|
+
UNITS_PER_uM = NATIVE_UNIT_PER_INCH / uM_PER_INCH
|
53
|
+
UNITS_PER_MM = NATIVE_UNIT_PER_INCH / MM_PER_INCH
|
54
|
+
UNITS_PER_CM = NATIVE_UNIT_PER_INCH / CM_PER_INCH
|
55
|
+
UNITS_PER_NM = NATIVE_UNIT_PER_INCH / NM_PER_INCH
|
56
|
+
UNITS_PER_PIXEL = NATIVE_UNIT_PER_INCH / DEFAULT_PPI
|
57
|
+
UNITS_PER_POINT = UNITS_PER_PIXEL * 4.0 / 3.0
|
58
|
+
PX_PER_UNIT = 1.0 / UNITS_PER_PIXEL
|
59
|
+
|
60
|
+
UNITS_NANOMETER = 0
|
61
|
+
UNITS_MM = 1
|
62
|
+
UNITS_CM = 2
|
63
|
+
UNITS_MILS = 3
|
64
|
+
UNITS_INCH = 4
|
65
|
+
UNITS_PERCENT = 100
|
66
|
+
|
67
|
+
|
68
|
+
ACCEPTED_UNITS = (
|
69
|
+
"",
|
70
|
+
"cm",
|
71
|
+
"mm",
|
72
|
+
"in",
|
73
|
+
"inch",
|
74
|
+
"inches",
|
75
|
+
"mil",
|
76
|
+
"pt",
|
77
|
+
"pc",
|
78
|
+
"px",
|
79
|
+
"%",
|
80
|
+
"tat",
|
81
|
+
)
|
82
|
+
|
83
|
+
ACCEPTED_ANGLE_UNITS = (
|
84
|
+
"",
|
85
|
+
"deg",
|
86
|
+
"grad",
|
87
|
+
"rad",
|
88
|
+
"turn",
|
89
|
+
"%",
|
90
|
+
)
|
91
|
+
|
92
|
+
|
93
|
+
class Length:
|
94
|
+
"""
|
95
|
+
Amounts are converted to UNITS.
|
96
|
+
Initial unit is saved as preferred units.
|
97
|
+
"""
|
98
|
+
|
99
|
+
units_per_spx = 50
|
100
|
+
|
101
|
+
def __init__(
|
102
|
+
self,
|
103
|
+
*args,
|
104
|
+
amount=None,
|
105
|
+
relative_length=None,
|
106
|
+
unitless=1.0,
|
107
|
+
preferred_units=None,
|
108
|
+
digits=None,
|
109
|
+
):
|
110
|
+
self._digits = digits
|
111
|
+
self._amount = amount
|
112
|
+
if relative_length:
|
113
|
+
self._relative = Length(relative_length, unitless=unitless).units
|
114
|
+
else:
|
115
|
+
self._relative = None
|
116
|
+
if self._amount is None:
|
117
|
+
if len(args) == 2:
|
118
|
+
value = str(args[0]) + str(args[1])
|
119
|
+
elif len(args) == 1:
|
120
|
+
value = args[0]
|
121
|
+
else:
|
122
|
+
raise ValueError("Arguments not acceptable")
|
123
|
+
s = str(value)
|
124
|
+
match = REGEX_LENGTH.match(s)
|
125
|
+
if not match:
|
126
|
+
raise ValueError(f"Length was not parsable: '{s}'.")
|
127
|
+
amount = float(match.group(1))
|
128
|
+
units = match.group(2)
|
129
|
+
if units == "inch" or units == "inches":
|
130
|
+
units = "in"
|
131
|
+
scale = 1.0
|
132
|
+
if units == "":
|
133
|
+
if unitless:
|
134
|
+
scale = unitless
|
135
|
+
elif units == "tat":
|
136
|
+
scale = UNITS_PER_TAT
|
137
|
+
elif units == "mm":
|
138
|
+
scale = UNITS_PER_MM
|
139
|
+
elif units == "cm":
|
140
|
+
scale = UNITS_PER_CM
|
141
|
+
elif units == "um":
|
142
|
+
scale = UNITS_PER_uM
|
143
|
+
elif units == "nm":
|
144
|
+
scale = UNITS_PER_NM
|
145
|
+
elif units == "in":
|
146
|
+
scale = UNITS_PER_INCH
|
147
|
+
elif units == "mil":
|
148
|
+
scale = UNITS_PER_MIL
|
149
|
+
elif units == "px":
|
150
|
+
scale = UNITS_PER_PIXEL
|
151
|
+
elif units == "pt":
|
152
|
+
scale = UNITS_PER_POINT
|
153
|
+
elif units == "spx":
|
154
|
+
scale = self.units_per_spx
|
155
|
+
elif units == "pc":
|
156
|
+
scale = UNITS_PER_PIXEL * 16.0
|
157
|
+
elif units == "%":
|
158
|
+
if relative_length is not None:
|
159
|
+
fraction = amount / 100.0
|
160
|
+
if isinstance(relative_length, (str, Length)):
|
161
|
+
relative_length = Length(
|
162
|
+
relative_length, unitless=unitless
|
163
|
+
).units
|
164
|
+
amount = relative_length
|
165
|
+
scale = fraction
|
166
|
+
units = ""
|
167
|
+
else:
|
168
|
+
raise ValueError("Percent without relative length is meaningless.")
|
169
|
+
else:
|
170
|
+
raise ValueError(f"Units '{units}' was not recognized for '{s}'")
|
171
|
+
self._amount = scale * amount
|
172
|
+
if preferred_units is None:
|
173
|
+
preferred_units = units
|
174
|
+
else:
|
175
|
+
# amount is only ever a number.
|
176
|
+
if not isinstance(amount, (float, int)):
|
177
|
+
raise ValueError("Amount must be an number.")
|
178
|
+
if preferred_units is None:
|
179
|
+
preferred_units = ""
|
180
|
+
if preferred_units == "inch" or preferred_units == "inches":
|
181
|
+
preferred_units = "in"
|
182
|
+
self._preferred_units = preferred_units
|
183
|
+
|
184
|
+
def __float__(self):
|
185
|
+
return self._amount
|
186
|
+
|
187
|
+
def __imul__(self, other):
|
188
|
+
if isinstance(other, (int, float)):
|
189
|
+
self._amount *= other
|
190
|
+
return self
|
191
|
+
if self._amount == 0.0:
|
192
|
+
return 0.0
|
193
|
+
raise ValueError
|
194
|
+
|
195
|
+
def __iadd__(self, other):
|
196
|
+
if not isinstance(other, Length):
|
197
|
+
other = Length(other)
|
198
|
+
self._amount += other._amount
|
199
|
+
return self
|
200
|
+
|
201
|
+
def __abs__(self):
|
202
|
+
c = self.__copy__()
|
203
|
+
c._amount = abs(c._amount)
|
204
|
+
return c
|
205
|
+
|
206
|
+
def __truediv__(self, other):
|
207
|
+
if not isinstance(other, Length):
|
208
|
+
other = Length(other)
|
209
|
+
return self._amount / other._amount
|
210
|
+
|
211
|
+
__floordiv__ = __truediv__
|
212
|
+
__div__ = __truediv__
|
213
|
+
|
214
|
+
def __lt__(self, other):
|
215
|
+
return (self - other)._amount - ERROR < 0
|
216
|
+
|
217
|
+
def __gt__(self, other):
|
218
|
+
return (self - other)._amount + ERROR > 0
|
219
|
+
|
220
|
+
def __le__(self, other):
|
221
|
+
return (self - other)._amount - ERROR <= 0
|
222
|
+
|
223
|
+
def __ge__(self, other):
|
224
|
+
return (self - other)._amount + ERROR >= 0
|
225
|
+
|
226
|
+
def __ne__(self, other):
|
227
|
+
return not self.__eq__(other)
|
228
|
+
|
229
|
+
def __add__(self, other):
|
230
|
+
if isinstance(other, (str, float, int)):
|
231
|
+
other = Length(other)
|
232
|
+
c = self.__copy__()
|
233
|
+
c += other
|
234
|
+
return c
|
235
|
+
|
236
|
+
__radd__ = __add__
|
237
|
+
|
238
|
+
def __mul__(self, other):
|
239
|
+
c = copy(self)
|
240
|
+
c *= other
|
241
|
+
return c
|
242
|
+
|
243
|
+
def __rdiv__(self, other):
|
244
|
+
c = copy(self)
|
245
|
+
c *= 1.0 / other._amount
|
246
|
+
return c
|
247
|
+
|
248
|
+
def __neg__(self):
|
249
|
+
s = self.__copy__()
|
250
|
+
s._amount = -s._amount
|
251
|
+
return s
|
252
|
+
|
253
|
+
def __isub__(self, other):
|
254
|
+
if not isinstance(other, Length):
|
255
|
+
other = Length(other)
|
256
|
+
self += -other
|
257
|
+
return self
|
258
|
+
|
259
|
+
def __sub__(self, other):
|
260
|
+
s = self.__copy__()
|
261
|
+
s -= other
|
262
|
+
return s
|
263
|
+
|
264
|
+
def __round__(self, ndigits=0):
|
265
|
+
return round(self._amount, ndigits=ndigits)
|
266
|
+
|
267
|
+
def __rsub__(self, other):
|
268
|
+
if not isinstance(other, Length):
|
269
|
+
other = Length(other)
|
270
|
+
return (-self) + other
|
271
|
+
|
272
|
+
def __copy__(self):
|
273
|
+
return Length(
|
274
|
+
None,
|
275
|
+
amount=self._amount,
|
276
|
+
preferred_units=self._preferred_units,
|
277
|
+
digits=self._digits,
|
278
|
+
)
|
279
|
+
|
280
|
+
__rmul__ = __mul__
|
281
|
+
|
282
|
+
def __repr__(self):
|
283
|
+
c = self.__copy__()
|
284
|
+
c._digits = None
|
285
|
+
return c.preferred_length
|
286
|
+
|
287
|
+
def __str__(self):
|
288
|
+
return self.preferred_length
|
289
|
+
|
290
|
+
def __eq__(self, other):
|
291
|
+
if other is None:
|
292
|
+
return False
|
293
|
+
if isinstance(other, (int, float)):
|
294
|
+
return self._amount == other
|
295
|
+
if not isinstance(other, Length):
|
296
|
+
try:
|
297
|
+
other = Length(other)
|
298
|
+
except ValueError:
|
299
|
+
# Not a length, we do not equal this.
|
300
|
+
return False
|
301
|
+
return abs(self._amount - other._amount) <= ERROR
|
302
|
+
|
303
|
+
@property
|
304
|
+
def preferred(self):
|
305
|
+
if self._preferred_units == "px":
|
306
|
+
return self.pixels
|
307
|
+
elif self._preferred_units == "in":
|
308
|
+
return self.inches
|
309
|
+
elif self._preferred_units == "cm":
|
310
|
+
return self.cm
|
311
|
+
elif self._preferred_units == "mm":
|
312
|
+
return self.mm
|
313
|
+
elif self._preferred_units == "nm":
|
314
|
+
return self.nm
|
315
|
+
elif self._preferred_units == "mil":
|
316
|
+
return self.mil
|
317
|
+
elif self._preferred_units == "um":
|
318
|
+
return self.um
|
319
|
+
elif self._preferred_units == "pt":
|
320
|
+
return self.pt
|
321
|
+
elif self._preferred_units == "spx":
|
322
|
+
return self.spx
|
323
|
+
elif self._preferred_units == "%":
|
324
|
+
return self.percent
|
325
|
+
else:
|
326
|
+
return self.units
|
327
|
+
|
328
|
+
@property
|
329
|
+
def preferred_length(self):
|
330
|
+
if self._preferred_units == "px":
|
331
|
+
return self.length_pixels
|
332
|
+
elif self._preferred_units == "in":
|
333
|
+
return self.length_inches
|
334
|
+
elif self._preferred_units == "cm":
|
335
|
+
return self.length_cm
|
336
|
+
elif self._preferred_units == "mm":
|
337
|
+
return self.length_mm
|
338
|
+
elif self._preferred_units == "nm":
|
339
|
+
return self.length_nm
|
340
|
+
elif self._preferred_units == "mil":
|
341
|
+
return self.length_mil
|
342
|
+
elif self._preferred_units == "um":
|
343
|
+
return self.length_um
|
344
|
+
elif self._preferred_units == "pt":
|
345
|
+
return self.length_pt
|
346
|
+
elif self._preferred_units == "%":
|
347
|
+
return self.length_percent
|
348
|
+
else:
|
349
|
+
return self.length_units
|
350
|
+
|
351
|
+
@property
|
352
|
+
def pixels(self):
|
353
|
+
amount = self._amount / UNITS_PER_PIXEL
|
354
|
+
if self._digits:
|
355
|
+
amount = round(amount, self._digits)
|
356
|
+
return amount
|
357
|
+
|
358
|
+
@property
|
359
|
+
def inches(self):
|
360
|
+
amount = self._amount / UNITS_PER_INCH
|
361
|
+
if self._digits:
|
362
|
+
amount = round(amount, self._digits)
|
363
|
+
return amount
|
364
|
+
|
365
|
+
@property
|
366
|
+
def cm(self):
|
367
|
+
amount = self._amount / UNITS_PER_CM
|
368
|
+
if self._digits:
|
369
|
+
amount = round(amount, self._digits)
|
370
|
+
return amount
|
371
|
+
|
372
|
+
@property
|
373
|
+
def mm(self):
|
374
|
+
amount = self._amount / UNITS_PER_MM
|
375
|
+
if self._digits:
|
376
|
+
amount = round(amount, self._digits)
|
377
|
+
return amount
|
378
|
+
|
379
|
+
@property
|
380
|
+
def nm(self):
|
381
|
+
amount = self._amount / UNITS_PER_NM
|
382
|
+
if self._digits:
|
383
|
+
amount = round(amount, self._digits)
|
384
|
+
return amount
|
385
|
+
|
386
|
+
@property
|
387
|
+
def mil(self):
|
388
|
+
amount = self._amount / UNITS_PER_MIL
|
389
|
+
if self._digits:
|
390
|
+
amount = round(amount, self._digits)
|
391
|
+
return amount
|
392
|
+
|
393
|
+
@property
|
394
|
+
def um(self):
|
395
|
+
amount = self._amount / UNITS_PER_uM
|
396
|
+
if self._digits:
|
397
|
+
amount = round(amount, self._digits)
|
398
|
+
return amount
|
399
|
+
|
400
|
+
@property
|
401
|
+
def pt(self):
|
402
|
+
amount = self._amount / UNITS_PER_POINT
|
403
|
+
if self._digits:
|
404
|
+
amount = round(amount, self._digits)
|
405
|
+
return amount
|
406
|
+
|
407
|
+
@property
|
408
|
+
def spx(self):
|
409
|
+
amount = self._amount / self.units_per_spx
|
410
|
+
if self._digits:
|
411
|
+
amount = round(amount, self._digits)
|
412
|
+
return amount
|
413
|
+
|
414
|
+
@property
|
415
|
+
def units(self):
|
416
|
+
amount = self._amount
|
417
|
+
if self._digits:
|
418
|
+
amount = round(amount, self._digits)
|
419
|
+
return amount
|
420
|
+
|
421
|
+
@property
|
422
|
+
def percent(self):
|
423
|
+
if self._relative is None or self._relative == 0:
|
424
|
+
raise ValueError("Percent without relative length is meaningless.")
|
425
|
+
amount = 100.0 * self._amount / self._relative
|
426
|
+
if self._digits:
|
427
|
+
amount = round(amount, self._digits)
|
428
|
+
return amount
|
429
|
+
|
430
|
+
@property
|
431
|
+
def length_pixels(self):
|
432
|
+
amount = self.pixels
|
433
|
+
return f"{round(amount, 8)}px"
|
434
|
+
|
435
|
+
@property
|
436
|
+
def length_inches(self):
|
437
|
+
amount = self.inches
|
438
|
+
return f"{round(amount, 8)}in"
|
439
|
+
|
440
|
+
@property
|
441
|
+
def length_cm(self):
|
442
|
+
amount = self.cm
|
443
|
+
return f"{round(amount, 8)}cm"
|
444
|
+
|
445
|
+
@property
|
446
|
+
def length_mm(self):
|
447
|
+
amount = self.mm
|
448
|
+
return f"{round(amount, 8)}mm"
|
449
|
+
|
450
|
+
@property
|
451
|
+
def length_nm(self):
|
452
|
+
amount = self.nm
|
453
|
+
return f"{round(amount, 8)}nm"
|
454
|
+
|
455
|
+
@property
|
456
|
+
def length_mil(self):
|
457
|
+
amount = self.mil
|
458
|
+
return f"{round(amount, 8)}mil"
|
459
|
+
|
460
|
+
@property
|
461
|
+
def length_um(self):
|
462
|
+
amount = self.um
|
463
|
+
return f"{round(amount, 8)}um"
|
464
|
+
|
465
|
+
@property
|
466
|
+
def length_pt(self):
|
467
|
+
amount = self.pt
|
468
|
+
return f"{round(amount, 8)}pt"
|
469
|
+
|
470
|
+
@property
|
471
|
+
def length_spx(self):
|
472
|
+
amount = self.spx
|
473
|
+
return f"{round(amount, 8)}spx"
|
474
|
+
|
475
|
+
@property
|
476
|
+
def length_percent(self):
|
477
|
+
amount = self.percent
|
478
|
+
return f"{round(amount, 8)}%"
|
479
|
+
|
480
|
+
@property
|
481
|
+
def length_units(self):
|
482
|
+
return f"{self.units}"
|
483
|
+
|
484
|
+
def as_percent(self, relative_length):
|
485
|
+
return 100.00 * self._amount / Length(relative_length).units
|
486
|
+
|
487
|
+
|
488
|
+
class Angle:
|
489
|
+
"""
|
490
|
+
Angle conversion and math, stores angle as a float in radians and
|
491
|
+
converts to other forms of angle. Failures to parse raise ValueError.
|
492
|
+
"""
|
493
|
+
|
494
|
+
def __init__(self, angle, digits=None, preferred_units="rad"):
|
495
|
+
if isinstance(angle, Angle):
|
496
|
+
self._digits = angle._digits
|
497
|
+
self.angle = angle.angle
|
498
|
+
self.preferred_units = angle.preferred_units
|
499
|
+
return
|
500
|
+
self._digits = digits
|
501
|
+
if not isinstance(angle, str):
|
502
|
+
self.angle = float(angle)
|
503
|
+
self.preferred_units = preferred_units
|
504
|
+
return
|
505
|
+
angle = angle.lower()
|
506
|
+
if angle.endswith("deg"):
|
507
|
+
self.angle = float(angle[:-3]) * tau / 360.0
|
508
|
+
self.preferred_units = "deg"
|
509
|
+
elif angle.endswith("grad"):
|
510
|
+
self.angle = float(angle[:-4]) * tau / 400.0
|
511
|
+
self.preferred_units = "grad"
|
512
|
+
elif angle.endswith("rad"):
|
513
|
+
# Must be after 'grad' since 'grad' ends with 'rad' too.
|
514
|
+
self.angle = float(angle[:-3])
|
515
|
+
self.preferred_units = "rad"
|
516
|
+
elif angle.endswith("turn"):
|
517
|
+
self.angle = float(angle[:-4]) * tau
|
518
|
+
self.preferred_units = "turn"
|
519
|
+
elif angle.endswith("%"):
|
520
|
+
self.angle = float(angle[:-1]) * tau / 100.0
|
521
|
+
self.preferred_units = "%"
|
522
|
+
else:
|
523
|
+
self.angle = float(angle)
|
524
|
+
self.preferred_units = preferred_units
|
525
|
+
|
526
|
+
def __str__(self):
|
527
|
+
return self.angle_preferred
|
528
|
+
|
529
|
+
def __copy__(self):
|
530
|
+
return Angle(
|
531
|
+
self.angle, preferred_units=self.preferred_units, digits=self._digits
|
532
|
+
)
|
533
|
+
|
534
|
+
def __eq__(self, other):
|
535
|
+
if hasattr(other, "angle"):
|
536
|
+
other = other.angle
|
537
|
+
c1 = abs((self.angle % tau) - (other % tau)) <= 1e-11
|
538
|
+
return c1
|
539
|
+
|
540
|
+
def __add__(self, other):
|
541
|
+
if isinstance(other, Angle):
|
542
|
+
return Angle(
|
543
|
+
self.angle + other.angle,
|
544
|
+
preferred_units=self.preferred_units,
|
545
|
+
digits=self._digits,
|
546
|
+
)
|
547
|
+
return Angle(
|
548
|
+
self.angle + other,
|
549
|
+
preferred_units=self.preferred_units,
|
550
|
+
digits=self._digits,
|
551
|
+
)
|
552
|
+
|
553
|
+
def __sub__(self, other):
|
554
|
+
return -self + other
|
555
|
+
|
556
|
+
def __truediv__(self, other):
|
557
|
+
return Angle(
|
558
|
+
self.radians / other,
|
559
|
+
preferred_units=self.preferred_units,
|
560
|
+
digits=self._digits,
|
561
|
+
)
|
562
|
+
|
563
|
+
def __mul__(self, other):
|
564
|
+
return Angle(
|
565
|
+
self.radians * other,
|
566
|
+
preferred_units=self.preferred_units,
|
567
|
+
digits=self._digits,
|
568
|
+
)
|
569
|
+
|
570
|
+
def __radd__(self, other):
|
571
|
+
return self.__add__(other)
|
572
|
+
|
573
|
+
def __rsub__(self, other):
|
574
|
+
return self.__neg__().__add__(other)
|
575
|
+
|
576
|
+
def __rmul__(self, other):
|
577
|
+
return self.__mul__(other)
|
578
|
+
|
579
|
+
def __iadd__(self, other):
|
580
|
+
if isinstance(other, Angle):
|
581
|
+
other = other.angle
|
582
|
+
self.angle += other
|
583
|
+
return self
|
584
|
+
|
585
|
+
def __isub__(self, other):
|
586
|
+
if isinstance(other, Angle):
|
587
|
+
other = other.angle
|
588
|
+
self.angle -= other
|
589
|
+
return self
|
590
|
+
|
591
|
+
def __imul__(self, other):
|
592
|
+
if isinstance(other, Angle):
|
593
|
+
other = other.angle
|
594
|
+
self.angle *= other
|
595
|
+
return self
|
596
|
+
|
597
|
+
def __idiv__(self, other):
|
598
|
+
if isinstance(other, Angle):
|
599
|
+
other = other.angle
|
600
|
+
self.angle /= other
|
601
|
+
return self
|
602
|
+
|
603
|
+
def __float__(self):
|
604
|
+
return self.angle
|
605
|
+
|
606
|
+
def __neg__(self):
|
607
|
+
return Angle(
|
608
|
+
-self.angle, preferred_units=self.preferred_units, digits=self._digits
|
609
|
+
)
|
610
|
+
|
611
|
+
def normalize(self):
|
612
|
+
self.angle /= tau
|
613
|
+
|
614
|
+
@classmethod
|
615
|
+
def from_radians(cls, radians):
|
616
|
+
return cls(radians)
|
617
|
+
|
618
|
+
@classmethod
|
619
|
+
def from_degrees(cls, degrees):
|
620
|
+
return cls(tau * degrees / 360.0)
|
621
|
+
|
622
|
+
@classmethod
|
623
|
+
def from_gradians(cls, gradians):
|
624
|
+
return cls(tau * gradians / 400.0)
|
625
|
+
|
626
|
+
@classmethod
|
627
|
+
def from_turns(cls, turns):
|
628
|
+
return cls(tau * turns)
|
629
|
+
|
630
|
+
@property
|
631
|
+
def angle_preferred(self):
|
632
|
+
if self.preferred_units == "rad":
|
633
|
+
return self.angle_radians
|
634
|
+
elif self.preferred_units == "grad":
|
635
|
+
return self.angle_gradians
|
636
|
+
elif self.preferred_units == "deg":
|
637
|
+
return self.angle_degrees
|
638
|
+
elif self.preferred_units == "turn":
|
639
|
+
return self.angle_turns
|
640
|
+
|
641
|
+
@property
|
642
|
+
def radians(self):
|
643
|
+
return self.angle
|
644
|
+
|
645
|
+
@property
|
646
|
+
def degrees(self):
|
647
|
+
return self.angle * 360.0 / tau
|
648
|
+
|
649
|
+
@property
|
650
|
+
def gradians(self):
|
651
|
+
return self.angle * 400.0 / tau
|
652
|
+
|
653
|
+
@property
|
654
|
+
def turns(self):
|
655
|
+
return self.angle / tau
|
656
|
+
|
657
|
+
@property
|
658
|
+
def angle_radians(self):
|
659
|
+
digits = 4 if self._digits is None else self._digits
|
660
|
+
angle = f"{self.radians:.{digits}f}".rstrip("0").rstrip(".")
|
661
|
+
return f"{angle}rad"
|
662
|
+
|
663
|
+
@property
|
664
|
+
def angle_degrees(self):
|
665
|
+
digits = 4 if self._digits is None else self._digits
|
666
|
+
angle = f"{self.degrees:.{digits}f}".rstrip("0").rstrip(".")
|
667
|
+
return f"{angle}deg"
|
668
|
+
|
669
|
+
@property
|
670
|
+
def angle_gradians(self):
|
671
|
+
digits = 4 if self._digits is None else self._digits
|
672
|
+
angle = f"{self.gradians:.{digits}f}".rstrip("0").rstrip(".")
|
673
|
+
return f"{angle}grad"
|
674
|
+
|
675
|
+
@property
|
676
|
+
def angle_turns(self):
|
677
|
+
digits = 4 if self._digits is None else self._digits
|
678
|
+
angle = f"{self.turns:.{digits}f}".rstrip("0").rstrip(".")
|
679
|
+
return f"{angle}turn"
|
680
|
+
|
681
|
+
def is_orthogonal(self):
|
682
|
+
return (self.angle % (tau / 4.0)) == 0
|
683
|
+
|
684
|
+
|
685
|
+
def viewbox_transform(
|
686
|
+
e_x, e_y, e_width, e_height, vb_x, vb_y, vb_width, vb_height, aspect
|
687
|
+
):
|
688
|
+
"""
|
689
|
+
SVG 1.1 7.2, SVG 2.0 8.2 equivalent transform of an SVG viewport.
|
690
|
+
Regarding https://github.com/w3c/svgwg/issues/215 use 8.2 version.
|
691
|
+
|
692
|
+
It creates transform commands equal to that viewport expected.
|
693
|
+
|
694
|
+
Let e-x, e-y, e-width, e-height be the position and size of the element respectively.
|
695
|
+
Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the viewBox attribute
|
696
|
+
respectively.
|
697
|
+
|
698
|
+
Let align be align value of preserveAspectRatio, or 'xMidYMid' if preserveAspectRatio is not defined.
|
699
|
+
Let meetOrSlice be the meetOrSlice value of preserveAspectRatio, or 'meet' if preserveAspectRatio is not defined
|
700
|
+
or if meetOrSlice is missing from this value.
|
701
|
+
|
702
|
+
@param e_x: element_x value
|
703
|
+
@param e_y: element_y value
|
704
|
+
@param e_width: element_width value
|
705
|
+
@param e_height: element_height value
|
706
|
+
@param vb_x: viewbox_x value
|
707
|
+
@param vb_y: viewbox_y value
|
708
|
+
@param vb_width: viewbox_width value
|
709
|
+
@param vb_height: viewbox_height value
|
710
|
+
@param aspect: preserve aspect ratio value
|
711
|
+
@return: string of the SVG transform commands to account for the viewbox.
|
712
|
+
"""
|
713
|
+
if (
|
714
|
+
e_x is None
|
715
|
+
or e_y is None
|
716
|
+
or e_width is None
|
717
|
+
or e_height is None
|
718
|
+
or vb_x is None
|
719
|
+
or vb_y is None
|
720
|
+
or vb_width is None
|
721
|
+
or vb_height is None
|
722
|
+
):
|
723
|
+
return ""
|
724
|
+
if aspect is not None:
|
725
|
+
aspect_slice = aspect.split(" ")
|
726
|
+
try:
|
727
|
+
align = aspect_slice[0]
|
728
|
+
except IndexError:
|
729
|
+
align = "xMidyMid"
|
730
|
+
try:
|
731
|
+
meet_or_slice = aspect_slice[1]
|
732
|
+
except IndexError:
|
733
|
+
meet_or_slice = "meet"
|
734
|
+
else:
|
735
|
+
align = "xMidyMid"
|
736
|
+
meet_or_slice = "meet"
|
737
|
+
# Initialize scale-x to e-width/vb-width.
|
738
|
+
scale_x = e_width / vb_width
|
739
|
+
# Initialize scale-y to e-height/vb-height.
|
740
|
+
scale_y = e_height / vb_height
|
741
|
+
|
742
|
+
# If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to the smaller.
|
743
|
+
if align != "none" and meet_or_slice == "meet":
|
744
|
+
scale_x = scale_y = min(scale_x, scale_y)
|
745
|
+
# Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x and scale-y to the larger
|
746
|
+
elif align != "none" and meet_or_slice == "slice":
|
747
|
+
scale_x = scale_y = max(scale_x, scale_y)
|
748
|
+
# Initialize translate-x to e-x - (vb-x * scale-x).
|
749
|
+
translate_x = e_x - (vb_x * scale_x)
|
750
|
+
# Initialize translate-y to e-y - (vb-y * scale-y)
|
751
|
+
translate_y = e_y - (vb_y * scale_y)
|
752
|
+
# If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x.
|
753
|
+
align = align.lower()
|
754
|
+
if "xmid" in align:
|
755
|
+
translate_x += (e_width - vb_width * scale_x) / 2.0
|
756
|
+
# If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x.
|
757
|
+
if "xmax" in align:
|
758
|
+
translate_x += e_width - vb_width * scale_x
|
759
|
+
# If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y.
|
760
|
+
if "ymid" in align:
|
761
|
+
translate_y += (e_height - vb_height * scale_y) / 2.0
|
762
|
+
# If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y.
|
763
|
+
if "ymax" in align:
|
764
|
+
translate_y += e_height - vb_height * scale_y
|
765
|
+
# The transform applied to content contained by the element is given by:
|
766
|
+
# translate(translate-x, translate-y) scale(scale-x, scale-y)
|
767
|
+
if isinstance(scale_x, Length) or isinstance(scale_y, Length):
|
768
|
+
raise ValueError
|
769
|
+
if translate_x == 0 and translate_y == 0:
|
770
|
+
if scale_x == 1 and scale_y == 1:
|
771
|
+
return "" # Nothing happens.
|
772
|
+
else:
|
773
|
+
return f"scale({scale_x:.12f}, {scale_y:.12f})"
|
774
|
+
else:
|
775
|
+
if scale_x == 1 and scale_y == 1:
|
776
|
+
return f"translate({translate_x:.12f}, {translate_y:.12f})"
|
777
|
+
else:
|
778
|
+
return (
|
779
|
+
f"translate({translate_x:.12f}, {translate_y:.12f}) "
|
780
|
+
f"scale({scale_x:.12f}, {scale_y:.12f})"
|
781
|
+
)
|
782
|
+
|
783
|
+
|
784
|
+
# TODO: Add in speed for units. mm/s in/s mm/minute.
|