diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 00868e29ac..376a6f0e63 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -50,6 +50,7 @@ # Reference - [Configuration](./reference/configuration.md) +- [Datum Creator](./reference/datum-creator.md) - [Glossary](./reference/glossary.md) # C++ API Reference diff --git a/docs/src/reference/datum-creator.md b/docs/src/reference/datum-creator.md new file mode 100644 index 0000000000..88c1c41223 --- /dev/null +++ b/docs/src/reference/datum-creator.md @@ -0,0 +1,177 @@ +# Datum Creator System + +The ZTools Datum Creator (`ZTools_DatumCreator`) creates parametric datum planes, axes, and points. It auto-detects the datum type from selected geometry and provides a unified task panel with 16 creation modes. + +**Source files:** + +- `mods/ztools/ztools/ztools/commands/datum_commands.py` -- UI, selection handling, mode detection +- `mods/ztools/ztools/ztools/datums/core.py` -- geometry computation and FreeCAD object creation + +## Geometry Classification + +The `SelectionItem` class wraps a selected geometry element and classifies it into one of seven types: + +| Type | Detection | Icon | +|------|-----------|------| +| face | Planar `Part.Face` or object with "Plane" in TypeId | ▢ | +| plane | Datum plane objects or planar faces | ▣ | +| cylinder | `Part.Face` with `Surface.Cylinder` | ◎ | +| edge | `Part.Edge` with `Part.Line` curve | ― | +| circle | `Part.Edge` with `Part.Circle` or `Part.ArcOfCircle` | ○ | +| vertex | `Part.Vertex` | • | +| unknown | Unclassified geometry | ? | + +Classification flow: + +1. Extract shape from object using the sub-element name (Face#, Edge#, Vertex#) +2. Check shape type (Face, Edge, Vertex) +3. For faces: check `surface.isPlanar()` or `isinstance(surface, Part.Cylinder)` +4. For edges: check curve type (Line, Circle, ArcOfCircle) +5. Fall back to `unknown` + +## Creation Modes + +### Planes (7 modes) + +| Mode | Required Selection | Parameters | Description | +|------|--------------------|------------|-------------| +| `offset_face` | 1 face | distance (mm) | Plane parallel to face at offset | +| `offset_plane` | 1 plane | distance (mm) | Plane parallel to datum plane at offset | +| `midplane` | 2 faces | -- | Plane halfway between two parallel faces | +| `3_points` | 3 vertices | -- | Plane through three non-collinear points | +| `normal_edge` | 1 edge | position (0--1) | Plane perpendicular to edge at parameter | +| `angled` | 1 face + 1 edge | angle (deg) | Plane at angle to face, rotating about edge | +| `tangent_cyl` | 1 cylinder | angle (deg) | Plane tangent to cylinder at angular position | + +### Axes (4 modes) + +| Mode | Required Selection | Parameters | Description | +|------|--------------------|------------|-------------| +| `axis_2pt` | 2 vertices | -- | Axis through two points | +| `axis_edge` | 1 edge | -- | Axis along linear edge | +| `axis_cyl` | 1 cylinder | -- | Axis along cylinder centerline | +| `axis_intersect` | 2 planes | -- | Axis at intersection of two planes | + +### Points (5 modes) + +| Mode | Required Selection | Parameters | Description | +|------|--------------------|------------|-------------| +| `point_vertex` | 1 vertex | -- | Point at vertex location | +| `point_xyz` | (none) | x, y, z (mm) | Point at explicit coordinates | +| `point_edge` | 1 edge | position (0--1) | Point at parameter location on edge | +| `point_face` | 1 face | -- | Point at center of mass of face | +| `point_circle` | 1 circle | -- | Point at center of circular edge | + +## Auto-Detection Algorithm + +The `_match_score()` method scores how well the current selection matches each mode's required types. + +**Scoring:** + +1. If the selection has fewer items than required, score is **0** (no match). +2. For each required type, find a matching selected type using fuzzy matching: + - `face` requirement matches `face` or `cylinder` + - `edge` requirement matches `edge` or `circle` + - All other types require exact match +3. Score calculation: + - **Exact cardinality** (selection count == required count): score = `100 + matched_count` + - **Over-selected** (more items than required): score = `matched_count` + - **No match**: score = `0` + +The mode with the highest score wins. On each selection change, `update_mode_from_selection()` re-evaluates all 16 modes and activates the best match. + +The detected mode is displayed with a category color: + +- Planes: Mauve (#cba6f7) +- Axes: Teal (#94e2d5) +- Points: Yellow (#f9e2af) + +## Task Panel UI + +``` ++-------------------------------------+ +| ZTools Datum Creator | ++-------------------------------------+ +| Selection | +| [icon] Element Name [Remove] | +| [Add Selected] [Remove] [Clear] | ++-------------------------------------+ +| Datum Type | +| DETECTED MODE (colored) | +| Override: [dropdown] | ++-------------------------------------+ +| Parameters (dynamic per mode) | +| Offset: [spinner] mm | +| Angle: [spinner] deg | +| Position: [spinner] 0-1 | +| X/Y/Z: [spinner] mm | ++-------------------------------------+ +| Options | +| [ ] Link to Spreadsheet | +| [x] Add to Active Body | +| [ ] Custom Name: [text] | ++-------------------------------------+ +| [OK] [Cancel] | ++-------------------------------------+ +``` + +### Selection table + +Three columns: type icon (28px), element name (stretch), remove button (28px). Duplicates are rejected. A FreeCAD `SelectionObserver` keeps the "Add Selected" button state synchronized with the active 3D selection. + +### Mode override + +The dropdown lists all 16 modes prefixed by category (`[P]` plane, `[A]` axis, `[Pt]` point). Selecting a mode disables auto-detection until "(Auto-detect)" is re-selected. + +### Parameters section + +Rebuilt dynamically when the mode changes. Only the parameter widgets relevant to the active mode are shown. Modes with no parameters hide the section entirely. + +### Options + +- **Link to Spreadsheet**: creates a spreadsheet alias and expression-links the datum parameter (offset, angle, coordinates) for parametric control. +- **Add to Active Body**: when checked, creates a `PartDesign::Plane/Line/Point` inside the active body. When unchecked, creates a document-level `Part::Plane/Line/Vertex`. +- **Custom Name**: overrides the auto-generated name (format: `ZPlane_Offset_001`). + +## Dispatch to core.py + +`DatumCreatorTaskPanel.accept()` calls `create_datum()`, which: + +1. Reads the current mode, body, name, and parameters from the UI +2. Extracts `SelectionItem` objects by type +3. Dispatches to the corresponding `core.*` function: + +| Mode | Core function | +|------|---------------| +| `offset_face` | `core.plane_offset_from_face(face, distance, ...)` | +| `offset_plane` | `core.plane_offset_from_plane(plane, distance, ...)` | +| `midplane` | `core.plane_midplane(face1, face2, ...)` | +| `3_points` | `core.plane_from_3_points(p1, p2, p3, ...)` | +| `normal_edge` | `core.plane_normal_to_edge(edge, parameter, ...)` | +| `angled` | `core.plane_angled(face, edge, angle, ...)` | +| `tangent_cyl` | `core.plane_tangent_to_cylinder(face, angle, ...)` | +| `axis_2pt` | `core.axis_from_2_points(p1, p2, ...)` | +| `axis_edge` | `core.axis_from_edge(edge, ...)` | +| `axis_cyl` | `core.axis_cylinder_center(face, ...)` | +| `axis_intersect` | `core.axis_intersection_planes(plane1, plane2, ...)` | +| `point_vertex` | `core.point_at_vertex(vertex, ...)` | +| `point_xyz` | `core.point_at_coordinates(x, y, z, ...)` | +| `point_edge` | `core.point_on_edge(edge, parameter, ...)` | +| `point_face` | `core.point_center_of_face(face, ...)` | +| `point_circle` | `core.point_center_of_circle(edge, ...)` | + +## Core Implementation + +Each `core.*` function: + +1. Creates the FreeCAD object (`PartDesign::Plane` in a body, `Part::Plane` at document level) +2. Computes the placement from the source geometry +3. Configures attachment (MapMode, AttachmentSupport, offset) for parametric updates +4. Stores ZTools metadata in custom properties: + - `ZTools_Type` -- creation method identifier (e.g. `"offset_from_face"`) + - `ZTools_Params` -- parameters as JSON (e.g. `{"distance": 10}`) + - `ZTools_SourceRefs` -- source geometry references as JSON +5. Applies Catppuccin Mocha styling (mauve at 70% transparency for planes) +6. Optionally links parameters to a spreadsheet alias + +Auto-naming uses the format `ZPlane_Offset_001`, incrementing the index for each new datum of the same type.