meerk40t 0.9.7050__py2.py3-none-any.whl → 0.9.7900__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meerk40t/balormk/controller.py +3 -3
- meerk40t/balormk/device.py +7 -0
- meerk40t/balormk/driver.py +23 -14
- meerk40t/balormk/galvo_commands.py +18 -3
- meerk40t/balormk/gui/balorconfig.py +6 -0
- meerk40t/balormk/livelightjob.py +36 -14
- meerk40t/camera/camera.py +1 -0
- meerk40t/camera/gui/camerapanel.py +154 -58
- meerk40t/camera/plugin.py +46 -5
- meerk40t/core/elements/branches.py +90 -20
- meerk40t/core/elements/elements.py +59 -37
- meerk40t/core/elements/trace.py +10 -6
- meerk40t/core/node/node.py +2 -0
- meerk40t/core/plotplanner.py +7 -4
- meerk40t/device/gui/defaultactions.py +78 -14
- meerk40t/dxf/dxf_io.py +42 -0
- meerk40t/grbl/controller.py +245 -35
- meerk40t/grbl/device.py +102 -26
- meerk40t/grbl/driver.py +8 -2
- meerk40t/grbl/gui/grblconfiguration.py +6 -0
- meerk40t/grbl/gui/grblcontroller.py +1 -1
- meerk40t/gui/about.py +7 -0
- meerk40t/gui/choicepropertypanel.py +20 -30
- meerk40t/gui/devicepanel.py +27 -16
- meerk40t/gui/icons.py +15 -0
- meerk40t/gui/laserpanel.py +102 -54
- meerk40t/gui/materialtest.py +12 -2
- meerk40t/gui/mkdebug.py +268 -9
- meerk40t/gui/navigationpanels.py +65 -7
- meerk40t/gui/propertypanels/operationpropertymain.py +185 -91
- meerk40t/gui/scenewidgets/elementswidget.py +7 -1
- meerk40t/gui/scenewidgets/selectionwidget.py +24 -9
- meerk40t/gui/simulation.py +1 -1
- meerk40t/gui/statusbarwidgets/shapepropwidget.py +50 -40
- meerk40t/gui/statusbarwidgets/statusbar.py +2 -2
- meerk40t/gui/toolwidgets/toolmeasure.py +1 -1
- meerk40t/gui/toolwidgets/toolnodeedit.py +4 -1
- meerk40t/gui/toolwidgets/tooltabedit.py +9 -7
- meerk40t/gui/wxmeerk40t.py +2 -0
- meerk40t/gui/wxmmain.py +23 -9
- meerk40t/gui/wxmribbon.py +36 -0
- meerk40t/gui/wxutils.py +66 -42
- meerk40t/kernel/inhibitor.py +120 -0
- meerk40t/kernel/kernel.py +38 -0
- meerk40t/lihuiyu/controller.py +33 -3
- meerk40t/lihuiyu/device.py +99 -4
- meerk40t/lihuiyu/driver.py +62 -5
- meerk40t/lihuiyu/gui/lhycontrollergui.py +69 -24
- meerk40t/lihuiyu/gui/lhydrivergui.py +6 -0
- meerk40t/lihuiyu/laserspeed.py +17 -10
- meerk40t/lihuiyu/parser.py +23 -0
- meerk40t/main.py +1 -1
- meerk40t/moshi/gui/moshidrivergui.py +7 -0
- meerk40t/newly/controller.py +3 -2
- meerk40t/newly/device.py +23 -2
- meerk40t/newly/driver.py +8 -3
- meerk40t/newly/gui/newlyconfig.py +7 -0
- meerk40t/ruida/gui/ruidaconfig.py +7 -0
- meerk40t/tools/geomstr.py +68 -48
- meerk40t/tools/rasterplotter.py +0 -5
- meerk40t/tools/ttfparser.py +155 -82
- {meerk40t-0.9.7050.dist-info → meerk40t-0.9.7900.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7050.dist-info → meerk40t-0.9.7900.dist-info}/RECORD +68 -67
- {meerk40t-0.9.7050.dist-info → meerk40t-0.9.7900.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7050.dist-info → meerk40t-0.9.7900.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7050.dist-info → meerk40t-0.9.7900.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7050.dist-info → meerk40t-0.9.7900.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7050.dist-info → meerk40t-0.9.7900.dist-info}/zip-safe +0 -0
meerk40t/gui/laserpanel.py
CHANGED
@@ -29,7 +29,6 @@ from meerk40t.gui.wxutils import (
|
|
29
29
|
wxButton,
|
30
30
|
wxCheckBox,
|
31
31
|
wxComboBox,
|
32
|
-
wxStaticBitmap,
|
33
32
|
wxStaticText,
|
34
33
|
)
|
35
34
|
from meerk40t.kernel import lookup_listener, signal_listener
|
@@ -262,7 +261,7 @@ class LaserPanel(wx.Panel):
|
|
262
261
|
self.check_laser_arm()
|
263
262
|
|
264
263
|
self.button_outline = wxButton(self, wx.ID_ANY, _("Outline"))
|
265
|
-
self.button_outline.SetToolTip(_("Trace the outline the job"))
|
264
|
+
self.button_outline.SetToolTip(_("Trace the outline of the job"))
|
266
265
|
self.button_outline.SetBitmap(
|
267
266
|
icons8_pentagon.GetBitmap(
|
268
267
|
resize=self.icon_size,
|
@@ -332,6 +331,7 @@ class LaserPanel(wx.Panel):
|
|
332
331
|
lb_speed = wxStaticText(self, wx.ID_ANY, _("Speed"))
|
333
332
|
self.label_speed = wxStaticText(self, wx.ID_ANY, "0%")
|
334
333
|
self.slider_size = 20
|
334
|
+
self.power_mode = "relative"
|
335
335
|
self.slider_speed = wx.Slider(
|
336
336
|
self, wx.ID_ANY, value=10, minValue=1, maxValue=20
|
337
337
|
)
|
@@ -380,33 +380,67 @@ class LaserPanel(wx.Panel):
|
|
380
380
|
self.button_start_was_clicked = False
|
381
381
|
|
382
382
|
def update_override_controls(self):
|
383
|
+
def set_boundaries(slider, current_value, min_value, max_value):
|
384
|
+
slider.SetMin(min_value)
|
385
|
+
slider.SetMax(max_value)
|
386
|
+
slider.SetValue(current_value)
|
387
|
+
|
383
388
|
flag_power = False
|
384
389
|
override = False
|
385
|
-
if
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
390
|
+
if (
|
391
|
+
hasattr(self.context.device.driver, "has_adjustable_power")
|
392
|
+
and self.context.device.driver.has_adjustable_power
|
393
|
+
):
|
394
|
+
flag_power = True
|
395
|
+
# Let's establish the value and update the slider...
|
396
|
+
value = self.context.device.driver.power_scale
|
397
|
+
if value != 1:
|
398
|
+
override = True
|
399
|
+
half = self.slider_size / 2
|
400
|
+
sliderval = int(value * half)
|
401
|
+
sliderval = max(1, min(self.slider_size, sliderval))
|
402
|
+
set_boundaries(self.slider_power, sliderval, 1, self.slider_size)
|
403
|
+
self.slider_power.SetToolTip(
|
404
|
+
_("Increases/decreases the regular laser power by this amount.")
|
405
|
+
+ "\n"
|
406
|
+
+ _("This affects running jobs, so use with care!")
|
407
|
+
)
|
408
|
+
self.power_mode = "relative"
|
409
|
+
self.on_slider_power(None)
|
410
|
+
elif (
|
411
|
+
hasattr(self.context.device.driver, "has_adjustable_maximum_power")
|
412
|
+
and self.context.device.driver.has_adjustable_maximum_power
|
413
|
+
):
|
414
|
+
flag_power = True
|
415
|
+
override = True
|
416
|
+
dev_mode = getattr(self.context.kernel.root, "developer_mode", False)
|
417
|
+
# Let's establish the value and update the slider...
|
418
|
+
min_value = 1
|
419
|
+
max_value = 100 if dev_mode else 50
|
420
|
+
sliderval = min(max_value, self.context.device.driver.max_power_scale)
|
421
|
+
set_boundaries(self.slider_power, sliderval, min_value, max_value)
|
422
|
+
self.slider_power.SetToolTip(
|
423
|
+
_("Sets the maximum laser power level.")
|
424
|
+
+ "\n"
|
425
|
+
+ _("Setting this too high may cause damage to your laser tube!")
|
426
|
+
)
|
427
|
+
self.power_mode = "maximum"
|
428
|
+
self.on_slider_power(None)
|
397
429
|
flag_speed = False
|
398
|
-
if
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
430
|
+
if (
|
431
|
+
hasattr(self.context.device.driver, "has_adjustable_speed")
|
432
|
+
and self.context.device.driver.has_adjustable_speed
|
433
|
+
):
|
434
|
+
flag_speed = True
|
435
|
+
# Let's establish the value and update the slider...
|
436
|
+
value = self.context.device.driver.speed_scale
|
437
|
+
if value != 1:
|
438
|
+
override = True
|
439
|
+
half = self.slider_size / 2
|
440
|
+
sliderval = int(value * half)
|
441
|
+
sliderval = max(1, min(self.slider_size, sliderval))
|
442
|
+
set_boundaries(self.slider_speed, sliderval, 1, self.slider_size)
|
443
|
+
self.on_slider_speed(None)
|
410
444
|
|
411
445
|
self.sizer_power.Show(flag_power)
|
412
446
|
self.sizer_power.ShowItems(flag_power)
|
@@ -427,18 +461,22 @@ class LaserPanel(wx.Panel):
|
|
427
461
|
else:
|
428
462
|
self.slider_power.Enable(False)
|
429
463
|
self.slider_speed.Enable(False)
|
430
|
-
if
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
self.
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
464
|
+
if (
|
465
|
+
hasattr(self.context.device.driver, "has_adjustable_power")
|
466
|
+
and self.context.device.driver.has_adjustable_power
|
467
|
+
):
|
468
|
+
if event is not None:
|
469
|
+
self.context.device.driver.set_power_scale(1.0)
|
470
|
+
self.slider_power.SetValue(10)
|
471
|
+
self.on_slider_power(None)
|
472
|
+
if (
|
473
|
+
hasattr(self.context.device.driver, "has_adjustable_speed")
|
474
|
+
and self.context.device.driver.has_adjustable_speed
|
475
|
+
):
|
476
|
+
if event is not None:
|
477
|
+
self.context.device.driver.set_speed_scale(1.0)
|
478
|
+
self.slider_speed.SetValue(10)
|
479
|
+
self.on_slider_speed(None)
|
442
480
|
|
443
481
|
def on_slider_speed(self, event):
|
444
482
|
sliderval = self.slider_speed.GetValue()
|
@@ -452,12 +490,18 @@ class LaserPanel(wx.Panel):
|
|
452
490
|
|
453
491
|
def on_slider_power(self, event):
|
454
492
|
sliderval = self.slider_power.GetValue()
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
493
|
+
if self.power_mode == "maximum":
|
494
|
+
# Maximum power mode, so we just set the value.
|
495
|
+
if event is not None:
|
496
|
+
self.context.device.driver.max_power_scale = sliderval
|
497
|
+
msg = f"{sliderval}%"
|
498
|
+
else:
|
499
|
+
half = self.slider_size / 2
|
500
|
+
newvalue = sliderval - half # -> -9 to +10
|
501
|
+
factor = 1 + newvalue / half
|
502
|
+
if event is not None:
|
503
|
+
self.context.device.driver.set_power_scale(factor)
|
504
|
+
msg = f"{'+' if factor > 1 else ''}{100 * (factor - 1.0):.0f}%"
|
461
505
|
self.label_power.SetLabel(msg)
|
462
506
|
|
463
507
|
def on_optimize(self, event):
|
@@ -478,6 +522,14 @@ class LaserPanel(wx.Panel):
|
|
478
522
|
if self.checkbox_optimize.GetValue() != newvalue:
|
479
523
|
self.checkbox_optimize.SetValue(newvalue)
|
480
524
|
|
525
|
+
@signal_listener("pwm_mode_changed")
|
526
|
+
def on_pwm_mode_changed(self, origin, *message):
|
527
|
+
"""
|
528
|
+
This is called when the power scale of the device changes.
|
529
|
+
It updates the slider and label accordingly.
|
530
|
+
"""
|
531
|
+
self.update_override_controls()
|
532
|
+
|
481
533
|
@signal_listener("device;modified")
|
482
534
|
@signal_listener("device;renamed")
|
483
535
|
@lookup_listener("service/device/active")
|
@@ -655,13 +707,12 @@ class LaserPanel(wx.Panel):
|
|
655
707
|
self.context.setting(bool, "laserpane_hold", False)
|
656
708
|
if plan.plan and self.context.laserpane_hold:
|
657
709
|
self.context("planz spool\n")
|
710
|
+
elif self.checkbox_optimize.GetValue():
|
711
|
+
self.context(
|
712
|
+
"planz clear copy preprocess validate blob preopt optimize spool\n"
|
713
|
+
)
|
658
714
|
else:
|
659
|
-
|
660
|
-
self.context(
|
661
|
-
"planz clear copy preprocess validate blob preopt optimize spool\n"
|
662
|
-
)
|
663
|
-
else:
|
664
|
-
self.context("planz clear copy preprocess validate blob spool\n")
|
715
|
+
self.context("planz clear copy preprocess validate blob spool\n")
|
665
716
|
self.armed = False
|
666
717
|
self.check_laser_arm()
|
667
718
|
if self.context.auto_spooler:
|
@@ -807,10 +858,7 @@ class JobPanel(wx.Panel):
|
|
807
858
|
|
808
859
|
if not pathname.lower().endswith(f".{extension}"):
|
809
860
|
pathname += f".{extension}"
|
810
|
-
if self.context.planner.do_optimization
|
811
|
-
optpart = "preopt optimize "
|
812
|
-
else:
|
813
|
-
optpart = ""
|
861
|
+
optpart = "preopt optimize " if self.context.planner.do_optimization else ""
|
814
862
|
self.context(
|
815
863
|
f'planz clear copy preprocess validate blob {optpart}save_job "{pathname}"\n'
|
816
864
|
)
|
meerk40t/gui/materialtest.py
CHANGED
@@ -947,6 +947,11 @@ class TemplatePanel(wx.Panel):
|
|
947
947
|
standard_items = False
|
948
948
|
choices = self.parameters[idx][7]
|
949
949
|
self.list_options_1.Set(choices)
|
950
|
+
self.list_options_1.SetToolTip(
|
951
|
+
_("Select the values you want to test for {param}").format(
|
952
|
+
param=self.parameters[idx][2]
|
953
|
+
)
|
954
|
+
)
|
950
955
|
checked_strings = [
|
951
956
|
s for s in self.context.template_list1.split("|") if s
|
952
957
|
]
|
@@ -981,6 +986,11 @@ class TemplatePanel(wx.Panel):
|
|
981
986
|
standard_items = False
|
982
987
|
choices = self.parameters[idx][7]
|
983
988
|
self.list_options_2.Set(choices)
|
989
|
+
self.list_options_2.SetToolTip(
|
990
|
+
_("Select the values you want to test for {param}").format(
|
991
|
+
param=self.parameters[idx][2]
|
992
|
+
)
|
993
|
+
)
|
984
994
|
checked_strings = [
|
985
995
|
s for s in self.context.template_list2.split("|") if s
|
986
996
|
]
|
@@ -1031,7 +1041,7 @@ class TemplatePanel(wx.Panel):
|
|
1031
1041
|
if self.parameters[idx1][7] is not None:
|
1032
1042
|
if not self.list_options_1.GetCheckedStrings():
|
1033
1043
|
active = False
|
1034
|
-
valid_interval_1 =
|
1044
|
+
valid_interval_1 = False
|
1035
1045
|
else:
|
1036
1046
|
if not valid_float(self.text_min_1):
|
1037
1047
|
active = False
|
@@ -1042,7 +1052,7 @@ class TemplatePanel(wx.Panel):
|
|
1042
1052
|
if self.parameters[idx2][7] is not None:
|
1043
1053
|
if not self.list_options_2.GetCheckedStrings():
|
1044
1054
|
active = False
|
1045
|
-
valid_interval_2 =
|
1055
|
+
valid_interval_2 = False
|
1046
1056
|
else:
|
1047
1057
|
if not valid_float(self.text_min_2):
|
1048
1058
|
active = False
|
meerk40t/gui/mkdebug.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
"""
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
This module contains panels that display internal developer information.
|
3
|
+
They will become visible if you type 'set debug_mode True' in the
|
4
|
+
console and restart the program.
|
5
5
|
"""
|
6
6
|
|
7
7
|
import time
|
@@ -10,6 +10,17 @@ import wx
|
|
10
10
|
from wx import aui
|
11
11
|
|
12
12
|
import meerk40t.gui.icons as mkicons
|
13
|
+
from meerk40t.constants import (
|
14
|
+
RASTER_B2T,
|
15
|
+
RASTER_CROSSOVER,
|
16
|
+
RASTER_GREEDY_H,
|
17
|
+
RASTER_GREEDY_V,
|
18
|
+
RASTER_HATCH,
|
19
|
+
RASTER_L2R,
|
20
|
+
RASTER_R2L,
|
21
|
+
RASTER_SPIRAL,
|
22
|
+
RASTER_T2B,
|
23
|
+
)
|
13
24
|
from meerk40t.core.units import Angle, Length
|
14
25
|
from meerk40t.gui.wxutils import (
|
15
26
|
ScrolledPanel,
|
@@ -123,6 +134,25 @@ def register_panel_window(window, context):
|
|
123
134
|
context.register("pane/debug_window", pane)
|
124
135
|
|
125
136
|
|
137
|
+
def register_panel_plotter(window, context):
|
138
|
+
pane = (
|
139
|
+
aui.AuiPaneInfo()
|
140
|
+
.Float()
|
141
|
+
.MinSize(225, 110)
|
142
|
+
.FloatingSize(400, 400)
|
143
|
+
.Caption(_("Plotter Test"))
|
144
|
+
.CaptionVisible(not context.pane_lock)
|
145
|
+
.Name("debug_plotter")
|
146
|
+
.Hide()
|
147
|
+
)
|
148
|
+
pane.dock_proportion = 225
|
149
|
+
pane.control = DebugRasterPlotterPanel(window, wx.ID_ANY, context=context)
|
150
|
+
pane.submenu = "_ZZ_" + _("Debug")
|
151
|
+
pane.helptext = _("Raster plotter test")
|
152
|
+
window.on_pane_create(pane)
|
153
|
+
context.register("pane/debug_plotter", pane)
|
154
|
+
|
155
|
+
|
126
156
|
class ShutdownPanel(wx.Panel):
|
127
157
|
"""
|
128
158
|
Tries to create a scenario that has led to multiple runtime errors durign shutdown
|
@@ -339,7 +369,7 @@ class DebugColorPanel(ScrolledPanel):
|
|
339
369
|
sizer_main.Add(sizer_line, 0, wx.EXPAND, 0)
|
340
370
|
count = 0
|
341
371
|
|
342
|
-
col:wx.Colour = wx.SystemSettings().GetColour(getattr(wx, prop))
|
372
|
+
col: wx.Colour = wx.SystemSettings().GetColour(getattr(wx, prop))
|
343
373
|
infosizer = wx.BoxSizer(wx.VERTICAL)
|
344
374
|
box = wxStaticBitmap(
|
345
375
|
self, wx.ID_ANY, size=wx.Size(32, 32), style=wx.SB_RAISED
|
@@ -518,8 +548,13 @@ class DebugIconPanel(wx.Panel):
|
|
518
548
|
if obj is not None:
|
519
549
|
if isinstance(obj, (mkicons.VectorIcon, mkicons.PyEmbeddedImage)):
|
520
550
|
imgs = self.icon_show.Size
|
521
|
-
ms =
|
522
|
-
|
551
|
+
ms = (
|
552
|
+
min(imgs[0], imgs[1])
|
553
|
+
* self.context.root.bitmap_correction_scale
|
554
|
+
)
|
555
|
+
bmp = obj.GetBitmap(
|
556
|
+
resize=ms, force_darkmode=self.context.themes.dark
|
557
|
+
)
|
523
558
|
self.icon_show.SetBitmap(bmp)
|
524
559
|
|
525
560
|
def pane_show(self, *args):
|
@@ -578,11 +613,19 @@ class DebugWindowPanel(wx.Panel):
|
|
578
613
|
toggle_left = wx.ToggleButton(self, wx.ID_ANY, "Toggle")
|
579
614
|
radio_left = wx.RadioBox(self, wx.ID_ANY, choices=("Yes", "No", "Maybe"))
|
580
615
|
btn_bmap_left = wx.BitmapButton(
|
581
|
-
self,
|
616
|
+
self,
|
617
|
+
wx.ID_ANY,
|
618
|
+
mkicons.icon_bell.GetBitmap(
|
619
|
+
resize=mkicons.get_default_icon_size(self.context) / 2
|
620
|
+
),
|
582
621
|
)
|
583
622
|
slider_left = wx.Slider(self, wx.ID_ANY, value=0, minValue=0, maxValue=100)
|
584
623
|
static_left = wx.StaticBitmap(
|
585
|
-
self,
|
624
|
+
self,
|
625
|
+
wx.ID_ANY,
|
626
|
+
mkicons.icon_closed_door.GetBitmap(
|
627
|
+
resize=mkicons.get_default_icon_size(self.context)
|
628
|
+
),
|
586
629
|
)
|
587
630
|
left_side.Add(cb_left, 0, 0, 0)
|
588
631
|
left_side.Add(text_left, 0, 0, 0)
|
@@ -605,7 +648,11 @@ class DebugWindowPanel(wx.Panel):
|
|
605
648
|
toggle_right = wxToggleButton(self, wx.ID_ANY, "Toggle")
|
606
649
|
radio_right = wxRadioBox(self, wx.ID_ANY, choices=("Yes", "No", "Maybe"))
|
607
650
|
static_right = wxStaticBitmap(
|
608
|
-
self,
|
651
|
+
self,
|
652
|
+
wx.ID_ANY,
|
653
|
+
mkicons.icon_closed_door.GetBitmap(
|
654
|
+
resize=mkicons.get_default_icon_size(self.context)
|
655
|
+
),
|
609
656
|
)
|
610
657
|
# right_side.Add(cb_right, 0, 0, 0)
|
611
658
|
right_side.Add(text_right, 0, 0, 0)
|
@@ -644,3 +691,215 @@ class DebugWindowPanel(wx.Panel):
|
|
644
691
|
|
645
692
|
def pane_hide(self, *args):
|
646
693
|
return
|
694
|
+
|
695
|
+
|
696
|
+
class DebugRasterPlotterPanel(wx.Panel):
|
697
|
+
def __init__(self, *args, context=None, **kwds):
|
698
|
+
# begin wxGlade: PositionPanel.__init__
|
699
|
+
kwds["style"] = kwds.get("style", 0) | wx.TAB_TRAVERSAL
|
700
|
+
wx.Panel.__init__(self, *args, **kwds)
|
701
|
+
|
702
|
+
self.context = context
|
703
|
+
self.context.themes.set_window_colors(self)
|
704
|
+
|
705
|
+
sizer_main = wx.BoxSizer(wx.VERTICAL)
|
706
|
+
info = StaticBoxSizer(
|
707
|
+
self, wx.ID_ANY, _("Raster Plotter Test Info"), wx.HORIZONTAL
|
708
|
+
)
|
709
|
+
info.Add(
|
710
|
+
wxStaticText(self, wx.ID_ANY, "Dimensions:"), 0, wx.ALIGN_CENTER_VERTICAL, 0
|
711
|
+
)
|
712
|
+
self.text_x = TextCtrl(self, wx.ID_ANY, "1", check="int")
|
713
|
+
self.text_y = TextCtrl(self, wx.ID_ANY, "1", check="int")
|
714
|
+
info.Add(self.text_x, 1, wx.EXPAND, 0)
|
715
|
+
info.Add(wxStaticText(self, wx.ID_ANY, "x"), 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
716
|
+
info.Add(self.text_y, 1, wx.EXPAND, 0)
|
717
|
+
info.Add(wxStaticText(self, wx.ID_ANY, "pixel"), 0, wx.ALIGN_CENTER_VERTICAL, 0)
|
718
|
+
# raster properties
|
719
|
+
raster_sizer = StaticBoxSizer(
|
720
|
+
self, wx.ID_ANY, _("Raster Properties"), wx.VERTICAL
|
721
|
+
)
|
722
|
+
raster_type_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
723
|
+
raster_sizer.Add(raster_type_sizer, 0, wx.EXPAND, 0)
|
724
|
+
self.raster_terms = [
|
725
|
+
(RASTER_T2B, "Top To Bottom"),
|
726
|
+
(RASTER_B2T, "Bottom To Top"),
|
727
|
+
(RASTER_R2L, "Right To Left"),
|
728
|
+
(RASTER_L2R, "Left To Right"),
|
729
|
+
(RASTER_HATCH, "Crosshatch"),
|
730
|
+
(RASTER_GREEDY_H, "Greedy horizontal"),
|
731
|
+
(RASTER_GREEDY_V, "Greedy vertical"),
|
732
|
+
(RASTER_CROSSOVER, "Crossover"),
|
733
|
+
(RASTER_SPIRAL, "Spiral"),
|
734
|
+
]
|
735
|
+
# Look for registered raster (image) preprocessors,
|
736
|
+
# these are routines that take one image as parameter
|
737
|
+
# and deliver a set of (result image, method (aka raster_direction) )
|
738
|
+
# that will be dealt with independently
|
739
|
+
# The registered datastructure is (rasterid, description, method)
|
740
|
+
self.raster_terms.extend(
|
741
|
+
(key, description)
|
742
|
+
for key, description, method in self.context.kernel.lookup_all(
|
743
|
+
"raster_preprocessor/.*"
|
744
|
+
)
|
745
|
+
)
|
746
|
+
# Add a couple of testcases
|
747
|
+
# test_methods = (
|
748
|
+
# (-1, "Test: Horizontal Rectangle"),
|
749
|
+
# (-2, "Test: Vertical Rectangle"),
|
750
|
+
# (-3, "Test: Horizontal Snake"),
|
751
|
+
# (-4, "Test: Vertical Snake"),
|
752
|
+
# (-5, "Test: Spiral"),
|
753
|
+
# )
|
754
|
+
# self.raster_terms.extend(test_methods)
|
755
|
+
|
756
|
+
self.raster_methods = [key for key, info in self.raster_terms]
|
757
|
+
|
758
|
+
self.combo_raster_direction = wxComboBox(
|
759
|
+
self,
|
760
|
+
wx.ID_ANY,
|
761
|
+
style=wx.CB_DROPDOWN | wx.CB_READONLY,
|
762
|
+
)
|
763
|
+
raster_type_sizer.Add(
|
764
|
+
wxStaticText(self, wx.ID_ANY, "Raster Direction:"),
|
765
|
+
0,
|
766
|
+
wx.ALIGN_CENTER_VERTICAL,
|
767
|
+
0,
|
768
|
+
)
|
769
|
+
self.combo_raster_direction.AppendItems(
|
770
|
+
[info for key, info in self.raster_terms]
|
771
|
+
)
|
772
|
+
raster_type_sizer.Add(
|
773
|
+
self.combo_raster_direction, 1, wx.ALIGN_CENTER_VERTICAL, 0
|
774
|
+
)
|
775
|
+
self.check_raster_bidirectional = wxCheckBox(self, wx.ID_ANY, "Bidirectional")
|
776
|
+
|
777
|
+
raster_type_sizer.Add(
|
778
|
+
self.check_raster_bidirectional, 0, wx.ALIGN_CENTER_VERTICAL, 0
|
779
|
+
)
|
780
|
+
self.combo_raster_direction.SetSelection(0)
|
781
|
+
|
782
|
+
buttons = wx.BoxSizer(wx.HORIZONTAL)
|
783
|
+
self.btn_test_onepixel_black = wxButton(self, wx.ID_ANY, "Fully Black")
|
784
|
+
self.btn_test_onepixel_white = wxButton(self, wx.ID_ANY, "Fully White")
|
785
|
+
buttons.Add(self.btn_test_onepixel_black, 1, wx.EXPAND, 0)
|
786
|
+
buttons.Add(self.btn_test_onepixel_white, 1, wx.EXPAND, 0)
|
787
|
+
self.text_result = TextCtrl(
|
788
|
+
self, wx.ID_ANY, style=wx.TE_MULTILINE | wx.TE_READONLY
|
789
|
+
)
|
790
|
+
|
791
|
+
sizer_main.Add(info, 0, wx.EXPAND, 0)
|
792
|
+
sizer_main.Add(raster_sizer, 0, wx.EXPAND, 0)
|
793
|
+
sizer_main.Add(buttons, 0, wx.EXPAND, 0)
|
794
|
+
sizer_main.Add(self.text_result, 1, wx.EXPAND, 0)
|
795
|
+
|
796
|
+
self.SetSizer(sizer_main)
|
797
|
+
sizer_main.Fit(self)
|
798
|
+
self.Layout()
|
799
|
+
|
800
|
+
self.btn_test_onepixel_black.Bind(wx.EVT_BUTTON, self.test_empty_image)
|
801
|
+
self.btn_test_onepixel_white.Bind(wx.EVT_BUTTON, self.test_fully_covered_image)
|
802
|
+
|
803
|
+
def test_empty_image(self, event):
|
804
|
+
"""
|
805
|
+
Tests the speed of rasterplotter for a fully black image.
|
806
|
+
"""
|
807
|
+
import numpy as np
|
808
|
+
from PIL import Image, ImageDraw
|
809
|
+
|
810
|
+
from meerk40t.tools.rasterplotter import RasterPlotter
|
811
|
+
|
812
|
+
try:
|
813
|
+
x = int(self.text_x.GetValue())
|
814
|
+
y = int(self.text_y.GetValue())
|
815
|
+
except ValueError:
|
816
|
+
self.text_result.SetValue("Invalid dimensions. Please enter integers.")
|
817
|
+
return
|
818
|
+
raster_string = self.combo_raster_direction.GetStringSelection()
|
819
|
+
raster_direction = -1
|
820
|
+
for key, info in self.raster_terms:
|
821
|
+
if raster_string == info:
|
822
|
+
raster_direction = key
|
823
|
+
break
|
824
|
+
if raster_direction < 0:
|
825
|
+
self.text_result.SetValue("Invalid raster direction selected.")
|
826
|
+
return
|
827
|
+
bidir = self.check_raster_bidirectional.GetValue()
|
828
|
+
|
829
|
+
# Notabene: a black pixel is a non-burnt one, so we invert the logic here
|
830
|
+
image = Image.new("RGBA", (x, y), "white")
|
831
|
+
image = image.convert("L")
|
832
|
+
plotter = RasterPlotter(image.load(), x, y, direction=raster_direction, bidirectional=bidir)
|
833
|
+
t = time.time()
|
834
|
+
i = 0
|
835
|
+
res = []
|
836
|
+
pixels = 0
|
837
|
+
last_x, last_y = plotter.initial_position_in_scene()
|
838
|
+
for x, y, on in plotter.plot():
|
839
|
+
i += 1
|
840
|
+
if on:
|
841
|
+
pixels += (abs(x - last_x) + 1) * (abs(y - last_y) + 1)
|
842
|
+
res.append(f"{i}: ({x}, {y}) {'on' if on else 'off'}")
|
843
|
+
last_x, last_y = x, y
|
844
|
+
ipos = plotter.initial_position_in_scene()
|
845
|
+
lpos = plotter.final_position_in_scene()
|
846
|
+
res.insert(
|
847
|
+
0,
|
848
|
+
f"Black found: {pixels} pixels: ranging from ({ipos[0]}, {ipos[1]}) to ({lpos[0]}, {lpos[1]})",
|
849
|
+
)
|
850
|
+
res.append(f"Time taken to finish process {time.time() - t:.3f}s\n")
|
851
|
+
self.text_result.SetValue("\n".join(res))
|
852
|
+
|
853
|
+
def test_fully_covered_image(self, event):
|
854
|
+
"""
|
855
|
+
Tests the speed of rasterplotter for a fully black image.
|
856
|
+
"""
|
857
|
+
import numpy as np
|
858
|
+
from PIL import Image, ImageDraw
|
859
|
+
|
860
|
+
from meerk40t.tools.rasterplotter import RasterPlotter
|
861
|
+
|
862
|
+
try:
|
863
|
+
x = int(self.text_x.GetValue())
|
864
|
+
y = int(self.text_y.GetValue())
|
865
|
+
except ValueError:
|
866
|
+
self.text_result.SetValue("Invalid dimensions. Please enter integers.")
|
867
|
+
return
|
868
|
+
if self.combo_raster_direction.GetSelection() < 0:
|
869
|
+
self.text_result.SetValue("Please select a raster direction.")
|
870
|
+
return
|
871
|
+
raster_string = self.combo_raster_direction.GetStringSelection()
|
872
|
+
raster_direction = -1
|
873
|
+
for key, info in self.raster_terms:
|
874
|
+
if raster_string == info:
|
875
|
+
raster_direction = key
|
876
|
+
break
|
877
|
+
if raster_direction < 0:
|
878
|
+
self.text_result.SetValue("Invalid raster direction selected.")
|
879
|
+
return
|
880
|
+
bidir = self.check_raster_bidirectional.GetValue()
|
881
|
+
|
882
|
+
# Notabene: a black pixel is a non-burnt one, so we invert the logic here
|
883
|
+
image = Image.new("RGBA", (x, y), "black")
|
884
|
+
image = image.convert("L")
|
885
|
+
|
886
|
+
plotter = RasterPlotter(image.load(), x, y, direction=raster_direction, bidirectional=bidir)
|
887
|
+
t = time.time()
|
888
|
+
i = 0
|
889
|
+
res = []
|
890
|
+
pixels = 0
|
891
|
+
ipos = plotter.initial_position_in_scene()
|
892
|
+
lpos = plotter.final_position_in_scene()
|
893
|
+
last_x, last_y = ipos
|
894
|
+
for x, y, on in plotter.plot():
|
895
|
+
i += 1
|
896
|
+
if on:
|
897
|
+
pixels += (abs(x - last_x) + 1) * (abs(y - last_y) + 1)
|
898
|
+
res.append(f"{i}: ({x}, {y}) {'on' if on else 'off'}")
|
899
|
+
last_x, last_y = x, y
|
900
|
+
res.insert(
|
901
|
+
0,
|
902
|
+
f"White found: {pixels} pixels: ranging from ({ipos[0]}, {ipos[1]}) to ({lpos[0]}, {lpos[1]})",
|
903
|
+
)
|
904
|
+
res.append(f"Time taken to finish process {time.time() - t:.3f}s\n")
|
905
|
+
self.text_result.SetValue("\n".join(res))
|