diff --git a/ztools/ztools/commands/datum_viewprovider.py b/ztools/ztools/commands/datum_viewprovider.py index d7656b5..39036fa 100644 --- a/ztools/ztools/commands/datum_viewprovider.py +++ b/ztools/ztools/commands/datum_viewprovider.py @@ -2,6 +2,7 @@ # Custom ViewProvider for ZTools datum objects import json +import math import FreeCAD as App import FreeCADGui as Gui @@ -141,6 +142,23 @@ class ZToolsDatumViewProvider: return None +def _resolve_source_refs(datum_obj): + """Parse ZTools_SourceRefs and resolve to (object, subname, shape) tuples.""" + refs_json = getattr(datum_obj, "ZTools_SourceRefs", "[]") + try: + refs = json.loads(refs_json) + except json.JSONDecodeError: + return [] + doc = datum_obj.Document + resolved = [] + for ref in refs: + obj = doc.getObject(ref.get("object", "")) + sub = ref.get("subname", "") + shape = obj.getSubObject(sub) if obj and sub else None + resolved.append((obj, sub, shape)) + return resolved + + class DatumEditTaskPanel: """ Task panel for editing existing ZTools datum objects. @@ -364,8 +382,45 @@ class DatumEditTaskPanel: self.datum_obj.AttachmentOffset = new_offset self._update_params({"distance": distance}) - elif ztools_type in ("angled", "tangent_cylinder"): - self._update_params({"angle": self.angle_spin.value()}) + elif ztools_type == "angled": + angle = self.angle_spin.value() + if self._has_attachment(): + refs = _resolve_source_refs(self.datum_obj) + if len(refs) >= 2 and refs[0][2] and refs[1][2]: + face_normal = refs[0][2].normalAt(0, 0) + edge_shape = refs[1][2] + edge_dir = ( + edge_shape.Vertexes[-1].Point - edge_shape.Vertexes[0].Point + ).normalize() + face_rot = App.Rotation(App.Vector(0, 0, 1), face_normal) + local_edge_dir = face_rot.inverted().multVec(edge_dir) + angle_rot = App.Rotation(local_edge_dir, angle) + self.datum_obj.AttachmentOffset = App.Placement( + App.Vector(0, 0, 0), angle_rot + ) + self._update_params({"angle": angle}) + + elif ztools_type == "tangent_cylinder": + angle = self.angle_spin.value() + refs = _resolve_source_refs(self.datum_obj) + if refs and refs[0][2]: + face = refs[0][2] + if isinstance(face.Surface, Part.Cylinder): + cyl = face.Surface + axis = cyl.Axis + center = cyl.Center + radius = cyl.Radius + rad = math.radians(angle) + if abs(axis.dot(App.Vector(1, 0, 0))) < 0.99: + local_x = axis.cross(App.Vector(1, 0, 0)).normalize() + else: + local_x = axis.cross(App.Vector(0, 1, 0)).normalize() + local_y = axis.cross(local_x) + radial = local_x * math.cos(rad) + local_y * math.sin(rad) + tangent_point = center + radial * radius + rot = App.Rotation(App.Vector(0, 0, 1), radial) + self.datum_obj.Placement = App.Placement(tangent_point, rot) + self._update_params({"angle": angle}) elif ztools_type in ("normal_to_edge", "on_edge"): parameter = self.param_spin.value()