fix(model): repair solid booleans
Track selection order for directional subtraction and use the kernel fixes for periodic curved-face intersections.\n\nRefs #816
This commit is contained in:
commit
bb49f92e99
5 changed files with 57 additions and 10 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -878,7 +878,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cadkernel"
|
name = "cadkernel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=eda1263#eda1263da23c1b18e7593151a277a0593bb317ef"
|
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=3d5de36#3d5de36cb5b391f17da924c5f80e34a0cdc1d948"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"acadrust",
|
"acadrust",
|
||||||
"cavalier_contours",
|
"cavalier_contours",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ rfd = "0.17"
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "0975677", features = ["serde"] }
|
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "0975677", features = ["serde"] }
|
||||||
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "eda1263", features = ["acis", "offset"] }
|
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "3d5de36", features = ["acis", "offset"] }
|
||||||
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,8 @@ impl super::OpenCADStudio {
|
||||||
// Selected entities that have a cached B-rep.
|
// Selected entities that have a cached B-rep.
|
||||||
let handles: Vec<Handle> = self.tabs[i]
|
let handles: Vec<Handle> = self.tabs[i]
|
||||||
.scene
|
.scene
|
||||||
.selected
|
.selected_handles_in_order()
|
||||||
.iter()
|
.into_iter()
|
||||||
.copied()
|
|
||||||
.filter(|h| !self.tabs[i].scene.is_layer_locked(*h))
|
.filter(|h| !self.tabs[i].scene.is_layer_locked(*h))
|
||||||
.filter(|h| self.tabs[i].scene.solid_models.contains_key(h))
|
.filter(|h| self.tabs[i].scene.solid_models.contains_key(h))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
||||||
|
|
@ -1422,6 +1422,7 @@ pub struct Scene {
|
||||||
lighting_cache: RefCell<HashMap<(Handle, u64), Vec<SceneLight>>>,
|
lighting_cache: RefCell<HashMap<(Handle, u64), Vec<SceneLight>>>,
|
||||||
/// Currently selected entity handles.
|
/// Currently selected entity handles.
|
||||||
pub selected: HashSet<Handle>,
|
pub selected: HashSet<Handle>,
|
||||||
|
selected_order: Vec<Handle>,
|
||||||
/// Session-only ISOLATEOBJECTS / HIDEOBJECTS state. Never written to DWG/DXF.
|
/// Session-only ISOLATEOBJECTS / HIDEOBJECTS state. Never written to DWG/DXF.
|
||||||
pub object_isolation: ObjectIsolationState,
|
pub object_isolation: ObjectIsolationState,
|
||||||
/// Entity handles temporarily removed from the base render while an
|
/// Entity handles temporarily removed from the base render while an
|
||||||
|
|
@ -1841,6 +1842,7 @@ impl Scene {
|
||||||
object_data_cache: crate::entities::object_data::ObjectDataCache::default(),
|
object_data_cache: crate::entities::object_data::ObjectDataCache::default(),
|
||||||
lighting_cache: RefCell::new(HashMap::default()),
|
lighting_cache: RefCell::new(HashMap::default()),
|
||||||
selected: HashSet::default(),
|
selected: HashSet::default(),
|
||||||
|
selected_order: Vec::new(),
|
||||||
object_isolation: ObjectIsolationState::default(),
|
object_isolation: ObjectIsolationState::default(),
|
||||||
preview_hidden: HashSet::default(),
|
preview_hidden: HashSet::default(),
|
||||||
command_preview_hidden: HashSet::default(),
|
command_preview_hidden: HashSet::default(),
|
||||||
|
|
@ -4377,6 +4379,7 @@ impl Scene {
|
||||||
.hidden
|
.hidden
|
||||||
.extend(self.selected.iter().copied());
|
.extend(self.selected.iter().copied());
|
||||||
self.selected.clear();
|
self.selected.clear();
|
||||||
|
self.selected_order.clear();
|
||||||
self.bump_entities(&changes);
|
self.bump_entities(&changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,17 +40,42 @@ impl Scene {
|
||||||
|
|
||||||
if exclusive {
|
if exclusive {
|
||||||
self.selected.clear();
|
self.selected.clear();
|
||||||
|
self.selected_order.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.selected.extend(handles);
|
for handle in handles {
|
||||||
|
if self.selected.insert(handle) {
|
||||||
|
self.selected_order.push(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.bump_selection();
|
self.bump_selection();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deselect_all(&mut self) {
|
pub fn deselect_all(&mut self) {
|
||||||
self.selected.clear();
|
self.selected.clear();
|
||||||
|
self.selected_order.clear();
|
||||||
self.bump_selection();
|
self.bump_selection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn selected_handles_in_order(&self) -> Vec<Handle> {
|
||||||
|
let mut seen = HashSet::default();
|
||||||
|
let mut ordered: Vec<_> = self
|
||||||
|
.selected_order
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|handle| self.selected.contains(handle) && seen.insert(*handle))
|
||||||
|
.collect();
|
||||||
|
let mut missing: Vec<_> = self
|
||||||
|
.selected
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|handle| seen.insert(*handle))
|
||||||
|
.collect();
|
||||||
|
missing.sort_unstable_by_key(|handle| handle.value());
|
||||||
|
ordered.extend(missing);
|
||||||
|
ordered
|
||||||
|
}
|
||||||
|
|
||||||
/// Replace the complete selection and invalidate the GPU highlight overlay
|
/// Replace the complete selection and invalidate the GPU highlight overlay
|
||||||
/// only when its contents actually changed. History/file/command paths must
|
/// only when its contents actually changed. History/file/command paths must
|
||||||
/// use this instead of assigning `selected` directly.
|
/// use this instead of assigning `selected` directly.
|
||||||
|
|
@ -62,7 +87,22 @@ impl Scene {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if self.selected != selected {
|
if self.selected != selected {
|
||||||
|
let mut seen = HashSet::default();
|
||||||
|
let mut order: Vec<_> = self
|
||||||
|
.selected_order
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|handle| selected.contains(handle) && seen.insert(*handle))
|
||||||
|
.collect();
|
||||||
|
let mut added: Vec<_> = selected
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|handle| seen.insert(*handle))
|
||||||
|
.collect();
|
||||||
|
added.sort_unstable_by_key(|handle| handle.value());
|
||||||
|
order.extend(added);
|
||||||
self.selected = selected;
|
self.selected = selected;
|
||||||
|
self.selected_order = order;
|
||||||
self.bump_selection();
|
self.bump_selection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +114,7 @@ impl Scene {
|
||||||
|
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
changed |= self.selected.remove(&handle);
|
changed |= self.selected.remove(&handle);
|
||||||
|
self.selected_order.retain(|selected| *selected != handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if changed {
|
if changed {
|
||||||
|
|
@ -82,9 +123,9 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selected_entities(&self) -> Vec<(Handle, &EntityType)> {
|
pub fn selected_entities(&self) -> Vec<(Handle, &EntityType)> {
|
||||||
self.selected
|
self.selected_handles_in_order()
|
||||||
.iter()
|
.into_iter()
|
||||||
.filter_map(|&h| self.document.get_entity(h).map(|e| (h, e)))
|
.filter_map(|h| self.document.get_entity(h).map(|e| (h, e)))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +148,7 @@ impl Scene {
|
||||||
match scope {
|
match scope {
|
||||||
crate::app::QSelectScope::CurrentSpace => self.current_layout_entity_handles(),
|
crate::app::QSelectScope::CurrentSpace => self.current_layout_entity_handles(),
|
||||||
crate::app::QSelectScope::CurrentSelection => {
|
crate::app::QSelectScope::CurrentSelection => {
|
||||||
self.selected.iter().copied().collect()
|
self.selected_handles_in_order()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -152,6 +193,7 @@ impl Scene {
|
||||||
let key = (entity_type_name(e), e.as_entity().layer().to_string());
|
let key = (entity_type_name(e), e.as_entity().layer().to_string());
|
||||||
if pairs.contains(&key) {
|
if pairs.contains(&key) {
|
||||||
self.selected.insert(h);
|
self.selected.insert(h);
|
||||||
|
self.selected_order.push(h);
|
||||||
added += 1;
|
added += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -174,9 +216,11 @@ impl Scene {
|
||||||
.filter_map(|w| Self::handle_from_wire_name(&w.name))
|
.filter_map(|w| Self::handle_from_wire_name(&w.name))
|
||||||
.collect();
|
.collect();
|
||||||
self.selected.clear();
|
self.selected.clear();
|
||||||
|
self.selected_order.clear();
|
||||||
for h in all {
|
for h in all {
|
||||||
if !prev.contains(&h) {
|
if !prev.contains(&h) {
|
||||||
self.selected.insert(h);
|
self.selected.insert(h);
|
||||||
|
self.selected_order.push(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.bump_selection();
|
self.bump_selection();
|
||||||
|
|
@ -679,6 +723,7 @@ impl Scene {
|
||||||
self.remember_removed_cache_categories(h);
|
self.remember_removed_cache_categories(h);
|
||||||
self.document.remove_entity_arc(h);
|
self.document.remove_entity_arc(h);
|
||||||
highlight_changed |= self.selected.remove(&h);
|
highlight_changed |= self.selected.remove(&h);
|
||||||
|
self.selected_order.retain(|selected| *selected != h);
|
||||||
if self.hover_highlight == Some(h) {
|
if self.hover_highlight == Some(h) {
|
||||||
self.hover_highlight = None;
|
self.hover_highlight = None;
|
||||||
highlight_changed = true;
|
highlight_changed = true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue