From d101111f646256a8da2a9920bc4682d5f1836a53 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Thu, 21 Jun 2018 23:25:26 -0700 Subject: [PATCH] Added flipping of edge to PathGeom. --- src/Mod/Path/PathScripts/PathGeom.py | 20 ++++++- src/Mod/Path/PathTests/PathTestUtils.py | 24 ++++++++ src/Mod/Path/PathTests/TestPathGeom.py | 80 +++++++++++++++++++++---- 3 files changed, 111 insertions(+), 13 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index d0f0f13c03..32c05db21d 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -23,10 +23,10 @@ # *************************************************************************** import FreeCAD -import math import Part import Path import PathScripts.PathLog as PathLog +import math from FreeCAD import Vector from PySide import QtCore @@ -455,3 +455,21 @@ def removeDuplicateEdges(wire): unique.append(e) return Part.Wire(unique) +def flipEdge(edge): + '''flipEdge(edge) + Flips given edge around so the new Vertexes[0] was the old Vertexes[-1] and vice versa, without changing the shape. + Currently only lines, line segments, circles and arcs are supported.''' + + if Part.Line == type(edge.Curve) and not edge.Vertexes: + return Part.Edge(Part.Line(edge.valueAt(edge.LastParameter), edge.valueAt(edge.FirstParameter))) + elif Part.Line == type(edge.Curve) or Part.LineSegment == type(edge.Curve): + return Part.Edge(Part.LineSegment(edge.Vertexes[-1].Point, edge.Vertexes[0].Point)) + elif Part.Circle == type(edge.Curve): + return Part.makeCircle(edge.Curve.Radius, edge.Curve.Center, -edge.Curve.Axis, -math.degrees(edge.LastParameter), -math.degrees(edge.FirstParameter)) + elif Part.BSplineCurve == type(edge.Curve): + spline = edge.Curve + poles = [p for p in reversed(spline.getPoles())] + weights = [w for w in reversed(spline.getWeights())] + degree = spline.Degree + return Part.Edge(Part.BSplineCurve(poles, degree=degree, weights=weights)) + diff --git a/src/Mod/Path/PathTests/PathTestUtils.py b/src/Mod/Path/PathTests/PathTestUtils.py index 7614565d1e..cf12ad48ff 100644 --- a/src/Mod/Path/PathTests/PathTestUtils.py +++ b/src/Mod/Path/PathTests/PathTestUtils.py @@ -135,3 +135,27 @@ class PathTestBase(unittest.TestCase): q2=FreeCAD.Units.Quantity(s2) self.assertEqual(q1.UserString, q2.UserString) + def assertEdgeShapesMatch(self,e1,e2): + """Verify that 2 edges have the same start/end points and the mid point matches too.""" + self.assertEqual(type(e1.Curve), type(e2.Curve)) + self.assertEqual(len(e1.Vertexes), len(e2.Vertexes)) + if not e1.Vertexes: + self.assertEqual(Part.Line, type(e1.Curve)) + k1 = e1.valueAt(e1.LastParameter) - e1.valueAt(e1.FirstParameter) + k2 = e2.valueAt(e2.LastParameter) - e2.valueAt(e2.FirstParameter) + self.assertCoincide(k1, -k2) + elif 1 == len(e1.Vertexes): + self.assertEqual(Part.Circle, type(e1.Curve)) + self.assertRoughly(e1.Curve.Radius, e2.Curve.Radius) + self.assertCoincide(e1.Curve.Center, e2.Curve.Center) + self.assertCoincide(e1.Curve.Axis, -e2.Curve.Axis) + else: + if PathGeom.pointsCoincide(e1.Vertexes[0].Point, e2.Vertexes[0].Point): + self.assertCoincide(e1.Vertexes[-1].Point, e2.Vertexes[-1].Point) + else: + self.assertCoincide(e1.Vertexes[0].Point, e2.Vertexes[-1].Point) + self.assertCoincide(e1.Vertexes[-1].Point, e2.Vertexes[0].Point) + pm1 = e1.valueAt((e1.FirstParameter + e1.LastParameter)/2) + pm2 = e2.valueAt((e2.FirstParameter + e2.LastParameter)/2) + self.assertCoincide(pm1, pm2) + diff --git a/src/Mod/Path/PathTests/TestPathGeom.py b/src/Mod/Path/PathTests/TestPathGeom.py index fd5b90914a..0bc0f70957 100644 --- a/src/Mod/Path/PathTests/TestPathGeom.py +++ b/src/Mod/Path/PathTests/TestPathGeom.py @@ -145,12 +145,12 @@ class TestPathGeom(PathTestBase): """Verify isVertical/isHorizontal for faces""" # planes - xPlane = Part.makePlane(100, 100, FreeCAD.Vector(), FreeCAD.Vector(1, 0, 0)) - yPlane = Part.makePlane(100, 100, FreeCAD.Vector(), FreeCAD.Vector(0, 1, 0)) - zPlane = Part.makePlane(100, 100, FreeCAD.Vector(), FreeCAD.Vector(0, 0, 1)) - xyPlane = Part.makePlane(100, 100, FreeCAD.Vector(), FreeCAD.Vector(1, 1, 0)) - xzPlane = Part.makePlane(100, 100, FreeCAD.Vector(), FreeCAD.Vector(1, 0, 1)) - yzPlane = Part.makePlane(100, 100, FreeCAD.Vector(), FreeCAD.Vector(0, 1, 1)) + xPlane = Part.makePlane(100, 100, Vector(), Vector(1, 0, 0)) + yPlane = Part.makePlane(100, 100, Vector(), Vector(0, 1, 0)) + zPlane = Part.makePlane(100, 100, Vector(), Vector(0, 0, 1)) + xyPlane = Part.makePlane(100, 100, Vector(), Vector(1, 1, 0)) + xzPlane = Part.makePlane(100, 100, Vector(), Vector(1, 0, 1)) + yzPlane = Part.makePlane(100, 100, Vector(), Vector(0, 1, 1)) self.assertTrue(PathGeom.isVertical(xPlane)) self.assertTrue(PathGeom.isVertical(yPlane)) @@ -167,12 +167,12 @@ class TestPathGeom(PathTestBase): self.assertFalse(PathGeom.isHorizontal(yzPlane)) # cylinders - xCylinder = [f for f in Part.makeCylinder(1, 1, FreeCAD.Vector(), FreeCAD.Vector(1, 0, 0)).Faces if type(f.Surface) == Part.Cylinder][0] - yCylinder = [f for f in Part.makeCylinder(1, 1, FreeCAD.Vector(), FreeCAD.Vector(0, 1, 0)).Faces if type(f.Surface) == Part.Cylinder][0] - zCylinder = [f for f in Part.makeCylinder(1, 1, FreeCAD.Vector(), FreeCAD.Vector(0, 0, 1)).Faces if type(f.Surface) == Part.Cylinder][0] - xyCylinder = [f for f in Part.makeCylinder(1, 1, FreeCAD.Vector(), FreeCAD.Vector(1, 1, 0)).Faces if type(f.Surface) == Part.Cylinder][0] - xzCylinder = [f for f in Part.makeCylinder(1, 1, FreeCAD.Vector(), FreeCAD.Vector(1, 0, 1)).Faces if type(f.Surface) == Part.Cylinder][0] - yzCylinder = [f for f in Part.makeCylinder(1, 1, FreeCAD.Vector(), FreeCAD.Vector(0, 1, 1)).Faces if type(f.Surface) == Part.Cylinder][0] + xCylinder = [f for f in Part.makeCylinder(1, 1, Vector(), Vector(1, 0, 0)).Faces if type(f.Surface) == Part.Cylinder][0] + yCylinder = [f for f in Part.makeCylinder(1, 1, Vector(), Vector(0, 1, 0)).Faces if type(f.Surface) == Part.Cylinder][0] + zCylinder = [f for f in Part.makeCylinder(1, 1, Vector(), Vector(0, 0, 1)).Faces if type(f.Surface) == Part.Cylinder][0] + xyCylinder = [f for f in Part.makeCylinder(1, 1, Vector(), Vector(1, 1, 0)).Faces if type(f.Surface) == Part.Cylinder][0] + xzCylinder = [f for f in Part.makeCylinder(1, 1, Vector(), Vector(1, 0, 1)).Faces if type(f.Surface) == Part.Cylinder][0] + yzCylinder = [f for f in Part.makeCylinder(1, 1, Vector(), Vector(0, 1, 1)).Faces if type(f.Surface) == Part.Cylinder][0] self.assertTrue(PathGeom.isHorizontal(xCylinder)) self.assertTrue(PathGeom.isHorizontal(yCylinder)) @@ -381,3 +381,59 @@ class TestPathGeom(PathTestBase): pl = e[1].valueAt((e[1].FirstParameter + e[1].LastParameter)/2) self.assertCurve(e[0], p1, p12, p2) self.assertCurve(e[1], p2, p23, p3) + + def test70(self): + '''Flip a line.''' + edge = Part.Edge(Part.Line(Vector(0,0,0), Vector(3, 2, 1))) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.Edge(Part.Line(Vector(0,0,0), Vector(-3, -2, -1))) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + + def test71(self): + '''Flip a line segment.''' + edge = Part.Edge(Part.LineSegment(Vector(0,0,0), Vector(3, 2, 1))) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.Edge(Part.LineSegment(Vector(4,2,1), Vector(-3, -7, 9))) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeLine(Vector(1,0,3), Vector(3, 2, 1)) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + + def test72(self): + '''Flip a circle''' + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, 1)) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, -1)) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + + def test73(self): + '''Flip an arc''' + # make sure all 4 quadrants work + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, 1), 45, 90) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, 1), 100, 170) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, 1), 200, 250) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, 1), 300, 340) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + + # and the other way around too + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, -1), 45, 90) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, -1), 100, 170) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, -1), 200, 250) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + edge = Part.makeCircle(3, Vector(1, 3, 2), Vector(0, 0, -1), 300, 340) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + + + def xtest75(self): + '''Flip a b-spline''' + # Disabling for now, there's a bit of a difference + spline = Part.BSplineCurve() + spline.interpolate([Vector(1,2,3), Vector(-3,0,7), Vector(-3,1,9), Vector(1, 3, 5)]) + edge = Part.Edge(spline) + self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge)) + +