| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD |
| | import Part |
| | import Path |
| | import Path.Op.Util as PathOpUtil |
| | import CAMTests.PathTestUtils as PathTestUtils |
| | import math |
| |
|
| | from FreeCAD import Vector |
| |
|
| | Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule()) |
| | |
| |
|
| | DOC = FreeCAD.getHomePath() + "Mod/CAM/CAMTests/test_geomop.fcstd" |
| |
|
| |
|
| | def getWire(obj, nr=0): |
| | return obj.Tip.Profile[0].Shape.Wires[nr] |
| |
|
| |
|
| | def getWireInside(obj): |
| | w1 = getWire(obj, 0) |
| | w2 = getWire(obj, 1) |
| | if w2.BoundBox.isInside(w1.BoundBox): |
| | return w1 |
| | return w2 |
| |
|
| |
|
| | def getWireOutside(obj): |
| | w1 = getWire(obj, 0) |
| | w2 = getWire(obj, 1) |
| | if w2.BoundBox.isInside(w1.BoundBox): |
| | return w2 |
| | return w1 |
| |
|
| |
|
| | def getPositiveShape(obj): |
| | return obj.Tool.Shape |
| |
|
| |
|
| | def getNegativeShape(obj): |
| | return obj.Shape |
| |
|
| |
|
| | def makeWire(pts): |
| | edges = [] |
| | first = pts[0] |
| | last = pts[0] |
| | for p in pts[1:]: |
| | edges.append(Part.Edge(Part.LineSegment(last, p))) |
| | last = p |
| | edges.append(Part.Edge(Part.LineSegment(last, first))) |
| | return Part.Wire(edges) |
| |
|
| |
|
| | def wireMarkers(wire): |
| | pts = [wire.Edges[0].valueAt(wire.Edges[0].FirstParameter)] |
| | for edge in wire.Edges: |
| | pts.append(edge.valueAt(edge.LastParameter)) |
| | return pts |
| |
|
| |
|
| | class TestPathOpUtil(PathTestUtils.PathTestBase): |
| | @classmethod |
| | def setUpClass(cls): |
| | FreeCAD.ConfigSet("SuppressRecomputeRequiredDialog", "True") |
| | cls.doc = FreeCAD.openDocument(DOC) |
| | FreeCAD.ConfigSet("SuppressRecomputeRequiredDialog", "") |
| |
|
| | @classmethod |
| | def tearDownClass(cls): |
| | FreeCAD.closeDocument(cls.doc.Name) |
| |
|
| | def test00(self): |
| | """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(PathOpUtil.isWireClockwise(makeWire([pa, pb, pc, pd]))) |
| | self.assertFalse(PathOpUtil.isWireClockwise(makeWire([pa, pd, pc, pb]))) |
| |
|
| | def test01(self): |
| | """Verify isWireClockwise for single edge circle wires.""" |
| | self.assertTrue( |
| | PathOpUtil.isWireClockwise(Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, -1))) |
| | ) |
| | self.assertFalse( |
| | PathOpUtil.isWireClockwise(Part.makeCircle(5, Vector(1, 2, 3), Vector(0, 0, +1))) |
| | ) |
| |
|
| | 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(PathOpUtil.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(PathOpUtil.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(PathOpUtil.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(PathOpUtil.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(PathOpUtil.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(PathOpUtil.isWireClockwise(Part.Wire([e0, e3]))) |
| |
|
| | def test11(self): |
| | """Check offsetting a circular hole.""" |
| | obj = self.doc.getObjectsByLabel("offset-circle")[0] |
| |
|
| | small = getWireInside(obj) |
| | self.assertRoughly(10, small.Edges[0].Curve.Radius) |
| |
|
| | wire = PathOpUtil.offsetWire(small, obj.Shape, 3, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(1, len(wire.Edges)) |
| | self.assertRoughly(7, wire.Edges[0].Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis) |
| |
|
| | wire = PathOpUtil.offsetWire(small, obj.Shape, 9.9, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(1, len(wire.Edges)) |
| | self.assertRoughly(0.1, wire.Edges[0].Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis) |
| |
|
| | def test12(self): |
| | """Check offsetting a circular hole by the radius or more makes the hole vanish.""" |
| | obj = self.doc.getObjectsByLabel("offset-circle")[0] |
| |
|
| | small = getWireInside(obj) |
| | self.assertRoughly(10, small.Edges[0].Curve.Radius) |
| | wire = PathOpUtil.offsetWire(small, obj.Shape, 10, True) |
| | self.assertIsNone(wire) |
| |
|
| | wire = PathOpUtil.offsetWire(small, obj.Shape, 15, True) |
| | self.assertIsNone(wire) |
| |
|
| | def test13(self): |
| | """Check offsetting a cylinder succeeds.""" |
| | obj = self.doc.getObjectsByLabel("offset-circle")[0] |
| |
|
| | big = getWireOutside(obj) |
| | self.assertRoughly(20, big.Edges[0].Curve.Radius) |
| |
|
| | wire = PathOpUtil.offsetWire(big, obj.Shape, 10, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(1, len(wire.Edges)) |
| | self.assertRoughly(30, wire.Edges[0].Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis) |
| |
|
| | wire = PathOpUtil.offsetWire(big, obj.Shape, 20, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(1, len(wire.Edges)) |
| | self.assertRoughly(40, wire.Edges[0].Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis) |
| |
|
| | def test14(self): |
| | """Check offsetting a hole with Placement.""" |
| | obj = self.doc.getObjectsByLabel("offset-placement")[0] |
| |
|
| | wires = [ |
| | w |
| | for w in obj.Shape.Wires |
| | if 1 == len(w.Edges) and Path.Geom.isRoughly(0, w.Edges[0].Vertexes[0].Point.z) |
| | ] |
| | self.assertEqual(2, len(wires)) |
| | w = wires[1] if wires[0].BoundBox.isInside(wires[1].BoundBox) else wires[0] |
| |
|
| | self.assertRoughly(10, w.Edges[0].Curve.Radius) |
| | |
| | self.assertFalse(Path.Geom.pointsCoincide(Vector(), w.Edges[0].Placement.Base)) |
| |
|
| | wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(1, len(wire.Edges)) |
| | self.assertRoughly(8, wire.Edges[0].Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, 0), wire.Edges[0].Curve.Center) |
| | self.assertCoincide(Vector(0, 0, 1), wire.Edges[0].Curve.Axis) |
| |
|
| | def test15(self): |
| | """Check offsetting a cylinder with Placement.""" |
| | obj = self.doc.getObjectsByLabel("offset-placement")[0] |
| |
|
| | wires = [ |
| | w |
| | for w in obj.Shape.Wires |
| | if 1 == len(w.Edges) and Path.Geom.isRoughly(0, w.Edges[0].Vertexes[0].Point.z) |
| | ] |
| | self.assertEqual(2, len(wires)) |
| | w = wires[0] if wires[0].BoundBox.isInside(wires[1].BoundBox) else wires[1] |
| |
|
| | self.assertRoughly(20, w.Edges[0].Curve.Radius) |
| | |
| | self.assertFalse(Path.Geom.pointsCoincide(Vector(), w.Edges[0].Placement.Base)) |
| |
|
| | wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(1, len(wire.Edges)) |
| | self.assertRoughly(22, wire.Edges[0].Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, 0), wire.Edges[0].Curve.Center) |
| | self.assertCoincide(Vector(0, 0, -1), wire.Edges[0].Curve.Axis) |
| |
|
| | def test20(self): |
| | """Check offsetting hole wire succeeds.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | small = getWireInside(obj) |
| | |
| | y = 10 |
| | x = 10 * math.cos(math.pi / 6) |
| | self.assertLines( |
| | small.Edges, |
| | False, |
| | [ |
| | Vector(0, y, 0), |
| | Vector(-x, -y / 2, 0), |
| | Vector(x, -y / 2, 0), |
| | Vector(0, y, 0), |
| | ], |
| | ) |
| |
|
| | wire = PathOpUtil.offsetWire(small, obj.Shape, 3, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(3, len(wire.Edges)) |
| | self.assertTrue(wire.isClosed()) |
| | |
| | self.assertFalse(PathOpUtil.isWireClockwise(wire)) |
| | y = 4 |
| | 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)], |
| | ) |
| |
|
| | def test21(self): |
| | """Check offsetting hole wire for more than it's size makes hole vanish.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | small = getWireInside(obj) |
| | |
| | y = 10 |
| | x = 10 * math.cos(math.pi / 6) |
| | self.assertLines( |
| | small.Edges, |
| | False, |
| | [ |
| | Vector(0, y, 0), |
| | Vector(-x, -y / 2, 0), |
| | Vector(x, -y / 2, 0), |
| | Vector(0, y, 0), |
| | ], |
| | ) |
| | wire = PathOpUtil.offsetWire(small, obj.Shape, 5, True) |
| | self.assertIsNone(wire) |
| |
|
| | def test22(self): |
| | """Check offsetting a body wire succeeds.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | big = getWireOutside(obj) |
| | |
| | y = 20 |
| | x = 20 * math.cos(math.pi / 6) |
| | self.assertLines( |
| | big.Edges, |
| | False, |
| | [ |
| | Vector(0, y, 0), |
| | Vector(-x, -y / 2, 0), |
| | Vector(x, -y / 2, 0), |
| | Vector(0, y, 0), |
| | ], |
| | ) |
| |
|
| | wire = PathOpUtil.offsetWire(big, obj.Shape, 5, True) |
| | self.assertIsNotNone(wire) |
| | self.assertEqual(6, len(wire.Edges)) |
| | lastAngle = None |
| | refAngle = math.pi / 3 |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(5, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) |
| | else: |
| | self.assertRoughly(34.641, e.Length, 0.001) |
| | begin = e.Vertexes[0].Point |
| | end = e.Vertexes[1].Point |
| | v = end - begin |
| | angle = Path.Geom.getAngle(v) |
| | if Path.Geom.isRoughly(0, angle) or Path.Geom.isRoughly(math.pi, math.fabs(angle)): |
| | if lastAngle: |
| | self.assertRoughly(-refAngle, lastAngle) |
| | elif Path.Geom.isRoughly(+refAngle, angle): |
| | if lastAngle: |
| | self.assertRoughly(math.pi, math.fabs(lastAngle)) |
| | elif Path.Geom.isRoughly(-refAngle, angle): |
| | if lastAngle: |
| | self.assertRoughly(+refAngle, lastAngle) |
| | else: |
| | self.assertIsNone("%s: angle=%s" % (type(e.Curve), angle)) |
| | lastAngle = angle |
| | self.assertTrue(PathOpUtil.isWireClockwise(wire)) |
| |
|
| | def test31(self): |
| | """Check offsetting a cylinder.""" |
| | obj = self.doc.getObjectsByLabel("circle-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True) |
| | self.assertEqual(1, len(wire.Edges)) |
| | edge = wire.Edges[0] |
| | self.assertCoincide(Vector(), edge.Curve.Center) |
| | self.assertCoincide(Vector(0, 0, -1), edge.Curve.Axis) |
| | self.assertRoughly(33, edge.Curve.Radius) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False) |
| | self.assertEqual(1, len(wire.Edges)) |
| | edge = wire.Edges[0] |
| | self.assertCoincide(Vector(), edge.Curve.Center) |
| | self.assertCoincide(Vector(0, 0, +1), edge.Curve.Axis) |
| | self.assertRoughly(33, edge.Curve.Radius) |
| |
|
| | def test32(self): |
| | """Check offsetting a box.""" |
| | obj = self.doc.getObjectsByLabel("square-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True) |
| | self.assertEqual(8, len(wire.Edges)) |
| | self.assertEqual(4, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(4, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x): |
| | self.assertEqual(40, e.Length) |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y): |
| | self.assertEqual(60, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(3, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) |
| | self.assertTrue(PathOpUtil.isWireClockwise(wire)) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False) |
| | self.assertEqual(8, len(wire.Edges)) |
| | self.assertEqual(4, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(4, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x): |
| | self.assertEqual(40, e.Length) |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y): |
| | self.assertEqual(60, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(3, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) |
| | self.assertFalse(PathOpUtil.isWireClockwise(wire)) |
| |
|
| | def test33(self): |
| | """Check offsetting a triangle.""" |
| | obj = self.doc.getObjectsByLabel("triangle-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True) |
| | self.assertEqual(6, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | length = 60 * math.sin(math.radians(60)) |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | self.assertRoughly(length, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(3, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False) |
| | self.assertEqual(6, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | self.assertRoughly(length, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(3, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) |
| |
|
| | def test34(self): |
| | """Check offsetting a shape.""" |
| | obj = self.doc.getObjectsByLabel("shape-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, True) |
| | self.assertEqual(6, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | length = 40 |
| | radius = 20 + 3 |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | self.assertRoughly(length, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(radius, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getPositiveShape(obj), 3, False) |
| | self.assertEqual(6, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | self.assertRoughly(length, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(radius, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) |
| |
|
| | def test35(self): |
| | """Check offsetting a cylindrical hole.""" |
| | obj = self.doc.getObjectsByLabel("circle-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True) |
| | self.assertEqual(1, len(wire.Edges)) |
| | edge = wire.Edges[0] |
| | self.assertCoincide(Vector(), edge.Curve.Center) |
| | self.assertCoincide(Vector(0, 0, +1), edge.Curve.Axis) |
| | self.assertRoughly(27, edge.Curve.Radius) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False) |
| | self.assertEqual(1, len(wire.Edges)) |
| | edge = wire.Edges[0] |
| | self.assertCoincide(Vector(), edge.Curve.Center) |
| | self.assertCoincide(Vector(0, 0, -1), edge.Curve.Axis) |
| | self.assertRoughly(27, edge.Curve.Radius) |
| |
|
| | def test36(self): |
| | """Check offsetting a square hole.""" |
| | obj = self.doc.getObjectsByLabel("square-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True) |
| | self.assertEqual(4, len(wire.Edges)) |
| | self.assertEqual(4, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | for e in wire.Edges: |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x): |
| | self.assertRoughly(34, e.Length) |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y): |
| | self.assertRoughly(54, e.Length) |
| | self.assertFalse(PathOpUtil.isWireClockwise(wire)) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False) |
| | self.assertEqual(4, len(wire.Edges)) |
| | self.assertEqual(4, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | for e in wire.Edges: |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.x, e.Vertexes[1].Point.x): |
| | self.assertRoughly(34, e.Length) |
| | if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y): |
| | self.assertRoughly(54, e.Length) |
| | self.assertTrue(PathOpUtil.isWireClockwise(wire)) |
| |
|
| | def test37(self): |
| | """Check offsetting a triangular holee.""" |
| | obj = self.doc.getObjectsByLabel("triangle-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True) |
| | self.assertEqual(3, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | length = 48 * math.sin(math.radians(60)) |
| | for e in wire.Edges: |
| | self.assertRoughly(length, e.Length) |
| | self.assertFalse(PathOpUtil.isWireClockwise(wire)) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False) |
| | self.assertEqual(3, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | for e in wire.Edges: |
| | self.assertRoughly(length, e.Length) |
| | self.assertTrue(PathOpUtil.isWireClockwise(wire)) |
| |
|
| | def test38(self): |
| | """Check offsetting a shape hole.""" |
| | obj = self.doc.getObjectsByLabel("shape-cut")[0] |
| |
|
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, True) |
| | self.assertEqual(6, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | length = 40 |
| | radius = 20 - 3 |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | self.assertRoughly(length, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(radius, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, +1), e.Curve.Axis) |
| |
|
| | |
| | wire = PathOpUtil.offsetWire(getWire(obj.Tool), getNegativeShape(obj), 3, False) |
| | self.assertEqual(6, len(wire.Edges)) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Line)])) |
| | self.assertEqual(3, len([e for e in wire.Edges if isinstance(e.Curve, Part.Circle)])) |
| | for e in wire.Edges: |
| | if isinstance(e.Curve, Part.Line): |
| | self.assertRoughly(length, e.Length) |
| | if isinstance(e.Curve, Part.Circle): |
| | self.assertRoughly(radius, e.Curve.Radius) |
| | self.assertCoincide(Vector(0, 0, -1), e.Curve.Axis) |
| |
|
| | def test40(self): |
| | """Check offsetting a single outside edge forward.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | w = getWireOutside(obj) |
| | length = 40 * math.cos(math.pi / 6) |
| | for e in w.Edges: |
| | self.assertRoughly(length, e.Length) |
| |
|
| | |
| | hEdges = [ |
| | e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| |
|
| | x = length / 2 |
| | y = -10 |
| | self.assertEqual(1, len(hEdges)) |
| | edge = hEdges[0] |
| |
|
| | self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point) |
| | self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point) |
| |
|
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, True) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | y = y - 5 |
| | self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point) |
| | self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point) |
| |
|
| | |
| | edge = Path.Geom.flipEdge(edge) |
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, True) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | 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 test41(self): |
| | """Check offsetting a single outside edge not forward.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | w = getWireOutside(obj) |
| | length = 40 * math.cos(math.pi / 6) |
| | for e in w.Edges: |
| | self.assertRoughly(length, e.Length) |
| |
|
| | |
| | hEdges = [ |
| | e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| |
|
| | x = length / 2 |
| | y = -10 |
| | self.assertEqual(1, len(hEdges)) |
| | edge = hEdges[0] |
| | self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point) |
| | self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point) |
| |
|
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, False) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | y = y - 5 |
| | self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point) |
| | self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point) |
| |
|
| | |
| | edge = Path.Geom.flipEdge(edge) |
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 5, False) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | 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 test42(self): |
| | """Check offsetting multiple outside edges.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| | obj.Shape.tessellate(0.01) |
| | self.doc.recompute() |
| |
|
| | w = getWireOutside(obj) |
| | length = 40 * math.cos(math.pi / 6) |
| |
|
| | |
| | lEdges = [ |
| | e |
| | for e in w.Edges |
| | if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| | self.assertEqual(2, len(lEdges)) |
| |
|
| | wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, True) |
| |
|
| | x = length / 2 + 2 * math.cos(math.pi / 6) |
| | y = -10 + 2 * math.sin(math.pi / 6) |
| |
|
| | 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 isinstance(e.Curve, Part.Circle)] |
| |
|
| | 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) |
| |
|
| | |
| | wire = PathOpUtil.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) |
| |
|
| | rEdges = [e for e in wire.Edges if isinstance(e.Curve, Part.Circle)] |
| |
|
| | 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 test43(self): |
| | """Check offsetting multiple backwards outside edges.""" |
| | |
| | |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | w = getWireOutside(obj) |
| | length = 40 * math.cos(math.pi / 6) |
| |
|
| | |
| | lEdges = [ |
| | e |
| | for e in w.Edges |
| | if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| | self.assertEqual(2, len(lEdges)) |
| |
|
| | w = Path.Geom.flipWire(Part.Wire(lEdges)) |
| | wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True) |
| |
|
| | x = length / 2 + 2 * math.cos(math.pi / 6) |
| | y = -10 + 2 * math.sin(math.pi / 6) |
| |
|
| | 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 isinstance(e.Curve, Part.Circle)] |
| |
|
| | 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) |
| |
|
| | |
| | wire = PathOpUtil.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) |
| |
|
| | rEdges = [e for e in wire.Edges if isinstance(e.Curve, Part.Circle)] |
| |
|
| | 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 test44(self): |
| | """Check offsetting a single inside edge forward.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | w = getWireInside(obj) |
| | length = 20 * math.cos(math.pi / 6) |
| | for e in w.Edges: |
| | self.assertRoughly(length, e.Length) |
| |
|
| | |
| | hEdges = [ |
| | e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| |
|
| | x = length / 2 |
| | y = -5 |
| | self.assertEqual(1, len(hEdges)) |
| | edge = hEdges[0] |
| |
|
| | self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point) |
| | self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point) |
| |
|
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, True) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | y = y + 2 |
| | self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[0].Point) |
| | self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[1].Point) |
| |
|
| | |
| | edge = Path.Geom.flipEdge(edge) |
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, True) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | 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 test45(self): |
| | """Check offsetting a single inside edge not forward.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | w = getWireInside(obj) |
| | length = 20 * math.cos(math.pi / 6) |
| | for e in w.Edges: |
| | self.assertRoughly(length, e.Length) |
| |
|
| | |
| | hEdges = [ |
| | e for e in w.Edges if Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| |
|
| | x = length / 2 |
| | y = -5 |
| | self.assertEqual(1, len(hEdges)) |
| | edge = hEdges[0] |
| |
|
| | self.assertCoincide(Vector(-x, y, 0), edge.Vertexes[0].Point) |
| | self.assertCoincide(Vector(+x, y, 0), edge.Vertexes[1].Point) |
| |
|
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, False) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | y = y + 2 |
| | self.assertCoincide(Vector(+x, y, 0), wire.Edges[0].Vertexes[0].Point) |
| | self.assertCoincide(Vector(-x, y, 0), wire.Edges[0].Vertexes[1].Point) |
| |
|
| | |
| | edge = Path.Geom.flipEdge(edge) |
| | wire = PathOpUtil.offsetWire(Part.Wire([edge]), obj.Shape, 2, False) |
| | self.assertEqual(1, len(wire.Edges)) |
| |
|
| | 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 test46(self): |
| | """Check offsetting multiple inside edges.""" |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | w = getWireInside(obj) |
| | length = 20 * math.cos(math.pi / 6) |
| |
|
| | |
| | lEdges = [ |
| | e |
| | for e in w.Edges |
| | if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| | self.assertEqual(2, len(lEdges)) |
| |
|
| | wire = PathOpUtil.offsetWire(Part.Wire(lEdges), obj.Shape, 2, True) |
| |
|
| | x = length / 2 - 2 * math.cos(math.pi / 6) |
| | y = -5 - 2 * math.sin(math.pi / 6) |
| |
|
| | 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 isinstance(e.Curve, Part.Circle)] |
| | self.assertEqual(0, len(rEdges)) |
| |
|
| | |
| | wire = PathOpUtil.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) |
| |
|
| | rEdges = [e for e in wire.Edges if isinstance(e.Curve, Part.Circle)] |
| | self.assertEqual(0, len(rEdges)) |
| |
|
| | def test47(self): |
| | """Check offsetting multiple backwards inside edges.""" |
| | |
| | |
| | obj = self.doc.getObjectsByLabel("offset-edge")[0] |
| |
|
| | w = getWireInside(obj) |
| | length = 20 * math.cos(math.pi / 6) |
| |
|
| | |
| | lEdges = [ |
| | e |
| | for e in w.Edges |
| | if not Path.Geom.isRoughly(e.Vertexes[0].Point.y, e.Vertexes[1].Point.y) |
| | ] |
| | self.assertEqual(2, len(lEdges)) |
| |
|
| | w = Path.Geom.flipWire(Part.Wire(lEdges)) |
| | wire = PathOpUtil.offsetWire(w, obj.Shape, 2, True) |
| |
|
| | x = length / 2 - 2 * math.cos(math.pi / 6) |
| | y = -5 - 2 * math.sin(math.pi / 6) |
| |
|
| | 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 isinstance(e.Curve, Part.Circle)] |
| | self.assertEqual(0, len(rEdges)) |
| |
|
| | |
| | wire = PathOpUtil.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) |
| |
|
| | rEdges = [e for e in wire.Edges if isinstance(e.Curve, Part.Circle)] |
| | self.assertEqual(0, len(rEdges)) |
| |
|
| | def test50(self): |
| | """Orient an already oriented wire""" |
| | p0 = Vector() |
| | p1 = Vector(1, 2, 3) |
| | p2 = Vector(2, 3, 4) |
| | pts = [p0, p1, p2] |
| |
|
| | e0 = Part.Edge(Part.LineSegment(p0, p1)) |
| | e1 = Part.Edge(Part.LineSegment(p1, p2)) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0, e1])) |
| | wirePts = wireMarkers(wire) |
| |
|
| | self.assertPointsMatch(wirePts, pts) |
| |
|
| | def test51(self): |
| | """Orient a potentially misoriented wire""" |
| | p0 = Vector() |
| | p1 = Vector(1, 2, 3) |
| | p2 = Vector(2, 3, 4) |
| | pts = [p0, p1, p2] |
| |
|
| | e0p = Part.Edge(Part.LineSegment(p0, p1)) |
| | e0m = Part.Edge(Part.LineSegment(p1, p0)) |
| | e1p = Part.Edge(Part.LineSegment(p1, p2)) |
| | e1m = Part.Edge(Part.LineSegment(p2, p1)) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0p, e1p])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0p, e1m])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0m, e1p])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0m, e1m])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | def test52(self): |
| | """Orient a potentially misoriented longer wire""" |
| | p0 = Vector() |
| | p1 = Vector(1, 2, 3) |
| | p2 = Vector(4, 5, 6) |
| | p3 = Vector(7, 8, 9) |
| | pts = [p0, p1, p2, p3] |
| |
|
| | e0p = Part.Edge(Part.LineSegment(p0, p1)) |
| | e0m = Part.Edge(Part.LineSegment(p1, p0)) |
| | e1p = Part.Edge(Part.LineSegment(p1, p2)) |
| | e1m = Part.Edge(Part.LineSegment(p2, p1)) |
| | e2p = Part.Edge(Part.LineSegment(p2, p3)) |
| | e2m = Part.Edge(Part.LineSegment(p3, p2)) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0p, e1p, e2p])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0p, e1m, e2p])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0m, e1p, e2p])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0m, e1m, e2p])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0p, e1p, e2m])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0p, e1m, e2m])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0m, e1p, e2m])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|
| | wire = PathOpUtil.orientWire(Part.Wire([e0m, e1m, e2m])) |
| | self.assertPointsMatch(wireMarkers(wire), pts) |
| |
|