| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | import FreeCAD |
| | import Path |
| | from typing import Dict, Any, Optional, Union |
| | from .util import units_from_json |
| |
|
| |
|
| | class ParameterAccessor: |
| | """ |
| | Unified accessor for dicts and FreeCAD objects for migration logic. |
| | """ |
| |
|
| | def __init__(self, target): |
| | self.target = target |
| | self.is_dict = isinstance(target, dict) |
| |
|
| | def has(self, key): |
| | if self.is_dict: |
| | |
| | param = self.target.get("parameter", {}) |
| | return key in param if isinstance(param, dict) else False |
| | else: |
| | return key in getattr(self.target, "PropertiesList", []) |
| |
|
| | def get(self, key): |
| | if self.is_dict: |
| | |
| | param = self.target.get("parameter", {}) |
| | return param.get(key) if isinstance(param, dict) else None |
| | else: |
| | return self.target.getPropertyByName(key) |
| |
|
| | def set(self, key, value): |
| | if self.is_dict: |
| | |
| | if "parameter" not in self.target: |
| | self.target["parameter"] = {} |
| | self.target["parameter"][key] = value |
| | else: |
| | setattr(self.target, key, value) |
| |
|
| | def add_property(self, prop_type, key, group, doc): |
| | if self.is_dict: |
| | |
| | pass |
| | else: |
| | self.target.addProperty(prop_type, key, group, doc) |
| |
|
| | def set_editor_mode(self, key, mode): |
| | if self.is_dict: |
| | pass |
| | else: |
| | self.target.setEditorMode(key, mode) |
| |
|
| | def name(self): |
| | if self.is_dict: |
| | return self.target.get("name", "toolbit") |
| | else: |
| | return getattr(self.target, "Label", "unknown toolbit") |
| |
|
| | def get_shape_type(self): |
| | if self.is_dict: |
| | |
| | return self.target.get("shape-type") |
| | else: |
| | |
| | return getattr(self.target, "ShapeType", None) |
| |
|
| |
|
| | if False: |
| | Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule()) |
| | Path.Log.trackModule(Path.Log.thisModule()) |
| | else: |
| | Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule()) |
| |
|
| |
|
| | def migrate_parameters(accessor: ParameterAccessor) -> bool: |
| | """ |
| | Migrates legacy parameters using a unified accessor. |
| | |
| | Currently handles: |
| | - TorusRadius → CornerRadius |
| | - FlatRadius/Diameter → CornerRadius |
| | - Infers Units from parameter strings if not set |
| | |
| | Args: |
| | accessor: ParameterAccessor instance wrapping dict or FreeCAD object |
| | |
| | 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") |
| | has_units = accessor.has("Units") |
| | name = accessor.name() |
| | shape_type = accessor.get_shape_type() |
| |
|
| | |
| | if not has_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 |
| |
|
| | |
| | if shape_type and str(shape_type).lower() == "bullnose": |
| | |
| | if has_torus and not has_corner: |
| | value = accessor.get("TorusRadius") |
| | accessor.add_property( |
| | "App::PropertyLength", |
| | "CornerRadius", |
| | "Shape", |
| | "Corner radius copied from TorusRadius", |
| | ) |
| | accessor.set_editor_mode("CornerRadius", 0) |
| | accessor.set("CornerRadius", value) |
| | Path.Log.info(f"Copied TorusRadius to CornerRadius={value} for {name}") |
| | migrated = True |
| |
|
| | |
| | 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") |
| | diameter = FreeCAD.Units.Quantity(diam_raw) |
| | flat_radius = FreeCAD.Units.Quantity(flat_raw) |
| | corner_radius = (float(diameter) / 2.0) - float(flat_radius) |
| |
|
| | |
| | if isinstance(diam_raw, str) and diam_raw.strip().endswith("in"): |
| | cr_in = FreeCAD.Units.Quantity(f"{corner_radius} mm").getValueAs("in") |
| | value = f"{float(cr_in):.4f} in" |
| | else: |
| | if isinstance(diam_raw, str) and not diam_raw.strip().endswith("mm"): |
| | cr_mm = FreeCAD.Units.Quantity(f"{corner_radius} in").getValueAs("mm") |
| | value = f"{float(cr_mm):.4f} mm" |
| | else: |
| | value = f"{float(corner_radius):.4f} mm" |
| |
|
| | accessor.add_property( |
| | "App::PropertyLength", |
| | "CornerRadius", |
| | "Shape", |
| | "Corner radius migrated from FlatRadius/Diameter", |
| | ) |
| | accessor.set_editor_mode("CornerRadius", 0) |
| | accessor.set("CornerRadius", value) |
| | 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 {name}: {e}") |
| |
|
| | return migrated |
| |
|