From af4026bcd552ee7b5fe114a73f5c61ca160383e4 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Wed, 23 Jan 2019 22:08:45 -0800 Subject: [PATCH] Added support for feeds and speeds to to cmdsForEdge. --- src/Mod/Path/PathScripts/PathGeom.py | 36 +++++++++++++++- src/Mod/Path/PathTests/TestPathGeom.py | 59 +++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index 43a09771bc..467cc276fb 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -208,7 +208,30 @@ def xy(point): Convenience function to return the projection of the Vector in the XY-plane.""" return Vector(point.x, point.y, 0) -def cmdsForEdge(edge, flip = False, useHelixForBSpline = True, segm = 50): +def speedBetweenPoints(p0, p1, hSpeed, vSpeed): + if isRoughly(hSpeed, vSpeed): + return hSpeed + + d = p1 - p0 + if isRoughly(0.0, d.z): + return hSpeed + if isRoughly(0.0, d.x) and isRoughly(0.0, d.y): + return vSpeed + # need to interpolate between hSpeed and vSpeed depending on the pitch + pitch = 2 * math.atan2(xy(d).Length, math.fabs(d.z)) / math.pi + while pitch < 0: + pitch = pitch + 1 + while pitch > 1: + pitch = pitch - 1 + print(" pitch = %g %g (%.2f, %.2f, %.2f) -> %.2f" % (pitch, math.atan2(xy(d).Length, d.z), d.x, d.y, d.z, xy(d).Length)) + speed = vSpeed + pitch * (hSpeed - vSpeed) + if speed > hSpeed and speed > vSpeed: + return max(hSpeed, vSpeed) + if speed < hSpeed and speed < vSpeed: + return min(hSpeed, vSpeed) + return speed + +def cmdsForEdge(edge, flip = False, useHelixForBSpline = True, segm = 50, hSpeed = 0, vSpeed = 0): """(edge, flip=False, useHelixForBSpline=True, segm=50) -> List(Path.Command) Returns a list of Path.Command representing the given edge. If flip is True the edge is considered to be backwards. @@ -220,6 +243,9 @@ def cmdsForEdge(edge, flip = False, useHelixForBSpline = True, segm = 50): pt = edge.valueAt(edge.LastParameter) if not flip else edge.valueAt(edge.FirstParameter) params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z} if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment: + if hSpeed > 0 and vSpeed > 0: + pt2 = edge.valueAt(edge.FirstParameter) if not flip else edge.valueAt(edge.LastParameter) + params.update({'F': speedBetweenPoints(pt, pt2, hSpeed, vSpeed)}) commands = [Path.Command('G1', params)] else: p1 = edge.valueAt(edge.FirstParameter) if not flip else edge.valueAt(edge.LastParameter) @@ -251,6 +277,9 @@ def cmdsForEdge(edge, flip = False, useHelixForBSpline = True, segm = 50): PathLog.debug("**** (%.2f, %.2f, %.2f)" % (offset.x, offset.y, offset.z)) params.update({'I': offset.x, 'J': offset.y, 'K': (p3.z - p1.z)/2}) + # G2/G3 commands are always performed at hSpeed + if hSpeed > 0: + params.update({'F': hSpeed}) commands = [ Path.Command(cmd, params) ] else: @@ -266,14 +295,19 @@ def cmdsForEdge(edge, flip = False, useHelixForBSpline = True, segm = 50): segments = int(math.ceil((deviation / eStraight.Length) * segm)) #print("**** pixellation with %d segments" % segments) dParameter = (edge.LastParameter - edge.FirstParameter) / segments + # starting point + p0 = edge.valueAt(edge.LastParameter) if flip else edge.valueAt(edge.FirstParameter) for i in range(0, segments): if flip: p = edge.valueAt(edge.LastParameter - (i + 1) * dParameter) else: p = edge.valueAt(edge.FirstParameter + (i + 1) * dParameter) + if hSpeed > 0 and vSpeed > 0: + params.update({'F': speedBetweenPoints(p0, p, hSpeed, vSpeed)}) cmd = Path.Command('G1', {'X': p.x, 'Y': p.y, 'Z': p.z}) #print("***** %s" % cmd) commands.append(cmd) + p0 = p #print commands return commands diff --git a/src/Mod/Path/PathTests/TestPathGeom.py b/src/Mod/Path/PathTests/TestPathGeom.py index 1f6aa179bd..bb175760b6 100644 --- a/src/Mod/Path/PathTests/TestPathGeom.py +++ b/src/Mod/Path/PathTests/TestPathGeom.py @@ -181,12 +181,68 @@ class TestPathGeom(PathTestBase): self.assertFalse(PathGeom.isHorizontal(xzCylinder)) self.assertFalse(PathGeom.isHorizontal(yzCylinder)) + def test07(self): + """Verify speed interpolation works for different pitches""" + # horizontal + self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(), Vector(1,1,0), 100, 50)) + self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(1,1,0), Vector(), 100, 50)) + # vertical + self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(), Vector(0,0,1), 100, 50)) + self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(0,0,1), Vector(), 100, 50)) + # 45° + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(), Vector(1,0,1), 100, 50)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(), Vector(0,1,1), 100, 50)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(), Vector(0.707,0.707,1), 100, 50), 0.01) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(1,0,1), Vector(), 100, 50)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(0,1,1), Vector(), 100, 50)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(0.707,0.707,1), Vector(), 100, 50), 0.01) + # 30° + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(), Vector(0.5774,0,1), 100, 50), 0.01) + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(), Vector(0,0.5774,1), 100, 50), 0.01) + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(0.5774,0,1), Vector(), 100, 50), 0.01) + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(0,0.5774,1), Vector(), 100, 50), 0.01) + # 60° + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(), Vector(1,0,0.5774), 100, 50), 0.01) + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(), Vector(0,1,0.5774), 100, 50), 0.01) + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(1,0,0.5774), Vector(), 100, 50), 0.01) + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(0,1,0.5774), Vector(), 100, 50), 0.01) + + def test08(self): + """Verify speed interpolation works for different pitches if vSpeed > hSpeed""" + # horizontal + self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(), Vector(1,1,0), 50, 100)) + self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(1,1,0), Vector(), 50, 100)) + # vertical + self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(), Vector(0,0,1), 50, 100)) + self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(0,0,1), Vector(), 50, 100)) + # 45° + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(), Vector(1,0,1), 50, 100)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(), Vector(0,1,1), 50, 100)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(), Vector(0.707,0.707,1), 50, 100), 0.01) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(1,0,1), Vector(), 50, 100)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(0,1,1), Vector(), 50, 100)) + self.assertRoughly( 75, PathGeom.speedBetweenPoints(Vector(0.707,0.707,1), Vector(), 50, 100), 0.01) + # 30° + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(), Vector(0.5774,0,1), 50, 100), 0.01) + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(), Vector(0,0.5774,1), 50, 100), 0.01) + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(0.5774,0,1), Vector(), 50, 100), 0.01) + self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(0,0.5774,1), Vector(), 50, 100), 0.01) + # 60° + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(), Vector(1,0,0.5774), 50, 100), 0.01) + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(), Vector(0,1,0.5774), 50, 100), 0.01) + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(1,0,0.5774), Vector(), 50, 100), 0.01) + self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(0,1,0.5774), Vector(), 50, 100), 0.01) + def test10(self): """Verify proper geometry objects for G1 and G01 commands are created.""" spt = Vector(1,2,3) self.assertLine(PathGeom.edgeForCmd(Path.Command('G1', {'X': 7, 'Y': 2, 'Z': 3}), spt), spt, Vector(7, 2, 3)) self.assertLine(PathGeom.edgeForCmd(Path.Command('G01', {'X': 1, 'Y': 3, 'Z': 5}), spt), spt, Vector(1, 3, 5)) + def test15(self): + """Verify proper feed rate for G1 commands is assigned.""" + pass + def test20(self): """Verify proper geometry for arcs in the XY-plane are created.""" p1 = Vector(0, -1, 2) @@ -262,7 +318,6 @@ class TestPathGeom(PathTestBase): self.assertCommandEqual(cmds(center, radius), cmd('G3', Vector(15, 10, 0), Vector(-5, 0, 0))) - def test50(self): """Verify proper wire(s) aggregation from a Path.""" commands = [] @@ -448,3 +503,5 @@ class TestPathGeom(PathTestBase): edge = Part.Edge(Part.BSplineCurve([Vector(-8,4,0), Vector(1,-5,0), Vector(5,11,0), Vector(12,-5,0)], weights=[2,3,5,7])) self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + +