From bf982218857d36d02b95bf807d957024392bc250 Mon Sep 17 00:00:00 2001 From: tarman3 Date: Fri, 6 Mar 2026 10:38:47 +0200 Subject: [PATCH 1/2] CAM: Linking - Tolerance in get_linking_moves() --- src/Mod/CAM/CAMTests/TestLinkingGenerator.py | 14 ++++++++++++++ src/Mod/CAM/Path/Base/Generator/linking.py | 7 ++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Mod/CAM/CAMTests/TestLinkingGenerator.py b/src/Mod/CAM/CAMTests/TestLinkingGenerator.py index 072741e4f6..77effc94f0 100644 --- a/src/Mod/CAM/CAMTests/TestLinkingGenerator.py +++ b/src/Mod/CAM/CAMTests/TestLinkingGenerator.py @@ -82,6 +82,20 @@ class TestGetLinkingMoves(PathTestUtils.PathTestBase): solids=[blocking_box], ) + def test_path_blocked_by_solid_with_tolerance(self): + blocking_box = Part.makeBox(1, 10, 10) + blocking_box.translate(FreeCAD.Vector(5, -5, 0)) + with self.assertRaises(RuntimeError): + generator.get_linking_moves( + start_position=self.start, + target_position=self.target, + local_clearance=5, + global_clearance=11, + tool_shape=self.tool, + tolerance=1.1, + solids=[blocking_box], + ) + def test_plunge_to_zero_depth(self): """Test that plunge moves correctly go to Z=0 (regression test for depth==0 bug)""" start = FreeCAD.Vector(0, 0, 1) # Start below clearance diff --git a/src/Mod/CAM/Path/Base/Generator/linking.py b/src/Mod/CAM/Path/Base/Generator/linking.py index f410de22f9..d80b85cb1e 100644 --- a/src/Mod/CAM/Path/Base/Generator/linking.py +++ b/src/Mod/CAM/Path/Base/Generator/linking.py @@ -62,7 +62,7 @@ def check_collision( # Create direct path wire wire = Part.Wire([Part.makeLine(start_position, target_position)]) distance = wire.distToShape(collision_model)[0] - return distance < tolerance + return distance < tolerance and not Path.Geom.isRoughly(distance, tolerance) def get_linking_moves( @@ -74,6 +74,7 @@ def get_linking_moves( solids: Optional[List[Part.Shape]] = None, retract_height_offset: Optional[float] = None, skip_if_no_collision: bool = False, + tolerance: float = 0.001, ) -> list: """ Generate linking moves from start to target position. @@ -121,7 +122,7 @@ def get_linking_moves( # Try each height for height in heights: wire = make_linking_wire(start_position, target_position, height) - if is_wire_collision_free(wire, collision_model): + if is_wire_collision_free(wire, collision_model, tolerance): cmds = Path.fromShape(wire).Commands # Ensure all commands have complete XYZ coordinates # Path.fromShape() may omit coordinates that don't change @@ -170,4 +171,4 @@ def is_wire_collision_free( if not solid: return True distance = wire.distToShape(solid)[0] - return distance >= tolerance + return distance >= tolerance or Path.Geom.isRoughly(distance, tolerance) From e561950ff8ab5d2fbf1207d8b1f76b088887b352 Mon Sep 17 00:00:00 2001 From: tarman3 Date: Sat, 7 Mar 2026 17:44:04 +0200 Subject: [PATCH 2/2] CAM: Linking - Minor optimization for simple solid --- src/Mod/CAM/Path/Base/Generator/linking.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Mod/CAM/Path/Base/Generator/linking.py b/src/Mod/CAM/Path/Base/Generator/linking.py index d80b85cb1e..c5c8c3f548 100644 --- a/src/Mod/CAM/Path/Base/Generator/linking.py +++ b/src/Mod/CAM/Path/Base/Generator/linking.py @@ -61,6 +61,12 @@ def check_collision( # Create direct path wire wire = Part.Wire([Part.makeLine(start_position, target_position)]) + + bbDistance = wire.BoundBox.ZMin - collision_model.BoundBox.ZMax + if bbDistance >= tolerance or Path.Geom.isRoughly(bbDistance, tolerance): + # attempt to skip long time computation for simple model + return False + distance = wire.distToShape(collision_model)[0] return distance < tolerance and not Path.Geom.isRoughly(distance, tolerance) @@ -168,7 +174,17 @@ def make_linking_wire(start: Vector, target: Vector, z: float) -> Part.Wire: def is_wire_collision_free( wire: Part.Wire, solid: Optional[Part.Shape], tolerance: float = 0.001 ) -> bool: + """ + Check if a horizontal edge of wire would not collide with solids. + Returns True if path is clear, False if collision detected. + """ if not solid: return True + + bbDistance = wire.BoundBox.ZMax - solid.BoundBox.ZMax + if bbDistance >= tolerance or Path.Geom.isRoughly(bbDistance, tolerance): + # attempt to skip long time computation for simple model + return True + distance = wire.distToShape(solid)[0] return distance >= tolerance or Path.Geom.isRoughly(distance, tolerance)