Merge pull request 'docs: Datum Creator system reference' (#212) from docs/datum-creator-system into main
Reviewed-on: #212
This commit was merged in pull request #212.
This commit is contained in:
@@ -50,6 +50,7 @@
|
|||||||
# Reference
|
# Reference
|
||||||
|
|
||||||
- [Configuration](./reference/configuration.md)
|
- [Configuration](./reference/configuration.md)
|
||||||
|
- [Datum Creator](./reference/datum-creator.md)
|
||||||
- [Glossary](./reference/glossary.md)
|
- [Glossary](./reference/glossary.md)
|
||||||
|
|
||||||
# C++ API Reference
|
# C++ API Reference
|
||||||
|
|||||||
177
docs/src/reference/datum-creator.md
Normal file
177
docs/src/reference/datum-creator.md
Normal 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.
|
||||||
Reference in New Issue
Block a user