forked from 1b-agent/opencadstudio-upstream
Complete CHAMFEREDGE workflow and history
This commit is contained in:
1 parent
ed8cddc556
commit
8822371e18
10 files changed
+678
-157
No files matched your search
@@ -4105,10 +4105,19 @@ impl OpenCADStudio {
|
||||
CmdResult::SolidEdgeBlend {
|
||||
handle,
|
||||
edges,
|
||||
base_face,
|
||||
value,
|
||||
other_value,
|
||||
fillet,
|
||||
} => {
|
||||
let task = self.solid_edge_blend(handle, &edges, value, fillet);
|
||||
let task = self.solid_edge_blend(
|
||||
handle,
|
||||
&edges,
|
||||
base_face,
|
||||
value,
|
||||
other_value,
|
||||
fillet,
|
||||
);
|
||||
self.tabs[i].active_cmd = None;
|
||||
self.tabs[i].snap_result = None;
|
||||
self.tabs[i].scene.clear_preview_wire();
|
||||
|
||||
+41
-16
@@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
fn selected_solid(app: &OpenCADStudio, tab: usize) -> Option<acadrust::Handle> {
|
||||
fn selected_edge_body(app: &OpenCADStudio, tab: usize) -> Option<acadrust::Handle> {
|
||||
let scene = &app.tabs.get(tab)?.scene;
|
||||
let selected = scene.selected_handles_in_order();
|
||||
let [handle] = selected.as_slice() else {
|
||||
@@ -9,7 +9,7 @@ fn selected_solid(app: &OpenCADStudio, tab: usize) -> Option<acadrust::Handle> {
|
||||
|
||||
if matches!(
|
||||
scene.document.get_entity(*handle),
|
||||
Some(acadrust::EntityType::Solid3D(_))
|
||||
Some(acadrust::EntityType::Solid3D(_) | acadrust::EntityType::Surface(_))
|
||||
) {
|
||||
Some(*handle)
|
||||
} else {
|
||||
@@ -26,7 +26,10 @@ fn solid_edge_sources(
|
||||
.document
|
||||
.entities()
|
||||
.filter_map(|entity| {
|
||||
matches!(entity, acadrust::EntityType::Solid3D(_))
|
||||
matches!(
|
||||
entity,
|
||||
acadrust::EntityType::Solid3D(_) | acadrust::EntityType::Surface(_)
|
||||
)
|
||||
.then_some(entity.common().handle)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -989,7 +992,7 @@ impl OpenCADStudio {
|
||||
|
||||
"FILLETEDGE" | "SOLIDFILLET" => {
|
||||
use crate::modules::model::edge_cmd::{EdgeOperation, SolidEdgeCommand};
|
||||
let target = selected_solid(self, i);
|
||||
let target = selected_edge_body(self, i);
|
||||
let bodies = solid_edge_sources(self, i);
|
||||
let command = SolidEdgeCommand::new(
|
||||
EdgeOperation::Fillet,
|
||||
@@ -1001,9 +1004,9 @@ impl OpenCADStudio {
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
}
|
||||
|
||||
"FILLET" if selected_solid(self, i).is_some() => {
|
||||
"FILLET" if selected_edge_body(self, i).is_some() => {
|
||||
use crate::modules::model::edge_cmd::{EdgeOperation, SolidEdgeCommand};
|
||||
let target = selected_solid(self, i);
|
||||
let target = selected_edge_body(self, i);
|
||||
let bodies = solid_edge_sources(self, i);
|
||||
let command = SolidEdgeCommand::new(
|
||||
EdgeOperation::Fillet,
|
||||
@@ -1148,29 +1151,51 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
|
||||
"SOLIDCHAMFER" => {
|
||||
use crate::modules::model::edge_cmd::{EdgeOperation, SolidEdgeCommand};
|
||||
let target = selected_solid(self, i);
|
||||
"CHAMFEREDGE" | "SOLIDCHAMFER" => {
|
||||
use crate::modules::model::edge_cmd::SolidEdgeCommand;
|
||||
let target = selected_edge_body(self, i);
|
||||
let header = &self.tabs[i].scene.document.header;
|
||||
let distances = (header.chamfer_distance_a, header.chamfer_distance_b);
|
||||
let bodies = solid_edge_sources(self, i);
|
||||
let command = SolidEdgeCommand::new(
|
||||
EdgeOperation::Chamfer,
|
||||
let command = SolidEdgeCommand::new_chamfer(
|
||||
target,
|
||||
bodies,
|
||||
crate::scene::WireModel::SELECTED,
|
||||
distances,
|
||||
);
|
||||
let distances = command.chamfer_distances();
|
||||
self.command_line.push_output(
|
||||
crate::tf!(
|
||||
"Distance1 = {:.4}, Distance2 = {:.4}",
|
||||
distances.0,
|
||||
distances.1
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
}
|
||||
|
||||
"CHAMFER" if selected_solid(self, i).is_some() => {
|
||||
use crate::modules::model::edge_cmd::{EdgeOperation, SolidEdgeCommand};
|
||||
let target = selected_solid(self, i);
|
||||
"CHAMFER" if selected_edge_body(self, i).is_some() => {
|
||||
use crate::modules::model::edge_cmd::SolidEdgeCommand;
|
||||
let target = selected_edge_body(self, i);
|
||||
let header = &self.tabs[i].scene.document.header;
|
||||
let distances = (header.chamfer_distance_a, header.chamfer_distance_b);
|
||||
let bodies = solid_edge_sources(self, i);
|
||||
let command = SolidEdgeCommand::new(
|
||||
EdgeOperation::Chamfer,
|
||||
let command = SolidEdgeCommand::new_chamfer(
|
||||
target,
|
||||
bodies,
|
||||
crate::scene::WireModel::SELECTED,
|
||||
distances,
|
||||
);
|
||||
let distances = command.chamfer_distances();
|
||||
self.command_line.push_output(
|
||||
crate::tf!(
|
||||
"Distance1 = {:.4}, Distance2 = {:.4}",
|
||||
distances.0,
|
||||
distances.1
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
|
||||
+158
-73
@@ -7,7 +7,7 @@ use acadrust::{
|
||||
objects::SolidHistoryOperation,
|
||||
EntityType, Handle,
|
||||
};
|
||||
use cadkernel::brep::{Body, EdgeKey};
|
||||
use cadkernel::brep::{Body, EdgeKey, FaceKey};
|
||||
use iced::Task;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -244,6 +244,29 @@ fn entity_with_boolean_body(mut source: EntityType, body: &Body) -> Option<Entit
|
||||
Some(source)
|
||||
}
|
||||
|
||||
fn entity_with_history_body(mut source: EntityType, body: &Body) -> Option<EntityType> {
|
||||
let document = crate::scene::convert::acis_export::solid_to_sat(body)?;
|
||||
let wires = solid_model::edge_wires(body);
|
||||
match &mut source {
|
||||
EntityType::Solid3D(entity) => {
|
||||
entity.wires = wires;
|
||||
entity.silhouettes.clear();
|
||||
entity.set_sat_document(&document);
|
||||
}
|
||||
EntityType::Surface(entity) => {
|
||||
entity.wires = wires;
|
||||
entity.silhouettes.clear();
|
||||
if entity.kind != SurfaceKind::Plane {
|
||||
entity.kind = SurfaceKind::Generic;
|
||||
entity.surface_data = SurfaceData::Generic;
|
||||
}
|
||||
entity.acis_data = AcisData::from_sat(&document.to_sat_string());
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
Some(source)
|
||||
}
|
||||
|
||||
enum IntersectBodyOutcome {
|
||||
Area(Body),
|
||||
Touching,
|
||||
@@ -551,51 +574,6 @@ impl super::OpenCADStudio {
|
||||
groups
|
||||
}
|
||||
|
||||
fn replace_solid_body(&mut self, handle: Handle, result: Body, label: &str) -> bool {
|
||||
let i = self.active_tab;
|
||||
let Some(document) =
|
||||
crate::scene::convert::acis_export::solid_to_sat(&result)
|
||||
else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("The result could not be encoded as ACIS.").as_ref());
|
||||
return false;
|
||||
};
|
||||
let Some(EntityType::Solid3D(mut entity)) =
|
||||
self.tabs[i].scene.document.get_entity(handle).cloned()
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
entity.wires = solid_model::edge_wires(&result);
|
||||
entity.silhouettes.clear();
|
||||
entity.history_handle = None;
|
||||
entity.set_sat_document(&document);
|
||||
|
||||
let Some(display) = self.tabs[i].scene.prepare_solid_model_display(handle, &result)
|
||||
.filter(|display| display.0.complete)
|
||||
else {
|
||||
self.command_line.push_error(crate::t!("The result could not be displayed completely. The original solid was retained.").as_ref());
|
||||
return false;
|
||||
};
|
||||
self.push_undo_snapshot(i, label);
|
||||
self.tabs[i].scene.delete_solid_history(handle);
|
||||
if !self.tabs[i]
|
||||
.scene
|
||||
.update_entity(EntityType::Solid3D(entity))
|
||||
{
|
||||
self.command_line
|
||||
.push_error(crate::t!("The solid could not be updated.").as_ref());
|
||||
return false;
|
||||
}
|
||||
let history = solid_history::brep_op(&result);
|
||||
self.tabs[i].scene.create_solid_history(handle, history);
|
||||
self.tabs[i].scene.register_prepared_solid_model(handle, result, display);
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].scene.select_entity(handle, false);
|
||||
self.tabs[i].dirty = true;
|
||||
self.refresh_properties();
|
||||
true
|
||||
}
|
||||
|
||||
fn replace_solid_body_with_fillet(
|
||||
&mut self,
|
||||
handle: Handle,
|
||||
@@ -605,17 +583,12 @@ impl super::OpenCADStudio {
|
||||
radius: f64,
|
||||
) -> bool {
|
||||
let i = self.active_tab;
|
||||
let Some(document) = crate::scene::convert::acis_export::solid_to_sat(&result) else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("The result could not be encoded as ACIS.").as_ref());
|
||||
return false;
|
||||
};
|
||||
let Some(display) = self.tabs[i]
|
||||
.scene
|
||||
.prepare_solid_model_display(handle, &result)
|
||||
.filter(|display| display.0.complete)
|
||||
else {
|
||||
self.command_line.push_error(crate::t!("The result could not be displayed completely. The original solid was retained.").as_ref());
|
||||
self.command_line.push_error(crate::t!("The result could not be displayed completely. The original edge body was retained.").as_ref());
|
||||
return false;
|
||||
};
|
||||
let ordered = source.edge_keys().collect::<Vec<_>>();
|
||||
@@ -630,7 +603,7 @@ impl super::OpenCADStudio {
|
||||
.collect::<Option<Vec<_>>>()
|
||||
else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("A selected edge no longer belongs to the solid.").as_ref());
|
||||
.push_error(crate::t!("A selected edge no longer belongs to the body.").as_ref());
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -641,7 +614,7 @@ impl super::OpenCADStudio {
|
||||
.create_solid_history(handle, solid_history::brep_op(source))
|
||||
{
|
||||
self.command_line
|
||||
.push_error(crate::t!("The solid history could not be created.").as_ref());
|
||||
.push_error(crate::t!("The edge body history could not be created.").as_ref());
|
||||
return false;
|
||||
}
|
||||
if !self.tabs[i].scene.append_solid_history(
|
||||
@@ -652,20 +625,103 @@ impl super::OpenCADStudio {
|
||||
.push_error(crate::t!("The fillet history could not be recorded.").as_ref());
|
||||
return false;
|
||||
}
|
||||
let Some(EntityType::Solid3D(mut entity)) =
|
||||
self.tabs[i].scene.document.get_entity(handle).cloned()
|
||||
else {
|
||||
let Some(entity) = self.tabs[i].scene.document.get_entity(handle).cloned() else {
|
||||
return false;
|
||||
};
|
||||
entity.wires = solid_model::edge_wires(&result);
|
||||
entity.silhouettes.clear();
|
||||
entity.set_sat_document(&document);
|
||||
if !self.tabs[i]
|
||||
let Some(entity) = entity_with_history_body(entity, &result) else {
|
||||
return false;
|
||||
};
|
||||
if !self.tabs[i].scene.update_entity(entity) {
|
||||
self.command_line
|
||||
.push_error(crate::t!("The edge body could not be updated.").as_ref());
|
||||
return false;
|
||||
}
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.update_entity(EntityType::Solid3D(entity))
|
||||
.register_prepared_solid_model(handle, result, display);
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].scene.select_entity(handle, false);
|
||||
self.tabs[i].dirty = true;
|
||||
self.refresh_properties();
|
||||
true
|
||||
}
|
||||
|
||||
fn replace_edge_body_with_chamfer(
|
||||
&mut self,
|
||||
handle: Handle,
|
||||
source: &Body,
|
||||
result: Body,
|
||||
edges: &[EdgeKey],
|
||||
base_face: FaceKey,
|
||||
base_distance: f64,
|
||||
other_distance: f64,
|
||||
) -> bool {
|
||||
let i = self.active_tab;
|
||||
let Some(display) = self.tabs[i]
|
||||
.scene
|
||||
.prepare_solid_model_display(handle, &result)
|
||||
.filter(|display| display.0.complete)
|
||||
else {
|
||||
self.command_line.push_error(crate::t!("The result could not be displayed completely. The original edge body was retained.").as_ref());
|
||||
return false;
|
||||
};
|
||||
let ordered_edges = source.edge_keys().collect::<Vec<_>>();
|
||||
let Some(history_edges) = edges
|
||||
.iter()
|
||||
.map(|edge| {
|
||||
ordered_edges
|
||||
.iter()
|
||||
.position(|candidate| candidate == edge)
|
||||
.and_then(|ordinal| i32::try_from(ordinal).ok())
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()
|
||||
else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("A selected edge no longer belongs to the body.").as_ref());
|
||||
return false;
|
||||
};
|
||||
let Some(history_face) = source
|
||||
.face_keys()
|
||||
.position(|candidate| candidate == base_face)
|
||||
.and_then(|ordinal| i32::try_from(ordinal).ok())
|
||||
else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("The selected base face no longer belongs to the body.").as_ref());
|
||||
return false;
|
||||
};
|
||||
|
||||
self.push_undo_snapshot(i, "CHAMFEREDGE");
|
||||
if self.tabs[i].scene.document.solid_history_graph(handle).is_none()
|
||||
&& !self.tabs[i]
|
||||
.scene
|
||||
.create_solid_history(handle, solid_history::brep_op(source))
|
||||
{
|
||||
self.command_line
|
||||
.push_error(crate::t!("The solid could not be updated.").as_ref());
|
||||
.push_error(crate::t!("The edge body history could not be created.").as_ref());
|
||||
return false;
|
||||
}
|
||||
if !self.tabs[i].scene.append_solid_history(
|
||||
handle,
|
||||
solid_history::chamfer_op(
|
||||
history_edges,
|
||||
history_face,
|
||||
base_distance,
|
||||
other_distance,
|
||||
),
|
||||
) {
|
||||
self.command_line
|
||||
.push_error(crate::t!("The chamfer history could not be recorded.").as_ref());
|
||||
return false;
|
||||
}
|
||||
let Some(entity) = self.tabs[i].scene.document.get_entity(handle).cloned() else {
|
||||
return false;
|
||||
};
|
||||
let Some(entity) = entity_with_history_body(entity, &result) else {
|
||||
return false;
|
||||
};
|
||||
if !self.tabs[i].scene.update_entity(entity) {
|
||||
self.command_line
|
||||
.push_error(crate::t!("The edge body could not be updated.").as_ref());
|
||||
return false;
|
||||
}
|
||||
self.tabs[i]
|
||||
@@ -682,19 +738,20 @@ impl super::OpenCADStudio {
|
||||
&mut self,
|
||||
handle: Handle,
|
||||
edges: &[EdgeKey],
|
||||
base_face: Option<FaceKey>,
|
||||
value: f64,
|
||||
other_value: f64,
|
||||
fillet: bool,
|
||||
) -> Task<Message> {
|
||||
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(_))
|
||||
) {
|
||||
if !matches!(self.tabs[i].scene.document.get_entity(handle), Some(
|
||||
EntityType::Solid3D(_) | EntityType::Surface(_)
|
||||
)) {
|
||||
self.command_line
|
||||
.push_error(crate::t!("Select a 3D solid edge.").as_ref());
|
||||
.push_error(crate::t!("Select a 3D solid or surface edge.").as_ref());
|
||||
return Task::none();
|
||||
}
|
||||
self.tabs[i].scene.restore_solid_models(&[handle]);
|
||||
@@ -713,9 +770,25 @@ impl super::OpenCADStudio {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
edges
|
||||
.first()
|
||||
.and_then(|edge| cadkernel::brep::chamfer(&body, *edge, value))
|
||||
let Some(base_face) = base_face else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("CHAMFEREDGE: select a base face edge.").as_ref());
|
||||
return Task::none();
|
||||
};
|
||||
match cadkernel::brep::chamfer_edges(
|
||||
&body,
|
||||
edges,
|
||||
base_face,
|
||||
value,
|
||||
other_value,
|
||||
) {
|
||||
Ok(result) => Some(result),
|
||||
Err(error) => {
|
||||
self.command_line
|
||||
.push_error(&format!("CHAMFEREDGE: {error}"));
|
||||
return Task::none();
|
||||
}
|
||||
}
|
||||
};
|
||||
let Some(result) = result else {
|
||||
self.command_line.push_error(
|
||||
@@ -724,13 +797,25 @@ impl super::OpenCADStudio {
|
||||
);
|
||||
return Task::none();
|
||||
};
|
||||
let label = if fillet { "FILLETEDGE" } else { "SOLIDCHAMFER" };
|
||||
let label = if fillet { "FILLETEDGE" } else { "CHAMFEREDGE" };
|
||||
let updated = if fillet {
|
||||
self.replace_solid_body_with_fillet(handle, &body, result, edges, value)
|
||||
} else {
|
||||
self.replace_solid_body(handle, result, label)
|
||||
self.replace_edge_body_with_chamfer(
|
||||
handle,
|
||||
&body,
|
||||
result,
|
||||
edges,
|
||||
base_face.expect("checked chamfer face"),
|
||||
value,
|
||||
other_value,
|
||||
)
|
||||
};
|
||||
if updated {
|
||||
if !fillet {
|
||||
self.tabs[i].scene.document.header.chamfer_distance_a = value;
|
||||
self.tabs[i].scene.document.header.chamfer_distance_b = other_value;
|
||||
}
|
||||
self.command_line
|
||||
.push_output(crate::tf!("{label}: solid updated.").as_ref());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user