fix(hit_test): correct hatch selection — NaN-aware ray-cast + block-insert resolve
Two related click bugs: 1. `point_in_polygon` treated NaN points (the path separators used by multi-path hatches with islands / holes) as regular vertices, producing spurious closing edges between sub-paths. The cursor inside a real hatch failed the test → the click iterator moved on to the NEXT hatch in HashMap order and silently returned the wrong one. Rewrite the ray-cast to reset the previous-vertex / path-start state at every NaN, so each sub-path closes against its own first vertex and contributes its parity flip correctly. 2. Clicking on a hatch *inside* a block was either missing entirely (after the visible_hatches_for_click filter) or returning the block-defn source hatch handle (misleading — that handle isn't the thing the user sees). AutoCAD selects the parent Insert when a sub-entity of a block is clicked. Add `Scene::insert_hatches_for_click` which walks the same explode path `synced_hatch_models` uses and tags every exploded sub-hatch with its parent Insert handle, plus `hit_test::click_hit_insert_hatch` which iterates that list. The click resolver now tries wire → MSPACE hatch → insert-internal hatch in order, so clicking on a block-internal hatch selects the Insert. Box / lasso select paths are unchanged — wire hit-test already picks up Inserts, and dragging a box over block-internal hatches is rare enough not to need its own resolution path yet. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
0f252e8b53
commit
c815be9c6f
3 changed files with 174 additions and 20 deletions
|
|
@ -1103,6 +1103,79 @@ impl Scene {
|
|||
arc
|
||||
}
|
||||
|
||||
/// Hatches eligible for click / box / lasso hit-testing in the current
|
||||
/// layout. Filters out block-internal source hatches (stored in
|
||||
/// `self.hatches` at block-local coords for the block-defn position,
|
||||
/// which doesn't project correctly through the offset-rel view_proj
|
||||
/// and was causing the wrong hatch to be selected on click).
|
||||
pub fn visible_hatches_for_click(&self) -> HashMap<Handle, HatchModel> {
|
||||
let layout_block = self.current_layout_block_handle();
|
||||
self.hatches
|
||||
.iter()
|
||||
.filter_map(|(&h, m)| {
|
||||
let owner = self.document.get_entity(h)?.common().owner_handle;
|
||||
if self.belongs_to_visible_block(h, owner, layout_block) {
|
||||
Some((h, m.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Per-Insert hatch models in the current layout, keyed by the Insert
|
||||
/// handle so a click on a block-internal hatch can select the parent
|
||||
/// Insert (AutoCAD behaviour: sub-entities of a block aren't directly
|
||||
/// selectable; the click resolves to the Insert).
|
||||
pub fn insert_hatches_for_click(&self) -> Vec<(Handle, HatchModel)> {
|
||||
let layout_block = self.current_layout_block_handle();
|
||||
let hatch_offset = if self.current_layout == "Model" {
|
||||
self.world_offset
|
||||
} else {
|
||||
[0.0; 3]
|
||||
};
|
||||
let layer_hidden = |layer: &str| {
|
||||
self.document
|
||||
.layers
|
||||
.get(layer)
|
||||
.map(|l| l.flags.off || l.flags.frozen)
|
||||
.unwrap_or(false)
|
||||
};
|
||||
let mut out: Vec<(Handle, HatchModel)> = Vec::new();
|
||||
for entity in self.document.entities() {
|
||||
let EntityType::Insert(ins) = entity else {
|
||||
continue;
|
||||
};
|
||||
if ins.common.invisible || layer_hidden(&ins.common.layer) {
|
||||
continue;
|
||||
}
|
||||
if !self.belongs_to_visible_block(
|
||||
ins.common.handle,
|
||||
ins.common.owner_handle,
|
||||
layout_block,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
for sub in ins
|
||||
.explode_from_document(&self.document)
|
||||
.into_iter()
|
||||
.map(crate::modules::home::modify::explode::normalize_insert_entity)
|
||||
{
|
||||
let EntityType::Hatch(dxf) = sub else {
|
||||
continue;
|
||||
};
|
||||
if dxf.common.invisible || layer_hidden(&dxf.common.layer) {
|
||||
continue;
|
||||
}
|
||||
let color = self.render_style(&EntityType::Hatch(dxf.clone())).0;
|
||||
if let Some(model) = Self::hatch_model_from_dxf(&dxf, color, hatch_offset) {
|
||||
out.push((ins.common.handle, model));
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Wires that should participate in hit-testing, snapping, and selection.
|
||||
///
|
||||
/// - Model layout: all entity wires (same as entity_wires).
|
||||
|
|
|
|||
Loading…
Reference in a new issue