Implement solid shell workflow and properties

This commit is contained in:
ramox81 committed 2026-09-08 19:37:35 +03:00
1 parent febedad916
commit be06a756da
16 files changed
+780 -52

No files matched your search

+102 -1
View File
@@ -9,7 +9,7 @@ use acadrust::{
};
use cadkernel::brep::Body;
use iced::Task;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use super::Message;
use crate::modules::model::boolean_cmd::BoolOp;
@@ -646,6 +646,107 @@ impl super::OpenCADStudio {
Task::none()
}
pub(super) fn solid_shell(
&mut self,
handle: Handle,
actions: &[crate::command::ShellFaceAction],
distance: f64,
) -> Task<Message> {
use crate::command::ShellFaceAction;
let i = self.active_tab;
if self.reject_locked_edit(i, handle) {
return Task::none();
}
if !matches!(
self.tabs[i].scene.document.get_entity(handle),
Some(EntityType::Solid3D(_))
) {
self.command_line
.push_error(crate::t!("Select a 3D solid.").as_ref());
return Task::none();
}
if !distance.is_finite() || distance.abs() <= f64::EPSILON {
self.command_line
.push_error(crate::t!("The shell offset distance must be nonzero.").as_ref());
return Task::none();
}
self.tabs[i].scene.restore_solid_models(&[handle]);
let Some(body) = self.tabs[i].scene.solid_models.get(&handle).cloned() else {
self.command_line
.push_error(crate::t!("The solid geometry could not be restored.").as_ref());
return Task::none();
};
let all_faces = body.face_keys().collect::<Vec<_>>();
let mut removed = HashSet::new();
for action in actions {
match *action {
ShellFaceAction::Remove(point) => {
let Some(face) = solid_model::nearest_face(&body, point.to_array()) else {
self.command_line
.push_error(crate::t!("A selected face could not be resolved.").as_ref());
return Task::none();
};
removed.insert(face);
}
ShellFaceAction::Add(point) => {
let Some(face) = solid_model::nearest_face(&body, point.to_array()) else {
self.command_line
.push_error(crate::t!("A selected face could not be resolved.").as_ref());
return Task::none();
};
removed.remove(&face);
}
ShellFaceAction::RemoveAll => removed.extend(all_faces.iter().copied()),
ShellFaceAction::AddAll => removed.clear(),
}
}
let removed = removed.into_iter().collect::<Vec<_>>();
let result = match cadkernel::brep::shell(&body, &removed, distance) {
Ok(result) => result,
Err(cadkernel::brep::ShellError::InvalidDistance) => {
self.command_line
.push_error(crate::t!("The shell offset distance must be nonzero.").as_ref());
return Task::none();
}
Err(cadkernel::brep::ShellError::UnsupportedSolid) => {
self.command_line.push_error(
crate::t!("SHELL supports rectangular boxes, circular cylinders, and spheres.")
.as_ref(),
);
return Task::none();
}
Err(cadkernel::brep::ShellError::UnknownFace) => {
self.command_line
.push_error(crate::t!("A selected face does not belong to the solid.").as_ref());
return Task::none();
}
Err(cadkernel::brep::ShellError::NoMaterial) => {
self.command_line.push_error(
crate::t!("The offset removes all material. Use a smaller distance or add a face back.")
.as_ref(),
);
return Task::none();
}
Err(cadkernel::brep::ShellError::Kernel(_)) => {
self.command_line.push_error(
crate::t!("The shell could not be constructed from the selected solid and distance.")
.as_ref(),
);
return Task::none();
}
};
if self.replace_solid_body(handle, result, "SHELL") {
self.command_line
.push_output(crate::t!("SHELL: solid updated.").as_ref());
}
Task::none()
}
/// Intersect compatible selected solids, Regions, and coplanar Surfaces.
pub(super) fn solid_intersect(&mut self) -> Task<Message> {
let i = self.active_tab;