Merge pull request 'docs: Datum Creator system reference' (#212) from docs/datum-creator-system into main
Some checks failed
Deploy Docs / build-and-deploy (push) Successful in 54s
Build and Test / build (push) Has been cancelled

Reviewed-on: #212
This commit was merged in pull request #212.
This commit is contained in:
2026-02-14 19:28:48 +00:00
2 changed files with 178 additions and 0 deletions

View File

@@ -50,6 +50,7 @@
# Reference
- [Configuration](./reference/configuration.md)
- [Datum Creator](./reference/datum-creator.md)
- [Glossary](./reference/glossary.md)
# C++ API Reference

View File

@@ -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.