fix(osnap): snap to 3D solids and meshes through edge wires (#1030)

Volume entities (Solid3D/Region/Body/Surface, OBJ-imported and SubD
meshes, polyface meshes) render through the mesh pipeline and their
wire path was deliberately empty, so the snapper had no candidates:
END/MID/NEA/PER/INT never fired on them — only Insertion at the
reference point. Each volume entity now contributes one interaction-
only edge wire (B-rep edge chains where the entity stores them, LOD-0
triangle edges otherwise, 100k-point cap), invisible to rendering and
PDF export, riding the normal wire set so the interaction index,
tiers, and 2D-wins priority apply unchanged. The SubD key_vertices
list no longer fabricates floating midpoints. Scene-level test drives
the exact OBJ-import path (Solid3D + meshes cache) through the real
snapper; INSERT-nested solids remain scoped out (block-cache path has
no mesh cache yet).
This commit is contained in:
Afonsop committed 2026-09-17 15:26:50 +01:00
1 parent 99fca8b74b
commit 02d9273a19
6 files changed
+488 -10

No files matched your search

+21
View File
@@ -269,6 +269,27 @@ pub fn edge_wires(body: &Body) -> Vec<acadrust::entities::Wire> {
.collect()
}
/// Interaction-only snap wire for a volume entity's stored edge `Wire`s
/// (`Solid3D::wires` and friends — pre-computed B-rep edge chains, also set
/// on the temporary live-section entity). Each chain contributes its
/// consecutive point pairs as snap segments (#1030). Returns `None` when the
/// chains carry no usable segments or exceed the shared snap-wire point cap.
pub fn entity_edge_snap_wire(
chains: &[acadrust::entities::Wire],
name: String,
color: [f32; 4],
) -> Option<WireModel> {
let pairs = chains.iter().flat_map(|chain| {
chain.points.windows(2).map(|segment| {
(
[segment[0].x, segment[0].y, segment[0].z],
[segment[1].x, segment[1].y, segment[1].z],
)
})
});
super::mesh_model::edge_snap_wire(name, color, false, pairs)
}
/// White wireframe used while a solid-history grip is hot. Surface previews
/// include the requested construction isolines so their cage follows the edit.
///