meerk40t 0.9.7910__py2.py3-none-any.whl → 0.9.7930__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 +46 -13
- meerk40t/balormk/livelightjob.py +34 -7
- meerk40t/core/cutcode/plotcut.py +2 -1
- meerk40t/core/elements/branches.py +35 -14
- meerk40t/core/elements/clipboard.py +10 -12
- meerk40t/core/elements/elements.py +23 -0
- meerk40t/core/elements/geometry.py +48 -14
- meerk40t/core/elements/grid.py +56 -24
- meerk40t/core/elements/offset_clpr.py +2 -4
- meerk40t/core/elements/placements.py +17 -22
- meerk40t/core/elements/render.py +30 -11
- meerk40t/core/elements/shapes.py +205 -125
- meerk40t/core/spoolers.py +1 -1
- meerk40t/core/units.py +4 -0
- meerk40t/grbl/emulator.py +10 -8
- meerk40t/grbl/gcodejob.py +11 -3
- meerk40t/grbl/plugin.py +10 -1
- meerk40t/gui/wxmmain.py +7 -0
- meerk40t/lihuiyu/driver.py +2 -5
- meerk40t/main.py +1 -1
- meerk40t/ruida/emulator.py +12 -9
- meerk40t/ruida/plugin.py +5 -0
- meerk40t/ruida/rdjob.py +5 -5
- meerk40t/tools/geomstr.py +15 -0
- {meerk40t-0.9.7910.dist-info → meerk40t-0.9.7930.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7910.dist-info → meerk40t-0.9.7930.dist-info}/RECORD +31 -31
- {meerk40t-0.9.7910.dist-info → meerk40t-0.9.7930.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7910.dist-info → meerk40t-0.9.7930.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7910.dist-info → meerk40t-0.9.7930.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7910.dist-info → meerk40t-0.9.7930.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7910.dist-info → meerk40t-0.9.7930.dist-info}/zip-safe +0 -0
meerk40t/balormk/controller.py
CHANGED
@@ -438,6 +438,16 @@ class GalvoController:
|
|
438
438
|
# MODE SHIFTS
|
439
439
|
#######################
|
440
440
|
|
441
|
+
def mode_shift(self, mode):
|
442
|
+
if self.source == "fiber":
|
443
|
+
self.set_fiber_mo(mode)
|
444
|
+
elif self.source == "uv":
|
445
|
+
# unclear what this does.
|
446
|
+
pass
|
447
|
+
elif self.source == "co2":
|
448
|
+
# unclear what this does.
|
449
|
+
pass
|
450
|
+
|
441
451
|
def raw_mode(self):
|
442
452
|
self.mode = DRIVER_STATE_RAW
|
443
453
|
|
@@ -452,8 +462,7 @@ class GalvoController:
|
|
452
462
|
self._list_executing = False
|
453
463
|
self._number_of_list_packets = 0
|
454
464
|
self.wait_idle()
|
455
|
-
|
456
|
-
self.set_fiber_mo(0)
|
465
|
+
self.mode_shift(0)
|
457
466
|
self.port_off(bit=0)
|
458
467
|
self.write_port()
|
459
468
|
marktime = self.get_mark_time()
|
@@ -472,15 +481,13 @@ class GalvoController:
|
|
472
481
|
self.light_off()
|
473
482
|
self.port_on(bit=0)
|
474
483
|
self.write_port()
|
475
|
-
|
476
|
-
self.set_fiber_mo(1)
|
484
|
+
self.mode_shift(1)
|
477
485
|
else:
|
478
486
|
self.mode = DRIVER_STATE_PROGRAM
|
479
487
|
self.reset_list()
|
480
488
|
self.port_on(bit=0)
|
481
489
|
self.write_port()
|
482
|
-
|
483
|
-
self.set_fiber_mo(1)
|
490
|
+
self.mode_shift(1)
|
484
491
|
self._ready = None
|
485
492
|
self._speed = None
|
486
493
|
self._travel_speed = None
|
@@ -494,8 +501,23 @@ class GalvoController:
|
|
494
501
|
self._delay_poly = None
|
495
502
|
self._delay_end = None
|
496
503
|
self.list_ready()
|
497
|
-
|
498
|
-
|
504
|
+
# Type specific initialization.
|
505
|
+
if self.source == "fiber":
|
506
|
+
if self.service.delay_openmo != 0:
|
507
|
+
self.list_delay_time(int(self.service.delay_openmo * 100))
|
508
|
+
elif self.source == "co2":
|
509
|
+
# unclear what this does.
|
510
|
+
pass
|
511
|
+
elif self.source == "uv":
|
512
|
+
"""
|
513
|
+
According to https://discord.com/channels/910979180970278922/932730275253854209/1394709596647592006
|
514
|
+
self.list_mark_frequency(0x014D) # 333
|
515
|
+
self.list_set_co2_fpk(0x0043, 0x0043) # 67, 67
|
516
|
+
self.list_mark_power_ratio(0x00F0) # 240
|
517
|
+
|
518
|
+
fpk, power, frequency are already done in set_settings.
|
519
|
+
"""
|
520
|
+
pass
|
499
521
|
self.list_write_port()
|
500
522
|
self.list_jump_speed(self.service.default_rapid_speed)
|
501
523
|
|
@@ -503,8 +525,7 @@ class GalvoController:
|
|
503
525
|
if self.mode == DRIVER_STATE_LIGHT:
|
504
526
|
return
|
505
527
|
if self.mode == DRIVER_STATE_PROGRAM:
|
506
|
-
|
507
|
-
self.set_fiber_mo(0)
|
528
|
+
self.mode_shift(0)
|
508
529
|
self.port_off(bit=0)
|
509
530
|
self.port_on(self._light_bit)
|
510
531
|
self.write_port()
|
@@ -635,6 +656,11 @@ class GalvoController:
|
|
635
656
|
self.frequency(frequency)
|
636
657
|
self.fpk(fpk)
|
637
658
|
self.power(power)
|
659
|
+
elif self.source == "uv":
|
660
|
+
self.frequency(frequency)
|
661
|
+
self.fpk(fpk)
|
662
|
+
self.power(power)
|
663
|
+
|
638
664
|
self.list_mark_speed(float(settings.get("speed", self.service.default_speed)))
|
639
665
|
|
640
666
|
if str(settings.get("timing_enabled", False)).lower() == "true":
|
@@ -893,8 +919,11 @@ class GalvoController:
|
|
893
919
|
if self.source == "co2":
|
894
920
|
power_ratio = int(round(200 * power / self._frequency))
|
895
921
|
self.list_mark_power_ratio(power_ratio)
|
896
|
-
|
922
|
+
elif self.source == "fiber":
|
897
923
|
self.list_mark_current(self._convert_power(power))
|
924
|
+
elif self.source == "uv":
|
925
|
+
power_ratio = int(round(200 * power / self._frequency))
|
926
|
+
self.list_mark_power_ratio(power_ratio)
|
898
927
|
|
899
928
|
def frequency(self, frequency):
|
900
929
|
if self._frequency == frequency:
|
@@ -904,6 +933,10 @@ class GalvoController:
|
|
904
933
|
self.list_qswitch_period(self._convert_frequency(frequency, base=20000.0))
|
905
934
|
elif self.source == "co2":
|
906
935
|
self.list_mark_frequency(self._convert_frequency(frequency, base=10000.0))
|
936
|
+
elif self.source == "uv":
|
937
|
+
# UV source uses the same frequency as CO2.
|
938
|
+
# It is not clear if this is correct.
|
939
|
+
self.list_mark_frequency(self._convert_frequency(frequency, base=10000.0))
|
907
940
|
|
908
941
|
def fpk(self, fpk):
|
909
942
|
"""
|
@@ -911,8 +944,8 @@ class GalvoController:
|
|
911
944
|
@param fpk: first_pulse_killer value in percent.
|
912
945
|
@return:
|
913
946
|
"""
|
914
|
-
if self.source
|
915
|
-
# FPK only used for CO2
|
947
|
+
if self.source not in ("co2", "uv"):
|
948
|
+
# FPK only used for CO2 and UV sources.
|
916
949
|
return
|
917
950
|
if self._fpk == fpk or fpk is None:
|
918
951
|
return
|
meerk40t/balormk/livelightjob.py
CHANGED
@@ -86,9 +86,9 @@ class LiveLightJob:
|
|
86
86
|
|
87
87
|
@property
|
88
88
|
def status(self):
|
89
|
-
if self.is_running and self.time_started is not None:
|
89
|
+
if self.is_running() and self.time_started is not None:
|
90
90
|
return "Running"
|
91
|
-
elif not self.is_running:
|
91
|
+
elif not self.is_running():
|
92
92
|
return "Disabled"
|
93
93
|
else:
|
94
94
|
return "Queued"
|
@@ -233,8 +233,8 @@ class LiveLightJob:
|
|
233
233
|
# We required them in frame.
|
234
234
|
continue
|
235
235
|
# Fix them.
|
236
|
-
x
|
237
|
-
y
|
236
|
+
x = max(min(x, 0xFFFF), 0)
|
237
|
+
y = max(min(y, 0xFFFF), 0)
|
238
238
|
if first:
|
239
239
|
first_x, first_y = x, y
|
240
240
|
first = False
|
@@ -333,7 +333,7 @@ class LiveLightJob:
|
|
333
333
|
self.update()
|
334
334
|
|
335
335
|
def update_crosshair(self):
|
336
|
-
"""Update the redlight path to display crosshairs. Fallback case when
|
336
|
+
"""Update the redlight path to display crosshairs. Fallback case when nothing can be displayed"""
|
337
337
|
margin = 5000
|
338
338
|
geometry = Geomstr.lines(
|
339
339
|
(0x8000, 0x8000),
|
@@ -348,10 +348,37 @@ class LiveLightJob:
|
|
348
348
|
)
|
349
349
|
self.prepare_redlight_point(geometry, False, "crosshair")
|
350
350
|
|
351
|
+
def update_lightning(self):
|
352
|
+
"""
|
353
|
+
Update the redlight path to display lightning bolts.
|
354
|
+
Fallback case for out of bounds paths
|
355
|
+
"""
|
356
|
+
margin = float(Length("1cm"))
|
357
|
+
orgx = self.service.view.width // 2
|
358
|
+
orgy = self.service.view.height // 2
|
359
|
+
|
360
|
+
geometry = Geomstr.lines(
|
361
|
+
(orgx - margin, orgy - 2 * margin), # top
|
362
|
+
(orgx - margin, orgy + margin),
|
363
|
+
(orgx + margin, orgy - margin),
|
364
|
+
(orgx + margin, orgy + 2 * margin),
|
365
|
+
)
|
366
|
+
geometry2 = Geomstr.lines(
|
367
|
+
(orgx + 0.5 * margin, orgy + 1.5 * margin), # left
|
368
|
+
(orgx + 0.5 * margin, orgy + 1.5 * margin), # left
|
369
|
+
(orgx + margin, orgy + 2 * margin),
|
370
|
+
(orgx + 1.5 * margin, orgy + 1.5 * margin),
|
371
|
+
(orgx + 0.5 * margin, orgy + 1.5 * margin), # left
|
372
|
+
)
|
373
|
+
geometry.append(geometry2)
|
374
|
+
|
375
|
+
self.prepare_redlight_point(geometry, True, "lightning")
|
376
|
+
|
351
377
|
def update_geometry(self):
|
352
378
|
"""Update the redlight path based on the provided geometry. Static, won't be changed."""
|
353
379
|
if self._geometry is None:
|
354
|
-
self.update_crosshair()
|
380
|
+
# self.update_crosshair()
|
381
|
+
self.update_lightning()
|
355
382
|
return
|
356
383
|
geometry = Geomstr(self._geometry)
|
357
384
|
self.prepare_redlight_point(geometry, not self.raw, "geometry")
|
@@ -363,7 +390,7 @@ class LiveLightJob:
|
|
363
390
|
return
|
364
391
|
geometry = method(elems)
|
365
392
|
if geometry is None:
|
366
|
-
self.
|
393
|
+
self.update_lightning()
|
367
394
|
return
|
368
395
|
|
369
396
|
self.prepare_redlight_point(geometry, True, source)
|
meerk40t/core/cutcode/plotcut.py
CHANGED
@@ -59,7 +59,8 @@ class PlotCut(CutObject):
|
|
59
59
|
# Default to vector settings.
|
60
60
|
self.settings["raster_step_x"] = 0
|
61
61
|
self.settings["raster_step_y"] = 0
|
62
|
-
|
62
|
+
# We shouldn't reset power here, because it is set by the plot planner.
|
63
|
+
# self.settings["power"] = 1000.0
|
63
64
|
speed = self.settings.get("speed", 0)
|
64
65
|
if speed is None:
|
65
66
|
return False
|
@@ -830,13 +830,13 @@ def init_commands(kernel):
|
|
830
830
|
|
831
831
|
@self.console_argument(
|
832
832
|
"x",
|
833
|
-
type=
|
833
|
+
type=str,
|
834
834
|
default=0,
|
835
835
|
help=_("X-Coordinate of Goto?"),
|
836
836
|
)
|
837
837
|
@self.console_argument(
|
838
838
|
"y",
|
839
|
-
type=
|
839
|
+
type=str,
|
840
840
|
default=0,
|
841
841
|
help=_("Y-Coordinate of Goto?"),
|
842
842
|
)
|
@@ -848,11 +848,22 @@ def init_commands(kernel):
|
|
848
848
|
)
|
849
849
|
def gotoop(
|
850
850
|
command,
|
851
|
+
channel,
|
852
|
+
_,
|
851
853
|
x=0,
|
852
854
|
y=0,
|
853
855
|
**kwargs,
|
854
856
|
):
|
855
|
-
|
857
|
+
lensett = self.length_settings()
|
858
|
+
try:
|
859
|
+
# fmt: off
|
860
|
+
# The goto operation expects x and y to be in parsable length format.
|
861
|
+
sx = Length(x, relative_length=self.device.view.width, settings=lensett).length_mm
|
862
|
+
sy = Length(y, relative_length=self.device.view.height, settings=lensett).length_mm
|
863
|
+
# fmt: on
|
864
|
+
except ValueError:
|
865
|
+
raise CommandSyntaxError(_("Invalid length value."))
|
866
|
+
op = self.op_branch.add(type="util goto", x=sx, y=sy)
|
856
867
|
return "ops", [op]
|
857
868
|
|
858
869
|
@self.console_command(
|
@@ -1326,10 +1337,10 @@ def init_commands(kernel):
|
|
1326
1337
|
return "elements", data
|
1327
1338
|
|
1328
1339
|
@self.console_option(
|
1329
|
-
"dx", "x", help=_("copy offset x (for elems)"), type=
|
1340
|
+
"dx", "x", help=_("copy offset x (for elems)"), type=str, default=0
|
1330
1341
|
)
|
1331
1342
|
@self.console_option(
|
1332
|
-
"dy", "y", help=_("copy offset y (for elems)"), type=
|
1343
|
+
"dy", "y", help=_("copy offset y (for elems)"), type=str, default=0
|
1333
1344
|
)
|
1334
1345
|
@self.console_option(
|
1335
1346
|
"copies", "c", help=_("amount of copies to be created"), type=int, default=1
|
@@ -1341,7 +1352,16 @@ def init_commands(kernel):
|
|
1341
1352
|
output_type=("elements", "ops"),
|
1342
1353
|
)
|
1343
1354
|
def e_copy(
|
1344
|
-
|
1355
|
+
command,
|
1356
|
+
channel,
|
1357
|
+
_,
|
1358
|
+
data=None,
|
1359
|
+
data_type=None,
|
1360
|
+
post=None,
|
1361
|
+
dx=None,
|
1362
|
+
dy=None,
|
1363
|
+
copies=None,
|
1364
|
+
**kwargs,
|
1345
1365
|
):
|
1346
1366
|
if data_type is None:
|
1347
1367
|
if data is None:
|
@@ -1378,14 +1398,15 @@ def init_commands(kernel):
|
|
1378
1398
|
self.add_ops(add_ops)
|
1379
1399
|
return "ops", add_ops
|
1380
1400
|
else:
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
x_pos = float(dx)
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1401
|
+
lensett = self.length_settings()
|
1402
|
+
try:
|
1403
|
+
# fmt: off
|
1404
|
+
x_pos = 0 if dx is None else float(Length(dx, relative_length=self.device.view.width, settings=lensett))
|
1405
|
+
y_pos = 0 if dy is None else float(Length(dy, relative_length=self.device.view.height, settings=lensett))
|
1406
|
+
# fmt: on
|
1407
|
+
except ValueError:
|
1408
|
+
channel(_("Invalid length value for copy offset."))
|
1409
|
+
return
|
1389
1410
|
add_elem = list()
|
1390
1411
|
shift = list()
|
1391
1412
|
tx = 0
|
@@ -77,8 +77,8 @@ def init_commands(kernel):
|
|
77
77
|
self.signal("icons")
|
78
78
|
return "elements", self._clipboard[destination]
|
79
79
|
|
80
|
-
@self.console_option("dx", "x", help=_("paste offset x"), type=
|
81
|
-
@self.console_option("dy", "y", help=_("paste offset y"), type=
|
80
|
+
@self.console_option("dx", "x", help=_("paste offset x"), type=str, default=0)
|
81
|
+
@self.console_option("dy", "y", help=_("paste offset y"), type=str, default=0)
|
82
82
|
@self.console_command(
|
83
83
|
"paste",
|
84
84
|
help=_("clipboard paste"),
|
@@ -123,15 +123,11 @@ def init_commands(kernel):
|
|
123
123
|
if len(pasted) == 0:
|
124
124
|
channel(_("Error: Clipboard Empty"))
|
125
125
|
return
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
else
|
130
|
-
|
131
|
-
if dy is not None:
|
132
|
-
dy = float(dy)
|
133
|
-
else:
|
134
|
-
dy = 0
|
126
|
+
lensett = self.length_settings()
|
127
|
+
# fmt: off
|
128
|
+
dx = 0 if dx is None else float(Length(dx, relative_length=self.device.view.width, settings=lensett))
|
129
|
+
dy = 0 if dy is None else float(Length(dy, relative_length=self.device.view.height, settings=lensett))
|
130
|
+
# fmt: on
|
135
131
|
if dx != 0 or dy != 0:
|
136
132
|
matrix = Matrix.translate(dx, dy)
|
137
133
|
for node in pasted:
|
@@ -139,7 +135,9 @@ def init_commands(kernel):
|
|
139
135
|
# _("Clipboard paste")
|
140
136
|
with self.undoscope("Clipboard paste"):
|
141
137
|
if len(pasted) > 1:
|
142
|
-
group = self.elem_branch.add(
|
138
|
+
group = self.elem_branch.add(
|
139
|
+
type="group", label="Group", id="Copy", expanded=True
|
140
|
+
)
|
143
141
|
else:
|
144
142
|
group = self.elem_branch
|
145
143
|
target = []
|
@@ -4404,6 +4404,29 @@ class Elemental(Service):
|
|
4404
4404
|
|
4405
4405
|
return changed, before, after
|
4406
4406
|
|
4407
|
+
def length_settings(self):
|
4408
|
+
settings = {}
|
4409
|
+
bb = self.selected_area()
|
4410
|
+
if bb is None:
|
4411
|
+
bb = [
|
4412
|
+
0,
|
4413
|
+
0,
|
4414
|
+
float(Length(self.device.view.width)),
|
4415
|
+
float(Length(self.device.view.height)),
|
4416
|
+
]
|
4417
|
+
|
4418
|
+
settings["min_x"] = bb[0]
|
4419
|
+
settings["min_y"] = bb[1]
|
4420
|
+
settings["max_x"] = bb[2]
|
4421
|
+
settings["max_y"] = bb[3]
|
4422
|
+
settings["center_x"] = (bb[0] + bb[2]) / 2
|
4423
|
+
settings["center_y"] = (bb[1] + bb[3]) / 2
|
4424
|
+
settings["width"] = bb[2] - bb[0]
|
4425
|
+
settings["height"] = bb[3] - bb[1]
|
4426
|
+
settings["width_2"] = (bb[2] - bb[0]) / 2
|
4427
|
+
settings["height_2"] = (bb[3] - bb[1]) / 2
|
4428
|
+
return settings
|
4429
|
+
|
4407
4430
|
|
4408
4431
|
def linearize_path(path, interp=50, point=False):
|
4409
4432
|
import numpy as np
|
@@ -138,6 +138,7 @@ Functions:
|
|
138
138
|
"""
|
139
139
|
|
140
140
|
from meerk40t.core.units import Angle, Length
|
141
|
+
from meerk40t.kernel import CommandSyntaxError
|
141
142
|
from meerk40t.svgelements import Matrix
|
142
143
|
from meerk40t.tools.geomstr import BeamTable, Geomstr
|
143
144
|
|
@@ -218,9 +219,9 @@ def init_commands(kernel):
|
|
218
219
|
except AssertionError:
|
219
220
|
channel(_("Geometry was not valid."))
|
220
221
|
|
221
|
-
@self.console_argument("x_pos", type=
|
222
|
-
@self.console_argument("y_pos", type=
|
223
|
-
@self.console_argument("r_pos", type=
|
222
|
+
@self.console_argument("x_pos", type=str, help=_("X position for circle center."))
|
223
|
+
@self.console_argument("y_pos", type=str, help=_("Y position for circle center."))
|
224
|
+
@self.console_argument("r_pos", type=str, help=_("Radius for circle."))
|
224
225
|
@self.console_command(
|
225
226
|
"circle",
|
226
227
|
help=_("circle <x> <y> <r>"),
|
@@ -229,7 +230,19 @@ def init_commands(kernel):
|
|
229
230
|
all_arguments_required=True,
|
230
231
|
)
|
231
232
|
def element_circle(channel, _, x_pos, y_pos, r_pos, data=None, post=None, **kwargs):
|
232
|
-
|
233
|
+
lensett = self.length_settings()
|
234
|
+
try:
|
235
|
+
# fmt: off
|
236
|
+
xp = float(Length(x_pos, relative_length=self.device.view.width, settings=lensett))
|
237
|
+
yp = float(Length(y_pos, relative_length=self.device.view.height, settings=lensett))
|
238
|
+
rp = float(Length(r_pos, settings=lensett))
|
239
|
+
# fmt: on
|
240
|
+
except ValueError:
|
241
|
+
channel(_("Invalid length value for circle."))
|
242
|
+
return
|
243
|
+
if data is None:
|
244
|
+
data = Geomstr()
|
245
|
+
data.append(Geomstr.circle(rp, xp, yp, slices=4))
|
233
246
|
return "geometry", data
|
234
247
|
|
235
248
|
@self.console_argument(
|
@@ -242,10 +255,10 @@ def init_commands(kernel):
|
|
242
255
|
type=Length,
|
243
256
|
help=_("y position for top left corner of rectangle."),
|
244
257
|
)
|
245
|
-
@self.console_argument("width", type=
|
246
|
-
@self.console_argument("height", type=
|
247
|
-
@self.console_option("rx", "x", type=
|
248
|
-
@self.console_option("ry", "y", type=
|
258
|
+
@self.console_argument("width", type=str, help=_("width of the rectangle."))
|
259
|
+
@self.console_argument("height", type=str, help=_("height of the rectangle."))
|
260
|
+
@self.console_option("rx", "x", type=str, help=_("rounded rx corner value."))
|
261
|
+
@self.console_option("ry", "y", type=str, help=_("rounded ry corner value."))
|
249
262
|
@self.console_command(
|
250
263
|
"rect",
|
251
264
|
help=_("adds rectangle to geometry"),
|
@@ -269,10 +282,21 @@ def init_commands(kernel):
|
|
269
282
|
"""
|
270
283
|
Draws a svg rectangle with optional rounded corners.
|
271
284
|
"""
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
285
|
+
lensett = self.length_settings()
|
286
|
+
try:
|
287
|
+
# fmt: off
|
288
|
+
x_pos = float(Length(x_pos, relative_length=self.device.view.width, settings=lensett))
|
289
|
+
y_pos = float(Length(y_pos, relative_length=self.device.view.height, settings=lensett))
|
290
|
+
width = float(Length(width, relative_length=self.device.view.width, settings=lensett))
|
291
|
+
height = float(Length(height, relative_length=self.device.view.height, settings=lensett))
|
292
|
+
rx = 0 if rx is None else float(Length(rx, relative_length=self.device.view.width, settings=lensett))
|
293
|
+
ry = rx if ry is None else float(Length(ry, relative_length=self.device.view.height, settings=lensett))
|
294
|
+
# fmt: on
|
295
|
+
except ValueError:
|
296
|
+
channel(_("Invalid length value."))
|
297
|
+
return
|
298
|
+
if data is None:
|
299
|
+
data = Geomstr()
|
276
300
|
data.append(
|
277
301
|
Geomstr.rect(
|
278
302
|
x=float(x_pos),
|
@@ -347,8 +371,8 @@ def init_commands(kernel):
|
|
347
371
|
data.greedy_distance(0j, flips=not no_flips)
|
348
372
|
return "geometry", data
|
349
373
|
|
350
|
-
@self.console_argument("tx", type=
|
351
|
-
@self.console_argument("ty", type=
|
374
|
+
@self.console_argument("tx", type=str, help=_("translate x value"))
|
375
|
+
@self.console_argument("ty", type=str, help=_("translate y value"))
|
352
376
|
@self.console_command(
|
353
377
|
"translate",
|
354
378
|
help=_("translate <tx> <ty>"),
|
@@ -356,6 +380,14 @@ def init_commands(kernel):
|
|
356
380
|
output_type="geometry",
|
357
381
|
)
|
358
382
|
def element_translate(tx, ty, data: Geomstr, **kwargs):
|
383
|
+
try:
|
384
|
+
lensett = self.length_settings()
|
385
|
+
# fmt: off
|
386
|
+
tx = float(Length(tx, relative_length=self.device.view.width, settings=lensett))
|
387
|
+
ty = float(Length(ty, relative_length=self.device.view.height, settings=lensett))
|
388
|
+
# fmt: on
|
389
|
+
except ValueError:
|
390
|
+
raise CommandSyntaxError(_("Invalid length value."))
|
359
391
|
data.translate(tx, ty)
|
360
392
|
return "geometry", data
|
361
393
|
|
@@ -404,6 +436,8 @@ def init_commands(kernel):
|
|
404
436
|
def geometry_hatch(data: Geomstr, distance: Length, angle: Angle, **kwargs):
|
405
437
|
segments = data.segmented()
|
406
438
|
hatch = Geomstr.hatch(segments, angle=angle.radians, distance=float(distance))
|
439
|
+
if data is None:
|
440
|
+
data = Geomstr()
|
407
441
|
data.append(hatch)
|
408
442
|
return "geometry", data
|
409
443
|
|
meerk40t/core/elements/grid.py
CHANGED
@@ -123,8 +123,18 @@ def init_commands(kernel):
|
|
123
123
|
# GRID SUBTYPE
|
124
124
|
# ==========
|
125
125
|
|
126
|
-
@self.console_argument(
|
127
|
-
|
126
|
+
@self.console_argument(
|
127
|
+
"columns",
|
128
|
+
type=int,
|
129
|
+
help=_("Number of columns"),
|
130
|
+
default=2,
|
131
|
+
)
|
132
|
+
@self.console_argument(
|
133
|
+
"rows",
|
134
|
+
type=int,
|
135
|
+
help=_("Number of rows"),
|
136
|
+
default=2,
|
137
|
+
)
|
128
138
|
@self.console_argument("x_distance", type=str, help=_("x distance"), default="100%")
|
129
139
|
@self.console_argument("y_distance", type=str, help=_("y distance"), default="100%")
|
130
140
|
@self.console_option(
|
@@ -132,7 +142,7 @@ def init_commands(kernel):
|
|
132
142
|
"o",
|
133
143
|
type=int,
|
134
144
|
nargs=2,
|
135
|
-
default
|
145
|
+
default=(1, 1),
|
136
146
|
help=_("Position of original in matrix (e.g '2,2' or '4,3')"),
|
137
147
|
)
|
138
148
|
@self.console_option(
|
@@ -186,8 +196,11 @@ def init_commands(kernel):
|
|
186
196
|
if y_distance is None:
|
187
197
|
y_distance = "100%"
|
188
198
|
try:
|
189
|
-
|
190
|
-
|
199
|
+
# fmt: off
|
200
|
+
lensett = self.length_settings()
|
201
|
+
x_distance = float(Length(x_distance, relative_length=Length(amount=width).length_mm, settings=lensett))
|
202
|
+
y_distance = float(Length(y_distance, relative_length=Length(amount=height).length_mm, settings=lensett))
|
203
|
+
# fmt: on
|
191
204
|
except ValueError:
|
192
205
|
raise CommandSyntaxError("Length could not be parsed.")
|
193
206
|
counted = 0
|
@@ -198,14 +211,16 @@ def init_commands(kernel):
|
|
198
211
|
y_distance += height
|
199
212
|
if origin is None:
|
200
213
|
origin = (1, 1)
|
201
|
-
if isinstance(origin, (tuple, list)) and isinstance(
|
214
|
+
if isinstance(origin, (tuple, list)) and isinstance(
|
215
|
+
origin[0], (tuple, list)
|
216
|
+
):
|
202
217
|
origin = origin[0]
|
203
218
|
try:
|
204
219
|
cx, cy = origin
|
205
220
|
except ValueError:
|
206
221
|
cx = 1
|
207
222
|
cy = 1
|
208
|
-
|
223
|
+
|
209
224
|
data_out = list(data)
|
210
225
|
if cx is None:
|
211
226
|
cx = 1
|
@@ -233,9 +248,13 @@ def init_commands(kernel):
|
|
233
248
|
return "elements", data_out
|
234
249
|
|
235
250
|
@self.console_argument("repeats", type=int, help=_("Number of repeats"), default=3)
|
236
|
-
@self.console_argument("radius", type=
|
237
|
-
@self.console_argument(
|
238
|
-
|
251
|
+
@self.console_argument("radius", type=str, help=_("Radius"), default="2cm")
|
252
|
+
@self.console_argument(
|
253
|
+
"startangle", type=Angle, help=_("Start-Angle"), default="0deg"
|
254
|
+
)
|
255
|
+
@self.console_argument(
|
256
|
+
"endangle", type=Angle, help=_("End-Angle"), default="360deg"
|
257
|
+
)
|
239
258
|
@self.console_option(
|
240
259
|
"unrotated",
|
241
260
|
"u",
|
@@ -271,7 +290,7 @@ def init_commands(kernel):
|
|
271
290
|
):
|
272
291
|
"""
|
273
292
|
Radial copy takes some parameters to create (potentially rotated) copies on a circular arc around a defined center
|
274
|
-
Notabene: While circ_copy is creating copies around the original elements, radial is creating all the copies
|
293
|
+
Notabene: While circ_copy is creating copies around the original elements, radial is creating all the copies
|
275
294
|
around a center just -1*radius to the left. So the original elements will be part of the circle.
|
276
295
|
"""
|
277
296
|
if data is None:
|
@@ -286,8 +305,11 @@ def init_commands(kernel):
|
|
286
305
|
raise CommandSyntaxError
|
287
306
|
if repeats <= 1:
|
288
307
|
raise CommandSyntaxError(_("repeats should be greater or equal to 2"))
|
289
|
-
|
290
|
-
|
308
|
+
try:
|
309
|
+
# fmt: off
|
310
|
+
radius = 0 if radius is None else float(Length(radius, settings=self.length_settings()))
|
311
|
+
except ValueError:
|
312
|
+
raise CommandSyntaxError(_("Invalid length value."))
|
291
313
|
|
292
314
|
if startangle is None:
|
293
315
|
startangle = Angle("0deg")
|
@@ -302,7 +324,9 @@ def init_commands(kernel):
|
|
302
324
|
return
|
303
325
|
data_out = list(data)
|
304
326
|
|
305
|
-
segment_len = (
|
327
|
+
segment_len = (
|
328
|
+
(endangle - startangle) / repeats if deltaangle is None else deltaangle
|
329
|
+
)
|
306
330
|
channel(f"Angle per step: {segment_len.angle_degrees}")
|
307
331
|
|
308
332
|
# Notabene: we are following the cartesian system here, but as the Y-Axis is top screen to bottom screen,
|
@@ -339,9 +363,9 @@ def init_commands(kernel):
|
|
339
363
|
data_out.extend(add_elem)
|
340
364
|
|
341
365
|
currentangle += segment_len
|
342
|
-
while
|
366
|
+
while currentangle.angle >= tau:
|
343
367
|
currentangle.angle -= tau
|
344
|
-
while
|
368
|
+
while currentangle.angle <= -tau:
|
345
369
|
currentangle.angle += tau
|
346
370
|
for e in images:
|
347
371
|
self.do_image_update(e)
|
@@ -353,9 +377,13 @@ def init_commands(kernel):
|
|
353
377
|
return "elements", data_out
|
354
378
|
|
355
379
|
@self.console_argument("copies", type=int, help=_("Number of copies"), default=1)
|
356
|
-
@self.console_argument("radius", type=
|
357
|
-
@self.console_argument(
|
358
|
-
|
380
|
+
@self.console_argument("radius", type=str, help=_("Radius"), default="2cm")
|
381
|
+
@self.console_argument(
|
382
|
+
"startangle", type=Angle, help=_("Start-Angle"), default="0deg"
|
383
|
+
)
|
384
|
+
@self.console_argument(
|
385
|
+
"endangle", type=Angle, help=_("End-Angle"), default="360deg"
|
386
|
+
)
|
359
387
|
@self.console_option(
|
360
388
|
"rotate",
|
361
389
|
"r",
|
@@ -392,7 +420,7 @@ def init_commands(kernel):
|
|
392
420
|
):
|
393
421
|
"""
|
394
422
|
Circular copy takes some parameters to create (potentially rotated) copies on a circular arc around the orginal element(s)
|
395
|
-
Notabene: While circ_copy is creating copies around the original elements, radial is creating all the copies
|
423
|
+
Notabene: While circ_copy is creating copies around the original elements, radial is creating all the copies
|
396
424
|
around a center just -1*radius to the left. So the original elements will be part of the circle.
|
397
425
|
"""
|
398
426
|
if data is None:
|
@@ -405,8 +433,12 @@ def init_commands(kernel):
|
|
405
433
|
raise CommandSyntaxError
|
406
434
|
if copies <= 0:
|
407
435
|
copies = 1
|
408
|
-
|
409
|
-
|
436
|
+
try:
|
437
|
+
# fmt: off
|
438
|
+
radius = 0 if radius is None else float(Length(radius, settings=self.length_settings()))
|
439
|
+
# fmt: on
|
440
|
+
except ValueError:
|
441
|
+
raise CommandSyntaxError(_("Invalid length value."))
|
410
442
|
|
411
443
|
if startangle is None:
|
412
444
|
startangle = Angle("0deg")
|
@@ -459,9 +491,9 @@ def init_commands(kernel):
|
|
459
491
|
counted += 1
|
460
492
|
data_out.extend(add_elem)
|
461
493
|
currentangle += segment_len
|
462
|
-
while
|
494
|
+
while currentangle.angle >= tau:
|
463
495
|
currentangle.angle -= tau
|
464
|
-
while
|
496
|
+
while currentangle.angle <= -tau:
|
465
497
|
currentangle.angle += tau
|
466
498
|
for e in images:
|
467
499
|
self.do_image_update(e)
|