forked from 1b-agent/opencadstudio-upstream
Merge pull request #1118 from MarcelP102/codex/fix-DELOBJ
Implement persistent DELOBJ source deletion policies and cover all four modes through the kernel-backed SWEEP flow.
This commit is contained in:
commit
b19992cbcb
7 files changed
+218
-20
No files matched your search
+113
-10
@@ -1779,7 +1779,7 @@ impl OpenCADStudio {
|
||||
} => {
|
||||
let label = self.history_label_from_active_cmd(i, "SOLID");
|
||||
let erase_source = erase_source.filter(|handle| {
|
||||
self.tabs[i].scene.document.header.delete_objects
|
||||
self.delete_objects != 0
|
||||
&& !self.tabs[i].scene.is_layer_locked(*handle)
|
||||
});
|
||||
let pending = self.begin_undo(
|
||||
@@ -2534,7 +2534,7 @@ impl OpenCADStudio {
|
||||
CmdResult::EditTableCell { handle, point } => {
|
||||
// TABLEDIT's pick: end the pick phase and hand (table, point)
|
||||
// to the shared cell-edit launcher. A miss or a locked cell
|
||||
// re-prompts, matching AutoCAD's select-until-valid loop.
|
||||
// re-prompts until a valid table cell is selected.
|
||||
use crate::modules::annotate::table_cmd::{table_cell_at, TableCellEditStart};
|
||||
self.tabs[i].active_cmd = None;
|
||||
self.tabs[i].snap_result = None;
|
||||
@@ -3661,7 +3661,7 @@ impl OpenCADStudio {
|
||||
taper_angle,
|
||||
color: _,
|
||||
} => {
|
||||
let delete_sources = self.tabs[i].scene.document.header.delete_objects;
|
||||
let delete_sources = self.delete_objects != 0;
|
||||
if handles.is_empty()
|
||||
|| handles
|
||||
.iter()
|
||||
@@ -3948,7 +3948,7 @@ impl OpenCADStudio {
|
||||
self.restore_pre_cmd_tangent();
|
||||
return Task::none();
|
||||
}
|
||||
let delete_sources = self.tabs[i].scene.document.header.delete_objects;
|
||||
let delete_sources = self.delete_objects != 0;
|
||||
use crate::command::ExtrudeMode;
|
||||
use crate::modules::insert::solid3d_cmds::{
|
||||
empty_revolved_surface, empty_solid3d,
|
||||
@@ -4082,7 +4082,8 @@ impl OpenCADStudio {
|
||||
use crate::command::ExtrudeMode;
|
||||
use crate::modules::insert::solid3d_cmds::empty_solid3d;
|
||||
use crate::scene::model::sweep_model;
|
||||
let delete_sources = self.tabs[i].scene.document.header.delete_objects;
|
||||
let delete_objects = self.delete_objects;
|
||||
let delete_profiles = delete_objects != 0;
|
||||
let path = self.tabs[i].scene.document.get_entity(path_handle).cloned();
|
||||
let mut profiles = Vec::new();
|
||||
let mut failed = 0usize;
|
||||
@@ -4120,6 +4121,14 @@ impl OpenCADStudio {
|
||||
failed += 1;
|
||||
continue;
|
||||
};
|
||||
let deletes_path = crate::app::delobj_deletes_auxiliary(
|
||||
delete_objects,
|
||||
surface,
|
||||
);
|
||||
if deletes_path && self.tabs[i].scene.is_layer_locked(path_handle) {
|
||||
failed += 1;
|
||||
continue;
|
||||
}
|
||||
let created = if surface {
|
||||
self.add_surface_model(sweep_model::swept_surface_entity(&record), body)
|
||||
} else {
|
||||
@@ -4132,9 +4141,12 @@ impl OpenCADStudio {
|
||||
failed += 1;
|
||||
} else {
|
||||
created_handles.push(created);
|
||||
if delete_sources {
|
||||
if delete_profiles {
|
||||
consumed.push(handle);
|
||||
}
|
||||
if deletes_path {
|
||||
consumed.push(path_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !created_handles.is_empty() {
|
||||
@@ -4175,12 +4187,14 @@ impl OpenCADStudio {
|
||||
}).collect::<Vec<_>>();
|
||||
sources.sort_unstable_by_key(|handle| handle.value());
|
||||
sources.dedup();
|
||||
let delete_sources = self.tabs[i].scene.document.header.delete_objects;
|
||||
let locked = delete_sources && sources.iter().any(|handle| self.tabs[i].scene.is_layer_locked(*handle));
|
||||
let delete_objects = self.delete_objects;
|
||||
let delete_sections = delete_objects != 0;
|
||||
let section_locked = delete_sections
|
||||
&& sources.iter().any(|handle| self.tabs[i].scene.is_layer_locked(*handle));
|
||||
let available = sources.iter().chain(guides.iter()).copied().chain(path)
|
||||
.filter_map(|handle| self.tabs[i].scene.document.get_entity(handle)
|
||||
.cloned().map(|entity| (handle, entity))).collect::<Vec<_>>();
|
||||
let result = if locked {
|
||||
let result = if section_locked {
|
||||
Err("LOFT: a source is on a locked layer; disable source deletion or unlock it.".to_string())
|
||||
} else {
|
||||
loft_command_model::record(§ions, &guides, path, &available, mode, options)
|
||||
@@ -4189,6 +4203,19 @@ impl OpenCADStudio {
|
||||
match result {
|
||||
Ok((body, record)) => {
|
||||
let surface = record.parameters.as_ref().is_some_and(|settings| settings.surface);
|
||||
let delete_auxiliary = crate::app::delobj_deletes_auxiliary(
|
||||
delete_objects,
|
||||
surface,
|
||||
);
|
||||
if delete_auxiliary
|
||||
&& guides.iter().copied().chain(path)
|
||||
.any(|handle| self.tabs[i].scene.is_layer_locked(handle))
|
||||
{
|
||||
self.command_line.push_error(
|
||||
"LOFT: a source is on a locked layer; disable source deletion or unlock it.",
|
||||
);
|
||||
return Task::none();
|
||||
}
|
||||
let dirty_before = self.tabs[i].dirty;
|
||||
let pending = self.begin_undo(i, "LOFT", 1, true);
|
||||
let created = if surface {
|
||||
@@ -4210,7 +4237,18 @@ impl OpenCADStudio {
|
||||
self.command_line.push_error(crate::t!("LOFT could not create a complete display. The source sections were preserved.").as_ref());
|
||||
return Task::none();
|
||||
} else {
|
||||
if delete_sources { self.tabs[i].scene.erase_entities(&sources); }
|
||||
let mut consumed = if delete_sections {
|
||||
sources.clone()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
if delete_auxiliary {
|
||||
consumed.extend(guides.iter().copied());
|
||||
consumed.extend(path);
|
||||
}
|
||||
consumed.sort_unstable_by_key(|handle| handle.value());
|
||||
consumed.dedup();
|
||||
self.tabs[i].scene.erase_entities(&consumed);
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].scene.select_entity(created, true);
|
||||
self.tabs[i].dirty = true;
|
||||
@@ -5835,6 +5873,71 @@ fn resample_widths(source: &[(f64, f64)], count: usize) -> Vec<(f64, f64)> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_arch = "wasm32")))]
|
||||
mod delobj_tests {
|
||||
use super::*;
|
||||
use acadrust::types::Vector3;
|
||||
|
||||
fn sweep_source_presence(value: i16, mode: crate::command::ExtrudeMode) -> (bool, bool) {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
app.automation_op(r#"{"op":"new"}"#);
|
||||
let i = app.active_tab;
|
||||
let mut circle = acadrust::Circle::new();
|
||||
circle.radius = 2.0;
|
||||
let profile = app.tabs[i]
|
||||
.scene
|
||||
.add_entity(acadrust::EntityType::Circle(circle));
|
||||
let path = app.tabs[i].scene.add_entity(acadrust::EntityType::Line(
|
||||
acadrust::Line::from_points(
|
||||
Vector3::new(0.0, 0.0, 0.0),
|
||||
Vector3::new(0.0, 0.0, 5.0),
|
||||
),
|
||||
));
|
||||
app.delete_objects = value;
|
||||
|
||||
let _ = app.apply_cmd_result(CmdResult::SweepEntities {
|
||||
handles: vec![profile],
|
||||
path_handle: path,
|
||||
mode,
|
||||
options: crate::command::SweepOptions::default(),
|
||||
color: [1.0; 4],
|
||||
});
|
||||
|
||||
let created = app.tabs[i].scene.document.entities().any(|entity| match mode {
|
||||
crate::command::ExtrudeMode::Solid => {
|
||||
matches!(entity, acadrust::EntityType::Solid3D(_))
|
||||
}
|
||||
crate::command::ExtrudeMode::Surface => {
|
||||
matches!(entity, acadrust::EntityType::Surface(_))
|
||||
}
|
||||
});
|
||||
assert!(created, "SWEEP must produce the requested result");
|
||||
(
|
||||
app.tabs[i].scene.document.get_entity(profile).is_some(),
|
||||
app.tabs[i].scene.document.get_entity(path).is_some(),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sweep_applies_all_four_source_deletion_modes() {
|
||||
let solid_expectations = [(true, true), (false, true), (false, false), (false, false)];
|
||||
for (value, expected) in solid_expectations.into_iter().enumerate() {
|
||||
assert_eq!(
|
||||
sweep_source_presence(value as i16, crate::command::ExtrudeMode::Solid),
|
||||
expected,
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
sweep_source_presence(2, crate::command::ExtrudeMode::Surface),
|
||||
(false, false),
|
||||
);
|
||||
assert_eq!(
|
||||
sweep_source_presence(3, crate::command::ExtrudeMode::Surface),
|
||||
(false, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_arch = "wasm32")))]
|
||||
mod thicken_tests {
|
||||
use super::*;
|
||||
|
||||
Reference in new issue
Block a user