diff --git a/src/Mod/CAM/CAMTests/Fixtures/OpHelix_v0-21.FCStd b/src/Mod/CAM/CAMTests/Fixtures/OpHelix_v0-21.FCStd
new file mode 100644
index 0000000000..087665c9fa
Binary files /dev/null and b/src/Mod/CAM/CAMTests/Fixtures/OpHelix_v0-21.FCStd differ
diff --git a/src/Mod/CAM/CAMTests/PathTestUtils.py b/src/Mod/CAM/CAMTests/PathTestUtils.py
index ffdbf01cd1..3e50ccf1ac 100644
--- a/src/Mod/CAM/CAMTests/PathTestUtils.py
+++ b/src/Mod/CAM/CAMTests/PathTestUtils.py
@@ -65,14 +65,14 @@ class PathTestBase(unittest.TestCase):
for i in range(0, len(edges)):
self.assertLine(edges[i], points[i], points[i + 1])
- def assertArc(self, edge, pt1, pt2, direction="Climb"):
+ def assertArc(self, edge, pt1, pt2, direction="CW"):
"""Verify that edge is an arc between pt1 and pt2 with the given direction."""
self.assertIs(type(edge.Curve), Part.Circle)
self.assertCoincide(edge.valueAt(edge.FirstParameter), pt1)
self.assertCoincide(edge.valueAt(edge.LastParameter), pt2)
ptm = edge.valueAt((edge.LastParameter + edge.FirstParameter) / 2)
side = Path.Geom.Side.of(pt2 - pt1, ptm - pt1)
- if "Climb" == direction:
+ if "CW" == direction:
self.assertEqual(side, Path.Geom.Side.Left)
else:
self.assertEqual(side, Path.Geom.Side.Right)
@@ -185,3 +185,14 @@ class PathTestBase(unittest.TestCase):
self.assertEqual(len(pts0), len(pts1))
for i in range(len(pts0)):
self.assertCoincide(pts0[i], pts1[i])
+
+ def assertSuccessfulRecompute(self, doc, *objs, msg=None):
+ """Asserts that the given objects can be successfully recomputed."""
+ if len(objs) == 0:
+ doc.recompute()
+ objs = doc.Objects
+ else:
+ doc.recompute(objs)
+ failed_objects = [o.Name for o in objs if "Invalid" in o.State]
+ if len(failed_objects) > 0:
+ self.fail(msg or f"Recompute failed for {failed_objects}")
diff --git a/src/Mod/CAM/CAMTests/TestPathDressupDogbone.py b/src/Mod/CAM/CAMTests/TestPathDressupDogbone.py
index 7eb66393c5..4b61b8cba1 100644
--- a/src/Mod/CAM/CAMTests/TestPathDressupDogbone.py
+++ b/src/Mod/CAM/CAMTests/TestPathDressupDogbone.py
@@ -59,7 +59,7 @@ class TestDressupDogbone(PathTestBase):
"""Verify bones are inserted for simple moves."""
base = TestProfile(
"Inside",
- "Climb",
+ "CW",
"""
G0 X10 Y10 Z10
G1 Z0
@@ -84,7 +84,7 @@ class TestDressupDogbone(PathTestBase):
"""Verify bones are inserted if hole ends with rapid move out."""
base = TestProfile(
"Inside",
- "Climb",
+ "CW",
"""
G0 X10 Y10 Z10
G1 Z0
@@ -175,7 +175,7 @@ class TestDressupDogbone(PathTestBase):
"""Verify no bone is inserted for straight move interrupted by plunge."""
base = TestProfile(
"Inside",
- "Climb",
+ "CW",
"""
G0 X10 Y10 Z10
G1 Z0
@@ -197,7 +197,7 @@ class TestDressupDogbone(PathTestBase):
"""Verify can handle comments between moves"""
base = TestProfile(
"Inside",
- "Climb",
+ "CW",
"""
G0 X10 Y10 Z10
G1 Z0
@@ -220,7 +220,7 @@ class TestDressupDogbone(PathTestBase):
base = TestProfile(
"Inside",
- "Climb",
+ "CW",
"""
G0 X10 Y10 Z10
G1 Z0
@@ -246,7 +246,7 @@ class TestDressupDogbone(PathTestBase):
"""Verify can handle noops between moves"""
base = TestProfile(
"Inside",
- "Climb",
+ "CW",
"""
G0 X10 Y10 Z10
G1 Z0
@@ -269,7 +269,7 @@ class TestDressupDogbone(PathTestBase):
base = TestProfile(
"Inside",
- "Climb",
+ "CW",
"""
G0 X10 Y10 Z10
G1 Z0
diff --git a/src/Mod/CAM/CAMTests/TestPathGeom.py b/src/Mod/CAM/CAMTests/TestPathGeom.py
index 67895e5f24..6e7cb20bef 100644
--- a/src/Mod/CAM/CAMTests/TestPathGeom.py
+++ b/src/Mod/CAM/CAMTests/TestPathGeom.py
@@ -44,64 +44,56 @@ class TestPathGeom(PathTestBase):
def test01(self):
"""Verify diffAngle functionality."""
- self.assertRoughly(Path.Geom.diffAngle(0, +0 * math.pi / 4, "Climb") / math.pi, 0 / 4.0)
- self.assertRoughly(Path.Geom.diffAngle(0, +3 * math.pi / 4, "Climb") / math.pi, 5 / 4.0)
- self.assertRoughly(Path.Geom.diffAngle(0, -3 * math.pi / 4, "Climb") / math.pi, 3 / 4.0)
- self.assertRoughly(Path.Geom.diffAngle(0, +4 * math.pi / 4, "Climb") / math.pi, 4 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, +0 * math.pi / 4, "CW") / math.pi, 0 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, +3 * math.pi / 4, "CW") / math.pi, 5 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, -3 * math.pi / 4, "CW") / math.pi, 3 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, +4 * math.pi / 4, "CW") / math.pi, 4 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, +0 * math.pi / 4, "CCW") / math.pi, 0 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, +3 * math.pi / 4, "CCW") / math.pi, 3 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, -3 * math.pi / 4, "CCW") / math.pi, 5 / 4.0)
+ self.assertRoughly(Path.Geom.diffAngle(0, +4 * math.pi / 4, "CCW") / math.pi, 4 / 4.0)
+
self.assertRoughly(
- Path.Geom.diffAngle(0, +0 * math.pi / 4, "Conventional") / math.pi, 0 / 4.0
+ Path.Geom.diffAngle(+math.pi / 4, +0 * math.pi / 4, "CW") / math.pi, 1 / 4.0
)
self.assertRoughly(
- Path.Geom.diffAngle(0, +3 * math.pi / 4, "Conventional") / math.pi, 3 / 4.0
+ Path.Geom.diffAngle(+math.pi / 4, +3 * math.pi / 4, "CW") / math.pi, 6 / 4.0
)
self.assertRoughly(
- Path.Geom.diffAngle(0, -3 * math.pi / 4, "Conventional") / math.pi, 5 / 4.0
+ Path.Geom.diffAngle(+math.pi / 4, -1 * math.pi / 4, "CW") / math.pi, 2 / 4.0
)
self.assertRoughly(
- Path.Geom.diffAngle(0, +4 * math.pi / 4, "Conventional") / math.pi, 4 / 4.0
+ Path.Geom.diffAngle(-math.pi / 4, +0 * math.pi / 4, "CW") / math.pi, 7 / 4.0
+ )
+ self.assertRoughly(
+ Path.Geom.diffAngle(-math.pi / 4, +3 * math.pi / 4, "CW") / math.pi, 4 / 4.0
+ )
+ self.assertRoughly(
+ Path.Geom.diffAngle(-math.pi / 4, -1 * math.pi / 4, "CW") / math.pi, 0 / 4.0
)
self.assertRoughly(
- Path.Geom.diffAngle(+math.pi / 4, +0 * math.pi / 4, "Climb") / math.pi, 1 / 4.0
- )
- self.assertRoughly(
- Path.Geom.diffAngle(+math.pi / 4, +3 * math.pi / 4, "Climb") / math.pi, 6 / 4.0
- )
- self.assertRoughly(
- Path.Geom.diffAngle(+math.pi / 4, -1 * math.pi / 4, "Climb") / math.pi, 2 / 4.0
- )
- self.assertRoughly(
- Path.Geom.diffAngle(-math.pi / 4, +0 * math.pi / 4, "Climb") / math.pi, 7 / 4.0
- )
- self.assertRoughly(
- Path.Geom.diffAngle(-math.pi / 4, +3 * math.pi / 4, "Climb") / math.pi, 4 / 4.0
- )
- self.assertRoughly(
- Path.Geom.diffAngle(-math.pi / 4, -1 * math.pi / 4, "Climb") / math.pi, 0 / 4.0
- )
-
- self.assertRoughly(
- Path.Geom.diffAngle(+math.pi / 4, +0 * math.pi / 4, "Conventional") / math.pi,
+ Path.Geom.diffAngle(+math.pi / 4, +0 * math.pi / 4, "CCW") / math.pi,
7 / 4.0,
)
self.assertRoughly(
- Path.Geom.diffAngle(+math.pi / 4, +3 * math.pi / 4, "Conventional") / math.pi,
+ Path.Geom.diffAngle(+math.pi / 4, +3 * math.pi / 4, "CCW") / math.pi,
2 / 4.0,
)
self.assertRoughly(
- Path.Geom.diffAngle(+math.pi / 4, -1 * math.pi / 4, "Conventional") / math.pi,
+ Path.Geom.diffAngle(+math.pi / 4, -1 * math.pi / 4, "CCW") / math.pi,
6 / 4.0,
)
self.assertRoughly(
- Path.Geom.diffAngle(-math.pi / 4, +0 * math.pi / 4, "Conventional") / math.pi,
+ Path.Geom.diffAngle(-math.pi / 4, +0 * math.pi / 4, "CCW") / math.pi,
1 / 4.0,
)
self.assertRoughly(
- Path.Geom.diffAngle(-math.pi / 4, +3 * math.pi / 4, "Conventional") / math.pi,
+ Path.Geom.diffAngle(-math.pi / 4, +3 * math.pi / 4, "CCW") / math.pi,
4 / 4.0,
)
self.assertRoughly(
- Path.Geom.diffAngle(-math.pi / 4, -1 * math.pi / 4, "Conventional") / math.pi,
+ Path.Geom.diffAngle(-math.pi / 4, -1 * math.pi / 4, "CCW") / math.pi,
0 / 4.0,
)
@@ -431,7 +423,7 @@ class TestPathGeom(PathTestBase):
),
p1,
p2,
- "Climb",
+ "CW",
)
self.assertArc(
Path.Geom.edgeForCmd(
@@ -440,7 +432,7 @@ class TestPathGeom(PathTestBase):
),
p2,
p1,
- "Conventional",
+ "CCW",
)
def test30(self):
diff --git a/src/Mod/CAM/CAMTests/TestPathHelix.py b/src/Mod/CAM/CAMTests/TestPathHelix.py
index bd32272eb7..18d0df432f 100644
--- a/src/Mod/CAM/CAMTests/TestPathHelix.py
+++ b/src/Mod/CAM/CAMTests/TestPathHelix.py
@@ -20,13 +20,18 @@
# * *
# ***************************************************************************
+import pathlib
+
import Draft
import FreeCAD
import Path
+import Path.Base.SetupSheetOpPrototype as PathSetupSheetOpPrototype
import Path.Main.Job as PathJob
import Path.Op.Helix as PathHelix
import CAMTests.PathTestUtils as PathTestUtils
+FIXTURE_PATH = pathlib.Path(__file__).parent / "Fixtures"
+
Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule())
# Path.Log.trackModule(Path.Log.thisModule())
@@ -39,6 +44,9 @@ class TestPathHelix(PathTestUtils.PathTestBase):
self.doc = FreeCAD.open(FreeCAD.getHomePath() + "Mod/CAM/CAMTests/test_holes00.fcstd")
self.job = PathJob.Create("Job", [self.doc.Body])
+ # the smallest hole in the fixture is 1mm in diameter, so our tool must be smaller.
+ self.job.Tools.Group[0].Tool.Diameter = 0.9
+
def tearDown(self):
FreeCAD.closeDocument(self.doc.Name)
@@ -48,6 +56,12 @@ class TestPathHelix(PathTestUtils.PathTestBase):
op = PathHelix.Create("Helix")
op.Proxy.execute(op)
+ def testCreateWithPrototype(self):
+ """Verify a Helix can be created on a SetupSheet's prototype instead of a real document object"""
+
+ ptt = PathSetupSheetOpPrototype.OpPrototype("Helix")
+ op = PathHelix.Create("OpPrototype.Helix", ptt)
+
def test01(self):
"""Verify Helix generates proper holes from model"""
@@ -62,8 +76,6 @@ class TestPathHelix(PathTestUtils.PathTestBase):
def test02(self):
"""Verify Helix generates proper holes for rotated model"""
- self.job.Tools.Group[0].Tool.Diameter = 0.5
-
op = PathHelix.Create("Helix")
proxy = op.Proxy
model = self.job.Model.Group[0]
@@ -126,3 +138,103 @@ class TestPathHelix(PathTestUtils.PathTestBase):
self.assertRoughly(
round(pos.Length / 10, 0), proxy.holeDiameter(op, model, sub)
)
+
+ def testPathDirection(self):
+ """Verify that the generated paths obays the given parameters"""
+ helix = PathHelix.Create("Helix")
+
+ def check(start_side, cut_mode, expected_direction):
+ with self.subTest(f"({start_side}, {cut_mode}) => {expected_direction}"):
+ helix.StartSide = start_side
+ helix.CutMode = cut_mode
+
+ self.assertSuccessfulRecompute(self.doc, helix)
+
+ self.assertEqual(
+ helix.Direction,
+ expected_direction,
+ msg=f"Direction was not correctly determined",
+ )
+ self.assertPathDirection(
+ helix.Path,
+ expected_direction,
+ msg=f"Path with wrong direction generated",
+ )
+
+ check("Inside", "Conventional", "CW")
+ check("Outside", "Climb", "CW")
+ check("Inside", "Climb", "CCW")
+ check("Outside", "Conventional", "CCW")
+
+ def testRecomputeHelixFromV021(self):
+ """Verify that we can still open and recompute a Helix created with older FreeCAD"""
+ self.tearDown()
+ self.doc = FreeCAD.openDocument(str(FIXTURE_PATH / "OpHelix_v0-21.FCStd"))
+ created_with = f"created with {self.doc.getProgramVersion()}"
+
+ def check(helix, direction, start_side, cut_mode):
+ with self.subTest(f"{helix.Name}: ({direction}, {start_side}) => {cut_mode}"):
+ # no recompute yet, i.e. check original as precondition
+ self.assertPathDirection(
+ helix.Path,
+ direction,
+ msg=f"Path direction does not match fixture for {helix.Name} {created_with}",
+ )
+ self.assertEqual(
+ helix.Direction,
+ direction,
+ msg=f"Direction does not match fixture for {helix.Name} {created_with}",
+ )
+ self.assertEqual(
+ helix.StartSide,
+ start_side,
+ msg=f"StartSide does not match fixture for {helix.Name} {created_with}",
+ )
+
+ # now see whether we can recompute the object from the old document
+ helix.enforceRecompute()
+ self.assertSuccessfulRecompute(
+ self.doc, helix, msg=f"Cannot recompute {helix.Name} {created_with}"
+ )
+ self.assertEqual(
+ helix.Direction,
+ direction,
+ msg=f"Direction changed after recomputing {helix.Name} {created_with}",
+ )
+ self.assertEqual(
+ helix.StartSide,
+ start_side,
+ msg=f"StartSide changed after recomputing {helix.Name} {created_with}",
+ )
+ self.assertEqual(
+ helix.CutMode,
+ cut_mode,
+ msg=f"CutMode not correctly derived for {helix.Name} {created_with}",
+ )
+ self.assertPathDirection(
+ helix.Path,
+ direction,
+ msg=f"Path with wrong direction generated for {helix.Name} {created_with}",
+ )
+
+ # object names and expected values defined in the fixture
+ check(self.doc.Helix, "CW", "Inside", "Conventional")
+ check(self.doc.Helix001, "CW", "Outside", "Climb")
+ check(self.doc.Helix002, "CCW", "Inside", "Climb")
+ check(self.doc.Helix003, "CCW", "Outside", "Conventional")
+
+ def assertPathDirection(self, path, expected_direction, msg=None):
+ """Asserts that the given path goes into the expected direction.
+
+ For the general case we'd need to check the sign of the second derivative,
+ but as we know we work on a helix here, we can take a short cut and just
+ look at the G2/G3 arc commands.
+ """
+ has_g2 = any(filter(lambda cmd: cmd.Name == "G2", path.Commands))
+ has_g3 = any(filter(lambda cmd: cmd.Name == "G3", path.Commands))
+ if has_g2 and not has_g3:
+ self.assertEqual("CW", expected_direction, msg)
+ elif has_g3 and not has_g2:
+ self.assertEqual("CCW", expected_direction, msg)
+ else:
+ raise NotImplementedError("Cannot determine direction for arbitrary paths")
diff --git a/src/Mod/CAM/CAMTests/TestPathHelixGenerator.py b/src/Mod/CAM/CAMTests/TestPathHelixGenerator.py
index 867b680d52..b46e3d3c43 100644
--- a/src/Mod/CAM/CAMTests/TestPathHelixGenerator.py
+++ b/src/Mod/CAM/CAMTests/TestPathHelixGenerator.py
@@ -44,7 +44,7 @@ def _resetArgs():
"step_over": 0.5,
"tool_diameter": 5.0,
"inner_radius": 0.0,
- "direction": "Climb",
+ "direction": "CW",
"startAt": "Inside",
}
diff --git a/src/Mod/CAM/CAMTests/TestPathProfile.py b/src/Mod/CAM/CAMTests/TestPathProfile.py
index b233b3e051..c9823ad7b1 100644
--- a/src/Mod/CAM/CAMTests/TestPathProfile.py
+++ b/src/Mod/CAM/CAMTests/TestPathProfile.py
@@ -123,7 +123,7 @@ class TestPathProfile(PathTestBase):
profile.processCircles = True
profile.processHoles = True
profile.UseComp = True
- profile.Direction = "Climb"
+ profile.Direction = "CW"
_addViewProvider(profile)
self.doc.recompute()
@@ -162,7 +162,7 @@ class TestPathProfile(PathTestBase):
profile.processCircles = True
profile.processHoles = True
profile.UseComp = False
- profile.Direction = "Climb"
+ profile.Direction = "CW"
_addViewProvider(profile)
self.doc.recompute()
@@ -205,7 +205,7 @@ class TestPathProfile(PathTestBase):
profile.processCircles = True
profile.processHoles = True
profile.UseComp = True
- profile.Direction = "Climb"
+ profile.Direction = "CW"
profile.OffsetExtra = -profile.OpToolDiameter / 2.0
_addViewProvider(profile)
self.doc.recompute()
diff --git a/src/Mod/CAM/CMakeLists.txt b/src/Mod/CAM/CMakeLists.txt
index ad349d54c6..48b6bca114 100644
--- a/src/Mod/CAM/CMakeLists.txt
+++ b/src/Mod/CAM/CMakeLists.txt
@@ -349,6 +349,10 @@ SET(Tests_SRCS
CAMTests/Tools/Shape/test-path-tool-bit-shape-00.fcstd
)
+SET(Tests_Fixtures
+ CAMTests/Fixtures/OpHelix_v0-21.FCStd
+)
+
SET(PathImages_Ops
Images/Ops/chamfer.svg
)
@@ -411,6 +415,7 @@ ADD_CUSTOM_TARGET(PathScripts ALL
SET(test_files
${Path_Scripts}
${Tests_SRCS}
+ ${Tests_Fixtures}
)
ADD_CUSTOM_TARGET(Tests ALL
@@ -536,6 +541,13 @@ INSTALL(
Mod/CAM/CAMTests
)
+INSTALL(
+ FILES
+ ${Tests_Fixtures}
+ DESTINATION
+ Mod/CAM/CAMTests/Fixtures
+)
+
INSTALL(
DIRECTORY
CAMTests/Tools
diff --git a/src/Mod/CAM/Gui/Resources/panels/PageOpDeburrEdit.ui b/src/Mod/CAM/Gui/Resources/panels/PageOpDeburrEdit.ui
index be4182f4f8..b10d7c6c19 100644
--- a/src/Mod/CAM/Gui/Resources/panels/PageOpDeburrEdit.ui
+++ b/src/Mod/CAM/Gui/Resources/panels/PageOpDeburrEdit.ui
@@ -1,422 +1,422 @@
- Form
-
-
-
- 0
- 0
- 350
- 450
-
+ Form
+
+
+
+ 0
+ 0
+ 350
+ 450
+
+
+
+ Form
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+
+ 0
+ 0
+
-
- Form
+
+
+ 125
+ 0
+
-
-
-
-
-
-
- 0
- 0
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 125
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
- Tool Controller
-
-
-
- -
-
-
- The tool and its settings to be used for this operation.
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 125
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
- Coolant Mode
-
-
-
- -
-
-
- The tool and its settings to be used for this operation.
-
-
-
-
-
-
- -
-
-
- 6
-
-
- 12
-
-
- 12
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 125
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
- Direction
-
-
-
- -
-
-
- The direction in which the profile is performed, clockwise or counterclockwise.
-
-
- Climb
-
-
- 0
-
-
-
-
- Climb
-
-
- -
-
- Conventional
-
-
-
-
-
-
- -
-
-
-
-
-
-
- 125
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
-
-
-
-
-
-
-
-
- 50
- 0
-
-
-
- W =
-
-
-
- -
-
-
- Width of chamfer cut.
-
-
- mm
-
-
-
-
-
- -
-
-
-
-
-
-
- 50
- 0
-
-
-
- h =
-
-
-
- -
-
-
- Extra depth of tool immersion.
-
-
- mm
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 13
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
- 0
-
-
- 6
-
-
- 0
-
-
- 3
-
-
- 3
-
-
-
-
-
-
-
-
-
- 50
- 0
-
-
-
- Join:
-
-
-
- -
-
-
- Round joint
-
-
-
-
-
- true
-
-
- true
-
-
- true
-
-
-
- -
-
-
- Miter joint
-
-
-
-
-
- true
-
-
- true
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 154
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 150
- 150
-
-
-
-
- 150
- 150
-
-
-
- TextLabel
-
-
- true
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 16777215
+ 16777215
+
+
+
+ Tool Controller
+
+
+
+ -
+
+
+ The tool and its settings to be used for this operation.
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 125
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Coolant Mode
+
+
+
+ -
+
+
+ The tool and its settings to be used for this operation.
+
+
+
+
-
-
- Gui::InputField
- QLineEdit
-
-
-
-
-
+
+ -
+
+
+ 6
+
+
+ 12
+
+
+ 12
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 125
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Direction
+
+
+
+ -
+
+
+ The direction in which the profile is performed, clockwise or counterclockwise.
+
+
+ CW
+
+
+ 0
+
+
-
+
+ CW
+
+
+ -
+
+ CCW
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 125
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+
-
+
+
-
+
+
+
+ 50
+ 0
+
+
+
+ W =
+
+
+
+ -
+
+
+ Width of chamfer cut.
+
+
+ mm
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 50
+ 0
+
+
+
+ h =
+
+
+
+ -
+
+
+ Extra depth of tool immersion.
+
+
+ mm
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 13
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 6
+
+
+ 0
+
+
+ 3
+
+
+ 3
+
+
-
+
+
-
+
+
+
+ 50
+ 0
+
+
+
+ Join:
+
+
+
+ -
+
+
+ Round joint
+
+
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ Miter joint
+
+
+
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 154
+
+
+
+
+
+
+
+ -
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 150
+ 150
+
+
+
+
+ 150
+ 150
+
+
+
+ TextLabel
+
+
+ true
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gui::InputField
+ QLineEdit
+
+
+
+
+
diff --git a/src/Mod/CAM/Gui/Resources/panels/PageOpHelixEdit.ui b/src/Mod/CAM/Gui/Resources/panels/PageOpHelixEdit.ui
index 69d4ee8e72..cf07cebfe7 100644
--- a/src/Mod/CAM/Gui/Resources/panels/PageOpHelixEdit.ui
+++ b/src/Mod/CAM/Gui/Resources/panels/PageOpHelixEdit.ui
@@ -1,175 +1,175 @@
- Form
-
-
-
- 0
- 0
- 400
- 365
-
-
-
- Form
-
-
+ Form
+
+
+
+ 0
+ 0
+ 400
+ 365
+
+
+
+ Form
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- Tool Controller
-
-
-
- -
-
-
- The tool and its settings to be used for this operation.
-
-
-
- -
-
-
- Coolant
-
-
-
- -
-
-
- The tool and its settings to be used for this operation.
-
-
-
-
-
+
+
+ Tool Controller
+
+
+
+ -
+
+
+ The tool and its settings to be used for this operation.
+
+
-
-
-
-
-
-
-
- Start from
-
-
-
- -
-
-
- Specify if the helix operation should start at the inside and work its way outwards, or start at the outside and work its way to the center.
-
-
-
-
- Inside
-
-
- -
-
- Outside
-
-
-
-
- -
-
-
- Direction
-
-
-
- -
-
-
- The direction for the helix, clockwise or counterclockwise.
-
-
-
-
- Climb
-
-
- -
-
- Conventional
-
-
-
-
- -
-
-
- Step over percent
-
-
-
- -
-
-
- Specify the percent of the tool diameter each helix will be offset to the previous one. A step over of 100% means no overlap of the individual cuts.
-
-
- 1
-
-
- 100
-
-
- 10
-
-
- 100
-
-
-
- -
-
-
- Extra Offset
-
-
-
- -
-
-
-
-
-
-
-
-
+
+
+ Coolant
+
+
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
+
-
+
+
+ The tool and its settings to be used for this operation.
+
+
-
-
-
-
- Gui::InputField
- QLineEdit
-
-
-
-
-
+
+
+
+ -
+
+
+
-
+
+
+ Start from
+
+
+
+ -
+
+
+ Specify if the helix operation should start at the inside and work its way outwards, or start at the outside and work its way to the center.
+
+
-
+
+ Inside
+
+
+ -
+
+ Outside
+
+
+
+
+ -
+
+
+ Direction
+
+
+
+ -
+
+
+ The direction for the helix, clockwise or counterclockwise.
+
+
-
+
+ Climb
+
+
+ -
+
+ Conventional
+
+
+
+
+ -
+
+
+ Step over percent
+
+
+
+ -
+
+
+ Specify the percent of the tool diameter each helix will be offset to the previous one. A step over of 100% means no overlap of the individual cuts.
+
+
+ 1
+
+
+ 100
+
+
+ 10
+
+
+ 100
+
+
+
+ -
+
+
+ Extra Offset
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+ Gui::InputField
+ QLineEdit
+
+
+
+
+
diff --git a/src/Mod/CAM/Path/Base/Generator/helix.py b/src/Mod/CAM/Path/Base/Generator/helix.py
index f81b501739..02560bf9d1 100644
--- a/src/Mod/CAM/Path/Base/Generator/helix.py
+++ b/src/Mod/CAM/Path/Base/Generator/helix.py
@@ -45,7 +45,7 @@ def generate(
step_over,
tool_diameter,
inner_radius=0.0,
- direction="Climb",
+ direction="CW",
startAt="Outside",
):
"""generate(edge, hole_radius, inner_radius, step_over) ... generate helix commands.
@@ -96,7 +96,7 @@ def generate(
elif startAt not in ["Inside", "Outside"]:
raise ValueError("Invalid value for parameter 'startAt'")
- elif direction not in ["Climb", "Conventional"]:
+ elif direction not in ["CW", "CCW"]:
raise ValueError("Invalid value for parameter 'direction'")
if type(step_over) not in [float, int]:
@@ -145,7 +145,7 @@ def generate(
def helix_cut_r(r):
commandlist = []
- arc_cmd = "G2" if direction == "Climb" else "G3"
+ arc_cmd = "G2" if direction == "CW" else "G3"
commandlist.append(Path.Command("G0", {"X": startPoint.x + r, "Y": startPoint.y}))
commandlist.append(Path.Command("G1", {"Z": startPoint.z}))
for i in range(1, turncount + 1):
diff --git a/src/Mod/CAM/Path/Base/SetupSheetOpPrototype.py b/src/Mod/CAM/Path/Base/SetupSheetOpPrototype.py
index 7052494f5a..c6cfb52958 100644
--- a/src/Mod/CAM/Path/Base/SetupSheetOpPrototype.py
+++ b/src/Mod/CAM/Path/Base/SetupSheetOpPrototype.py
@@ -224,6 +224,9 @@ class OpPrototype(object):
def setEditorMode(self, name, mode):
self.properties[name].setEditorMode(mode)
+ def setPropertyStatus(self, name, status):
+ pass
+
def getProperty(self, name):
return self.properties[name]
diff --git a/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py b/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py
index 4bc39ee3e0..3411cc3a2d 100644
--- a/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py
+++ b/src/Mod/CAM/Path/Dressup/Gui/LeadInOut.py
@@ -178,12 +178,12 @@ class ObjectDressup:
def getDirectionOfPath(self, obj):
op = PathDressup.baseOp(obj.Base)
side = op.Side if hasattr(op, "Side") else "Inside"
- direction = op.Direction if hasattr(op, "Direction") else "Conventional"
+ direction = op.Direction if hasattr(op, "Direction") else "CCW"
if side == "Outside":
- return "left" if direction == "Climb" else "right"
+ return "left" if direction == "CW" else "right"
else:
- return "right" if direction == "Climb" else "left"
+ return "right" if direction == "CW" else "left"
def getArcDirection(self, obj):
direction = self.getDirectionOfPath(obj)
diff --git a/src/Mod/CAM/Path/Geom.py b/src/Mod/CAM/Path/Geom.py
index ecca7f3e98..356faf1ad9 100644
--- a/src/Mod/CAM/Path/Geom.py
+++ b/src/Mod/CAM/Path/Geom.py
@@ -147,10 +147,10 @@ def getAngle(vector):
return a
-def diffAngle(a1, a2, direction="Climb"):
- """diffAngle(a1, a2, [direction='Climb'])
+def diffAngle(a1, a2, direction="CW"):
+ """diffAngle(a1, a2, [direction='CW'])
Returns the difference between two angles (a1 -> a2) into a given direction."""
- if direction == "Climb":
+ if direction == "CW":
while a1 < a2:
a1 += 2 * math.pi
a = a1 - a2
@@ -453,7 +453,7 @@ def edgeForCmd(cmd, startPoint):
cw = True
else:
cw = False
- angle = diffAngle(getAngle(A), getAngle(B), "Climb" if cw else "CCW")
+ angle = diffAngle(getAngle(A), getAngle(B), "CW" if cw else "CCW")
height = endPoint.z - startPoint.z
pitch = height * math.fabs(2 * math.pi / angle)
if angle > 0:
diff --git a/src/Mod/CAM/Path/Op/Area.py b/src/Mod/CAM/Path/Op/Area.py
index 1b4e4aee1b..8a2bbb2a3b 100644
--- a/src/Mod/CAM/Path/Op/Area.py
+++ b/src/Mod/CAM/Path/Op/Area.py
@@ -346,7 +346,7 @@ class ObjectOp(PathOp.ObjectOp):
verts = hWire.Wires[0].Vertexes
idx = 0
- if obj.Direction == "Conventional":
+ if obj.Direction == "CCW":
idx = len(verts) - 1
x = verts[idx].X
y = verts[idx].Y
diff --git a/src/Mod/CAM/Path/Op/Deburr.py b/src/Mod/CAM/Path/Op/Deburr.py
index 1123a4ae5b..e0c990c74a 100644
--- a/src/Mod/CAM/Path/Op/Deburr.py
+++ b/src/Mod/CAM/Path/Op/Deburr.py
@@ -144,7 +144,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
"Deburr",
QT_TRANSLATE_NOOP("App::Property", "Direction of toolpath"),
)
- # obj.Direction = ["Climb", "Conventional"]
+ # obj.Direction = ["CW", "CCW"]
obj.addProperty(
"App::PropertyEnumeration",
"Side",
@@ -178,8 +178,8 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
# Enumeration lists for App::PropertyEnumeration properties
enums = {
"Direction": [
- (translate("Path", "Climb"), "Climb"),
- (translate("Path", "Conventional"), "Conventional"),
+ (translate("Path", "CW"), "CW"),
+ (translate("Path", "CCW"), "CCW"),
], # this is the direction that the profile runs
"Join": [
(translate("PathDeburr", "Round"), "Round"),
@@ -382,7 +382,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
wires.append(wire)
# Set direction of op
- forward = obj.Direction == "Climb"
+ forward = obj.Direction == "CW"
# Set value of side
obj.Side = side[0]
@@ -417,7 +417,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
obj.Join = "Round"
obj.setExpression("StepDown", "0 mm")
obj.StepDown = "0 mm"
- obj.Direction = "Climb"
+ obj.Direction = "CW"
obj.Side = "Outside"
obj.EntryPoint = 0
diff --git a/src/Mod/CAM/Path/Op/Gui/Helix.py b/src/Mod/CAM/Path/Op/Gui/Helix.py
index 99edc2f321..c06166b076 100644
--- a/src/Mod/CAM/Path/Op/Gui/Helix.py
+++ b/src/Mod/CAM/Path/Op/Gui/Helix.py
@@ -52,7 +52,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
"""getForm() ... return UI"""
form = FreeCADGui.PySideUic.loadUi(":/panels/PageOpHelixEdit.ui")
- comboToPropertyMap = [("startSide", "StartSide"), ("direction", "Direction")]
+ comboToPropertyMap = [("startSide", "StartSide"), ("cutMode", "CutMode")]
enumTups = PathHelix.ObjectHelix.helixOpPropertyEnumerations(dataType="raw")
@@ -62,8 +62,8 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
def getFields(self, obj):
"""getFields(obj) ... transfers values from UI to obj's properties"""
Path.Log.track()
- if obj.Direction != str(self.form.direction.currentData()):
- obj.Direction = str(self.form.direction.currentData())
+ if obj.CutMode != str(self.form.cutMode.currentData()):
+ obj.CutMode = str(self.form.cutMode.currentData())
if obj.StartSide != str(self.form.startSide.currentData()):
obj.StartSide = str(self.form.startSide.currentData())
if obj.StepOver != self.form.stepOverPercent.value():
@@ -78,7 +78,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
Path.Log.track()
self.form.stepOverPercent.setValue(obj.StepOver)
- self.selectInComboBox(obj.Direction, self.form.direction)
+ self.selectInComboBox(obj.CutMode, self.form.cutMode)
self.selectInComboBox(obj.StartSide, self.form.startSide)
self.setupToolController(obj, self.form.toolController)
@@ -94,7 +94,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
signals.append(self.form.stepOverPercent.editingFinished)
signals.append(self.form.extraOffset.editingFinished)
- signals.append(self.form.direction.currentIndexChanged)
+ signals.append(self.form.cutMode.currentIndexChanged)
signals.append(self.form.startSide.currentIndexChanged)
signals.append(self.form.toolController.currentIndexChanged)
signals.append(self.form.coolantController.currentIndexChanged)
diff --git a/src/Mod/CAM/Path/Op/Helix.py b/src/Mod/CAM/Path/Op/Helix.py
index 7df87e70c4..3d0e3378dd 100644
--- a/src/Mod/CAM/Path/Op/Helix.py
+++ b/src/Mod/CAM/Path/Op/Helix.py
@@ -51,6 +51,36 @@ else:
translate = FreeCAD.Qt.translate
+def _caclulatePathDirection(mode, side):
+ """Calculates the path direction from cut mode and cut side"""
+ # NB: at the time of writing, we need py3.8 compat, thus not using py3.10 pattern machting
+ if mode == "Conventional" and side == "Inside":
+ return "CW"
+ elif mode == "Conventional" and side == "Outside":
+ return "CCW"
+ elif mode == "Climb" and side == "Inside":
+ return "CCW"
+ elif mode == "Climb" and side == "Outside":
+ return "CW"
+ else:
+ raise ValueError(f"No mapping for '{mode}'/'{side}'")
+
+
+def _caclulateCutMode(direction, side):
+ """Calculates the cut mode from path direction and cut side"""
+ # NB: at the time of writing, we need py3.8 compat, thus not using py3.10 pattern machting
+ if direction == "CW" and side == "Inside":
+ return "Conventional"
+ elif direction == "CW" and side == "Outside":
+ return "Climb"
+ elif direction == "CCW" and side == "Inside":
+ return "Climb"
+ elif direction == "CCW" and side == "Outside":
+ return "Conventional"
+ else:
+ raise ValueError(f"No mapping for '{direction}'/'{side}'")
+
+
class ObjectHelix(PathCircularHoleBase.ObjectOp):
"""Proxy class for Helix operations."""
@@ -68,13 +98,17 @@ class ObjectHelix(PathCircularHoleBase.ObjectOp):
# Enumeration lists for App::PropertyEnumeration properties
enums = {
"Direction": [
- (translate("CAM_Helix", "Climb"), "Climb"),
- (translate("CAM_Helix", "Conventional"), "Conventional"),
+ (translate("CAM_Helix", "CW"), "CW"),
+ (translate("CAM_Helix", "CCW"), "CCW"),
], # this is the direction that the profile runs
"StartSide": [
(translate("PathProfile", "Outside"), "Outside"),
(translate("PathProfile", "Inside"), "Inside"),
], # side of profile that cutter is on in relation to direction of profile
+ "CutMode": [
+ (translate("CAM_Helix", "Climb"), "Climb"),
+ (translate("CAM_Helix", "Conventional"), "Conventional"),
+ ], # whether the tool "rolls" with or against the feed direction along the profile
}
if dataType == "raw":
@@ -103,9 +137,11 @@ class ObjectHelix(PathCircularHoleBase.ObjectOp):
"Helix Drill",
QT_TRANSLATE_NOOP(
"App::Property",
- "The direction of the circular cuts, ClockWise (Climb), or CounterClockWise (Conventional)",
+ "The direction of the circular cuts, ClockWise (CW), or CounterClockWise (CCW)",
),
)
+ obj.setEditorMode("Direction", ["ReadOnly", "Hidden"])
+ obj.setPropertyStatus("Direction", ["ReadOnly", "Output"])
obj.addProperty(
"App::PropertyEnumeration",
@@ -114,6 +150,17 @@ class ObjectHelix(PathCircularHoleBase.ObjectOp):
QT_TRANSLATE_NOOP("App::Property", "Start cutting from the inside or outside"),
)
+ # TODO: revise property description once v1.0 release string freeze is lifted
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "CutMode",
+ "Helix Drill",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "The direction of the circular cuts, ClockWise (Climb), or CounterClockWise (Conventional)",
+ ),
+ )
+
obj.addProperty(
"App::PropertyPercent",
"StepOver",
@@ -163,9 +210,34 @@ class ObjectHelix(PathCircularHoleBase.ObjectOp):
),
)
+ if not hasattr(obj, "CutMode"):
+ # TODO: consolidate the duplicate definitions from opOnDocumentRestored and
+ # initCircularHoleOperation once back on the main line
+ obj.addProperty(
+ "App::PropertyEnumeration",
+ "CutMode",
+ "Helix Drill",
+ QT_TRANSLATE_NOOP(
+ "App::Property",
+ "The direction of the circular cuts, ClockWise (Climb), or CounterClockWise (Conventional)",
+ ),
+ )
+ obj.CutMode = ["Climb", "Conventional"]
+ if obj.Direction in ["Climb", "Conventional"]:
+ # For some month, late in the v1.0 release cycle, we had the cut mode assigned
+ # to the direction (see PR#14364). Let's fix files created in this time as well.
+ new_dir = "CW" if obj.Direction == "Climb" else "CCW"
+ obj.Direction = ["CW", "CCW"]
+ obj.Direction = new_dir
+ obj.CutMode = _caclulateCutMode(obj.Direction, obj.StartSide)
+ obj.setEditorMode("Direction", ["ReadOnly", "Hidden"])
+ obj.setPropertyStatus("Direction", ["ReadOnly", "Output"])
+
def circularHoleExecute(self, obj, holes):
"""circularHoleExecute(obj, holes) ... generate helix commands for each hole in holes"""
Path.Log.track()
+ obj.Direction = _caclulatePathDirection(obj.CutMode, obj.StartSide)
+
self.commandlist.append(Path.Command("(helix cut operation)"))
self.commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value}))
@@ -217,8 +289,9 @@ class ObjectHelix(PathCircularHoleBase.ObjectOp):
def SetupProperties():
+ """Returns property names for which the "Setup Sheet" should provide defaults."""
setup = []
- setup.append("Direction")
+ setup.append("CutMode")
setup.append("StartSide")
setup.append("StepOver")
setup.append("StartRadius")
diff --git a/src/Mod/CAM/Path/Op/PocketBase.py b/src/Mod/CAM/Path/Op/PocketBase.py
index 36cad37b6c..eb5558006e 100644
--- a/src/Mod/CAM/Path/Op/PocketBase.py
+++ b/src/Mod/CAM/Path/Op/PocketBase.py
@@ -125,7 +125,7 @@ class ObjectPocket(PathAreaOp.ObjectOp):
"Pocket",
QT_TRANSLATE_NOOP(
"App::Property",
- "The direction that the toolpath should go around the part ClockWise (Climb) or CounterClockWise (Conventional)",
+ "The direction that the toolpath should go around the part ClockWise (CW) or CounterClockWise (CCW)",
),
)
obj.addProperty(
diff --git a/src/Mod/CAM/Path/Op/Profile.py b/src/Mod/CAM/Path/Op/Profile.py
index 80d356af63..b2037e5494 100644
--- a/src/Mod/CAM/Path/Op/Profile.py
+++ b/src/Mod/CAM/Path/Op/Profile.py
@@ -102,7 +102,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
"Profile",
QT_TRANSLATE_NOOP(
"App::Property",
- "The direction that the toolpath should go around the part ClockWise (Climb) or CounterClockWise (Conventional)",
+ "The direction that the toolpath should go around the part ClockWise (CW) or CounterClockWise (CCW)",
),
),
(
@@ -188,8 +188,8 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# Enumeration lists for App::PropertyEnumeration properties
enums = {
"Direction": [
- (translate("PathProfile", "Climb"), "Climb"),
- (translate("PathProfile", "Conventional"), "Conventional"),
+ (translate("PathProfile", "CW"), "CW"),
+ (translate("PathProfile", "CCW"), "CCW"),
], # this is the direction that the profile runs
"HandleMultipleFeatures": [
(translate("PathProfile", "Collectively"), "Collectively"),
@@ -225,7 +225,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
"""areaOpPropertyDefaults(obj, job) ... returns a dictionary of default values
for the operation's properties."""
return {
- "Direction": "Climb",
+ "Direction": "CW",
"HandleMultipleFeatures": "Collectively",
"JoinType": "Round",
"MiterLimit": 0.1,
@@ -338,11 +338,11 @@ class ObjectProfile(PathAreaOp.ObjectOp):
# Reverse the direction for holes
if isHole:
- direction = "Climb" if obj.Direction == "Conventional" else "Conventional"
+ direction = "CW" if obj.Direction == "CCW" else "CCW"
else:
direction = obj.Direction
- if direction == "Conventional":
+ if direction == "CCW":
params["orientation"] = 0
else:
params["orientation"] = 1
@@ -351,7 +351,7 @@ class ObjectProfile(PathAreaOp.ObjectOp):
if obj.UseComp:
offset = self.radius + obj.OffsetExtra.Value
if offset == 0.0:
- if direction == "Conventional":
+ if direction == "CCW":
params["orientation"] = 1
else:
params["orientation"] = 0
diff --git a/src/Mod/CAM/Path/Post/scripts/heidenhain_post.py b/src/Mod/CAM/Path/Post/scripts/heidenhain_post.py
index e00754e57a..abbe1a2b23 100644
--- a/src/Mod/CAM/Path/Post/scripts/heidenhain_post.py
+++ b/src/Mod/CAM/Path/Post/scripts/heidenhain_post.py
@@ -370,11 +370,11 @@ def export(objectslist, filename, argstring):
STORED_COMPENSATED_OBJ = commands
# Find mill compensation
if hasattr(obj, "Side") and hasattr(obj, "Direction"):
- if obj.Side == "Outside" and obj.Direction == "Climb":
+ if obj.Side == "Outside" and obj.Direction == "CW":
Compensation = "L"
- elif obj.Side == "Outside" and obj.Direction == "Conventional":
+ elif obj.Side == "Outside" and obj.Direction == "CCW":
Compensation = "R"
- elif obj.Side != "Outside" and obj.Direction == "Climb":
+ elif obj.Side != "Outside" and obj.Direction == "CW":
Compensation = "R"
else:
Compensation = "L"
diff --git a/src/Mod/CAM/TestCAMApp.py b/src/Mod/CAM/TestCAMApp.py
index 2d6e6ae860..ee129b4d8a 100644
--- a/src/Mod/CAM/TestCAMApp.py
+++ b/src/Mod/CAM/TestCAMApp.py
@@ -37,9 +37,8 @@ from CAMTests.TestPathGeneratorDogboneII import TestGeneratorDogboneII
from CAMTests.TestPathGeom import TestPathGeom
from CAMTests.TestPathLanguage import TestPathLanguage
from CAMTests.TestPathOpDeburr import TestPathOpDeburr
-
-# from CAMTests.TestPathHelix import TestPathHelix
from CAMTests.TestPathHelpers import TestPathHelpers
+from CAMTests.TestPathHelix import TestPathHelix
from CAMTests.TestPathHelixGenerator import TestPathHelixGenerator
from CAMTests.TestPathLog import TestPathLog
from CAMTests.TestPathOpUtil import TestPathOpUtil
@@ -98,7 +97,7 @@ False if TestPathOpDeburr.__name__ else True
False if TestPathDrillable.__name__ else True
False if TestPathGeom.__name__ else True
False if TestPathHelpers.__name__ else True
-# False if TestPathHelix.__name__ else True
+False if TestPathHelix.__name__ else True
False if TestPathLog.__name__ else True
False if TestPathOpUtil.__name__ else True
# False if TestPathPost.__name__ else True