CAM: Convert tapping operation to experimental feature, Add tap pitch support, improve tapping logic, and update toolbit schema and legacy linuxcnc post
CAM/App/PathSegmentWalker.cpp - Add G74 to drill/tap/bore G-code recognition for tapping cycles CAM/InitGui.py - Move CAM_Tapping command behind experimental feature flag - Only group drilling/tapping commands if both are enabled CAM/Path/Base/Generator/tapping.py - Add pitch and spindle_speed parameters to tapping.generate - Output S (spindle speed) and F (pitch) in generated G-code CAM/Path/Op/Tapping.py - Require Pitch property for tap tools and SpindleSpeed for tool controllers - Pass pitch and spindle speed to tapping.generate - Use SpindleDirection to determine right/left hand tap CAM/Path/Post/scripts/linuxcnc_post.py - Handle G84/G74 tapping cycles: convert pitch and spindle speed to feed rate - Remove F and S from output and recalculate F as needed CAM/Path/Tool/shape/models/tap.py - Add Pitch property to ToolBitShapeTap schema - CAM/Path/Tool/toolbit/models/tap.py - Show pitch and rotation in tap tool summary - Use is_imperial_pitch to format pitch as TPI or mm CAM/Path/Tool/toolbit/util.py - Add is_imperial_pitch utility to classify pitch as imperial or metric CAM/Tools/Bit/375-16_Tap.fctb - Remove unused parameters (Coating, Rotation, TPI, Type) - Keep only relevant tap parameters for new schema
This commit is contained in:
@@ -56,6 +56,10 @@ class ToolBitShapeTap(ToolBitShape):
|
||||
FreeCAD.Qt.translate("ToolBitShape", "Tip angle"),
|
||||
"App::PropertyAngle",
|
||||
),
|
||||
"Pitch": (
|
||||
FreeCAD.Qt.translate("ToolBitShape", "Thread pitch"),
|
||||
"App::PropertyLength",
|
||||
),
|
||||
}
|
||||
|
||||
@property
|
||||
|
||||
@@ -24,6 +24,7 @@ import Path
|
||||
from ...shape import ToolBitShapeTap
|
||||
from ..mixins import RotaryToolBitMixin, CuttingToolMixin
|
||||
from .base import ToolBit
|
||||
from ..util import is_imperial_pitch
|
||||
|
||||
|
||||
class ToolBitTap(ToolBit, CuttingToolMixin, RotaryToolBitMixin):
|
||||
@@ -39,7 +40,34 @@ class ToolBitTap(ToolBit, CuttingToolMixin, RotaryToolBitMixin):
|
||||
diameter = self.get_property_str("Diameter", "?", precision=3)
|
||||
flutes = self.get_property("Flutes")
|
||||
cutting_edge_length = self.get_property_str("CuttingEdgeLength", "?", precision=3)
|
||||
pitch_raw = self.get_property("Pitch")
|
||||
|
||||
spindle_direction = self.get_property_str("SpindleDirection", "Forward")
|
||||
if spindle_direction == "Forward":
|
||||
rotation = "Right Hand"
|
||||
elif spindle_direction == "Reverse":
|
||||
rotation = "Left Hand"
|
||||
else:
|
||||
rotation = spindle_direction
|
||||
|
||||
if isinstance(pitch_raw, FreeCAD.Units.Quantity):
|
||||
pitch_mm = pitch_raw.getValueAs("mm")
|
||||
else:
|
||||
pitch_mm = FreeCAD.Units.Quantity(str(pitch_raw)).getValueAs("mm")
|
||||
|
||||
if pitch_raw:
|
||||
try:
|
||||
if is_imperial_pitch(pitch_raw):
|
||||
tpi = round(25.4 / pitch_mm, 2)
|
||||
pitch = f"{int(tpi) if tpi == int(tpi) else tpi} TPI"
|
||||
else:
|
||||
pitch = f"{pitch_mm} mm"
|
||||
except Exception:
|
||||
pitch = str(pitch_raw)
|
||||
else:
|
||||
pitch = "?"
|
||||
|
||||
return FreeCAD.Qt.translate(
|
||||
"CAM", f"{diameter} tap, {flutes}-flute, {cutting_edge_length} cutting edge"
|
||||
"CAM",
|
||||
f"{diameter} {pitch} {rotation} tap, {flutes}-flute, {cutting_edge_length} cutting edge",
|
||||
)
|
||||
|
||||
@@ -47,3 +47,33 @@ def format_value(value: FreeCAD.Units.Quantity | int | float | None, precision:
|
||||
return value.getUserPreferred()[0]
|
||||
return value.UserString
|
||||
return str(value)
|
||||
|
||||
|
||||
def is_imperial_pitch(pitch_mm, tol=1e-6):
|
||||
"""
|
||||
Classify a pitch in mm as imperial vs metric.
|
||||
Rule:
|
||||
- If pitch_mm is ~2 decimal places clean -> metric,
|
||||
unless it corresponds to an exact whole-number TPI.
|
||||
- Otherwise, treat as imperial.
|
||||
"""
|
||||
import math
|
||||
|
||||
try:
|
||||
mm = float(pitch_mm)
|
||||
except Exception:
|
||||
return False
|
||||
if mm <= 0:
|
||||
return False
|
||||
|
||||
# Check if it's "two-decimal clean"
|
||||
two_dec_clean = abs(mm - round(mm, 2)) <= tol
|
||||
|
||||
# Compute TPI
|
||||
tpi = 25.4 / mm
|
||||
whole_tpi = round(tpi)
|
||||
is_whole_tpi = math.isclose(tpi, whole_tpi, abs_tol=1e-6)
|
||||
|
||||
if two_dec_clean and not is_whole_tpi:
|
||||
return False # metric
|
||||
return True # imperial
|
||||
|
||||
Reference in New Issue
Block a user