meerk40t 0.9.7020__py2.py3-none-any.whl → 0.9.7030__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.
Files changed (39) hide show
  1. meerk40t/core/cutcode/cutcode.py +1 -1
  2. meerk40t/core/cutplan.py +70 -2
  3. meerk40t/core/elements/element_treeops.py +9 -7
  4. meerk40t/core/elements/grid.py +8 -1
  5. meerk40t/core/elements/offset_mk.py +2 -1
  6. meerk40t/core/elements/shapes.py +378 -259
  7. meerk40t/core/node/node.py +6 -3
  8. meerk40t/core/planner.py +23 -0
  9. meerk40t/core/undos.py +1 -1
  10. meerk40t/core/wordlist.py +1 -0
  11. meerk40t/dxf/dxf_io.py +6 -0
  12. meerk40t/extra/mk_potrace.py +1959 -0
  13. meerk40t/extra/param_functions.py +1 -1
  14. meerk40t/extra/potrace.py +14 -10
  15. meerk40t/grbl/interpreter.py +1 -1
  16. meerk40t/gui/about.py +3 -5
  17. meerk40t/gui/basicops.py +3 -3
  18. meerk40t/gui/choicepropertypanel.py +1 -4
  19. meerk40t/gui/gui_mixins.py +4 -1
  20. meerk40t/gui/spoolerpanel.py +6 -9
  21. meerk40t/gui/themes.py +7 -1
  22. meerk40t/gui/wxmeerk40t.py +26 -0
  23. meerk40t/gui/wxmscene.py +93 -0
  24. meerk40t/image/imagetools.py +1 -1
  25. meerk40t/kernel/kernel.py +10 -4
  26. meerk40t/kernel/settings.py +2 -0
  27. meerk40t/lihuiyu/device.py +9 -3
  28. meerk40t/main.py +22 -5
  29. meerk40t/ruida/gui/gui.py +6 -6
  30. meerk40t/ruida/gui/ruidaoperationproperties.py +1 -10
  31. meerk40t/ruida/rdjob.py +3 -3
  32. meerk40t/tools/geomstr.py +88 -0
  33. {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/METADATA +1 -1
  34. {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/RECORD +39 -38
  35. {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/WHEEL +1 -1
  36. {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/LICENSE +0 -0
  37. {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/entry_points.txt +0 -0
  38. {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/top_level.txt +0 -0
  39. {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7030.dist-info}/zip-safe +0 -0
@@ -132,7 +132,7 @@ class CutCode(CutGroup):
132
132
  length_of_previous_travel = Point.distance(prev.end, current.start)
133
133
  total_distance_travel += length_of_previous_travel
134
134
  rapid_speed = self._native_speed(cutcode)
135
- if rapid_speed is not None:
135
+ if rapid_speed is not None and rapid_speed != 0:
136
136
  total_duration_travel = total_distance_travel / rapid_speed
137
137
  duration_of_this_travel = length_of_previous_travel / rapid_speed
138
138
 
meerk40t/core/cutplan.py CHANGED
@@ -23,7 +23,7 @@ from functools import lru_cache
23
23
  import numpy as np
24
24
 
25
25
  from ..svgelements import Group, Matrix, Path, Polygon
26
- from ..tools.geomstr import Geomstr
26
+ from ..tools.geomstr import Geomstr, stitch_geometries
27
27
  from ..tools.pathtools import VectorMontonizer
28
28
  from .cutcode.cutcode import CutCode
29
29
  from .cutcode.cutgroup import CutGroup
@@ -32,7 +32,6 @@ from .cutcode.rastercut import RasterCut
32
32
  from .node.node import Node
33
33
  from .node.util_console import ConsoleOperation
34
34
  from .units import Length, UNITS_PER_MM
35
-
36
35
  """
37
36
  The time to compile does outweigh the benefit...
38
37
  try:
@@ -187,6 +186,7 @@ class CutPlan:
187
186
  placements.append(scene_to_device_matrix)
188
187
 
189
188
  original_ops = copy(self.plan)
189
+
190
190
  if self.context.opt_raster_optimisation and self.context.do_optimization:
191
191
  try:
192
192
  margin = float(Length(self.context.opt_raster_opt_margin, "0"))
@@ -244,6 +244,74 @@ class CutPlan:
244
244
  op_type = getattr(op, "type", "")
245
245
  if op_type.startswith("place "):
246
246
  continue
247
+ if op_type == "op cut" and self.context.opt_stitching and self.context.do_optimization:
248
+ # This isn't a lossless operation: dotted/dashed lines will be treated as solid lines
249
+ try:
250
+ stitch_tolerance = float(Length(self.context.opt_stitch_tolerance))
251
+ except ValueError:
252
+ stitch_tolerance = 0
253
+ default_stroke = None
254
+ default_strokewidth = None
255
+
256
+ def stitcheable_nodes(data, tolerance) -> list:
257
+ out = []
258
+ geoms = []
259
+ # Store all geometries together with an indicator, to which node they belong
260
+ for idx, node in enumerate(data):
261
+ if not hasattr(node, "as_geometry"):
262
+ continue
263
+ for g1 in node.as_geometry().as_contiguous():
264
+ geoms.append((idx, g1))
265
+ for idx1, (nodeidx1, g1) in enumerate(geoms):
266
+ for idx2 in range(idx1 + 1, len(geoms)):
267
+ nodeidx2 = geoms[idx2][0]
268
+ g2 = geoms[idx2][1]
269
+ fp1 = g1.first_point
270
+ fp2 = g2.first_point
271
+ lp1 = g1.last_point
272
+ lp2 = g2.last_point
273
+ if (
274
+ abs(lp1 - lp2) <= tolerance or
275
+ abs(lp1 - fp2) <= tolerance or
276
+ abs(fp1 - fp2) <= tolerance or
277
+ abs(fp1 - lp2) <= tolerance
278
+ ):
279
+ if nodeidx1 not in out:
280
+ out.append(nodeidx1)
281
+ if nodeidx2 not in out:
282
+ out.append(nodeidx2)
283
+
284
+ return [data[idx] for idx in out]
285
+
286
+ geoms = []
287
+ to_be_deleted = []
288
+ data = stitcheable_nodes(list(op.flat()), stitch_tolerance)
289
+ for node in data:
290
+ if node is op:
291
+ continue
292
+ if hasattr(node, "as_geometry"):
293
+ geom : Geomstr = node.as_geometry()
294
+ geoms.extend(iter(geom.as_contiguous()))
295
+ if default_stroke is None and hasattr(node, "stroke"):
296
+ default_stroke = node.stroke
297
+ if default_strokewidth is None and hasattr(node, "stroke_width"):
298
+ default_strokewidth = node.stroke_width
299
+ to_be_deleted.append(node)
300
+ result = stitch_geometries(geoms, stitch_tolerance)
301
+ if result is not None:
302
+ # print (f"Paths at start of action: {len(list(op.flat()))}")
303
+ for node in to_be_deleted:
304
+ node.remove_node()
305
+ for idx, g in enumerate(result):
306
+ node = op.add(
307
+ label=f"Stitch # {idx + 1}",
308
+ stroke=default_stroke,
309
+ stroke_width=default_strokewidth,
310
+ geometry=g,
311
+ type="elem path",
312
+ )
313
+ # print (f"Paths at start of action: {len(list(op.flat()))}")
314
+
247
315
  self.plan.append(op)
248
316
  if (op_type.startswith("op") or op_type.startswith("util")) and hasattr(op, "preprocess"):
249
317
  op.preprocess(self.context, placement, self)
@@ -2866,13 +2866,15 @@ def init_tree(kernel):
2866
2866
  dots_per_units = node.dpi / UNITS_PER_INCH
2867
2867
  new_width = width * dots_per_units
2868
2868
  new_height = height * dots_per_units
2869
-
2870
- image = make_raster(
2871
- data,
2872
- bounds=bounds,
2873
- width=new_width,
2874
- height=new_height,
2875
- )
2869
+ try:
2870
+ image = make_raster(
2871
+ data,
2872
+ bounds=bounds,
2873
+ width=new_width,
2874
+ height=new_height,
2875
+ )
2876
+ except Exception:
2877
+ return None, None
2876
2878
  matrix = Matrix.scale(width / new_width, height / new_height)
2877
2879
  matrix.post_translate(bounds[0], bounds[1])
2878
2880
  return image, matrix
@@ -198,7 +198,14 @@ def init_commands(kernel):
198
198
  y_distance += height
199
199
  if origin is None:
200
200
  origin = (1, 1)
201
- cx, cy = origin
201
+ if isinstance(origin, (tuple, list)) and isinstance(origin[0], (tuple, list)):
202
+ origin = origin[0]
203
+ try:
204
+ cx, cy = origin
205
+ except ValueError:
206
+ cx = 1
207
+ cy = 1
208
+
202
209
  data_out = list(data)
203
210
  if cx is None:
204
211
  cx = 1
@@ -360,10 +360,11 @@ def offset_path(self, path, offset_value=0):
360
360
  # As this oveloading a regular method in a class
361
361
  # it needs to have the very same definition (including the class
362
362
  # reference self)
363
+ # Radial connectors seem to have issues, so we don't use them for now...
363
364
  p = path_offset(
364
365
  path,
365
366
  offset_value=-offset_value,
366
- radial_connector=True,
367
+ radial_connector=False,
367
368
  linearize=True,
368
369
  interpolation=500,
369
370
  )