feat(model): 3D solid modelling tab — primitives + boolean ops

Rename the Home tab to "Draw" and add a Model tab beside it with two
groups:

- Model: BOX / CYLINDER / CONE / SPHERE / WEDGE / TORUS, placed with a
  footprint + height. Each is built as a real ACIS Solid3D (acadrust
  primitive builders) plus a truck B-rep, tessellated into the shaded
  mesh pipeline, with edge wires for picking + wireframe.
- Design: UNION / SUBTRACT / INTERSECT via truck-shapeops.

A session-only Scene.model_solids cache holds each solid's truck B-rep
so the boolean tools can combine and chain them. Supersedes the old
command-line BOX/SPHERE/CYLINDER (insert::solid3d_cmds keeps EXTRUDE/
REVOLVE/SWEEP/LOFT).

Known limitations: booleans need solids created this session; curved
ACIS primitives render in-session but not after reload (the SAT
tessellator handles only planar caps); geometry assumes world_offset 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-05-31 19:27:06 +03:00
1 parent 4acb820e01
commit 7bf9ce31ae
17 files changed
+1095 -397

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
// Model module — 3D solid modelling.
//
// Model group : create primitive solids (box, cylinder, cone, sphere, …)
// as ACIS Solid3D entities via acadrust's primitive builders.
// Design group : combine solids with truck boolean operations
// (union / subtract / intersect).
pub mod boolean_cmd;
pub mod primitive_cmd;
use crate::modules::{CadModule, IconKind, ModuleEvent, RibbonGroup, RibbonItem, ToolDef};
pub struct ModelModule;
/// Helper to declare a ribbon tool that fires a named command.
fn tool(id: &'static str, label: &'static str, glyph: &'static str) -> ToolDef {
ToolDef {
id,
label,
icon: IconKind::Glyph(glyph),
event: ModuleEvent::Command(id.to_string()),
}
}
impl CadModule for ModelModule {
fn id(&self) -> &'static str {
"model"
}
fn title(&self) -> &'static str {
"Model"
}
fn ribbon_groups(&self) -> Vec<RibbonGroup> {
vec![
RibbonGroup {
title: "Model",
tools: vec![
RibbonItem::LargeTool(tool("BOX", "Box", "▦")),
RibbonItem::LargeTool(tool("CYLINDER", "Cylinder", "⬭")),
RibbonItem::LargeTool(tool("CONE", "Cone", "△")),
RibbonItem::LargeTool(tool("SPHERE", "Sphere", "◯")),
RibbonItem::Dropdown {
id: "MODEL_MORE",
icon: IconKind::Glyph("◰"),
items: vec![
("WEDGE", "Wedge", IconKind::Glyph("◣")),
("TORUS", "Torus", IconKind::Glyph("◎")),
],
default: "WEDGE",
},
],
},
RibbonGroup {
title: "Design",
tools: vec![
RibbonItem::LargeTool(tool("UNION", "Union", "⊕")),
RibbonItem::LargeTool(tool("SUBTRACT", "Subtract", "⊖")),
RibbonItem::LargeTool(tool("INTERSECT", "Intersect", "⊗")),
],
},
]
}
}