# SPDX-License-Identifier: LGPL-2.1-or-later # *************************************************************************** # * Copyright (c) 2022 sliptonic * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU Library General Public License for more details. * # * * # * You should have received a copy of the GNU Library General Public * # * License along with this program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** import FreeCAD import Path import Path.Base.Generator.dogboneII as dogboneII import Path.Base.Language as PathLanguage import Path.Dressup.DogboneII import CAMTests.PathTestUtils as PathTestUtils import math PI = math.pi class MockTB(object): def __init__(self, dia): self.Name = "ToolBit" self.Label = "ToolBit" self.Diameter = FreeCAD.Units.Quantity(dia, FreeCAD.Units.Length) class MockTC(object): def __init__(self, dia=2): self.Name = "TC" self.Label = "TC" self.Tool = MockTB(dia) class MockOp(object): def __init__(self, path, dia=2): self.Name = "OP" self.Label = "OP" self.Path = Path.Path(path) self.ToolController = MockTC(dia) class MockFeaturePython(object): def __init__(self, name): self.prop = {} self.addProperty("App::PropertyString", "Name", val=name) self.addProperty("App::PropertyString", "Label", val=name) self.addProperty("App::PropertyLink", "Proxy") self.addProperty("Path::Path", "Path", val=Path.Path()) def addProperty(self, typ, name, grp=None, desc=None, val=None): self.prop[name] = (typ, val) def setEditorMode(self, name, mode): pass def __setattr__(self, name, val): if name == "prop": return super().__setattr__(name, val) self.prop[name] = (self.prop[name][0], val) def __getattr__(self, name): if name == "prop": return super().__getattr__(name) typ, val = self.prop.get(name, (None, None)) if typ is None and val is None: raise AttributeError if typ == "App::PropertyLength": if type(val) == float or type(val) == int: return FreeCAD.Units.Quantity(val, FreeCAD.Units.Length) return FreeCAD.Units.Quantity(val) return val def CreateDressup(path): op = MockOp(path) obj = MockFeaturePython("DressupDogbone") db = Path.Dressup.DogboneII.Proxy(obj, op) obj.Proxy = db return obj def MNVR(gcode, begin=None): # 'turns out the replace() isn't really necessary # leave it here anyway for clarity 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]) class TestDressupDogboneII(PathTestUtils.PathTestBase): """Unit tests for the DogboneII dressup.""" def assertEqualPath(self, path, s): def cmd2str(cmd): param = [ f"{k}{v:g}" if Path.Geom.isRoughly(0, v - int(v)) else f"{k}{v:.2f}" for k, v in cmd.Parameters.items() ] return f"{cmd.Name}{''.join(param)}" p = "/".join([cmd2str(cmd) for cmd in path.Commands]) self.assertEqual(p, s) def test00(self): """Verify adaptive length""" def adaptive(k, a, n): return Path.Dressup.DogboneII.calc_length_adaptive(k, a, n, n) if True: # horizontal bones self.assertRoughly(adaptive(KINK("G1X1/G1X2"), 0, 1), 0) self.assertRoughly(adaptive(KINK("G1X1/G1Y1"), 0, 1), 1) self.assertRoughly(adaptive(KINK("G1X1/G1X2Y1"), 0, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1X1/G1X0Y1"), 0, 1), 2.414211) self.assertRoughly(adaptive(KINK("G1X1/G1X0"), 0, 1), 1) self.assertRoughly(adaptive(KINK("G1X1/G1X0Y-1"), 0, 1), 2.414211) self.assertRoughly(adaptive(KINK("G1X1/G1X1Y-1"), 0, 1), 1) self.assertRoughly(adaptive(KINK("G1X1/G1X2Y-1"), 0, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1X1Y1/G1X0Y2"), 0, 1), 0.414214) if True: # more horizontal and some vertical bones self.assertRoughly(adaptive(KINK("G1Y1/G1Y2"), 0, 1), 0) self.assertRoughly(adaptive(KINK("G1Y1/G1Y1X1"), PI, 1), 1) self.assertRoughly(adaptive(KINK("G1Y1/G1Y2X1"), PI, 1), 0.089820) self.assertRoughly(adaptive(KINK("G1Y1/G1Y2X1"), PI / 2, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1Y1/G1Y0X1"), PI / 2, 1), 2.414211) self.assertRoughly(adaptive(KINK("G1Y1/G1Y0"), 0, 1), 1) self.assertRoughly(adaptive(KINK("G1Y1/G1Y0X-1"), PI / 2, 1), 2.414211) self.assertRoughly(adaptive(KINK("G1Y1/G1Y1X-1"), 0, 1), 1) self.assertRoughly(adaptive(KINK("G1Y1/G1Y2X-1"), 0, 1), 0.089820) self.assertRoughly(adaptive(KINK("G1Y1/G1Y2X-1"), PI / 2, 1), 0.414214) if True: # dogbones self.assertRoughly(adaptive(KINK("G1X1/G1Y1"), -PI / 4, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1X1/G1X0Y1"), -PI / 8, 1), 1.613126) self.assertRoughly(adaptive(KINK("G1X1/G1Y-1"), PI / 4, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1X1/G1X0Y-1"), PI / 8, 1), 1.613126) self.assertRoughly(adaptive(KINK("G1Y1/G1X-1"), PI / 4, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1Y1/G1X1"), 3 * PI / 4, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1Y-1/G1X1"), -3 * PI / 4, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1Y-1/G1X-1"), -PI / 4, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1X1Y1/G1X0Y2"), 0, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1X-1Y1/G1X0Y2"), PI, 1), 0.414214) self.assertRoughly(adaptive(KINK("G1X1Y1/G1X2Y0"), PI / 2, 2), 0.828428) self.assertRoughly(adaptive(KINK("G1X-1Y-1/G1X-2Y0"), -PI / 2, 2), 0.828428) self.assertRoughly(adaptive(KINK("G1X-1Y1/G1X-2Y0"), PI / 2, 2), 0.828428) self.assertRoughly(adaptive(KINK("G1X1Y-1/G1X2Y0"), -PI / 2, 2), 0.828428) def test01(self): """Verify nominal length""" def nominal(k, a, n): return Path.Dressup.DogboneII.calc_length_nominal(k, a, n, 0) # neither angle nor kink matter self.assertRoughly(nominal(KINK("G1X1/G1X2"), 0, 13), 13) self.assertRoughly(nominal(KINK("G1X1/G1X2"), PI / 2, 13), 13) self.assertRoughly(nominal(KINK("G1X1/G1X2"), PI, 13), 13) self.assertRoughly(nominal(KINK("G1X1/G1X2"), -PI / 2, 13), 13) self.assertRoughly(nominal(KINK("G1X8/G1X12"), 0, 13), 13) self.assertRoughly(nominal(KINK("G1X9/G1X0"), 0, 13), 13) self.assertRoughly(nominal(KINK("G1X7/G1X9"), 0, 13), 13) self.assertRoughly(nominal(KINK("G1X5/G1X1"), 0, 13), 13) def test02(self): """Verify custom length""" def custom(k, a, c): return Path.Dressup.DogboneII.calc_length_custom(k, a, 0, c) # neither angle nor kink matter self.assertRoughly(custom(KINK("G1X1/G1X2"), 0, 7), 7) self.assertRoughly(custom(KINK("G1X1/G1X2"), PI / 2, 7), 7) self.assertRoughly(custom(KINK("G1X1/G1X2"), PI, 7), 7) self.assertRoughly(custom(KINK("G1X1/G1X2"), -PI / 2, 7), 7) self.assertRoughly(custom(KINK("G1X8/G1X12"), 0, 7), 7) self.assertRoughly(custom(KINK("G1X9/G1X0"), 0, 7), 7) self.assertRoughly(custom(KINK("G1X7/G1X9"), 0, 7), 7) self.assertRoughly(custom(KINK("G1X5/G1X1"), 0, 7), 7) def test10(self): """Verify basic op dressup""" obj = CreateDressup("G1X10/G1Y20") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed obj.Style = Path.Dressup.DogboneII.Style.Tbone_H # bones on right side obj.Side = Path.Dressup.DogboneII.Side.Right obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, "G1X10/G1X11/G1X10/G1Y20") # no bones on left side obj.Side = Path.Dressup.DogboneII.Side.Left obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, "G1X10/G1Y20") def test11(self): """Verify retaining non-move instructions""" obj = CreateDressup("G1X10/(some comment)/G1Y20") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed obj.Style = Path.Dressup.DogboneII.Style.Tbone_H # bone on right side obj.Side = Path.Dressup.DogboneII.Side.Right obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, "G1X10/(some comment)/G1X11/G1X10/G1Y20") # no bone on left side obj.Side = Path.Dressup.DogboneII.Side.Left obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, "G1X10/(some comment)/G1Y20") def test20(self): """Verify bone on plunge moves""" obj = CreateDressup("G0Z10/G1Z0/G1X10/G1Y10/G1X0/G1Y0/G0Z10") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed obj.Style = Path.Dressup.DogboneII.Style.Tbone_H obj.Side = Path.Dressup.DogboneII.Side.Right obj.Proxy.execute(obj) self.assertEqualPath( obj.Path, "G0Z10/G1Z0/G1X10/G1X11/G1X10/G1Y10/G1X11/G1X10/G1X0/G1X-1/G1X0/G1Y0/G1X-1/G1X0/G0Z10", ) def test21(self): """Verify ignoring plunge moves that don't connect""" obj = CreateDressup("G0Z10/G1Z0/G1X10/G1Y10/G1X0/G1Y5/G0Z10") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed obj.Style = Path.Dressup.DogboneII.Style.Tbone_H obj.Side = Path.Dressup.DogboneII.Side.Right obj.Proxy.execute(obj) self.assertEqualPath( obj.Path, "G0Z10/G1Z0/G1X10/G1X11/G1X10/G1Y10/G1X11/G1X10/G1X0/G1X-1/G1X0/G1Y5/G0Z10", ) def test30(self): """Verify TBone_V style""" def check_tbone(d, i, path, out, right): obj = CreateDressup(f"({d}.{i:02})/{path}") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed if right: obj.Side = Path.Dressup.DogboneII.Side.Right else: obj.Side = Path.Dressup.DogboneII.Side.Left obj.Style = Path.Dressup.DogboneII.Style.Tbone_V obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, f"({d}.{i:02})/{out}") # test data with a horizontal lead in test_data_h = [ # top right quadrant ("G1X10Y0/G1X10Y10", "G1X10Y0/G1Y-1/G1Y0/G1X10Y10", True), ("G1X10Y0/G1X20Y10", "G1X10Y0/G1Y-1/G1Y0/G1X20Y10", True), ("G1X10Y0/G1X90Y10", "G1X10Y0/G1Y-1/G1Y0/G1X90Y10", True), ("G1X10Y0/G1X0Y10", "G1X10Y0/G1Y-1/G1Y0/G1X0Y10", True), # bottom right quadrant ("G1X10Y0/G1X90Y-10", "G1X10Y0/G1Y1/G1Y0/G1X90Y-10", False), ("G1X10Y0/G1X20Y-10", "G1X10Y0/G1Y1/G1Y0/G1X20Y-10", False), ("G1X10Y0/G1X10Y-10", "G1X10Y0/G1Y1/G1Y0/G1X10Y-10", False), ("G1X10Y0/G1X0Y-10", "G1X10Y0/G1Y1/G1Y0/G1X0Y-10", False), # top left quadrant ("G1X-10Y0/G1X-10Y10", "G1X-10Y0/G1Y-1/G1Y0/G1X-10Y10", False), ("G1X-10Y0/G1X-20Y10", "G1X-10Y0/G1Y-1/G1Y0/G1X-20Y10", False), ("G1X-10Y0/G1X-90Y10", "G1X-10Y0/G1Y-1/G1Y0/G1X-90Y10", False), ("G1X-10Y0/G1X-0Y10", "G1X-10Y0/G1Y-1/G1Y0/G1X-0Y10", False), # bottom left quadrant ("G1X-10Y0/G1X-90Y-10", "G1X-10Y0/G1Y1/G1Y0/G1X-90Y-10", True), ("G1X-10Y0/G1X-20Y-10", "G1X-10Y0/G1Y1/G1Y0/G1X-20Y-10", True), ("G1X-10Y0/G1X-10Y-10", "G1X-10Y0/G1Y1/G1Y0/G1X-10Y-10", True), ("G1X-10Y0/G1X-0Y-10", "G1X-10Y0/G1Y1/G1Y0/G1X-0Y-10", True), ] for i, (path, out, right) in enumerate(test_data_h): check_tbone("h", i, path, out, right) # test data with a vertical lead in test_data_v = [ # top right quadrant ("G1X0Y10/G1X10Y10", "G1X0Y10/G1Y11/G1Y10/G1X10Y10", False), ("G1X0Y10/G1X10Y20", "G1X0Y10/G1Y11/G1Y10/G1X10Y20", False), ("G1X0Y10/G1X10Y90", "G1X0Y10/G1Y11/G1Y10/G1X10Y90", False), ("G1X0Y10/G1X10Y0", "G1X0Y10/G1Y11/G1Y10/G1X10Y0", False), # bottom right quadrant ("G1X0Y-10/G1X10Y-90", "G1X0Y-10/G1Y-11/G1Y-10/G1X10Y-90", True), ("G1X0Y-10/G1X10Y-20", "G1X0Y-10/G1Y-11/G1Y-10/G1X10Y-20", True), ("G1X0Y-10/G1X10Y-10", "G1X0Y-10/G1Y-11/G1Y-10/G1X10Y-10", True), ("G1X0Y-10/G1X10Y-0", "G1X0Y-10/G1Y-11/G1Y-10/G1X10Y-0", True), # top left quadrant ("G1X0Y10/G1X-10Y10", "G1X0Y10/G1Y11/G1Y10/G1X-10Y10", True), ("G1X0Y10/G1X-10Y20", "G1X0Y10/G1Y11/G1Y10/G1X-10Y20", True), ("G1X0Y10/G1X-10Y90", "G1X0Y10/G1Y11/G1Y10/G1X-10Y90", True), ("G1X0Y10/G1X-10Y0", "G1X0Y10/G1Y11/G1Y10/G1X-10Y0", True), # bottom left quadrant ("G1X0Y-10/G1X-10Y-90", "G1X0Y-10/G1Y-11/G1Y-10/G1X-10Y-90", False), ("G1X0Y-10/G1X-10Y-20", "G1X0Y-10/G1Y-11/G1Y-10/G1X-10Y-20", False), ("G1X0Y-10/G1X-10Y-10", "G1X0Y-10/G1Y-11/G1Y-10/G1X-10Y-10", False), ("G1X0Y-10/G1X-10Y-0", "G1X0Y-10/G1Y-11/G1Y-10/G1X-10Y-0", False), ] for i, (path, out, right) in enumerate(test_data_v): check_tbone("v", i, path, out, right) def test40(self): """Verify TBone_S style""" def check_tbone_s(d, i, path, out, right): obj = CreateDressup(f"(m{d}.{i:02})/{path}") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed if right: obj.Side = Path.Dressup.DogboneII.Side.Right else: obj.Side = Path.Dressup.DogboneII.Side.Left obj.Style = Path.Dressup.DogboneII.Style.Tbone_S obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, f"(m{d}.{i:02})/{out}") # short edge m0 test_data_0 = [ # CCW ("G1X10/G1Y20", "G1X10/G1Y-1/G1Y0/G1Y20", True), ("G1X10Y10/G1X-10Y30", "G1X10Y10/G1X10.71Y9.29/G1X10Y10/G1X-10Y30", True), ("G1Y10/G1X-20", "G1Y10/G1X1/G1X0/G1X-20", True), ( "G1X-10Y10/G1X-30Y-10", "G1X-10Y10/G1X-9.29Y10.71/G1X-10Y10/G1X-30Y-10", True, ), ("G1X-10/G1Y-20", "G1X-10/G1Y1/G1Y0/G1Y-20", True), ( "G1X-10Y-10/G1X10Y-30", "G1X-10Y-10/G1X-10.71Y-9.29/G1X-10Y-10/G1X10Y-30", True, ), ("G1Y-10/G1X20", "G1Y-10/G1X-1/G1X0/G1X20", True), ("G1X10Y-10/G1X30Y10", "G1X10Y-10/G1X9.29Y-10.71/G1X10Y-10/G1X30Y10", True), # CW ("G1X10/G1Y-20", "G1X10/G1Y1/G1Y0/G1Y-20", False), ("G1X10Y10/G1X30Y-10", "G1X10Y10/G1X9.29Y10.71/G1X10Y10/G1X30Y-10", False), ("G1Y10/G1X20", "G1Y10/G1X-1/G1X0/G1X20", False), ( "G1X-10Y10/G1X10Y30", "G1X-10Y10/G1X-10.71Y9.29/G1X-10Y10/G1X10Y30", False, ), ("G1X-10/G1Y20", "G1X-10/G1Y-1/G1Y0/G1Y20", False), ( "G1X-10Y-10/G1X-30Y10", "G1X-10Y-10/G1X-9.29Y-10.71/G1X-10Y-10/G1X-30Y10", False, ), ("G1Y-10/G1X-20", "G1Y-10/G1X1/G1X0/G1X-20", False), ( "G1X10Y-10/G1X-10Y-30", "G1X10Y-10/G1X10.71Y-9.29/G1X10Y-10/G1X-10Y-30", False, ), ] for i, (path, out, right) in enumerate(test_data_0): check_tbone_s("0", i, path, out, right) # short edge m1 test_data_1 = [ # CCW ("G1X20/G1Y10", "G1X20/G1X21/G1X20/G1Y10", True), ("G1X20Y20/G1X10Y30", "G1X20Y20/G1X20.71Y20.71/G1X20Y20/G1X10Y30", True), ("G1Y20/G1X-10", "G1Y20/G1Y21/G1Y20/G1X-10", True), ( "G1X-20Y20/G1X-30Y10", "G1X-20Y20/G1X-20.71Y20.71/G1X-20Y20/G1X-30Y10", True, ), ("G1X-20/G1Y-10", "G1X-20/G1X-21/G1X-20/G1Y-10", True), ( "G1X-20Y-20/G1X-10Y-30", "G1X-20Y-20/G1X-20.71Y-20.71/G1X-20Y-20/G1X-10Y-30", True, ), ("G1Y-20/G1X10", "G1Y-20/G1Y-21/G1Y-20/G1X10", True), ( "G1X20Y-20/G1X30Y-10", "G1X20Y-20/G1X20.71Y-20.71/G1X20Y-20/G1X30Y-10", True, ), # CW ("G1X20/G1Y-10", "G1X20/G1X21/G1X20/G1Y-10", False), ("G1X20Y20/G1X30Y10", "G1X20Y20/G1X20.71Y20.71/G1X20Y20/G1X30Y10", False), ("G1Y20/G1X10", "G1Y20/G1Y21/G1Y20/G1X10", False), ( "G1X-20Y20/G1X-10Y30", "G1X-20Y20/G1X-20.71Y20.71/G1X-20Y20/G1X-10Y30", False, ), ("G1X-20/G1Y10", "G1X-20/G1X-21/G1X-20/G1Y10", False), ( "G1X-20Y-20/G1X-30Y-10", "G1X-20Y-20/G1X-20.71Y-20.71/G1X-20Y-20/G1X-30Y-10", False, ), ("G1Y-20/G1X-10", "G1Y-20/G1Y-21/G1Y-20/G1X-10", False), ( "G1X20Y-20/G1X10Y-30", "G1X20Y-20/G1X20.71Y-20.71/G1X20Y-20/G1X10Y-30", False, ), ] for i, (path, out, right) in enumerate(test_data_1): check_tbone_s("1", i, path, out, right) def test50(self): """Verify TBone_L style""" def check_tbone_l(d, i, path, out, right): obj = CreateDressup(f"(m{d}.{i:02})/{path}") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed if right: obj.Side = Path.Dressup.DogboneII.Side.Right else: obj.Side = Path.Dressup.DogboneII.Side.Left obj.Style = Path.Dressup.DogboneII.Style.Tbone_L obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, f"(m{d}.{i:02})/{out}") # long edge m1 test_data_1 = [ # CCW ("G1X10/G1Y20", "G1X10/G1X11/G1X10/G1Y20", True), ("G1X10Y10/G1X-10Y30", "G1X10Y10/G1X10.71Y10.71/G1X10Y10/G1X-10Y30", True), ("G1Y10/G1X-20", "G1Y10/G1Y11/G1Y10/G1X-20", True), ( "G1X-10Y10/G1X-30Y-10", "G1X-10Y10/G1X-10.71Y10.71/G1X-10Y10/G1X-30Y-10", True, ), ("G1X-10/G1Y-20", "G1X-10/G1X-11/G1X-10/G1Y-20", True), ( "G1X-10Y-10/G1X10Y-30", "G1X-10Y-10/G1X-10.71Y-10.71/G1X-10Y-10/G1X10Y-30", True, ), ("G1Y-10/G1X20", "G1Y-10/G1Y-11/G1Y-10/G1X20", True), ( "G1X10Y-10/G1X30Y10", "G1X10Y-10/G1X10.71Y-10.71/G1X10Y-10/G1X30Y10", True, ), # CW ("G1X10/G1Y-20", "G1X10/G1X11/G1X10/G1Y-20", False), ("G1X10Y10/G1X30Y-10", "G1X10Y10/G1X10.71Y10.71/G1X10Y10/G1X30Y-10", False), ("G1Y10/G1X20", "G1Y10/G1Y11/G1Y10/G1X20", False), ( "G1X-10Y10/G1X10Y30", "G1X-10Y10/G1X-10.71Y10.71/G1X-10Y10/G1X10Y30", False, ), ("G1X-10/G1Y20", "G1X-10/G1X-11/G1X-10/G1Y20", False), ( "G1X-10Y-10/G1X-30Y10", "G1X-10Y-10/G1X-10.71Y-10.71/G1X-10Y-10/G1X-30Y10", False, ), ("G1Y-10/G1X-20", "G1Y-10/G1Y-11/G1Y-10/G1X-20", False), ( "G1X10Y-10/G1X-10Y-30", "G1X10Y-10/G1X10.71Y-10.71/G1X10Y-10/G1X-10Y-30", False, ), ] for i, (path, out, right) in enumerate(test_data_1): check_tbone_l("1", i, path, out, right) # long edge m0 test_data_0 = [ # CCW ("G1X20/G1Y10", "G1X20/G1Y-1/G1Y0/G1Y10", True), ("G1X20Y20/G1X10Y30", "G1X20Y20/G1X20.71Y19.29/G1X20Y20/G1X10Y30", True), ("G1Y20/G1X-10", "G1Y20/G1X1/G1X0/G1X-10", True), ( "G1X-20Y20/G1X-30Y10", "G1X-20Y20/G1X-19.29Y20.71/G1X-20Y20/G1X-30Y10", True, ), ("G1X-20/G1Y-10", "G1X-20/G1Y1/G1Y0/G1Y-10", True), ( "G1X-20Y-20/G1X-10Y-30", "G1X-20Y-20/G1X-20.71Y-19.29/G1X-20Y-20/G1X-10Y-30", True, ), ("G1Y-20/G1X10", "G1Y-20/G1X-1/G1X0/G1X10", True), ( "G1X20Y-20/G1X30Y-10", "G1X20Y-20/G1X19.29Y-20.71/G1X20Y-20/G1X30Y-10", True, ), # CW ("G1X20/G1Y-10", "G1X20/G1Y1/G1Y0/G1Y-10", False), ("G1X20Y20/G1X30Y10", "G1X20Y20/G1X19.29Y20.71/G1X20Y20/G1X30Y10", False), ("G1Y20/G1X10", "G1Y20/G1X-1/G1X0/G1X10", False), ( "G1X-20Y20/G1X-10Y30", "G1X-20Y20/G1X-20.71Y19.29/G1X-20Y20/G1X-10Y30", False, ), ("G1X-20/G1Y10", "G1X-20/G1Y-1/G1Y0/G1Y10", False), ( "G1X-20Y-20/G1X-30Y-10", "G1X-20Y-20/G1X-19.29Y-20.71/G1X-20Y-20/G1X-30Y-10", False, ), ("G1Y-20/G1X-10", "G1Y-20/G1X1/G1X0/G1X-10", False), ( "G1X20Y-20/G1X10Y-30", "G1X20Y-20/G1X20.71Y-19.29/G1X20Y-20/G1X10Y-30", False, ), ] for i, (path, out, right) in enumerate(test_data_0): check_tbone_l("0", i, path, out, right) def test60(self): """Verify Dogbone style""" obj = CreateDressup("G1X10/G1Y20") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed obj.Side = Path.Dressup.DogboneII.Side.Right obj.Style = Path.Dressup.DogboneII.Style.Dogbone obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, "G1X10/G1X10.71Y-0.71/G1X10Y0/G1Y20") def test70(self): """Verify custom length.""" obj = CreateDressup("G0Z10/G1Z0/G1X10/G1Y10/G1X0/G1Y0/G0Z10") obj.Style = Path.Dressup.DogboneII.Style.Tbone_H obj.Side = Path.Dressup.DogboneII.Side.Right obj.Incision = Path.Dressup.DogboneII.Incision.Custom obj.Custom = 3 obj.Proxy.execute(obj) self.assertEqualPath( obj.Path, "G0Z10/G1Z0/G1X10/G1X13/G1X10/G1Y10/G1X13/G1X10/G1X0/G1X-3/G1X0/G1Y0/G1X-3/G1X0/G0Z10", ) obj.Custom = 2 obj.Proxy.execute(obj) self.assertEqualPath( obj.Path, "G0Z10/G1Z0/G1X10/G1X12/G1X10/G1Y10/G1X12/G1X10/G1X0/G1X-2/G1X0/G1Y0/G1X-2/G1X0/G0Z10", ) def test80(self): """Verify adaptive length.""" obj = CreateDressup("G1X10/G1Y20") obj.Incision = Path.Dressup.DogboneII.Incision.Adaptive obj.Side = Path.Dressup.DogboneII.Side.Right obj.Style = Path.Dressup.DogboneII.Style.Dogbone obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, "G1X10/G1X10.29Y-0.29/G1X10Y0/G1Y20") def test81(self): """Verify adaptive length II.""" obj = CreateDressup("G1X10/G1X20Y20") obj.Incision = Path.Dressup.DogboneII.Incision.Adaptive obj.Side = Path.Dressup.DogboneII.Side.Right obj.Style = Path.Dressup.DogboneII.Style.Dogbone obj.Proxy.execute(obj) self.assertEqualPath(obj.Path, "G1X10/G1X10.09Y-0.15/G1X10Y0/G1X20Y20") def test90(self): """Verify dogbone blacklist""" obj = CreateDressup("G0Z10/G1Z0/G1X10/G1Y10/G1X0/G1Y0/G0Z10") obj.Incision = Path.Dressup.DogboneII.Incision.Fixed obj.Style = Path.Dressup.DogboneII.Style.Tbone_H obj.Side = Path.Dressup.DogboneII.Side.Right obj.BoneBlacklist = [0, 2] obj.Proxy.execute(obj) self.assertEqualPath( obj.Path, "G0Z10/G1Z0/G1X10/G1Y10/G1X11/G1X10/G1X0/G1Y0/G1X-1/G1X0/G0Z10" ) return obj def test91(self): """Verify dogbone on dogbone""" obj = self.test90() obj2 = MockFeaturePython("DressupDogbone001") db2 = Path.Dressup.DogboneII.Proxy(obj2, obj) obj2.Proxy = db2 obj2.Incision = Path.Dressup.DogboneII.Incision.Fixed obj2.Style = Path.Dressup.DogboneII.Style.Tbone_H obj2.Side = Path.Dressup.DogboneII.Side.Right obj2.BoneBlacklist = [1] obj2.Proxy.execute(obj2) self.assertEqualPath( obj2.Path, "G0Z10/G1Z0/G1X10/G1X11/G1X10/G1Y10/G1X11/G1X10/G1X0/G1X-1/G1X0/G1Y0/G1X-1/G1X0/G0Z10", )