feat: BOX, SPHERE, CYLINDER primitives + EXTRUDE / REVOLVE commands

BOX, SPHERE, and CYLINDER build truck topology solids and tessellate
them into MeshModels stored alongside a Solid3D placeholder entity so
the GPU mesh pipeline renders them immediately.

EXTRUDE picks any closed 2D profile (Circle, LwPolyline, etc.),
attaches a planar face via try_attach_plane, and translational-sweeps
it (tsweep Face → Solid) along Z by the given height.

REVOLVE picks a profile, two axis points, and an angle (default 360°),
then rotational-sweeps the wire (rsweep) around the axis.

Three new CmdResult variants drive the operations:
  CommitSolid3D, ExtrudeEntity, RevolveEntity.

Scene::layer_color() added to retrieve the active layer's RGBA color.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-04-08 12:55:28 +03:00
commit 549ae38459
7 changed files with 592 additions and 1 deletions

View file

@ -3402,6 +3402,61 @@ impl H7CAD {
}
}
// ── 3D Primitive — BOX ────────────────────────────────────────
"BOX" => {
use crate::modules::insert::solid3d_cmds::BoxCommand;
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
let cmd = BoxCommand::new(color);
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
// ── 3D Primitive — SPHERE ─────────────────────────────────────
"SPHERE" => {
use crate::modules::insert::solid3d_cmds::SphereCommand;
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
let cmd = SphereCommand::new(color);
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
// ── 3D Primitive — CYLINDER ───────────────────────────────────
"CYLINDER" => {
use crate::modules::insert::solid3d_cmds::CylinderCommand;
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
let cmd = CylinderCommand::new(color);
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
// ── EXTRUDE ────────────────────────────────────────────────────
"EXTRUDE"|"EXT" => {
use crate::modules::insert::solid3d_cmds::ExtrudeCommand;
// If a single entity is already selected, skip the pick step.
let selected: Vec<_> = self.tabs[i].scene.selected_entities().into_iter().collect();
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
if selected.len() == 1 {
let handle = selected[0].0;
let mut cmd = ExtrudeCommand::new(color);
cmd.on_entity_pick(handle, glam::Vec3::ZERO);
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
} else {
let cmd = ExtrudeCommand::new(color);
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
}
// ── REVOLVE ────────────────────────────────────────────────────
"REVOLVE"|"REV" => {
use crate::modules::insert::solid3d_cmds::RevolveCommand;
let color = self.tabs[i].scene.layer_color(&self.tabs[i].active_layer);
let cmd = RevolveCommand::new(color);
self.command_line.push_info(&cmd.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
// ── STL export ────────────────────────────────────────────────
"STLOUT"|"EXPORTSTL" => {
return Task::done(Message::StlExport);