Snap 3D bridge lines to points on other sketch planes (#229)

* Snap 3D bridge drawing to points on visible sketch planes

* Keep cross-sketch point picks out of sketch tools

`pick()` returned every visible sketch's points while 3D drawing was on,
so `sketch_point_at` and the sketch tools could take another sketch's
point as an active-sketch local point plus id (flattening it or making a
bad coincident reference). `pick()` is local again; the bridge snap uses
`pick_3d` explicitly and hover mirrors it for feedback. `sketch_point_at`
also ignores foreign points defensively.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(sketch3d): check local point scope with a sketch tool active

Main's Project preselection fix now offers other sketches' points to idle
selection, so assert the local scope where it still applies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* style: rustfmt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-10-12 11:25:39 -04:00
1 parent cb8aa38cc9
commit e6e0a7ebb5
5 files changed
+163 -6

No files matched your search

+12 -3
View File
@@ -14,7 +14,7 @@ use solvecraft_engine::geom::{Vec2, Vec3};
use crate::SolveApp;
use crate::theme::Tokens;
use crate::tools::Tool;
use crate::viewport::{Hit, Proj, pick};
use crate::viewport::{Hit, Proj, pick_3d};
thread_local! {
/// Points of the curve being drawn in 3D (with the tool they belong to).
@@ -40,6 +40,11 @@ fn takes(cmd: &str) -> bool {
matches!(cmd, "sketch.line" | "sketch.spline.fit_point" | "sketch.point")
}
/// Only 3D point-placing tools broaden sketch-point picking; ordinary selection stays local.
pub fn drawing(app: &SolveApp) -> bool {
active(app) && app.tool.as_ref().is_some_and(|tool| takes(tool.cmd))
}
/// Points drawn in 3D: (wire id, fit index, point).
fn drawn_points(app: &SolveApp) -> Vec<(String, usize, Vec3)> {
let st = app.session.world_state();
@@ -69,9 +74,13 @@ pub fn point_at(app: &SolveApp, proj: &Proj, pos: Pos2) -> Option<(Vec3, &'stati
let st = app.session.world_state();
let ss = app.session.active_sketch.and_then(|s| st.sketch(s))?;
let (o, d) = proj.ray(pos);
for h in pick(app, proj, pos) {
for h in pick_3d(app, proj, pos) {
match h {
Hit::SketchPoint { at, .. } => return Some((ss.plane.to_world(at), "Pt")),
Hit::SketchPoint { sketch, at, .. } => {
if let Some(source) = st.sketch(sketch) {
return Some((source.plane.to_world(at), "Pt"));
}
}
Hit::Vertex { point, .. } => return Some((point, "Vertex")),
Hit::Edge { body, index, .. } => {
let ws = app.session.world_state();