| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD |
| | import Path |
| | import Path.Base.Generator.dogboneII as dogboneII |
| | import Path.Base.Language as PathLanguage |
| | import CAMTests.PathTestUtils as PathTestUtils |
| | import math |
| |
|
| |
|
| | |
| | Path.Log.setLevel(Path.Log.Level.NOTICE) |
| |
|
| | PI = math.pi |
| | DebugMode = Path.Log.getLevel(Path.Log.thisModule()) == Path.Log.Level.DEBUG |
| |
|
| |
|
| | def createKinks(maneuver): |
| | k = [] |
| | moves = maneuver.getMoves() |
| | if moves: |
| | move0 = moves[0] |
| | prev = move0 |
| | for m in moves[1:]: |
| | k.append(dogboneII.Kink(prev, m)) |
| | prev = m |
| | if Path.Geom.pointsCoincide(move0.positionBegin(), prev.positionEnd()): |
| | k.append(dogboneII.Kink(prev, move0)) |
| | return k |
| |
|
| |
|
| | def findDogboneKinks(maneuver, threshold): |
| | if threshold > 0: |
| | return [k for k in createKinks(maneuver) if k.deflection() > threshold] |
| | if threshold < 0: |
| | return [k for k in createKinks(maneuver) if k.deflection() < threshold] |
| | return createKinks(maneuver) |
| |
|
| |
|
| | def MNVR(gcode, begin=None): |
| | |
| | |
| | return PathLanguage.Maneuver.FromGCode(gcode.replace("/", "\n"), begin) |
| |
|
| |
|
| | def INSTR(gcode, begin=None): |
| | return MNVR(gcode, begin).instr[0] |
| |
|
| |
|
| | def KINK(gcode, begin=None): |
| | maneuver = MNVR(gcode, begin) |
| | if len(maneuver.instr) != 2: |
| | return None |
| | return dogboneII.Kink(maneuver.instr[0], maneuver.instr[1]) |
| |
|
| |
|
| | def GEN(generator, length): |
| | return generator(lambda k, a, n, c: n, length, 1) |
| |
|
| |
|
| | class TestGeneratorDogboneII(PathTestUtils.PathTestBase): |
| | """Unit tests for the dogboneII generator.""" |
| |
|
| | def assertKinks(self, maneuver, s): |
| | kinks = [f"{k.deflection():4.2f}" for k in createKinks(maneuver)] |
| | self.assertEqual(f"[{', '.join(kinks)}]", s) |
| |
|
| | def assertBones(self, maneuver, threshold, s): |
| | bones = [f"({int(b.x())},{int(b.y())})" for b in findDogboneKinks(maneuver, threshold)] |
| | self.assertEqual(f"[{', '.join(bones)}]", s) |
| |
|
| | def assertBone(self, bone, s, digits=0): |
| | if DebugMode and FreeCAD.GuiUp: |
| | Path.show(dogboneII.kink_to_path(bone.kink)) |
| | FreeCAD.ActiveDocument.Objects[-1].Visibility = False |
| | Path.show(dogboneII.bone_to_path(bone)) |
| | FreeCAD.ActiveDocument.Objects[-1].Visibility = False |
| | Path.Log.debug(f"{bone.kink} : {bone.angle / PI:.2f}") |
| |
|
| | b = [i.str(digits) for i in bone.instr] |
| | self.assertEqual(f"[{', '.join(b)}]", s) |
| |
|
| | def test20(self): |
| | """Verify kinks of maneuvers""" |
| | self.assertKinks(MNVR("G1X1/G1Y1"), "[1.57]") |
| | self.assertKinks(MNVR("G1X1/G1Y-1"), "[-1.57]") |
| | self.assertKinks(MNVR("G1X1/G1Y1/G1X0"), "[1.57, 1.57]") |
| | self.assertKinks(MNVR("G1X1/G1Y1/G1X0/G1Y0"), "[1.57, 1.57, 1.57, 1.57]") |
| |
|
| | self.assertKinks(MNVR("G1Y1/G1X1"), "[-1.57]") |
| | self.assertKinks(MNVR("G1Y1/G1X1/G1Y0"), "[-1.57, -1.57]") |
| | self.assertKinks(MNVR("G1Y1/G1X1/G1Y0/G1X0"), "[-1.57, -1.57, -1.57, -1.57]") |
| |
|
| | |
| | self.assertKinks(MNVR("G1X1/G3Y2J1"), "[0.00]") |
| | self.assertKinks(MNVR("G1X1/G3Y2J1G1X0"), "[0.00, 0.00]") |
| |
|
| | |
| | self.assertKinks(MNVR("G1X1/G2Y2J1"), "[-3.14]") |
| | self.assertKinks(MNVR("G1X1/G2Y2J1G1X0"), "[-3.14, 3.14]") |
| |
|
| | def test30(self): |
| | """Verify dogbone detection""" |
| | self.assertBones(MNVR("G1X1/G1Y1/G1X0/G1Y0"), PI / 4, "[(1,0), (1,1), (0,1), (0,0)]") |
| | self.assertBones(MNVR("G1X1/G1Y1/G1X0/G1Y0"), -PI / 4, "[]") |
| |
|
| | |
| | self.assertBones(MNVR("G1X1/G1X3Y1/G1X0/G1Y0"), PI / 4, "[(3,1), (0,1), (0,0)]") |
| | self.assertBones(MNVR("G1X1/G1X3Y1/G1X0/G1Y0"), -PI / 4, "[]") |
| |
|
| | |
| | self.assertBones(MNVR("G1X1/G3Y2J1/G1X0/G1Y0"), PI / 4, "[(0,2), (0,0)]") |
| | self.assertBones(MNVR("G1X1/G3Y2J1/G1X0/G1Y0"), -PI / 4, "[]") |
| |
|
| | |
| | self.assertBones(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), PI / 4, "[(3,1), (0,1), (0,0)]") |
| | self.assertBones(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), -PI / 4, "[(1,0)]") |
| |
|
| | def test40(self): |
| | """Verify horizontal t-bone creation""" |
| | |
| |
|
| | horizontal = GEN(dogboneII.GeneratorTBoneHorizontal, 1) |
| |
|
| | |
| | maneuver = MNVR("G1X1/G1Y1") |
| | kinks = findDogboneKinks(maneuver, PI / 4) |
| | self.assertEqual(len(kinks), 1) |
| | k = kinks[0] |
| | p = k.position() |
| | self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)") |
| | bone = horizontal.generate(k) |
| | self.assertBone(bone, "[G1{X: 2}, G1{X: 1}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G1Y1/G1X0/G1Y0"), PI / 4) |
| | bones = [horizontal.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 4) |
| | self.assertBone(bones[0], "[G1{X: 2}, G1{X: 1}]") |
| | self.assertBone(bones[1], "[G1{X: 2}, G1{X: 1}]") |
| | self.assertBone(bones[2], "[G1{X: -1}, G1{X: 0}]") |
| | self.assertBone(bones[3], "[G1{X: -1}, G1{X: 0}]") |
| |
|
| | |
| | maneuver = MNVR("G1X1/G1Y-1") |
| | kinks = findDogboneKinks(maneuver, -PI / 4) |
| | self.assertEqual(len(kinks), 1) |
| | k = kinks[0] |
| | p = k.position() |
| | self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)") |
| | bone = horizontal.generate(k) |
| | self.assertBone(bone, "[G1{X: 2}, G1{X: 1}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G1Y-1/G1X0/G1Y0"), -PI / 4) |
| | bones = [horizontal.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 4) |
| | self.assertBone(bones[0], "[G1{X: 2}, G1{X: 1}]") |
| | self.assertBone(bones[1], "[G1{X: 2}, G1{X: 1}]") |
| | self.assertBone(bones[2], "[G1{X: -1}, G1{X: 0}]") |
| | self.assertBone(bones[3], "[G1{X: -1}, G1{X: 0}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), PI / 4) |
| | bones = [horizontal.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 3) |
| | self.assertBone(bones[0], "[G1{X: 4}, G1{X: 3}]") |
| | self.assertBone(bones[1], "[G1{X: -1}, G1{X: 0}]") |
| | self.assertBone(bones[2], "[G1{X: -1}, G1{X: 0}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), -PI / 4) |
| | bones = [horizontal.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 1) |
| | self.assertBone(bones[0], "[G1{X: 2}, G1{X: 1}]") |
| |
|
| | def test50(self): |
| | """Verify vertical t-bone creation""" |
| | |
| |
|
| | vertical = GEN(dogboneII.GeneratorTBoneVertical, 1) |
| |
|
| | |
| | maneuver = MNVR("G1X1/G1Y1") |
| | kinks = findDogboneKinks(maneuver, PI / 4) |
| | self.assertEqual(len(kinks), 1) |
| | k = kinks[0] |
| | p = k.position() |
| | self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)") |
| | bone = vertical.generate(k) |
| | self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G1Y1/G1X0/G1Y0"), PI / 4) |
| | bones = [vertical.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 4) |
| | self.assertBone(bones[0], "[G1{Y: -1}, G1{Y: 0}]") |
| | self.assertBone(bones[1], "[G1{Y: 2}, G1{Y: 1}]") |
| | self.assertBone(bones[2], "[G1{Y: 2}, G1{Y: 1}]") |
| | self.assertBone(bones[3], "[G1{Y: -1}, G1{Y: 0}]") |
| |
|
| | |
| | maneuver = MNVR("G1X1/G1Y-1") |
| | kinks = findDogboneKinks(maneuver, -PI / 4) |
| | self.assertEqual(len(kinks), 1) |
| | k = kinks[0] |
| | p = k.position() |
| | self.assertEqual(f"({int(p.x)}, {int(p.y)})", "(1, 0)") |
| | bone = vertical.generate(k) |
| | self.assertBone(bone, "[G1{Y: 1}, G1{Y: 0}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G1Y-1/G1X0/G1Y0"), -PI / 4) |
| | bones = [vertical.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 4) |
| | self.assertBone(bones[0], "[G1{Y: 1}, G1{Y: 0}]") |
| | self.assertBone(bones[1], "[G1{Y: -2}, G1{Y: -1}]") |
| | self.assertBone(bones[2], "[G1{Y: -2}, G1{Y: -1}]") |
| | self.assertBone(bones[3], "[G1{Y: 1}, G1{Y: 0}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), PI / 4) |
| | bones = [vertical.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 3) |
| | self.assertBone(bones[0], "[G1{Y: 2}, G1{Y: 1}]") |
| | self.assertBone(bones[1], "[G1{Y: 2}, G1{Y: 1}]") |
| | self.assertBone(bones[2], "[G1{Y: -1}, G1{Y: 0}]") |
| |
|
| | |
| | kinks = findDogboneKinks(MNVR("G1X1/G3X3I1/G1Y1/G1X0/G1Y0"), -PI / 4) |
| | bones = [vertical.generate(k) for k in kinks] |
| | self.assertEqual(len(bones), 1) |
| | self.assertBone(bones[0], "[G1{Y: 1}, G1{Y: 0}]") |
| |
|
| | def test60(self): |
| | """Verify t-bones on edges""" |
| |
|
| | on_short_1 = GEN(dogboneII.GeneratorTBoneOnShort, 1) |
| | on_short_5 = GEN(dogboneII.GeneratorTBoneOnShort, 5) |
| |
|
| | |
| | bone = on_short_1.generate(KINK("G1X1/G1Y2")) |
| | self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]") |
| |
|
| | bone = on_short_1.generate(KINK("G1X-1/G1Y2")) |
| | self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]") |
| |
|
| | |
| | bone = on_short_1.generate(KINK("G1Y1/G1X2")) |
| | self.assertBone(bone, "[G1{X: -1}, G1{X: 0}]") |
| |
|
| | bone = on_short_1.generate(KINK("G1Y1/G1X-2")) |
| | self.assertBone(bone, "[G1{X: 1}, G1{X: 0}]") |
| |
|
| | |
| | bone = on_short_5.generate(KINK("G1X1Y1/G1Y-1")) |
| | self.assertBone(bone, "[G1{X: -2.5, Y: 4.5}, G1{X: 1.0, Y: 1.0}]", 2) |
| |
|
| | bone = on_short_5.generate(KINK("G1X-1Y-1/G1Y1")) |
| | self.assertBone(bone, "[G1{X: 2.5, Y: -4.5}, G1{X: -1.0, Y: -1.0}]", 2) |
| |
|
| | |
| | bone = on_short_5.generate(KINK("G1X2Y1/G1Y-3")) |
| | self.assertBone(bone, "[G1{X: -0.24, Y: 5.5}, G1{X: 2.0, Y: 1.0}]", 2) |
| |
|
| | bone = on_short_5.generate(KINK("G1X-2Y-1/G1Y3")) |
| | self.assertBone(bone, "[G1{X: 0.24, Y: -5.5}, G1{X: -2.0, Y: -1.0}]", 2) |
| |
|
| | |
| | bone = on_short_1.generate(KINK("G1Y2/G1X1")) |
| | self.assertBone(bone, "[G1{Y: 3}, G1{Y: 2}]") |
| | bone = on_short_1.generate(KINK("G1Y2/G1X-1")) |
| | self.assertBone(bone, "[G1{Y: 3}, G1{Y: 2}]") |
| |
|
| | bone = on_short_5.generate(KINK("G1Y-3/G1X2Y-2")) |
| | self.assertBone(bone, "[G1{X: 2.2, Y: -7.5}, G1{X: 0.0, Y: -3.0}]", 2) |
| |
|
| | bone = on_short_5.generate(KINK("G1Y3/G1X-2Y2")) |
| | self.assertBone(bone, "[G1{X: -2.2, Y: 7.5}, G1{X: 0.0, Y: 3.0}]", 2) |
| |
|
| | |
| | on_long_1 = GEN(dogboneII.GeneratorTBoneOnLong, 1) |
| | on_long_5 = GEN(dogboneII.GeneratorTBoneOnLong, 5) |
| |
|
| | bone = on_long_1.generate( |
| | KINK("G1X2/G1Y1"), |
| | ) |
| | self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]") |
| | bone = on_long_1.generate(KINK("G1X-2/G1Y1")) |
| | self.assertBone(bone, "[G1{Y: -1}, G1{Y: 0}]") |
| |
|
| | bone = on_long_5.generate(KINK("G1Y-1/G1X2Y0")) |
| | self.assertBone(bone, "[G1{X: 2.2, Y: -5.5}, G1{X: 0.0, Y: -1.0}]", 2) |
| |
|
| | bone = on_long_5.generate(KINK("G1Y1/G1X-2Y0")) |
| | self.assertBone(bone, "[G1{X: -2.2, Y: 5.5}, G1{X: 0.0, Y: 1.0}]", 2) |
| |
|
| | def test70(self): |
| | """Verify dogbone angles""" |
| | self.assertRoughly(180 * KINK("G1X1/G1Y+1").normAngle() / PI, -45) |
| | self.assertRoughly(180 * KINK("G1X1/G1Y-1").normAngle() / PI, 45) |
| |
|
| | self.assertRoughly(180 * KINK("G1X1/G1X2Y1").normAngle() / PI, -67.5) |
| | self.assertRoughly(180 * KINK("G1X1/G1X2Y-1").normAngle() / PI, 67.5) |
| |
|
| | self.assertRoughly(180 * KINK("G1Y1/G1X+1").normAngle() / PI, 135) |
| | self.assertRoughly(180 * KINK("G1Y1/G1X-1").normAngle() / PI, 45) |
| |
|
| | self.assertRoughly(180 * KINK("G1X-1/G1Y+1").normAngle() / PI, -135) |
| | self.assertRoughly(180 * KINK("G1X-1/G1Y-1").normAngle() / PI, 135) |
| |
|
| | self.assertRoughly(180 * KINK("G1Y-1/G1X-1").normAngle() / PI, -45) |
| | self.assertRoughly(180 * KINK("G1Y-1/G1X+1").normAngle() / PI, -135) |
| |
|
| | def test71(self): |
| | """Verify dogbones""" |
| |
|
| | dogbone = GEN(dogboneII.GeneratorDogbone, 1) |
| |
|
| | bone = dogbone.generate(KINK("G1X1/G1Y1")) |
| | self.assertBone(bone, "[G1{X: 1.7, Y: -0.71}, G1{X: 1.0, Y: 0.0}]", 2) |
| |
|
| | bone = dogbone.generate(KINK("G1X1/G1X3Y-1")) |
| | self.assertBone(bone, "[G1{X: 1.2, Y: 0.97}, G1{X: 1.0, Y: 0.0}]", 2) |
| |
|
| | bone = dogbone.generate(KINK("G1X1Y1/G1X2")) |
| | self.assertBone(bone, "[G1{X: 0.62, Y: 1.9}, G1{X: 1.0, Y: 1.0}]", 2) |
| |
|