forked from 1b-agent/opencadstudio-upstream
fix(select): click the front-most solid across top-level and block bodies
Clicking a block whose body is a solid tried top-level solid meshes first and block-internal ones only as a fallback, so a stray solid behind the block always won and the block couldn't be picked. Merge both into one depth-sorted hit-test (solid_click_hit) keyed by the solid's own handle or the parent INSERT, so the front-most body wins regardless of kind. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
d1395e8f3d
commit
cd10aa0363
2 files changed
+48
-3
No files matched your search
+5
-3
@@ -3880,8 +3880,10 @@ impl OpenCADStudio {
|
||||
})
|
||||
.or_else(|| {
|
||||
// 3D solids: click anywhere on the shaded
|
||||
// body, not just the thin projected edges.
|
||||
self.tabs[i].scene.mesh_click_hit(p, vp_mat, bounds)
|
||||
// body — top-level solids and block-internal
|
||||
// ones together, front-most wins (a block in
|
||||
// front of a solid resolves to the block).
|
||||
self.tabs[i].scene.solid_click_hit(p, vp_mat, bounds)
|
||||
});
|
||||
// Selection filter: drop a pick whose type is excluded.
|
||||
let hit =
|
||||
@@ -4376,7 +4378,7 @@ impl OpenCADStudio {
|
||||
bounds,
|
||||
)
|
||||
})
|
||||
.or_else(|| self.tabs[i].scene.mesh_click_hit(p, view_proj, bounds));
|
||||
.or_else(|| self.tabs[i].scene.solid_click_hit(p, view_proj, bounds));
|
||||
self.tabs[i].scene.set_hover_highlight(hovered);
|
||||
self.hover_dwell = None;
|
||||
Task::none()
|
||||
|
||||
@@ -2310,6 +2310,49 @@ impl Scene {
|
||||
pick::hit_test::mesh_poly_hit(poly, crossing, iter, view_proj, bounds)
|
||||
}
|
||||
|
||||
/// Front-most solid under the cursor across BOTH top-level solid meshes
|
||||
/// (keyed by their own handle) and block-internal solid instances (keyed
|
||||
/// by the parent INSERT). Combining them in one depth-sorted test means a
|
||||
/// block in front of a stray solid wins, instead of the solid always
|
||||
/// taking priority by virtue of being tried first.
|
||||
pub fn solid_click_hit(
|
||||
&self,
|
||||
cursor: iced::Point,
|
||||
view_proj: glam::Mat4,
|
||||
bounds: iced::Rectangle,
|
||||
) -> Option<Handle> {
|
||||
// Block-internal instances must be owned (transformed copies); keep
|
||||
// them in a Vec and chain references alongside the top-level meshes so
|
||||
// neither set is cloned wholesale.
|
||||
let mut block_owned: Vec<(Handle, crate::scene::model::mesh_model::MeshModel)> = Vec::new();
|
||||
if !self.block_meshes.is_empty() {
|
||||
let layout_block = self.current_layout_block_handle();
|
||||
let woff = self.world_offset;
|
||||
for e in self.document.entities() {
|
||||
if e.common().owner_handle != layout_block {
|
||||
continue;
|
||||
}
|
||||
let EntityType::Insert(ins) = e else { continue };
|
||||
if !self.mesh_entity_visible(ins.common.handle) {
|
||||
continue;
|
||||
}
|
||||
let mut sets = Vec::new();
|
||||
self.expand_block_meshes(&ins.block_name, &ins.get_transform(), 0, woff, &mut sets);
|
||||
for set in sets {
|
||||
if let Some(m) = set.lods.into_iter().next() {
|
||||
block_owned.push((ins.common.handle, m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let top = self
|
||||
.meshes
|
||||
.iter()
|
||||
.filter_map(|(h, set)| set.lods.first().map(|m| (*h, m)));
|
||||
let blk = block_owned.iter().map(|(h, m)| (*h, m));
|
||||
pick::hit_test::mesh_click_hit(cursor, top.chain(blk), view_proj, bounds)
|
||||
}
|
||||
|
||||
/// Parent INSERT handles whose block-internal solid meshes fall in a
|
||||
/// rectangular selection box. A block whose visible body is a solid has
|
||||
/// no wires to catch, so box/lasso selection must test its instanced
|
||||
|
||||
Reference in new issue
Block a user