freecad-cam/Mod/CAM/CAMTests/TestPathSetupSheet.py
2026-02-01 01:59:24 +01:00

329 lines
14 KiB
Python

# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2017 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.SetupSheet as PathSetupSheet
import json
import sys
# Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule())
from CAMTests.PathTestUtils import PathTestBase
def refstring(string):
return string.replace(" u'", " '")
class SomeOp(object):
def __init__(self, obj):
Path.Log.track(obj, type(obj))
obj.addProperty("App::PropertyPercent", "StepOver", "Base", "Some help you are")
@classmethod
def SetupProperties(cls):
return ["StepOver"]
@classmethod
def Create(cls, name, obj=None, parentJob=None):
Path.Log.track(name, obj)
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = SomeOp(obj)
return obj
class TestPathSetupSheet(PathTestBase):
def setUp(self):
self.doc = FreeCAD.newDocument("TestPathSetupSheet")
def tearDown(self):
FreeCAD.closeDocument(self.doc.Name)
def test00(self):
"""Verify SetupSheet templateAttributes"""
ss = PathSetupSheet.Create().Proxy
self.doc.recompute()
attrs = ss.templateAttributes(True, True)
self.assertEqualLocale(attrs[PathSetupSheet.Template.HorizRapid], "0.00 mm/s")
self.assertEqualLocale(attrs[PathSetupSheet.Template.VertRapid], "0.00 mm/s")
self.assertEqualLocale(attrs[PathSetupSheet.Template.SafeHeightOffset], "3.00 mm")
self.assertEqual(
attrs[PathSetupSheet.Template.SafeHeightExpression],
"OpStockZMax+SetupSheet.SafeHeightOffset",
)
self.assertEqualLocale(attrs[PathSetupSheet.Template.ClearanceHeightOffset], "5.00 mm")
self.assertEqual(
attrs[PathSetupSheet.Template.ClearanceHeightExpression],
"OpStockZMax+SetupSheet.ClearanceHeightOffset",
)
def test01(self):
"""Verify SetupSheet template attributes roundtrip."""
o1 = PathSetupSheet.Create()
self.doc.recompute()
o1.VertRapid = "10 mm/s"
o1.HorizRapid = "22 mm/s"
o1.SafeHeightOffset = "18 mm"
o1.SafeHeightExpression = "Hugo+Olga"
o1.ClearanceHeightOffset = "23 mm"
o1.ClearanceHeightExpression = "Peter+Paul"
o1.StartDepthExpression = "Alpha"
o1.FinalDepthExpression = "Omega"
o1.StepDownExpression = "1"
o2 = PathSetupSheet.Create()
self.doc.recompute()
o2.Proxy.setFromTemplate(o1.Proxy.templateAttributes())
self.doc.recompute()
# Need to compare the UserString's due to rounding errors depending on the
# user's unit settings - should have no impact on the validity
self.assertEqual(o1.VertRapid.UserString, o2.VertRapid.UserString)
self.assertEqual(o1.HorizRapid.UserString, o2.HorizRapid.UserString)
self.assertEqual(o1.SafeHeightOffset.UserString, o2.SafeHeightOffset.UserString)
self.assertEqual(o1.SafeHeightExpression, o2.SafeHeightExpression)
self.assertEqual(o1.ClearanceHeightOffset.UserString, o2.ClearanceHeightOffset.UserString)
self.assertEqual(o1.ClearanceHeightExpression, o2.ClearanceHeightExpression)
self.assertEqual(o1.StartDepthExpression, o2.StartDepthExpression)
self.assertEqual(o1.FinalDepthExpression, o2.FinalDepthExpression)
self.assertEqual(o1.StepDownExpression, o2.StepDownExpression)
def test02(self):
"""Verify default value detection logic."""
obj = PathSetupSheet.Create()
ss = obj.Proxy
self.assertTrue(ss.hasDefaultToolRapids())
self.assertTrue(ss.hasDefaultOperationHeights())
self.assertTrue(ss.hasDefaultOperationDepths())
obj.VertRapid = "1 mm/s"
self.assertFalse(ss.hasDefaultToolRapids())
obj.VertRapid = "0 mm/s"
self.assertTrue(ss.hasDefaultToolRapids())
obj.HorizRapid = "1 mm/s"
self.assertFalse(ss.hasDefaultToolRapids())
obj.HorizRapid = "0 mm/s"
self.assertTrue(ss.hasDefaultToolRapids())
obj.SafeHeightOffset = "0 mm"
self.assertFalse(ss.hasDefaultOperationHeights())
obj.SafeHeightOffset = ss.decodeAttributeString(
PathSetupSheet.SetupSheet.DefaultSafeHeightOffset
)
self.assertTrue(ss.hasDefaultOperationHeights())
obj.ClearanceHeightOffset = "0 mm"
self.assertFalse(ss.hasDefaultOperationHeights())
obj.ClearanceHeightOffset = ss.decodeAttributeString(
PathSetupSheet.SetupSheet.DefaultClearanceHeightOffset
)
self.assertTrue(ss.hasDefaultOperationHeights())
obj.SafeHeightExpression = "0 mm"
self.assertFalse(ss.hasDefaultOperationHeights())
obj.SafeHeightExpression = ss.decodeAttributeString(
PathSetupSheet.SetupSheet.DefaultSafeHeightExpression
)
self.assertTrue(ss.hasDefaultOperationHeights())
obj.ClearanceHeightExpression = "0 mm"
self.assertFalse(ss.hasDefaultOperationHeights())
obj.ClearanceHeightExpression = ss.decodeAttributeString(
PathSetupSheet.SetupSheet.DefaultClearanceHeightExpression
)
self.assertTrue(ss.hasDefaultOperationHeights())
obj.StartDepthExpression = ""
self.assertFalse(ss.hasDefaultOperationDepths())
obj.StartDepthExpression = ss.decodeAttributeString(
PathSetupSheet.SetupSheet.DefaultStartDepthExpression
)
self.assertTrue(ss.hasDefaultOperationDepths())
obj.FinalDepthExpression = ""
self.assertFalse(ss.hasDefaultOperationDepths())
obj.FinalDepthExpression = ss.decodeAttributeString(
PathSetupSheet.SetupSheet.DefaultFinalDepthExpression
)
self.assertTrue(ss.hasDefaultOperationDepths())
obj.StepDownExpression = ""
self.assertFalse(ss.hasDefaultOperationDepths())
obj.StepDownExpression = ss.decodeAttributeString(
PathSetupSheet.SetupSheet.DefaultStepDownExpression
)
self.assertTrue(ss.hasDefaultOperationDepths())
def test10(self):
"""Verify template attributes encoding/decoding of floats."""
ss = PathSetupSheet.Create().Proxy
self.assertEqual(ss.expressionReference(), "SetupSheet")
self.assertEqual(str(ss.encodeTemplateAttributes({"00": 13.00})), "{'00': 13.0}")
self.assertEqual(str(ss.decodeTemplateAttributes({"00": 13.00})), "{'00': 13.0}")
def test11(self):
"""Verify template attributes encoding/decoding of strings."""
ss = PathSetupSheet.Create().Proxy
self.assertEqual(
str(ss.encodeTemplateAttributes({"00": "hugo"})),
refstring("{'00': u'hugo'}"),
)
self.assertEqual(
str(ss.encodeTemplateAttributes({"00": "SetupSheet"})),
refstring("{'00': u'${SetupSheet}'}"),
)
self.assertEqual(
str(ss.encodeTemplateAttributes({"00": "SetupSheet.y"})),
refstring("{'00': u'${SetupSheet}.y'}"),
)
self.assertEqual(
str(ss.encodeTemplateAttributes({"00": "${hugo}"})),
refstring("{'00': u'${hugo}'}"),
)
self.assertEqual(
str(ss.decodeTemplateAttributes({"00": "hugo"})),
refstring("{'00': u'hugo'}"),
)
self.assertEqual(
str(ss.decodeTemplateAttributes({"00": "${SetupSheet}"})),
refstring("{'00': u'SetupSheet'}"),
)
self.assertEqual(
str(ss.decodeTemplateAttributes({"00": "${SetupSheet}.y"})),
refstring("{'00': u'SetupSheet.y'}"),
)
self.assertEqual(
str(ss.decodeTemplateAttributes({"00": "${SetupSheet}.y - ${SetupSheet}.z"})),
refstring("{'00': u'SetupSheet.y - SetupSheet.z'}"),
)
def test12(self):
"""Verify template attributes encoding/decoding of dictionaries."""
ss = PathSetupSheet.Create().Proxy
self.assertEqual(
str(ss.encodeTemplateAttributes({"00": {"01": "hugo"}})),
refstring("{'00': {'01': u'hugo'}}"),
)
self.assertEqual(
str(ss.encodeTemplateAttributes({"00": {"01": "SetupSheet.y - SetupSheet.z"}})),
refstring("{'00': {'01': u'${SetupSheet}.y - ${SetupSheet}.z'}}"),
)
self.assertEqual(
str(ss.decodeTemplateAttributes({"00": {"01": "hugo"}})),
refstring("{'00': {'01': u'hugo'}}"),
)
self.assertEqual(
str(ss.decodeTemplateAttributes({"00": {"01": "${SetupSheet}.y - ${SetupSheet}.z"}})),
refstring("{'00': {'01': u'SetupSheet.y - SetupSheet.z'}}"),
)
def test13(self):
"""Verify template attributes encoding/decoding of lists."""
ss = PathSetupSheet.Create().Proxy
attrs = {}
attrs["00"] = "x.SetupSheet"
attrs["01"] = [{"10": "SetupSheet", "11": "SetupSheet.y"}, {"20": "SetupSheet"}]
attrs["02"] = [
{
"a": [{"b": "SetupSheet"}, {"c": "SetupSheet"}],
"b": [{"b": "SetupSheet"}],
}
]
encoded = ss.encodeTemplateAttributes(attrs)
self.assertEqual(encoded["00"], "x.${SetupSheet}")
self.assertEqual(len(encoded["01"]), 2)
self.assertEqual(encoded["01"][0]["10"], "${SetupSheet}")
self.assertEqual(encoded["01"][0]["11"], "${SetupSheet}.y")
self.assertEqual(str(encoded["01"][1]), refstring("{'20': u'${SetupSheet}'}"))
self.assertEqual(len(encoded["02"]), 1)
self.assertEqual(len(encoded["02"][0]["a"]), 2)
self.assertEqual(str(encoded["02"][0]["a"][0]), refstring("{'b': u'${SetupSheet}'}"))
self.assertEqual(str(encoded["02"][0]["a"][1]), refstring("{'c': u'${SetupSheet}'}"))
self.assertEqual(len(encoded["02"][0]["b"]), 1)
self.assertEqual(str(encoded["02"][0]["b"][0]), refstring("{'b': u'${SetupSheet}'}"))
decoded = ss.decodeTemplateAttributes(encoded)
self.assertEqual(len(decoded), len(attrs))
self.assertEqual(decoded["00"], attrs["00"])
self.assertEqual(len(decoded["01"]), len(attrs["01"]))
self.assertEqual(decoded["01"][0]["10"], attrs["01"][0]["10"])
self.assertEqual(decoded["01"][0]["11"], attrs["01"][0]["11"])
self.assertEqual(decoded["01"][1]["20"], attrs["01"][1]["20"])
self.assertEqual(len(decoded["02"]), len(attrs["02"]))
self.assertEqual(len(decoded["02"][0]["a"]), len(attrs["02"][0]["a"]))
self.assertEqual(decoded["02"][0]["a"][0]["b"], attrs["02"][0]["a"][0]["b"])
self.assertEqual(decoded["02"][0]["a"][1]["c"], attrs["02"][0]["a"][1]["c"])
self.assertEqual(len(decoded["02"][0]["b"]), len(attrs["02"][0]["b"]))
self.assertEqual(decoded["02"][0]["b"][0]["b"], attrs["02"][0]["b"][0]["b"])
# just to be safe ...
s2 = PathSetupSheet.Create().Proxy
self.doc.recompute()
s2.setFromTemplate(ss.templateAttributes())
self.assertEqual(s2.expressionReference(), "SetupSheet001")
dec = s2.decodeTemplateAttributes(encoded)
# pick one
self.assertEqual(dec["01"][0]["11"], "SetupSheet001.y")
def test20(self):
"""Verify SetupSheet template op attributes roundtrip."""
opname = "whoop"
o1 = PathSetupSheet.Create()
PathSetupSheet.RegisterOperation(opname, SomeOp.Create, SomeOp.SetupProperties)
ptt = PathSetupSheet._RegisteredOps[opname].prototype("whoopsy")
pptt = ptt.getProperty("StepOver")
pptt.setupProperty(
o1,
PathSetupSheet.OpPropertyName(opname, pptt.name),
PathSetupSheet.OpPropertyGroup(opname),
75,
)
# save setup sheet in json "file"
attrs = o1.Proxy.templateAttributes(False, False, False, False, [opname])
encdd = o1.Proxy.encodeTemplateAttributes(attrs)
j1 = json.dumps({"SetupSheet": encdd}, sort_keys=True, indent=2)
# restore setup sheet from json "file"
j2 = json.loads(j1)
o2 = PathSetupSheet.Create()
o2.Proxy.setFromTemplate(j2["SetupSheet"])
op = SomeOp.Create(opname)
self.assertEqual(op.StepOver, 0)
o2.Proxy.setOperationProperties(op, opname)
self.assertEqual(op.StepOver, 75)