643 lines
26 KiB
Python
643 lines
26 KiB
Python
# -*- coding: utf-8 -*-
|
|
# ***************************************************************************
|
|
# * Copyright (c) 2022 sliptonic <shopinthewoods@gmail.com> *
|
|
# * *
|
|
# * 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",
|
|
)
|