diff --git a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py index e501c8173..3441eb042 100644 --- a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py +++ b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py @@ -175,36 +175,43 @@ class Tag: if type(edge.Curve) is Part.Line: z = edge.Curve.StartPoint.z elif type(edge.Curve) is Part.Circle: + # it's an arc z = edge.Curve.Center.z - + else: + # it's a helix -> transform to arc + z = 0 + p1 = PathGeom.xy(edge.valueAt(edge.FirstParameter)) + p2 = PathGeom.xy(edge.valueAt((edge.FirstParameter + edge.LastParameter)/2)) + p3 = PathGeom.xy(edge.valueAt(edge.LastParameter)) + edge = Part.Edge(Part.Arc(p1, p2, p3)) edge.translate(Vector(0, 0, self.tag.top() - z)) return edge def intersectP0Core(self, edge): - print("----- P0 (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) + #print("----- P0 (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.valueAt(edge.FirstParameter)) if i: if PathGeom.pointsCoincide(i, edge.valueAt(edge.FirstParameter)): # if P0 and P1 are the same, we need to insert a segment for the rise - print("------- insert vertical rise (%s)" % i) + #print("------- insert vertical rise (%s)" % i) self.edges.append(Part.Edge(Part.Line(i, FreeCAD.Vector(i.x, i.y, self.tag.top())))) self.p1 = i self.state = self.P1 return edge if PathGeom.pointsCoincide(i, edge.valueAt(edge.LastParameter)): - print("------- consumed (%s)" % i) + #print("------- consumed (%s)" % i) e = edge tail = None else: - print("------- split at (%s)" % i) + #print("------- split at (%s)" % i) e, tail = self.tag.splitEdgeAt(edge, i) self.p1 = e.valueAt(edge.LastParameter) self.edges.append(self.tag.mapEdgeToSolid(e)) self.state = self.P1 return tail # no intersection, the entire edge fits between P0 and P1 - print("------- no intersection") + #print("------- no intersection") self.edges.append(self.tag.mapEdgeToSolid(edge)) return None @@ -232,36 +239,46 @@ class Tag: def intersectP1(self, edge): - print("----- P1 (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) + #print("----- P1 (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) i = self.tag.nextIntersectionClosestTo(edge, self.tag.core, edge.valueAt(edge.LastParameter)) if i: if PathGeom.pointsCoincide(i, edge.valueAt(edge.FirstParameter)): + #print("----- P1 edge too short") self.edges.append(self.tag.mapEdgeToSolid(edge)) return self if PathGeom.pointsCoincide(i, edge.valueAt(edge.LastParameter)): + #print("----- P1 edge at end") e = edge tail = None else: + #print("----- P1 split edge @ (%.2f, %.2f, %.2f)" % (i.x, i.y, i.z)) e, tail = self.tag.splitEdgeAt(edge, i) - self.p2 = e.valueAt(edge.LastParameter) + f = e.valueAt(e.FirstParameter) + l = e.valueAt(e.LastParameter) + #print("----- P1 (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (f.x, f.y, f.z, l.x, l.y, l.z)) + self.p2 = e.valueAt(e.LastParameter) self.state = self.P2 else: + #print("----- P1 no intersect") e = edge tail = None + f = e.valueAt(e.FirstParameter) + l = e.valueAt(e.LastParameter) + #print("----- P1 (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (f.x, f.y, f.z, l.x, l.y, l.z)) self.edges.append(self.moveEdgeToPlateau(e)) return tail def intersectP2(self, edge): - print("----- P2 (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) + #print("----- P2 (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) i = self.tag.nextIntersectionClosestTo(edge, self.tag.solid, edge.valueAt(edge.LastParameter)) if i: if PathGeom.pointsCoincide(i, edge.valueAt(edge.FirstParameter)): - print("------- insert exit plunge (%s)" % i) + #print("------- insert exit plunge (%s)" % i) self.edges.append(Part.Edge(Part.Line(FreeCAD.Vector(i.x, i.y, self.tag.top()), i))) e = None tail = edge elif PathGeom.pointsCoincide(i, edge.valueAt(edge.LastParameter)): - print("------- entire segment added (%s)" % i) + #print("------- entire segment added (%s)" % i) e = edge tail = None else: @@ -280,8 +297,8 @@ class Tag: return tail def intersect(self, edge): - print("") - print(" >>> (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) + #print("") + #print(" >>> (%s - %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) if edge and self.state == self.P0: edge = self.intersectP0(edge) if edge and self.state == self.P1: @@ -294,25 +311,62 @@ class Tag: def splitEdgeAt(self, edge, pt): p = edge.Curve.parameter(pt) wire = edge.split(p) + # split does not carry the Placement of the original curve foward ... + wire.transformShape(edge.Placement.toMatrix()) return wire.Edges def mapEdgeToSolid(self, edge): - print("mapEdgeToSolid: (%s %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) + #print("mapEdgeToSolid: (%s %s)" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter))) p1a = edge.valueAt(edge.FirstParameter) p1b = FreeCAD.Vector(p1a.x, p1a.y, p1a.z + self.height) e1 = Part.Edge(Part.Line(p1a, p1b)) p1 = self.nextIntersectionClosestTo(e1, self.solid, p1b) # top most intersection - print(" p1: (%s %s) -> %s" % (p1a, p1b, p1)) + #print(" p1: (%s %s) -> %s" % (p1a, p1b, p1)) p2a = edge.valueAt(edge.LastParameter) p2b = FreeCAD.Vector(p2a.x, p2a.y, p2a.z + self.height) e2 = Part.Edge(Part.Line(p2a, p2b)) p2 = self.nextIntersectionClosestTo(e2, self.solid, p2b) # top most intersection - print(" p2: (%s %s) -> %s" % (p2a, p2b, p2)) + #print(" p2: (%s %s) -> %s" % (p2a, p2b, p2)) if type(edge.Curve) == Part.Line: return Part.Edge(Part.Line(p1, p2)) + m = FreeCAD.Matrix() + m.unity() + pd = p2 - p1 + + if type(edge.Curve) == Part.Circle: + m.A32 = pd.z / pd.y + m.A34 = - m.A32 + if pd.z < 0: + m.A34 *= p2.y + else: + m.A34 *= p1.y + e = edge.transformGeometry(m).Edges[0] + return e + + # it's already a helix, just need to lift it to the plateau + m.A33 = pd.z / (p2a.z - p1a.z) + m.A34 = (1 - m.A33) + if pd.z < 0: + m.A34 *= p2a.z + else: + m.A34 *= p1a.z + + #print + pf = edge.valueAt(edge.FirstParameter) + pl = edge.valueAt(edge.LastParameter) + #print("(%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f): %.2f" % (pf.x, pf.y, pf.z, pl.x, pl.y, pl.z, m.A33)) + #print("**** %.2f %.2f (%.2f - %.2f)" % (pd.z, p2a.z-p1a.z, p2a.z, p1a.z)) + e = edge.transformGeometry(m).Edges[0] + pf = e.valueAt(e.FirstParameter) + pl = e.valueAt(e.LastParameter) + #print("(%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (pf.x, pf.y, pf.z, pl.x, pl.y, pl.z)) + #raise Exception("mensch") + return e + + def filterIntersections(self, pts, face): if type(face.Surface) == Part.Cone or type(face.Surface) == Part.Cylinder: return filter(lambda pt: pt.z >= self.bottom() and pt.z <= self.top(), pts) @@ -331,7 +385,7 @@ class Tag: pts.extend(ps) if pts: closest = sorted(pts, key=lambda pt: (pt - refPt).Length)[0] - print("--pts: %s -> %s" % (pts, closest)) + #print("--pts: %s -> %s" % (pts, closest)) return closest return None @@ -351,10 +405,10 @@ class Tag: e,tail = self.splitEdgeAt(edge, i) inters.edges.append(e) return inters.intersect(tail) - else: - print("No intersection found.") - else: - print("Fly by") + #else: + # print("No intersection found.") + #else: + # print("Fly by") # if we get here there is no intersection with the tag inters.state = self.Intersection.P3 inters.tail = edge diff --git a/src/Mod/Path/PathTests/TestPathDressupHoldingTags.py b/src/Mod/Path/PathTests/TestPathDressupHoldingTags.py index e5e8917bd..4d4768498 100644 --- a/src/Mod/Path/PathTests/TestPathDressupHoldingTags.py +++ b/src/Mod/Path/PathTests/TestPathDressupHoldingTags.py @@ -250,7 +250,6 @@ class TestTag02SquareTag(PathTestBase): # ============= def test10(self): """Verify intersection of square tag with an arc.""" - print tag = Tag( 0, 0, 8, 3, 90, True, 0) p1 = Vector(10, -10, 0) p2 = Vector(10, +10, 0) @@ -259,7 +258,6 @@ class TestTag02SquareTag(PathTestBase): # ============= pi = Vector(0.8, -3.919184, 0) pj = Vector(0.8, +3.919184, 0) - print("(%s - %s) - %s" % (edge.valueAt(edge.FirstParameter), edge.valueAt(edge.LastParameter), edge.valueAt((edge.FirstParameter + edge.LastParameter)/2))) s = tag.intersect(edge) self.assertTrue(s.isComplete()) self.assertEqual(len(s.edges), 4) @@ -269,6 +267,25 @@ class TestTag02SquareTag(PathTestBase): # ============= self.assertLine(s.edges[3], pj + Vector(0, 0, 3), pj) self.assertCurve(s.tail, pj, Vector(4.486010, +8.342417, 0), p2) + def test20(self): + """Verify intersection of square tag with a helix.""" + tag = Tag( 0, 0, 8, 3, 90, True, 0) + p1 = Vector(10, -10, 0) + p2 = Vector(10, +10, 2) + edge = PathGeom.edgeForCmd(Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'J': 10, 'K': 1}), p1) + + pi = Vector(0.8, -3.919184, 0.743623) + pj = Vector(0.8, +3.919184, 1.256377) + + s = tag.intersect(edge) + self.assertTrue(s.isComplete()) + self.assertEqual(len(s.edges), 4) + self.assertCurve(s.edges[0], p1, Vector(4.486010, -8.342417, 0.371812), pi) + self.assertLine(s.edges[1], pi, pi + Vector(0, 0, 3-pi.z)) + self.assertCurve(s.edges[2], pi + Vector(0, 0, 3-pi.z), Vector(0, 0, 3), pj + Vector(0, 0, 3-pj.z)) + self.assertLine(s.edges[3], pj + Vector(0, 0, 3-pj.z), pj) + self.assertCurve(s.tail, pj, Vector(4.486010, +8.342417, 1.628188), p2) + class TestTag03TrapezoidTag(PathTestBase): # ============= """Unit tests for trapezoid tags.""" @@ -481,6 +498,48 @@ class TestTag03TrapezoidTag(PathTestBase): # ============= self.assertTrue(s.isComplete()) self.assertLine(s.tail, edge.Curve.StartPoint, edge.Curve.EndPoint) + def test10(self): + """Verify intersection with an arc.""" + tag = Tag( 0, 0, 8, 3, 45, True, 0) + p1 = Vector(10, -10, 0) + p2 = Vector(10, +10, 0) + edge = PathGeom.edgeForCmd(Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'J': 10}), p1) + + pi = Vector(0.8, -3.919184, 0) + pj = Vector(0.05, -0.998749, 3) + pk = Vector(0.05, +0.998749, 3) + pl = Vector(0.8, +3.919184, 0) + + s = tag.intersect(edge) + self.assertTrue(s.isComplete()) + self.assertEqual(len(s.edges), 4) + self.assertCurve(s.edges[0], p1, Vector(4.486010, -8.342417, 0), pi) + self.assertCurve(s.edges[1], pi, Vector(0.314296, -2.487396, 1.470795), pj) + self.assertCurve(s.edges[2], pj, Vector(0, 0, 3), pk) + self.assertCurve(s.edges[3], pk, Vector(.3142960, +2.487396, 1.470795), pl) + self.assertCurve(s.tail, pl, Vector(4.486010, +8.342417, 0), p2) + + def test20(self): + """Verify intersection with a helix.""" + tag = Tag( 0, 0, 8, 3, 45, True, 0) + p1 = Vector(10, -10, 0) + p2 = Vector(10, +10, 2) + edge = PathGeom.edgeForCmd(Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'J': 10, 'K': 1}), p1) + + pi = Vector(0.513574, -3.163498, 0.795085) + pj = Vector(0.050001, -0.998749, 3) + pk = Vector(0.050001, +0.998749, 3) + pl = Vector(0.397586, +2.791711, 1.180119) + + s = tag.intersect(edge) + self.assertTrue(s.isComplete()) + self.assertEqual(len(s.edges), 4) + self.assertCurve(s.edges[0], p1, Vector(4.153420, -8.112798, 0.397543), pi) + self.assertCurve(s.edges[1], pi, Vector(0.221698, -2.093992, 1.897543), pj) + self.assertCurve(s.edges[2], pj, Vector(0, 0, 3), pk) + self.assertCurve(s.edges[3], pk, Vector(0.182776, 1.903182, 2.090060), pl) + self.assertCurve(s.tail, pl, Vector(3.996548, +7.997409, 1.590060), p2) + class TestTag04TriangularTag(PathTestBase): # ======================== """Unit tests for tags that take on a triangular shape.""" @@ -566,3 +625,41 @@ class TestTag04TriangularTag(PathTestBase): # ======================== self.assertLines(i.edges, i.tail, [p0, p1, p2, p3, p4]) self.assertIsNotNone(i.tail) + def test10(self): + """Verify intersection with an arc.""" + tag = Tag( 0, 0, 8, 7, 45, True, 0) + p1 = Vector(10, -10, 0) + p2 = Vector(10, +10, 0) + edge = PathGeom.edgeForCmd(Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'J': 10}), p1) + + pi = Vector(0.8, -3.919184, 0) + pj = Vector(0.0, 0.0, 4) + pk = Vector(0.8, +3.919184, 0) + + s = tag.intersect(edge) + self.assertTrue(s.isComplete()) + self.assertEqual(len(s.edges), 3) + self.assertCurve(s.edges[0], p1, Vector(4.486010, -8.342417, 0), pi) + self.assertCurve(s.edges[1], pi, Vector(0.202041, -2., 1.958759), pj) + self.assertCurve(s.edges[2], pj, Vector(0.202041, +2., 1.958759), pk) + self.assertCurve(s.tail, pk, Vector(4.486010, +8.342417, 0), p2) + + def test20(self): + """Verify intersection with a helix.""" + tag = Tag( 0, 0, 8, 7, 45, True, 0) + p1 = Vector(10, -10, 0) + p2 = Vector(10, +10, 2) + edge = PathGeom.edgeForCmd(Path.Command('G2', {'X': p2.x, 'Y': p2.y, 'Z': p2.z, 'J': 10, 'K': 1}), p1) + + pi = Vector(0.513574, -3.163498, 0.795085) + pj = Vector(0.000001, 0, 4) + pk = Vector(0.397586, +2.791711, 1.180119) + + s = tag.intersect(edge) + self.assertTrue(s.isComplete()) + self.assertEqual(len(s.edges), 3) + self.assertCurve(s.edges[0], p1, Vector(4.153420, -8.112798, 0.397543), pi) + self.assertCurve(s.edges[1], pi, Vector(0.129229, -1.602457, 2.397542), pj) + self.assertCurve(s.edges[2], pj, Vector(0.099896, 1.409940, 2.590059), pk) + self.assertCurve(s.tail, pk, Vector(3.996548, +7.997409, 1.590060), p2) +