Merge pull request #26409 from Connor9220/ToolbitsUnitsMigration
CAM: Add migration for Toolbit Units property
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
import FreeCAD
|
||||
import Path
|
||||
from typing import Dict, Any, Optional, Union
|
||||
from .util import units_from_json
|
||||
|
||||
|
||||
class ParameterAccessor:
|
||||
@@ -74,9 +75,9 @@ class ParameterAccessor:
|
||||
else:
|
||||
self.target.setEditorMode(key, mode)
|
||||
|
||||
def label(self):
|
||||
def name(self):
|
||||
if self.is_dict:
|
||||
return "toolbit"
|
||||
return self.target.get("name", "toolbit")
|
||||
else:
|
||||
return getattr(self.target, "Label", "unknown toolbit")
|
||||
|
||||
@@ -103,6 +104,7 @@ def migrate_parameters(accessor: ParameterAccessor) -> bool:
|
||||
Currently handles:
|
||||
- TorusRadius → CornerRadius
|
||||
- FlatRadius/Diameter → CornerRadius
|
||||
- Infers Units from parameter strings if not set
|
||||
|
||||
Args:
|
||||
accessor: ParameterAccessor instance wrapping dict or FreeCAD object
|
||||
@@ -110,13 +112,28 @@ def migrate_parameters(accessor: ParameterAccessor) -> bool:
|
||||
Returns:
|
||||
True if migration occurred, False otherwise
|
||||
"""
|
||||
migrated = False
|
||||
has_torus = accessor.has("TorusRadius")
|
||||
has_flat = accessor.has("FlatRadius")
|
||||
has_diam = accessor.has("Diameter")
|
||||
has_corner = accessor.has("CornerRadius")
|
||||
label = accessor.label()
|
||||
has_units = accessor.has("Units")
|
||||
name = accessor.name()
|
||||
shape_type = accessor.get_shape_type()
|
||||
|
||||
# Infer Units from parameter strings if not set
|
||||
if not has_units:
|
||||
# Gather all parameters to check for units
|
||||
params = {}
|
||||
if accessor.is_dict:
|
||||
params = accessor.target.get("parameter", {})
|
||||
|
||||
inferred_units = units_from_json(params)
|
||||
if inferred_units:
|
||||
accessor.set("Units", inferred_units)
|
||||
Path.Log.info(f"Adding Units as '{inferred_units}' for {name}")
|
||||
migrated = True
|
||||
|
||||
# Only run migration logic if shape type == 'Bullnose'
|
||||
if shape_type and str(shape_type).lower() == "bullnose":
|
||||
# Case 1: TorusRadius exists, copy to CornerRadius
|
||||
@@ -130,11 +147,11 @@ def migrate_parameters(accessor: ParameterAccessor) -> bool:
|
||||
)
|
||||
accessor.set_editor_mode("CornerRadius", 0)
|
||||
accessor.set("CornerRadius", value)
|
||||
Path.Log.info(f"Copied TorusRadius to CornerRadius={value} for {label}")
|
||||
return True
|
||||
Path.Log.info(f"Copied TorusRadius to CornerRadius={value} for {name}")
|
||||
migrated = True
|
||||
|
||||
# Case 2: FlatRadius and Diameter exist, calculate CornerRadius
|
||||
if has_flat and has_diam and not has_corner:
|
||||
if has_flat and has_diam and not has_corner and not has_torus:
|
||||
try:
|
||||
diam_raw = accessor.get("Diameter")
|
||||
flat_raw = accessor.get("FlatRadius")
|
||||
@@ -161,10 +178,9 @@ def migrate_parameters(accessor: ParameterAccessor) -> bool:
|
||||
)
|
||||
accessor.set_editor_mode("CornerRadius", 0)
|
||||
accessor.set("CornerRadius", value)
|
||||
Path.Log.info(f"Migrated FlatRadius/Diameter to CornerRadius={value} for {label}")
|
||||
return True
|
||||
Path.Log.info(f"Migrated FlatRadius/Diameter to CornerRadius={value} for {name}")
|
||||
migrated = True
|
||||
except Exception as e:
|
||||
Path.Log.error(f"Failed to migrate FlatRadius for toolbit {label}: {e}")
|
||||
return False
|
||||
Path.Log.error(f"Failed to migrate FlatRadius for toolbit {name}: {e}")
|
||||
|
||||
return False
|
||||
return migrated
|
||||
|
||||
@@ -793,7 +793,7 @@ class ToolBit(Asset, ABC):
|
||||
|
||||
# 3. Ensure Units property exists and is set
|
||||
if not hasattr(self.obj, "Units"):
|
||||
print("Adding Units property")
|
||||
Path.Log.debug("Adding Units property")
|
||||
self.obj.addProperty(
|
||||
"App::PropertyEnumeration",
|
||||
"Units",
|
||||
|
||||
@@ -30,6 +30,49 @@ def to_json(value):
|
||||
return value
|
||||
|
||||
|
||||
def units_from_json(params):
|
||||
"""
|
||||
Infer Units (Metric/Imperial) from JSON parameter strings.
|
||||
|
||||
For JSON files from disk, values are stored as strings like "3.175 in" or "6 mm".
|
||||
This function examines common dimensional parameters (Diameter, Length, CuttingEdgeHeight, etc.)
|
||||
to determine if the toolbit uses metric or imperial units.
|
||||
|
||||
Args:
|
||||
params: Dictionary of parameters from JSON (before conversion to FreeCAD.Units.Quantity)
|
||||
|
||||
Returns:
|
||||
str: "Metric" or "Imperial", or None if units cannot be determined
|
||||
"""
|
||||
if not isinstance(params, dict):
|
||||
return None
|
||||
|
||||
imperial_count = 0
|
||||
metric_count = 0
|
||||
|
||||
for param_name in ("Diameter", "ShankDiameter", "Length", "CuttingEdgeLength"):
|
||||
value = params.get(param_name)
|
||||
if value is not None:
|
||||
# Check if it's a string with unit suffix
|
||||
if isinstance(value, str):
|
||||
value_lower = value.lower().strip()
|
||||
|
||||
# Check for imperial units
|
||||
if any(unit in value_lower for unit in ["in", "inch", '"', "thou"]):
|
||||
imperial_count += 1
|
||||
# Check for metric units
|
||||
elif any(unit in value_lower for unit in ["mm", "cm", "m "]):
|
||||
metric_count += 1
|
||||
|
||||
# Make a decision based on counts
|
||||
if imperial_count > metric_count:
|
||||
return "Imperial"
|
||||
elif metric_count > imperial_count:
|
||||
return "Metric"
|
||||
|
||||
return "Metric" # Default to Metric if uncertain
|
||||
|
||||
|
||||
def format_value(
|
||||
value: FreeCAD.Units.Quantity | int | float | None,
|
||||
precision: int | None = None,
|
||||
|
||||
Reference in New Issue
Block a user