Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **Task toolbar**: Sketch / Design / Workbench switcher; the tools row shows only the current task. Design has its own Move / Rotate / Scale / Align shafts (bake bodies for CSG). Workbench has Move / Rotate / Align shafts (instance pose). <kbd>G</kbd> / <kbd>R</kbd> / <kbd>J</kbd> stay on the current task; <kbd>S</kbd> enters Design Scale.
- **Mode names**: Design idle is `Design_inspection` (was `Normal`); Sketch idle is `Sketch_inspection` (was `Sketch_inspection_mode`). `ezy.get_mode()` / `ezy.set_mode` use the new names; `Normal` and `Sketch_inspection_mode` still parse.
- **Move / rotate / scale space**: Options **Local** (default) or **World**. Local uses the first selected solid's frame (origin and X/Y/Z from **Show axes**). World keeps global XYZ at that solid's bounding-box center. Persisted as **`gui.transform_space`**.
- **Desktop deps**: MSVC GLFW/GLEW come from **vcpkg** (`vcpkg.json` + toolchain) instead of NuGet; local configure matches CI.
- **Extrude Both sides**: Options **Both sides** defaults to on (session sticky; not a Settings key).

### Fixed

- **Workbench task icon**: `res/icons/Workbench_Assembly.png` is included so the task button and the usage guide can load it (Sphinx `-W` failed on the missing image).
- **Workbench toolbar**: the tools row no longer repeats the Workbench task icon; idle is the task button only.
- **Workbench Align shafts**: cylindrical face picking uses Face selection on Workbench instances (same as Design). Insert position uses the instance placement (axis direction was already correct).
- **Workbench set frame**: **Set from planar/cylindrical face** from the Workbench List stays in Workbench and updates the instance tool frame (pose unchanged).
- **List panes**: selecting or right-clicking a Shape List / Workbench List / Sketch List row switches to that task so the 3D view matches the pane.
- **Align shafts**: default axial sense is the smaller rotation so a hole whose face parametrization is opposite does not flip the part. **Flip direction** still forces the 180°.
- **Shape List right-click**: the row context menu opens from the whole entry (checkboxes, **M**, tree arrow, name field, and padding), not only from some widgets. Right-click on the name field opens the same menu.
- **Shape rotate axis**: Choosing X/Y/Z (or view-to-object) before the first drag is kept. Constrained rotation uses the plane perpendicular to that axis when the view faces it. Local space rotates about the assigned frame, not only world XYZ through the bbox.
- **Shape rotate drag**: View-to-object axis and the constrained axis-vs-view plane are captured on the first mouse sample. Orbit or pan during rotate no longer changes the axis/plane against the original mouse anchor.
Expand All @@ -26,6 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Workbench List**: separate pane of geometry **links** to Shape List solids (own location/rotation). **Add to Workbench** from the Shape List (button, context menu, or drag). Design geometry edits update links; Design move/rotate/scale do not move instances. Workbench Move / Rotate / Align shafts edit the instance frame only. `.ezy` stores `workbench[]` (no BREP). Settings: **`gui.show_workbench_list`**.

- **Status toast kinds**: the bottom-right toast is colored by kind (**success**, **info**, **constraint**, **warning**, **error**) instead of always red. Failed `Status` toasts follow `Result_status` (`User_error` is amber constraint). Scripts: `ezy.msg(text [, kind])`. **Add bone** uses info for the next click, amber for rejected input, green on commit, and red if create fails.

- **Curve segment angle**: **Settings -> View presentation** slider (**2** to **20** degrees, default **6**) sets Open CASCADE AIS curve tessellation. Smaller draws smoother arcs and fillets (display only). Persisted as **`gui.curve_deviation_angle_deg`**.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Shape List hierarchy phase 3: parent transforms and advanced assembly model

### Summary

Longer-term Shape List / document hierarchy work that should **not** ship with the organizational outliner. Phase 1 delivered folder-style groups without changing leaf BREP or transform semantics. Phase 2 covers outliner polish (reorder, duplicate, selection). Phase 3 is the product decision layer: inherited placement, optional boolean history, and part-local frames.
Longer-term Shape List / document hierarchy. Phase 1 delivered folder-style groups. Phase 3 (in progress): inherited placement, Part/Origin/planes. Workbench List is a second store of geometry links (`m_wbk_shps`), not a filter of `m_shps`. Editable Boolean history remains deferred (fuse/cut/common still replace inputs; they now evaluate world BREP).

### Context

Expand Down
26 changes: 26 additions & 0 deletions agents/drafts/issues/active/gh-268-workbench-geometry-links.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
github_issue: 268
github_pr: 269
status: open
paired_draft: ../prs/active/gh-269-workbench-geometry-links.md
---

# Workbench task with geometry links

**Suggested labels:** `enhancement`

## Title (GitHub)

Workbench task with geometry links

## Body (GitHub)

Filed: https://github.com/trailcode/EzyCad/issues/268

### Summary

Workbench task and list of placement instances linked to Design solids. Design cut, fuse, common, and cross-section clip keep the edited solid's `Shape_id` so those instances update.

## Related

- PR: https://github.com/trailcode/EzyCad/pull/269
30 changes: 30 additions & 0 deletions agents/drafts/prs/active/gh-269-workbench-geometry-links.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
github_issue: 268
github_pr: 269
status: open
paired_draft: ../issues/active/gh-268-workbench-geometry-links.md
---

# PR - Workbench task with geometry links

## Title

Workbench task with geometry links

## Summary

- Sketch / Design / Workbench task toolbar. Workbench List stores geometry links with their own placement.
- Cut, fuse, and common reuse the first operand's `Shape_id`. Cross-section clip keeps each survivor's id. `Shape_replace_delta` does not drop links for an id the same delta inserts again.
- Extrude sketch face is on the Sketch task.

## Related

- Issue: https://github.com/trailcode/EzyCad/issues/268
- PR: https://github.com/trailcode/EzyCad/pull/269
- Branch: `Trailcode/workbench`

## Test Plan

- [x] `EzyCad_tests` cut / fuse / common / workbench link filters
- [ ] Two Workbench instances, cut the Design solid, undo and redo
- [ ] Delete the Design source and confirm instances disappear
21 changes: 11 additions & 10 deletions agents/plans/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ shp-origin-orientation --> cross-section-tool --> sketch-from-shape-section
sketch-mode-shape-faint (done; parallel UX)
```

| Plan | Status | Load only when prompt is about |
| ---------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------- |
| [shp-origin-orientation.md](shp-origin-orientation.md) | partial | shape origin, shape frame, shape axes / orientation annotation |
| [cross-section-tool.md](cross-section-tool.md) | done | cross-section tool, section cut preview, cutting-plane experiment |
| [sketch-from-shape-section.md](sketch-from-shape-section.md) | partial | "sketch from shape", section → editable sketch |
| [sketch-mode-shape-faint.md](sketch-mode-shape-faint.md) | done | faint/ghost/wireframe shapes in sketch mode, alpha blending solids |
| [shape-list-hierarchy-phase3.md](shape-list-hierarchy-phase3.md) | deferred | parent transform inheritance, Parts/planes, Boolean history (#214) |
| [assembly-inspection-mode.md](assembly-inspection-mode.md) | deferred | assembly idle/inspection mode, Part vs arrange context, Move semantics |
| [wasm-multithreading.md](wasm-multithreading.md) | planning | WASM/Emscripten pthreads, SharedArrayBuffer, parallel OCCT on web |
| Plan | Status | Load only when prompt is about |
| ---------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------ |
| [shp-origin-orientation.md](shp-origin-orientation.md) | partial | shape origin, shape frame, shape axes / orientation annotation |
| [cross-section-tool.md](cross-section-tool.md) | done | cross-section tool, section cut preview, cutting-plane experiment |
| [sketch-from-shape-section.md](sketch-from-shape-section.md) | partial | "sketch from shape", section → editable sketch |
| [sketch-mode-shape-faint.md](sketch-mode-shape-faint.md) | done | faint/ghost/wireframe shapes in sketch mode, alpha blending solids |
| [tasks-workbenches.md](tasks-workbenches.md) | partial | Sketch/Design/Workbench task toolbar, Workbench List links |
| [shape-list-hierarchy-phase3.md](shape-list-hierarchy-phase3.md) | partial | parent transform inheritance, Parts/planes, Boolean history (#214) |
| [assembly-inspection-mode.md](assembly-inspection-mode.md) | deferred | assembly idle/inspection mode, Part vs arrange context, Workbench list |
| [wasm-multithreading.md](wasm-multithreading.md) | planning | WASM/Emscripten pthreads, SharedArrayBuffer, parallel OCCT on web |
| [wasm-alt-drag-multiselect.md](wasm-alt-drag-multiselect.md) | implemented | WASM Alt+LMB multi-select (#220); AABB pick supplement; close issue when ready |
| [configurable-hotkeys.md](configurable-hotkeys.md) | done | remappable shortcuts, keybindings, `gui.hotkeys`, free Dimension off D |
| [configurable-hotkeys.md](configurable-hotkeys.md) | done | remappable shortcuts, keybindings, `gui.hotkeys`, free Dimension off D |
56 changes: 35 additions & 21 deletions agents/plans/assembly-inspection-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,39 @@ Post-v1 product design. Do **not** ship Assembly inspection until [phase 3 place

Two phases of work, two kinds of idle mode:

1. **Make geometry** — Sketch inspection + Inspection (`Mode::Normal`): draw profiles, see solids alongside (or faint), extrude, fillet, boolean.
2. **Arrange components** — Assembly inspection (future): duplicate / place / move Parts relative to each other; later mates and instances.
1. **Make geometry** — Sketch inspection + Design inspection (`Mode::Design_inspection`): draw profiles, see solids alongside (or faint), extrude, fillet, boolean.
2. **Arrange components** — Workbench inspection (`Mode::Workbench_inspection`): duplicate / place / move Parts relative to each other; later mates and instances.

That split matches SolidWorks / Inventor / Fusion (sketch nested in part, part nested in assembly). EzyCad names the idle states “inspection” (= browse/select + launch tools + Esc parent), not metrology “Inspect.”
That split matches SolidWorks / Inventor / Fusion (sketch nested in part, part nested in assembly). EzyCad names the idle states "inspection" (= browse/select + launch tools + Esc parent), not metrology "Inspect." Workbench is the arrange task today; a later `Assembly_inspection` name can replace it if mates/instances need a fourth idle.

```mermaid
flowchart TB
assemblyIdle[Assembly_inspection]
partIdle[Inspection_Normal]
workbenchIdle[Workbench_inspection]
designIdle[Design_inspection]
sketchIdle[Sketch_inspection]
sketchTools[Sketch_tools]
assemblyIdle -->|"edit part"| partIdle
partIdle -->|"edit sketch"| sketchIdle
workbenchIdle -->|"edit part"| designIdle
designIdle -->|"edit sketch"| sketchIdle
sketchIdle --> sketchTools
sketchTools -->|"Esc"| sketchIdle
sketchIdle -->|"Esc"| partIdle
partIdle -->|"Esc"| assemblyIdle
sketchIdle -->|"Esc"| designIdle
```

Esc from Workbench tools returns to Workbench idle (not Design). Task buttons jump between Sketch, Design, and Workbench.

## What exists today

| UI label | Mode | Role |
| ---------------------- | ------------------------------ | ----------------------------------------------------------------------------- |
| Inspection mode | `Mode::Normal` | Idle 3D solids: selection filter, materials, booleans, transforms |
| Sketch inspection mode | `Mode::Sketch_inspection_mode` | Idle 2D sketch: show sketch, ortho, faint solids; Esc parent for sketch tools |
| UI label | Mode | Role |
| ---------------------- | ---------------------------- | ----------------------------------------------------------------------------- |
| Design inspection | `Mode::Design_inspection` | Idle 3D modeling: selection filter, materials, booleans, Scale, Align shafts |
| Workbench inspection | `Mode::Workbench_inspection` | Idle 3D arrange: Move / Rotate / Align shafts; Workbench list of Parts |
| Sketch inspection mode | `Mode::Sketch_inspection` | Idle 2D sketch: show sketch, ortho, faint solids; Esc parent for sketch tools |

Esc ladder (see [docs/usage.md](../../docs/usage.md)): sketch tool → sketch inspection → Normal.
Esc ladder (see [docs/usage.md](../../docs/usage.md)): sketch tool -> sketch inspection -> `Design_inspection`. Workbench tools -> `Workbench_inspection`.

**Not first-class yet:** Parts, instances, mates, inherited parent transforms. Shape List **groups** are organizational (STEP XCAF hierarchy on import). Move / Rotate / Scale / Align shafts **bake** into leaf BREP — one-shot geometry edits, not assembly placement. Toolbar icons named `Assembly_*.png` are FreeCAD-style assets for those shape tools, not an assembly workbench.
**Phase 3 engine:** relative placement, typed nodes (Body, Group, Part, Origin, Plane), Move/Rotate/Scale update placement. Shape List **groups** remain folders. Toolbar icons named `Assembly_*.png` are FreeCAD-style assets for Workbench tools. True mates / shared instances remain later.

Planned model: [shape-list-hierarchy-phase3.md](shape-list-hierarchy-phase3.md) (#214) — relative placement, typed nodes (Body, Group, Part, …), non-baking transforms.
See [shape-list-hierarchy-phase3.md](shape-list-hierarchy-phase3.md) (#214).

## The awkward nuance (and why it feels wrong)

Expand Down Expand Up @@ -123,16 +125,28 @@ CAD products rarely brand the idle state “inspection”; they use document or

Shared idea: layered contexts with Esc / finish stepping outward. EzyCad’s “inspection” vocabulary can stay for consistency, or later rename all three to Sketch / Part / Assembly **context** (larger UX rename).

## Lists (Design vs Workbench)

Two stores: Design `m_shps` (Shape List) and Workbench `m_wbk_shps` (Workbench List). Leaves in the workbench are **links** (`source_id` + own frame), not a second BREP and not a filter of `m_shps`.

| Task | List shows | Copy / instance |
| ------------- | ------------------------------------------- | --------------------------------------------- |
| **Design** | Bodies / features / groups you are editing | Clone or feature-array geometry |
| **Workbench** | Linked placements of Design solids / groups | `add_to_workbench`; later true Part instances |

Design geometry edits (same `Shape_id`) refresh links. Design move/rotate/scale do not move instances. Workbench transforms edit the instance frame. Polar array of parts can follow on Workbench. Sketch List stays Sketch-only. See [tasks-workbenches.md](tasks-workbenches.md).

## Product stance (fixed for this plan)

1. Keep `Mode::Normal` as the 3D idle mode through hierarchy phase 1–2; keep bake Move/Duplicate there until placement lands.
2. Introduce `Assembly_inspection` (name TBD in code) only with phase 3+ Part + relative placement; mates/instances can follow.
3. Then: Inspection = make/edit geometry; Assembly inspection = arrange Parts; Sketch inspection stays under Part.
4. No v1 Assembly inspection mode.
1. Design idle is `Mode::Design_inspection`; Workbench idle is `Mode::Workbench_inspection`.
2. Phase 3 placement / Parts: Move/Rotate on a Part updates relative placement (`world = parent * local`); children follow. Bake stays only for true geometry edits (fillet, scale-as-feature if needed).
3. Workbench List is the arrange tree (links with own pose). Design list is the modeling tree. Do not duplicate BREP for each placement.
4. True mates stay later. Sketch inspection stays under Part.

## Related

- Implementation of placement / Parts: [shape-list-hierarchy-phase3.md](shape-list-hierarchy-phase3.md)
- Task toolbars: Workbench vs Design tools row (see `src/doc/gui.md`)
- Modes / Esc parent map: [src/doc/gui.md](../../src/doc/gui.md), [src/mode.h](../../src/mode.h)
- User Esc ladder / tool docs: [docs/usage.md](../../docs/usage.md)
- Shape List groups today: [src/doc/shape.md](../../src/doc/shape.md)
- Shape List: [src/doc/shape.md](../../src/doc/shape.md)
10 changes: 6 additions & 4 deletions agents/plans/shape-list-hierarchy-phase3.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
status: deferred
status: partial
topic: shape-list-hierarchy-phase3
depends_on: null
blocks: null
blocks: [assembly-inspection-mode]
github_issue: 214
---

# Shape List hierarchy phase 3: placement, Parts, Boolean history

**Load only when** the prompt is about parent transform inheritance, Part/Origin/plane objects, editable Boolean history, or Shape List hierarchy phase 3 (#214). Skip otherwise ([token-lean](../conventions/token-lean.md)). Index: [plans/README.md](README.md).

Post-v1 work. Do **not** ship any of this in v1.
In progress: typed nodes, relative placement, Part/Origin/planes, Workbench vs Design list filter. Editable Boolean history (section 4) can follow; fuse/cut/common still replace inputs but evaluate **world** BREP so placed parts boolean correctly.

## Scope and fixed decisions

Expand Down Expand Up @@ -53,6 +53,7 @@ Post-v1 work. Do **not** ship any of this in v1.

## 5. Complete lifecycle, UI, and interchange semantics

- Shape List is the Design tree (`m_shps`). Workbench List is a second store of geometry links (`m_wbk_shps`). See [tasks-workbenches.md](tasks-workbenches.md) and [assembly-inspection-mode.md](assembly-inspection-mode.md#lists-design-vs-workbench).
- Expand Boolean rows as Base/Tool or numbered Operand children; add operation change, reorder, recompute, show operands, remove operand, and dissolve actions in [`src/gui.cpp`](../../src/gui.cpp).
- Cascade-delete Group, Part, and Boolean subtrees. Dissolve promotes ordinary children preserve-world; Part drops system references; Boolean removes its result and promotes operands.
- Traverse logical outputs for export: Body exports world geometry, Boolean exports its cached result once, Group/Part recurse, and Origin/Plane export nothing. Keep STEP/IGES/STL/PLY flattened; only `.ezy` preserves history.
Expand All @@ -71,4 +72,5 @@ Post-v1 work. Do **not** ship any of this in v1.
1. Placement/migration/reparent/export tests must pass before enabling inherited transforms.
2. Inherited transforms and Part references must be stable before Boolean history depends on them.
3. Boolean history ships only after nested recompute, failure recovery, persistence, undo, and export tests pass.
4. No phase 3 behavior is included in v1; sketches remain structurally unchanged throughout.
4. Sketches remain in `m_sketches` / Sketch List; no sketch Shape List parent.
5. Design vs Workbench are two lists: `m_shps` (bodies) and `m_wbk_shps` (links with own placement). Polar array of parts belongs on Workbench after instances exist.
Loading
Loading