feat(commands): add FLATSHOT and CONVTOSURFACE

- FLATSHOT: project the selected solid's edges to 2D Line entities at Z=0
- CONVTOSURFACE: convert the selected solid(s) to Surface entities

Both reuse the cached B-rep's edge wires. COMMANDS.md: 219/262.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-29 09:16:44 +03:00
1 parent 6f9565e9f7
commit c653a3f38e
4 files changed
+108 -4

No files matched your search

+4 -4
View File
@@ -230,9 +230,9 @@ Status of every standard CAD command in Open CAD Studio:
| `INTERFERE` | INF | Interference solid from overlap | ✅ |
| `SECTION` | — | Cross-section outline of a solid | ✅ |
| `CONVTOSOLID` | — | Convert to solid | ❌ |
| `CONVTOSURFACE` | — | Convert to surface | ❌ |
| `CONVTOSURFACE` | — | Convert to surface | ✅ |
| `SECTIONPLANE` | — | Section plane object | ❌ |
| `FLATSHOT` | — | 2D view from 3D | ❌ |
| `FLATSHOT` | — | 2D view from 3D | ✅ |
---
@@ -357,12 +357,12 @@ Status of every standard CAD command in Open CAD Studio:
| Text & Table | 10 | 7 | 1 | 2 |
| Layer | 19 | 17 | 0 | 2 |
| Block & Reference | 23 | 18 | 2 | 3 |
| 3D Modeling | 27 | 23 | 0 | 4 |
| 3D Modeling | 27 | 25 | 0 | 2 |
| View & Navigation | 32 | 15 | 8 | 9 |
| Inquiry | 12 | 12 | 0 | 0 |
| File & Plot | 17 | 16 | 0 | 1 |
| Manage & Customize | 22 | 13 | 3 | 6 |
| **Total** | **262** | **217** | **15** | **30** |
| **Total** | **262** | **219** | **15** | **28** |
> Counts include commands listed under more than one category (e.g. `SLICE`, `HELIX`,
> `MINSERT`, `SUBTRACT`/`UNION`/`INTERSECT` appear in both their 2D and 3D groups).
+10
View File
@@ -704,6 +704,16 @@ impl OpenCADStudio {
return Some(self.solid_interfere());
}
// FLATSHOT — flatten the selected solid's edges to 2D lines at Z=0.
"FLATSHOT" => {
return Some(self.solid_flatshot());
}
// CONVTOSURFACE — convert the selected solid(s) to surface entities.
"CONVTOSURFACE" => {
return Some(self.solid_convtosurface());
}
// POLYSOLID <width> <height> — extrude a selected polyline into a
// wall-like solid.
cmd if cmd == "POLYSOLID" || cmd.starts_with("POLYSOLID ") => {
+2
View File
@@ -346,6 +346,8 @@ inventory::submit!(crate::command::CommandRegistration {
"REG",
"ARCHIVE",
"ETRANSMIT",
"FLATSHOT",
"CONVTOSURFACE",
// Slice/section + interference + press-pull/thicken + 3D transforms + wall/pyramid.
"SLICE",
"SL",
+92
View File
@@ -748,4 +748,96 @@ impl super::OpenCADStudio {
.push_output(&format!("SPLINEFIT: fit a spline through {n} points."));
Task::none()
}
/// FLATSHOT — project the selected solid's edges onto the XY plane (Z=0) as
/// Line entities, giving a flattened 2D shot of the model. Reuses the cached
/// solid's edge wires (the same source SECTION uses).
pub(super) fn solid_flatshot(&mut self) -> Task<Message> {
use acadrust::types::Vector3;
use acadrust::Line;
let i = self.active_tab;
let handles: Vec<Handle> = self.tabs[i]
.scene
.selected
.iter()
.copied()
.filter(|h| self.tabs[i].scene.solid_models.contains_key(h))
.collect();
if handles.is_empty() {
self.command_line
.push_error("FLATSHOT: select a solid created this session.");
return Task::none();
}
self.push_undo_snapshot(i, "FLATSHOT");
let mut n = 0usize;
for h in &handles {
let solid = self.tabs[i].scene.solid_models[h].clone();
for w in solid_model::edge_wires(&solid) {
for seg in w.points.windows(2) {
let line = Line::from_points(
Vector3::new(seg[0].x, seg[0].y, 0.0),
Vector3::new(seg[1].x, seg[1].y, 0.0),
);
self.tabs[i].scene.add_entity(EntityType::Line(line));
n += 1;
}
}
}
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("FLATSHOT: created {n} projected edge(s) at Z=0."));
Task::none()
}
/// CONVTOSURFACE — convert the selected solid(s) into Surface entities,
/// carrying the solid's edge wires (reuses the cached B-rep's edge wires).
pub(super) fn solid_convtosurface(&mut self) -> Task<Message> {
use acadrust::entities::{Surface, SurfaceKind, Wire as AWire};
use acadrust::types::Vector3;
let i = self.active_tab;
let handles: Vec<Handle> = self.tabs[i]
.scene
.selected
.iter()
.copied()
.filter(|h| self.tabs[i].scene.solid_models.contains_key(h))
.collect();
if handles.is_empty() {
self.command_line
.push_error("CONVTOSURFACE: select a solid created this session.");
return Task::none();
}
let mut surfaces: Vec<Surface> = Vec::new();
for h in &handles {
let solid = self.tabs[i].scene.solid_models[h].clone();
let awires: Vec<AWire> = solid_model::edge_wires(&solid)
.into_iter()
.map(|w| {
let mut aw = AWire::new();
aw.points = w
.points
.iter()
.map(|p| Vector3::new(p.x, p.y, p.z))
.collect();
aw
})
.collect();
let mut surf = Surface::new(SurfaceKind::Generic);
surf.wires = awires;
surf.common.layer = self.tabs[i].active_layer.clone();
surfaces.push(surf);
}
self.push_undo_snapshot(i, "CONVTOSURFACE");
self.tabs[i].scene.erase_entities(&handles);
let n = surfaces.len();
for surf in surfaces {
self.tabs[i].scene.add_entity(EntityType::Surface(surf));
}
self.tabs[i].dirty = true;
self.refresh_properties();
self.command_line
.push_output(&format!("CONVTOSURFACE: converted {n} solid(s) to surface(s)."));
Task::none()
}
}