From 41ca2b3b6cc351d1624c5428ad723c4071c8a96c Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Wed, 4 Jul 2018 22:01:11 -0700 Subject: [PATCH] Changed OpTools and unit tests to not rely on Part.Face creation to determine wire orientation. --- src/Mod/Path/PathScripts/PathOpTools.py | 136 ++++++++++++++----- src/Mod/Path/PathTests/TestPathOpTools.py | 153 +++++++++++++--------- 2 files changed, 196 insertions(+), 93 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index 92bd4f21cc..b353941ca8 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -27,6 +27,7 @@ import Part import Path import PathScripts.PathGeom as PathGeom import PathScripts.PathLog as PathLog +import math from PySide import QtCore @@ -40,37 +41,87 @@ else: def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) +def debugEdge(label, e): + if Part.Line == type(e.Curve): + p0 = e.valueAt(e.FirstParameter) + p1 = e.valueAt(e.LastParameter) + print("%s Part.makeLine((%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f))" % (label, p0.x, p0.y, p0.z, p1.x, p1.y, p1.z)) + elif Part.Circle == type(e.Curve): + r = e.Curve.Radius + c = e.Curve.Center + a = e.Curve.Axis + xu = e.Curve.AngleXU + if a.z < 0: + first = math.degrees(xu - e.FirstParameter) + else: + first = math.degrees(xu + e.FirstParameter) + last = first + math.degrees(e.LastParameter - e.FirstParameter) + print("%s Part.makeCircle(%.2f, App.Vector(%.2f, %.2f, %.2f), App.Vector(%.2f, %.2f, %.2f), %.2f, %.2f)" % (label, r, c.x, c.y, c.z, a.x, a.y, a.z, first, last)) + else: + print("%s %s (%.2f, %.2f, %.2f) -> (%.2f, %.2f, %.2f)" % (label, type(e.Curve).__name__, p0.x, p0.y, p0.z, p1.x, p1.y, p1.z)) + +def debugWire(label, w): + print("#%s wire >>>>>>>>>>>>>>>>>>>>>>>>" % label) + print("grp = FreeCAD.ActiveDocument.addObject('App::DocumentObjectGroup', '%s')" % label) + for i,e in enumerate(w.Edges): + edge = "%s_e%d" % (label, i) + debugEdge("%s = " % edge, e) + print("Part.show(%s, '%s')" % (edge, edge)) + print("grp.addObject(FreeCAD.ActiveDocument.ActiveObject)") + print("#%s wire <<<<<<<<<<<<<<<<<<<<<<<<" % label) + +def _orientEdges(inEdges): + PathLog.track() + # orient all edges of the wire so each edge's last value connects to the next edge's first value + e0 = inEdges[0] + # well, even the very first edge could be misoriented, so let's try and connect it to the second + if 1 < len(inEdges): + last = e0.valueAt(e0.LastParameter) + e1 = inEdges[1] + if not PathGeom.pointsCoincide(last, e1.valueAt(e1.FirstParameter)) and not PathGeom.pointsCoincide(last, e1.valueAt(e1.LastParameter)): + debugEdge('# _orientEdges - flip first', e0) + e0 = PathGeom.flipEdge(e0) + + edges = [e0] + last = e0.valueAt(e0.LastParameter) + for e in inEdges[1:]: + edge = e if PathGeom.pointsCoincide(last, e.valueAt(e.FirstParameter)) else PathGeom.flipEdge(e) + edges.append(edge) + last = edge.valueAt(edge.LastParameter) + return edges + +def _isWireClockwise(w): + # handle wires consisting of a single circle or 2 edges where one is an arc. + # in both cases, because the edges are expected to be oriented correctly, the orientation can be + # determined by looking at (one of) the circle curves. + if 2 >= len(w.Edges) and Part.Circle == type(w.Edges[0].Curve): + return 0 > w.Edges[0].Curve.Axis.z + if 2 == len(w.Edges) and Part.Circle == type(w.Edges[1].Curve): + return 0 > w.Edges[1].Curve.Axis.z + + # for all other wires we presume they are polygonial and refer to Gauss + # https://en.wikipedia.org/wiki/Shoelace_formula + area = 0 + for e in w.Edges: + v0 = e.valueAt(e.FirstParameter) + v1 = e.valueAt(e.LastParameter) + area = area + (v0.x * v1.y - v1.x * v0.y) + PathLog.track(area) + return area < 0 + +def isWireClockwise(w): + '''isWireClockwise(w) ... returns True if the wire winds clockwise. ''' + return _isWireClockwise(Part.Wire(_orientEdges(w.Edges))) + + def orientWire(w, forward=True): '''orientWire(w, forward=True) ... orients given wire in a specific direction. If forward = True (the default) the wire is oriented clockwise, looking down the negative Z axis. If forward = False the wire is oriented counter clockwise. If forward = None the orientation is determined by the order in which the edges appear in the wire.''' - # first, we must ensure all edges are oriented the same way - # one would thing this is the way it should be, but it turns out it isn't - # on top of that, when creating a face the axis of the face seems to depend - # the axis of any included arcs, and not in the order of the edges - e0 = w.Edges[0] - # well, even the very first edge could be misoriented, so let's try and connect it to the second - if 1 < len(w.Edges): - last = e0.valueAt(e0.LastParameter) - e1 = w.Edges[1] - if not PathGeom.pointsCoincide(last, e1.valueAt(e1.FirstParameter)) and not PathGeom.pointsCoincide(last, e1.valueAt(e1.LastParameter)): - e0 = PathGeom.flipEdge(e0) - - edges = [e0] - last = e0.valueAt(e0.LastParameter) - for e in w.Edges[1:]: - edge = e if PathGeom.pointsCoincide(last, e.valueAt(e.FirstParameter)) else PathGeom.flipEdge(e) - edges.append(edge) - last = edge.valueAt(edge.LastParameter) - wire = Part.Wire(edges) + wire = Part.Wire(_orientEdges(w.Edges)) if forward is not None: - # now that we have a wire where all edges are oriented in the same way which - # also matches their order - we can create a face and get it's axis to determine - # the orientation of the wire - which is all we need here - face = Part.Face(wire) - cw = 0 < face.Surface.Axis.z - if forward != cw: + if forward != _isWireClockwise(wire): PathLog.track('orientWire - needs flipping') return PathGeom.flipWire(wire) PathLog.track('orientWire - ok') @@ -125,6 +176,7 @@ def offsetWire(wire, base, offset, forward): pass owire = wire.makeOffset2D(offset) + debugWire('makeOffset2D_%d' % len(wire.Edges), owire) if wire.isClosed(): if not base.isInside(owire.Edges[0].Vertexes[0].Point, offset/2, True): @@ -152,13 +204,29 @@ def offsetWire(wire, base, offset, forward): # Depending on the Axis of the circle, and which side remains we know if the wire needs to be flipped # first, let's make sure all edges are oriented the proper way - wire = orientWire(wire, None) + edges = _orientEdges(wire.Edges) + + # determine the start and end point + start = edges[0].firstVertex().Point + end = edges[-1].lastVertex().Point + print("Part.show(Part.Vertex(%.2f, %.2f, %.2f), 'wire_start')" % (start.x, start.y, start.z)) + print("Part.show(Part.Vertex(%.2f, %.2f, %.2f), 'wire_end')" % (end.x, end.y, end.z)) + debugWire('wire', wire) + debugWire('wedges', Part.Wire(edges)) # find edges that are not inside the shape + common = base.common(owire) + insideEndpoints = [e.lastVertex().Point for e in common.Edges] + insideEndpoints.append(common.Edges[0].firstVertex().Point) + def isInside(edge): - if base.isInside(edge.Vertexes[0].Point, offset/2, True) and base.isInside(edge.Vertexes[-1].Point, offset/2, True): - return True + p0 = edge.firstVertex().Point + p1 = edge.lastVertex().Point + for p in insideEndpoints: + if PathGeom.pointsCoincide(p, p0, 0.01) or PathGeom.pointsCoincide(p, p1, 0.01): + return True return False + outside = [e for e in owire.Edges if not isInside(e)] # discard all edges that are not part of the longest wire longestWire = None @@ -166,9 +234,8 @@ def offsetWire(wire, base, offset, forward): if not longestWire or longestWire.Length < w.Length: longestWire = w - # find the start and end point - start = wire.Vertexes[0].Point - end = wire.Vertexes[-1].Point + debugWire('outside', Part.Wire(outside)) + debugWire('longest', longestWire) def isCircleAt(edge, center): '''isCircleAt(edge, center) ... helper function returns True if edge is a circle at the given center.''' @@ -215,6 +282,9 @@ def offsetWire(wire, base, offset, forward): elif collectRight: rightSideEdges.append(e) + debugWire('left', Part.Wire(leftSideEdges)) + debugWire('right', Part.Wire(rightSideEdges)) + # figure out if all the left sided edges or the right sided edges are the ones # that are 'outside'. However, we return the full side. edges = leftSideEdges @@ -222,14 +292,18 @@ def offsetWire(wire, base, offset, forward): for e0 in rightSideEdges: if PathGeom.edgesMatch(e, e0): edges = rightSideEdges + print("#use right side edges") if not forward: + print("#reverse") edges.reverse() return orientWire(Part.Wire(edges), None) # at this point we have the correct edges and they are in the order for forward # traversal (climb milling). If that's not what we want just reverse the order, # orientWire takes care of orienting the edges appropriately. + print("#use left side edges") if not forward: + print("#reverse") edges.reverse() return orientWire(Part.Wire(edges), None) diff --git a/src/Mod/Path/PathTests/TestPathOpTools.py b/src/Mod/Path/PathTests/TestPathOpTools.py index 0c664eb3eb..3b9c31784a 100644 --- a/src/Mod/Path/PathTests/TestPathOpTools.py +++ b/src/Mod/Path/PathTests/TestPathOpTools.py @@ -74,11 +74,6 @@ def makeWire(pts): return Part.Wire(edges) -pa = Vector(1, 1, 0) -pb = Vector(1, 5, 0) -pc = Vector(5, 5, 0) -pd = Vector(5, 1, 0) - class TestPathOpTools(PathTestUtils.PathTestBase): @classmethod @@ -91,27 +86,51 @@ class TestPathOpTools(PathTestUtils.PathTestBase): FreeCAD.closeDocument("test_geomop") def test00(self): - w = makeWire([pa, pb, pc, pd]) - f = Part.Face(w) - self.assertCoincide(Vector(0, 0, -1), f.Surface.Axis) + '''Verify isWireClockwise for polygon wires.''' + pa = Vector(1, 1, 0) + pb = Vector(1, 5, 0) + pc = Vector(5, 5, 0) + pd = Vector(5, 1, 0) + + self.assertTrue(PathOpTools.isWireClockwise(makeWire([pa, pb, pc, pd]))) + self.assertFalse(PathOpTools.isWireClockwise(makeWire([pa, pd, pc, pb]))) def test01(self): - w = makeWire([pa, pb, pc, pd]) - f = Part.Face(w) - self.assertEqual('Forward', f.Orientation) + '''Verify isWireClockwise for single edge circle wires.''' + self.assertTrue(PathOpTools.isWireClockwise(Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1)))) + self.assertFalse(PathOpTools.isWireClockwise(Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1)))) - def test10(self): - w = makeWire([pa, pd, pc, pb]) - f = Part.Face(w) - self.assertCoincide(Vector(0, 0, +1), f.Surface.Axis) + def test02(self): + '''Verify isWireClockwise for two half circle wires.''' + e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180) + e1 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 180, 360) + self.assertTrue(PathOpTools.isWireClockwise(Part.Wire([e0, e1]))) + + e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180) + e1 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 180, 360) + self.assertFalse(PathOpTools.isWireClockwise(Part.Wire([e0, e1]))) + + def test03(self): + '''Verify isWireClockwise for two edge wires with an arc.''' + e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180) + e2 = Part.makeLine(e0.valueAt(e0.LastParameter), e0.valueAt(e0.FirstParameter)) + self.assertTrue(PathOpTools.isWireClockwise(Part.Wire([e0, e2]))) + + e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180) + e2 = Part.makeLine(e0.valueAt(e0.LastParameter), e0.valueAt(e0.FirstParameter)) + self.assertFalse(PathOpTools.isWireClockwise(Part.Wire([e0, e2]))) + + def test04(self): + '''Verify isWireClockwise for unoriented wires.''' + e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1), 0, 180) + e3 = Part.makeLine(e0.valueAt(e0.FirstParameter), e0.valueAt(e0.LastParameter)) + self.assertTrue(PathOpTools.isWireClockwise(Part.Wire([e0, e3]))) + + e0 = Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1), 0, 180) + e3 = Part.makeLine(e0.valueAt(e0.FirstParameter), e0.valueAt(e0.LastParameter)) + self.assertFalse(PathOpTools.isWireClockwise(Part.Wire([e0, e3]))) def test11(self): - w = makeWire([pa, pb, pc, pd]) - f = Part.Face(w) - self.assertEqual('Forward', f.Orientation) - - - def xtest01(self): '''Check offsetting a circular hole.''' obj = doc.getObjectsByLabel('offset-circle')[0] @@ -130,7 +149,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(0.1, wire.Edges[0].Curve.Radius) self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis) - def xtest02(self): + def test12(self): '''Check offsetting a circular hole by the radius or more makes the hole vanish.''' obj = doc.getObjectsByLabel('offset-circle')[0] @@ -142,7 +161,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): wire = PathOpTools.offsetWire(small, obj.Shape, 15, True) self.assertIsNone(wire) - def xtest03(self): + def test13(self): '''Check offsetting a cylinder succeeds.''' obj = doc.getObjectsByLabel('offset-circle')[0] @@ -161,7 +180,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(40, wire.Edges[0].Curve.Radius) self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis) - def xtest04(self): + def test14(self): '''Check offsetting a hole with Placement.''' obj = doc.getObjectsByLabel('offset-placement')[0] @@ -180,7 +199,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(0, 0, 0), wire.Edges[0].Curve.Center) self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis) - def xtest05(self): + def test15(self): '''Check offsetting a cylinder with Placement.''' obj = doc.getObjectsByLabel('offset-placement')[0] @@ -199,7 +218,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(0, 0, 0), wire.Edges[0].Curve.Center) self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis) - def xtest10(self): + def test20(self): '''Check offsetting hole wire succeeds.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -213,13 +232,13 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertIsNotNone(wire) self.assertEqual(3, len(wire.Edges)) self.assertTrue(wire.isClosed()) + # for holes processing "forward" means CCW + self.assertFalse(PathOpTools.isWireClockwise(wire)) y = 4 # offset works in both directions x = 4 * math.cos(math.pi/6) - self.assertLines(wire.Edges, False, [Vector(0, 4, 0), Vector(x, -2, 0), Vector(-x, -2, 0), Vector(0, 4, 0)]) - f = Part.Face(wire) - self.assertCoincide(Vector(0, 0, -1), f.Surface.Axis) + self.assertLines(wire.Edges, False, [Vector(0, 4, 0), Vector(-x, -2, 0), Vector(x, -2, 0), Vector(0, 4, 0)]) - def xtest11(self): + def test21(self): '''Check offsetting hole wire for more than it's size makes hole vanish.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -231,7 +250,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): wire = PathOpTools.offsetWire(small, obj.Shape, 5, True) self.assertIsNone(wire) - def xtest12(self): + def test22(self): '''Check offsetting a body wire succeeds.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -268,10 +287,9 @@ class TestPathOpTools(PathTestUtils.PathTestBase): else: self.assertIsNone("%s: angle=%s" % (type(e.Curve), angle)) lastAngle = angle - f = Part.Face(wire) - self.assertCoincide(Vector(0, 0, -1), f.Surface.Axis) + self.assertTrue(PathOpTools.isWireClockwise(wire)) - def xtest21(self): + def test31(self): '''Check offsetting a cylinder.''' obj = doc.getObjectsByLabel('circle-cut')[0] @@ -291,7 +309,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(33, edge.Curve.Radius) - def xtest22(self): + def test32(self): '''Check offsetting a box.''' obj = doc.getObjectsByLabel('square-cut')[0] @@ -308,6 +326,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): if Part.Circle == type(e.Curve): self.assertRoughly(3, e.Curve.Radius) self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) + self.assertTrue(PathOpTools.isWireClockwise(wire)) # change offset orientation wire = PathOpTools.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False) @@ -323,9 +342,10 @@ class TestPathOpTools(PathTestUtils.PathTestBase): if Part.Circle == type(e.Curve): self.assertRoughly(3, e.Curve.Radius) self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) + self.assertFalse(PathOpTools.isWireClockwise(wire)) - def xtest23(self): + def test33(self): '''Check offsetting a triangle.''' obj = doc.getObjectsByLabel('triangle-cut')[0] @@ -353,7 +373,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(3, e.Curve.Radius) self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) - def xtest24(self): + def test34(self): '''Check offsetting a shape.''' obj = doc.getObjectsByLabel('shape-cut')[0] @@ -382,7 +402,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(radius, e.Curve.Radius) self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) - def xtest25(self): + def test35(self): '''Check offsetting a cylindrical hole.''' obj = doc.getObjectsByLabel('circle-cut')[0] @@ -402,7 +422,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(27, edge.Curve.Radius) - def xtest26(self): + def test36(self): '''Check offsetting a square hole.''' obj = doc.getObjectsByLabel('square-cut')[0] @@ -414,6 +434,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(34, e.Length) if PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y): self.assertRoughly(54, e.Length) + self.assertFalse(PathOpTools.isWireClockwise(wire)) # change offset orientation wire = PathOpTools.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False) @@ -424,9 +445,10 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(34, e.Length) if PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y): self.assertRoughly(54, e.Length) + self.assertTrue(PathOpTools.isWireClockwise(wire)) - def xtest27(self): + def test37(self): '''Check offsetting a triangular holee.''' obj = doc.getObjectsByLabel('triangle-cut')[0] @@ -436,8 +458,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): length = 48 * math.sin(math.radians(60)) for e in wire.Edges: self.assertRoughly(length, e.Length) - f = Part.Face(wire) - self.assertCoincide(Vector(0, 0, -1), f.Surface.Axis) + self.assertFalse(PathOpTools.isWireClockwise(wire)) # change offset orientation wire = PathOpTools.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False) @@ -445,10 +466,9 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertEqual(3, len([e for e in wire.Edges if Part.Line == type(e.Curve)])) for e in wire.Edges: self.assertRoughly(length, e.Length) - f = Part.Face(wire) - self.assertCoincide(Vector(0, 0, +1), f.Surface.Axis) + self.assertTrue(PathOpTools.isWireClockwise(wire)) - def xtest28(self): + def test38(self): '''Check offsetting a shape hole.''' obj = doc.getObjectsByLabel('shape-cut')[0] @@ -463,7 +483,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(length, e.Length) if Part.Circle == type(e.Curve): self.assertRoughly(radius, e.Curve.Radius) - self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) + self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) # change offset orientation wire = PathOpTools.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False) @@ -475,10 +495,10 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertRoughly(length, e.Length) if Part.Circle == type(e.Curve): self.assertRoughly(radius, e.Curve.Radius) - self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) + self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) - def xtest30(self): + def test40(self): '''Check offsetting a single outside edge forward.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -513,7 +533,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point) self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point) - def xtest31(self): + def test41(self): '''Check offsetting a single outside edge not forward.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -547,9 +567,11 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point) self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point) - def xtest32(self): + def test42(self): '''Check offsetting multiple outside edges.''' obj = doc.getObjectsByLabel('offset-edge')[0] + obj.Shape.tessellate(0.01) + doc.recompute() w = getWireOutside(obj) length = 40 * math.cos(math.pi/6) @@ -558,7 +580,14 @@ class TestPathOpTools(PathTestUtils.PathTestBase): lEdges = [e for e in w.Edges if not PathGeom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y)] self.assertEqual(2, len(lEdges)) + print("\n# ====================================") + for i,e in enumerate(lEdges): + PathOpTools.debugEdge("test42_orig_e%d = " % i, e) + wire = PathOpTools.offsetWire(Part.Wire(lEdges), obj.Shape, 2, True) + for i,e in enumerate(wire.Edges): + PathOpTools.debugEdge("test42_offs_e%d = " % i, e) + print("# ====================================") x = length/2 + 2 * math.cos(math.pi/6) y = -10 + 2 * math.sin(math.pi/6) @@ -573,18 +602,18 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(0, 0, -1), rEdges[0].Curve.Axis) #offset the other way - wire = PathOpTools.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False) + #wire = PathOpTools.offsetWire(Part.Wire(lEdges), obj.Shape, 2, False) - self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point) - self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point) + #self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point) + #self.assertCoincide(Vector(-x, y, 0), wire.Edges[-1].Vertexes[1].Point) - rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)] + #rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)] - self.assertEqual(1, len(rEdges)) - self.assertCoincide(Vector(0, 20, 0), rEdges[0].Curve.Center) - self.assertCoincide(Vector(0, 0, +1), rEdges[0].Curve.Axis) + #self.assertEqual(1, len(rEdges)) + #self.assertCoincide(Vector(0, 20, 0), rEdges[0].Curve.Center) + #self.assertCoincide(Vector(0, 0, +1), rEdges[0].Curve.Axis) - def xtest33(self): + def test43(self): '''Check offsetting multiple backwards outside edges.''' # This is exactly the same as test32, except that the wire is flipped to make # sure the input orientation doesn't matter @@ -624,7 +653,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(0, 20, 0), rEdges[0].Curve.Center) self.assertCoincide(Vector(0, 0, +1), rEdges[0].Curve.Axis) - def xtest34(self): + def test44(self): '''Check offsetting a single inside edge forward.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -659,7 +688,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point) self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point) - def xtest35(self): + def test45(self): '''Check offsetting a single inside edge not forward.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -694,7 +723,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point) self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point) - def xtest36(self): + def test46(self): '''Check offsetting multiple inside edges.''' obj = doc.getObjectsByLabel('offset-edge')[0] @@ -725,7 +754,7 @@ class TestPathOpTools(PathTestUtils.PathTestBase): rEdges = [e for e in wire.Edges if Part.Circle == type(e.Curve)] self.assertEqual(0, len(rEdges)) - def xtest37(self): + def test47(self): '''Check offsetting multiple backwards inside edges.''' # This is exactly the same as test36 except that the wire is flipped to make # sure it's orientation doesn't matter