mirror of
https://git.mirrors.martin98.com/https://github.com/petaflot/pygcode
synced 2025-07-29 03:02:02 +08:00
outer arc linearization
This commit is contained in:
parent
0d398d5330
commit
436ef53398
@ -1,4 +1,4 @@
|
||||
from math import acos, atan2, pi, sqrt, ceil
|
||||
from math import cos, acos, atan2, pi, sqrt, ceil
|
||||
|
||||
from .gcodes import GCodeLinearMove
|
||||
from .gcodes import GCodeArcMove, GCodeArcMoveCW, GCodeArcMoveCCW
|
||||
@ -14,8 +14,6 @@ from .utils import Vector3, Quaternion, plane_projection
|
||||
# ==================== Arcs (G2,G3) --> Linear Motion (G1) ====================
|
||||
|
||||
class ArcLinearizeMethod(object):
|
||||
pass
|
||||
|
||||
def __init__(self, max_error, plane_normal,
|
||||
arc_p_start, arc_p_end, arc_p_center,
|
||||
arc_radius, arc_angle, helical_start, helical_end):
|
||||
@ -29,6 +27,9 @@ class ArcLinearizeMethod(object):
|
||||
self.helical_start = helical_start
|
||||
self.helical_end = helical_end
|
||||
|
||||
if self.max_error > self.arc_radius:
|
||||
self.max_error = self.arc_radius
|
||||
|
||||
def get_max_wedge_angle(self):
|
||||
"""Calculate angular coverage of a single line reaching maximum allowable error"""
|
||||
raise NotImplementedError("not overridden")
|
||||
@ -56,7 +57,7 @@ class ArcLinearizeInside(ArcLinearizeMethod):
|
||||
start_radius = self.arc_p_start - self.arc_p_center
|
||||
helical_delta = (self.helical_end - self.helical_start) / wedge_count
|
||||
|
||||
l_p_start = start_radius + self.arc_p_center
|
||||
l_p_start = self.arc_p_start
|
||||
l_start = l_p_start + self.helical_start
|
||||
for i in range(wedge_count):
|
||||
q_end = Quaternion.new_rotate_axis(
|
||||
@ -70,9 +71,8 @@ class ArcLinearizeInside(ArcLinearizeMethod):
|
||||
|
||||
yield (l_start, l_end)
|
||||
|
||||
# start of next line is the end of this line
|
||||
(l_p_start, l_start) = (l_p_end, l_end)
|
||||
|
||||
# start of next line is the end of this one
|
||||
l_start = l_end
|
||||
|
||||
|
||||
class ArcLinearizeOutside(ArcLinearizeMethod):
|
||||
@ -83,6 +83,38 @@ class ArcLinearizeOutside(ArcLinearizeMethod):
|
||||
# - perimeter milling action will remove less material
|
||||
# - 1st and last lines are 1/2 length of the others
|
||||
|
||||
def get_max_wedge_angle(self):
|
||||
return abs(2 * acos(self.arc_radius / (self.arc_radius + self.max_error)))
|
||||
|
||||
def iter_vertices(self):
|
||||
# n wedges distributed like:
|
||||
# - 1/2 wedge : first line
|
||||
# - n-1 wedges : outer perimeter
|
||||
# - last 1/2 wedge : last line
|
||||
wedge_count = int(ceil(abs(self.arc_angle) / self.get_max_wedge_angle()))
|
||||
wedge_angle = self.arc_angle / wedge_count
|
||||
start_radius = self.arc_p_start - self.arc_p_center
|
||||
# radius of outer circle (across which the linear lines will span)
|
||||
error_radius = start_radius.normalized() * (self.arc_radius / cos(wedge_angle / 2))
|
||||
|
||||
l_p_start = start_radius + self.arc_p_center
|
||||
l_start = l_p_start + self.helical_start
|
||||
for i in range(wedge_count):
|
||||
cur_angle = (wedge_angle * i) + (wedge_angle / 2)
|
||||
q_end = Quaternion.new_rotate_axis(angle=cur_angle, axis=-self.plane_normal)
|
||||
|
||||
# Projected on selected plane
|
||||
l_p_end = (q_end * error_radius) + self.arc_p_center
|
||||
# Helical displacement
|
||||
l_end = l_p_end + self.helical_start + ((self.helical_end - self.helical_start) * (cur_angle / self.arc_angle))
|
||||
|
||||
yield (l_start, l_end)
|
||||
|
||||
# start of next line is the end of this one
|
||||
l_start = l_end
|
||||
|
||||
yield (l_start, self.arc_p_end + self.helical_end)
|
||||
|
||||
|
||||
class ArcLinearizeMid(ArcLinearizeMethod):
|
||||
"""Lines cross original arc from tangent of arc radius - precision/2, until it reaches arc radius + precision/2"""
|
||||
@ -244,7 +276,7 @@ def linearize_arc(arc_gcode, start_pos, plane=None, method_class=None,
|
||||
}
|
||||
method = method_class(**method_class_params)
|
||||
|
||||
#import ipdb; ipdb.set_trace()
|
||||
# Iterate & yield each linear line (start, end) vertices
|
||||
if isinstance(dist_mode, GCodeAbsoluteDistanceMode):
|
||||
# Absolute coordinates
|
||||
for line_vertices in method.iter_vertices():
|
||||
@ -256,7 +288,7 @@ def linearize_arc(arc_gcode, start_pos, plane=None, method_class=None,
|
||||
for line_vertices in method.iter_vertices():
|
||||
(l_start, l_end) = line_vertices
|
||||
l_delta = l_end - cur_pos
|
||||
|
||||
|
||||
# round delta coordinates (introduces errors)
|
||||
for axis in 'xyz':
|
||||
setattr(l_delta, axis, round(getattr(l_delta, axis), decimal_places))
|
||||
|
@ -1,4 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Script to take (theoretically) any g-code file as input, and output a
|
||||
# normalized version of it.
|
||||
#
|
||||
# Script outcome can have cursory verification with:
|
||||
# https://nraynaud.github.io/webgcode/
|
||||
|
||||
import argparse
|
||||
import re
|
||||
from collections import defaultdict
|
||||
@ -37,7 +44,8 @@ parser.add_argument(
|
||||
|
||||
parser.add_argument(
|
||||
'--precision', '-p', dest='precision', type=float, default=DEFAULT_PRECISION,
|
||||
help="maximum positional error when generating gcodes (eg: arcs to lines)",
|
||||
help="maximum positional error when generating gcodes (eg: arcs to lines) "
|
||||
"(default: %g)" % DEFAULT_PRECISION,
|
||||
)
|
||||
|
||||
# Machine
|
||||
|
Loading…
x
Reference in New Issue
Block a user