Prevent crash (CAMTests) in ToolBitRecomputeObserver when the toolbit object has been deleted/missing
by catching ReferenceError before accessing its Document attribute. This ensures slotRecomputedDocument
exits gracefully if the object is no longer valid.
src/Mod/CAM/Path/Tool/toolbit/models/base.py
- Wrapped access to self.toolbit_proxy.obj.Document in try/except to handle ReferenceError
if object is deleted/missing, preventing crash during document recompute.
Introduced FLOAT_EPSILON for robust floating point comparisons, resolving cases
where Z axis retract moves were missing after geometry recompute in 3D Surface
rotational scan operations. This prevents precision errors from causing the
cutter to skip intended lifts between rings or scan lines.
src/Mod/CAM/Path/Op/Surface.py
- Added FLOAT_EPSILON constant
- Updated Z move comparison logic to use tolerance
A bug in the ToolBit model caused an infinite recompute loop and UI freeze when properties such as Diameter, Flutes, or CuttingEdgeHeight were set to expressions. The visual representation update was being triggered during document recompute, which could recursively trigger further recomputes. This fix defers visual updates by queuing them and processing only after the document recompute completes, using a document observer. The observer is cleaned up after use and on object deletion, preventing memory leaks and repeated recompute cycles.
src/Mod/CAM/Path/Tool/toolbit/models/base.py:
- ToolBitRecomputeObserver: Document observer class that triggers queued visual updates after recompute completes via slotRecomputedDocument.
- _queue_visual_update: Queues a visual update to be processed after document recompute.
- _setup_recompute_observer: Registers the document observer for recompute completion.
- _process_queued_visual_update: Processes the queued visual update and cleans up the observer.
- onChanged: Now queues visual updates instead of calling them directly.
- onDelete: Cleans up any pending document observer before object removal.
src/Gui/QuantitySpinBox.cpp:
- Call updateExpression() after setExpression() in QuantitySpinBox
src/Gui/SpinBox.cpp:
- Call updateExpression() after setExpression() in ExpressionSpinBox
src/Gui/Widgets.cpp:
- Call onChange() after setExpression() in ExpLineEdit
src/Mod/CAM/Path/Base/Gui/Util.py:
- Connect to showFormulaDialog signal and refresh CAM QuantitySpinBox Python wrapper when dialog closes
- Replace QDoubleSpinBox widgets with Gui::QuantitySpinBox in DressUpLeadInOutEdit.ui for all lead-in/out numeric fields, enabling unit/expressions support.
- Register QuantitySpinBox as a custom widget in the .ui file.
- Refactor TaskDressupLeadInOut panel setup:
- Add setupSpinBoxes, setupGroupBoxes, setupDynamicVisibility for cleaner UI initialization.
- Use PathGuiUtil.QuantitySpinBox for all numeric fields and ensure updateWidget() is called for each.
- Centralize signal registration and field updates using getSignalsForUpdate and pageGetFields.
- Move group box signal handler to a class method.
- Share hideModes dictionary for field visibility logic.
- Add dynamic label switching for "Radius"/"Length" with translation placeholders.
- Remove the Include layers Check Box
- Improve ObjectDressup migration:
- Use shared hideModes from TaskDressupLeadInOut.
- Set default angles to 90 instead of 45.
- Preserve previous style values when migrating StyleOn/StyleOff.
- Ensure field visibility is updated after migration.
- Add Perpendicular and Tangent to lead_styles in correct order.
- Enhance _promote_toolbit to handle embedded toolbits that still have a "Custom" shape type.
- If ShapeType is "Custom" but ShapeID is present, attempt to promote to the correct shape class using ShapeID.
- Log promotion for traceability.
- This improves migration of legacy embedded toolbits and ensures proper shape assignment.
- Use PathUtil.setProperty instead of direct setattr for schema properties to ensure proper FreeCAD notifications.
- Only update custom shape properties if the value has changed, reducing unnecessary recomputation.
- For SpindleDirection and Material, only update the property if the new value differs from the current value, and use PathUtil.setProperty for consistency.
- This prevents overwriting existing values with defaults and avoids triggering unwanted recomputation.
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
- Change missing property log in shape/doc.py from warning to debug
- Ensure SpindleDirection property exists and is set, defaulting to "Forward"
- Ensure Material property exists and is set, defaulting to "HSS"
- Update SpindleDirection and Material from toolbit file parameters if provided
Fix base template substitution and improve tool/op formatting in sanity report, also update HTML/CSS and image handling.
- Major HTML/CSS refactor for CAM Sanity Report template:
- Rewrote HTMLTemplate.py with modern, responsive CSS, semantic HTML, and accessibility improvements.
- Added CSS reset, responsive image handling, and improved table/list styling.
- Introduced .heading-container and .top-link for right-aligned "Top" navigation links on all major sections and tool headers (hidden in print).
- Updated all section and tool headers to use new navigation and layout.
- Cleaned up legacy markup, removed inline styles, and standardized variable substitution using string.Template syntax (${key}, ${val}).
- Updated base_template in HTMLTemplate.py to use string.Template syntax (${key}, ${val}) instead of %{key}, %{val} for correct variable substitution.
- Enhanced image generation and embedding:
- Updated ImageBuilder to support high-DPI (800x800) images and direct byte output for embedding.
- All report images (base, stock, datum, tool) now use in-memory bytes for embedding when possible.
- Tool images support a toggle for using toolbit thumbnails or fallback head-on renders.
- ReportGenerator now embeds images as base64 when requested, with correct HTML tags.
- Improved squawk, tool, and operation data formatting:
- Squawk dates now use localized string formatting.
- Tool diameter and feedrate now use .UserString for better display.
- Spindle speed now formatted as integer with "rpm" suffix.
- Operation feed and speed values also use .UserString and "rpm" formatting.
- Fixed _format_bases in ReportGenerator.py to iterate over base_data.items() and pass {"key": key, "val": val} to the template, ensuring all bases are listed correctly.
- General code cleanup and improved maintainability throughout the CAM Sanity reporting stack.
- Add type check in PropertyCreate to wrap CustomPropertyGroups as a list if not already
- Prevents dropdown from displaying each character of a string as a separate group option