implement rotation
fix crop issues
This commit is contained in:
parent
27b5a9d8a5
commit
1a48b80734
1 changed files with 75 additions and 9 deletions
|
@ -4,6 +4,7 @@ import argparse
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import math
|
||||||
from decimal import Decimal as d
|
from decimal import Decimal as d
|
||||||
|
|
||||||
AXIS = "XYZ"
|
AXIS = "XYZ"
|
||||||
|
@ -55,6 +56,10 @@ class GCodeFilter(object):
|
||||||
yield handler.get_line(None, None)
|
yield handler.get_line(None, None)
|
||||||
else:
|
else:
|
||||||
for pos in positions:
|
for pos in positions:
|
||||||
|
if callable(pos):
|
||||||
|
pos, line = pos()
|
||||||
|
yield line
|
||||||
|
else:
|
||||||
changed_axes = self.target_pos.get_changed_axes(pos)
|
changed_axes = self.target_pos.get_changed_axes(pos)
|
||||||
yield handler.get_line(pos, changed_axes)
|
yield handler.get_line(pos, changed_axes)
|
||||||
self.target_pos.update(pos)
|
self.target_pos.update(pos)
|
||||||
|
@ -152,6 +157,25 @@ class ShiftFilter(GCodeFilter):
|
||||||
yield self.pos
|
yield self.pos
|
||||||
|
|
||||||
|
|
||||||
|
class MatrixFilter(GCodeFilter):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.matrix = kwargs.pop("matrix", tuple([0] * len(AXIS)))
|
||||||
|
super(MatrixFilter, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _multiply_with_matrix(self, pos):
|
||||||
|
rows = []
|
||||||
|
for row in self.matrix:
|
||||||
|
rows.append(sum([(p * r).quantize(p) for p, r in zip(pos, row)]))
|
||||||
|
return tuple(rows)
|
||||||
|
|
||||||
|
def transform_position(self):
|
||||||
|
if self.is_inside(self.pos):
|
||||||
|
yield self._multiply_with_matrix(self.pos)
|
||||||
|
else:
|
||||||
|
yield self.pos
|
||||||
|
|
||||||
|
|
||||||
class DensifyFilter(GCodeFilter):
|
class DensifyFilter(GCodeFilter):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -224,6 +248,7 @@ class CropFilter(GCodeFilter):
|
||||||
|
|
||||||
def transform_position(self):
|
def transform_position(self):
|
||||||
stack = self.source_pos.stack
|
stack = self.source_pos.stack
|
||||||
|
target_stack = self.target_pos.stack
|
||||||
is_inside = self.is_inside(stack[0])
|
is_inside = self.is_inside(stack[0])
|
||||||
was_inside = (len(stack) < 2) or self.is_inside(stack[1])
|
was_inside = (len(stack) < 2) or self.is_inside(stack[1])
|
||||||
result = None
|
result = None
|
||||||
|
@ -232,7 +257,21 @@ class CropFilter(GCodeFilter):
|
||||||
yield stack[0]
|
yield stack[0]
|
||||||
elif not is_inside and not was_inside:
|
elif not is_inside and not was_inside:
|
||||||
# outside -> outside
|
# outside -> outside
|
||||||
pass
|
# only apply relative upward moves (safety height)
|
||||||
|
z_index = AXIS.lower().index("z")
|
||||||
|
diff = [(now - prev) for now, prev in zip(stack[0], stack[1])]
|
||||||
|
for index, value in enumerate(diff):
|
||||||
|
if index == z_index:
|
||||||
|
if value <= 0:
|
||||||
|
break
|
||||||
|
elif value != 0:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# this looks like an upward move
|
||||||
|
if target_stack[0][z_index] <= stack[0][z_index]:
|
||||||
|
new_target = list(target_stack[0])
|
||||||
|
new_target[z_index] = stack[0][z_index]
|
||||||
|
yield tuple(new_target)
|
||||||
else:
|
else:
|
||||||
# outside -> inside OR inside -> outside
|
# outside -> inside OR inside -> outside
|
||||||
if len(stack) >= 2:
|
if len(stack) >= 2:
|
||||||
|
@ -241,6 +280,13 @@ class CropFilter(GCodeFilter):
|
||||||
border_pos = tuple([value.quantize(template)
|
border_pos = tuple([value.quantize(template)
|
||||||
for value, template in zip(border_pos, stack[0])])
|
for value, template in zip(border_pos, stack[0])])
|
||||||
# the border position is always the first step
|
# the border position is always the first step
|
||||||
|
if is_inside:
|
||||||
|
# outside -> inside
|
||||||
|
line = "G0 %s" % " ".join([axis.upper() + str(value)
|
||||||
|
for axis, value in zip(AXIS, border_pos)])
|
||||||
|
yield lambda: (border_pos, line + os.linesep)
|
||||||
|
else:
|
||||||
|
# inside -> outside
|
||||||
yield border_pos
|
yield border_pos
|
||||||
# omit the current position if we are outside
|
# omit the current position if we are outside
|
||||||
if is_inside:
|
if is_inside:
|
||||||
|
@ -262,7 +308,26 @@ class CropFilter(GCodeFilter):
|
||||||
depth_limit=depth_limit-1)
|
depth_limit=depth_limit-1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_rotate_matrix(axis, angle):
|
||||||
|
rot = [d(0)] * 3
|
||||||
|
rot[AXIS.lower().index(axis.lower())] = d(1)
|
||||||
|
# clockwise angle
|
||||||
|
angle_pi = -angle * d(math.pi / 180.0)
|
||||||
|
sin = d(math.sin(angle_pi))
|
||||||
|
cos = d(math.cos(angle_pi))
|
||||||
|
return ((cos + rot[0] * rot[0] * (1 - cos),
|
||||||
|
rot[0] * rot[1] * (1-cos) - rot[2] * sin,
|
||||||
|
rot[0] * rot[2] * (1-cos) + rot[1] * sin),
|
||||||
|
(rot[1] * rot[0] *(1 - cos) + rot[2] * sin,
|
||||||
|
cos + rot[1] * rot[1] * (1 - cos),
|
||||||
|
rot[1] * rot[2] * (1 - cos) - rot[0] * sin),
|
||||||
|
(rot[2] * rot[0] * (1 - cos) - rot[1] * sin,
|
||||||
|
rot[2] * rot[1] * (1 - cos) + rot[0] * sin,
|
||||||
|
cos + rot[2] * rot[2] * (1 - cos)))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
axes_choices = tuple(AXIS.lower() + AXIS.upper())
|
||||||
parser = argparse.ArgumentParser(description="Shift parts of gcode")
|
parser = argparse.ArgumentParser(description="Shift parts of gcode")
|
||||||
parser.add_argument('--minx', dest="minx", type=d)
|
parser.add_argument('--minx', dest="minx", type=d)
|
||||||
parser.add_argument('--maxx', dest="maxx", type=d)
|
parser.add_argument('--maxx', dest="maxx", type=d)
|
||||||
|
@ -273,9 +338,10 @@ if __name__ == "__main__":
|
||||||
parser.add_argument('--shiftx', dest="shiftx", type=d, default=d(0))
|
parser.add_argument('--shiftx', dest="shiftx", type=d, default=d(0))
|
||||||
parser.add_argument('--shifty', dest="shifty", type=d, default=d(0))
|
parser.add_argument('--shifty', dest="shifty", type=d, default=d(0))
|
||||||
parser.add_argument('--shiftz', dest="shiftz", type=d, default=d(0))
|
parser.add_argument('--shiftz', dest="shiftz", type=d, default=d(0))
|
||||||
parser.add_argument('--rotatex', dest="rotatex", type=d, default=d(0))
|
parser.add_argument('--rotate-axis', dest="rotate_axis",
|
||||||
parser.add_argument('--rotatey', dest="rotatey", type=d, default=d(0))
|
choices=axes_choices, default=AXIS[0])
|
||||||
parser.add_argument('--rotatez', dest="rotatez", type=d, default=d(0))
|
parser.add_argument('--rotate-angle', dest="rotate_angle", type=d,
|
||||||
|
default=d(90))
|
||||||
parser.add_argument('--densify-dir', dest="densify_dir",
|
parser.add_argument('--densify-dir', dest="densify_dir",
|
||||||
choices=("x", "y", "z"), default="x")
|
choices=("x", "y", "z"), default="x")
|
||||||
parser.add_argument('--densify-loops', dest="densify_loops", type=int,
|
parser.add_argument('--densify-loops', dest="densify_loops", type=int,
|
||||||
|
@ -295,8 +361,8 @@ if __name__ == "__main__":
|
||||||
elif options.action == "crop":
|
elif options.action == "crop":
|
||||||
gcode_filter = CropFilter(low, high)
|
gcode_filter = CropFilter(low, high)
|
||||||
elif options.action == "rotate":
|
elif options.action == "rotate":
|
||||||
rotate = (options.rotatex, options.rotatey, options.rotatez)
|
matrix = get_rotate_matrix(options.rotate_axis, options.rotate_angle)
|
||||||
gcode_filter = RotateFilter(low, high, rotate=rotate)
|
gcode_filter = MatrixFilter(low, high, matrix=matrix)
|
||||||
elif options.action == "densify":
|
elif options.action == "densify":
|
||||||
gcode_filter = DensifyFilter(low, high, densify_dir=options.densify_dir,
|
gcode_filter = DensifyFilter(low, high, densify_dir=options.densify_dir,
|
||||||
densify_loops=options.densify_loops,
|
densify_loops=options.densify_loops,
|
||||||
|
|
Loading…
Reference in a new issue