forked from 1b-agent/opencadstudio-upstream
fix(osnap): snap to arc/circle centre when hovering the curve (#152)
The Center object snap was a pre-baked point gated purely on the cursor's screen distance to the centre point. A circle's centre sits inside it and an arc's centre is usually off in empty space well away from the curve, so hovering the curve — the natural gesture — never landed within the snap radius and no centre marker appeared. Add a curve-proximity pass: when Center is enabled and the cursor is near a circle/arc/ellipse curve, offer that curve's centre, ranked by the cursor's distance to the curve. It runs after the `try_pt` closure's borrow ends so it can update the candidate state directly, mirroring the Tangent pass. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
6fb5c89a7b
commit
ce2365e8f9
1 file changed
+49
@@ -892,6 +892,55 @@ impl Snapper {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Center via curve proximity ─────────────────────────────────────
|
||||
// A circle/arc/ellipse's centre is offset from its curve — for an arc
|
||||
// it usually sits in empty space well off the geometry — so gating the
|
||||
// Center snap purely on the cursor's distance to the centre *point*
|
||||
// (the pre-baked pass above) means hovering the curve, the natural
|
||||
// gesture, never offers it. Mirror running-osnap behaviour: when the
|
||||
// cursor is near such a curve, offer its centre, ranked by how close
|
||||
// the cursor is to the curve. Runs here, after `try_pt`'s borrow ends,
|
||||
// so it can update the candidate state directly. (#152)
|
||||
if self.is_on(SnapType::Center) {
|
||||
for wire in wires {
|
||||
if !wire_in_range(wire) {
|
||||
continue;
|
||||
}
|
||||
// Only tessellated curves carry a pre-baked Center hint; reuse
|
||||
// it as the snap target. Lines / polylines have none → skip.
|
||||
let Some(center) = wire
|
||||
.snap_pts
|
||||
.iter()
|
||||
.find(|(_, h)| matches!(h, SnapHint::Center))
|
||||
.map(|&(c, _)| c)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
// Nearest screen distance from the cursor to the curve itself.
|
||||
let mut curve_d2 = f32::INFINITY;
|
||||
for i in 0..wire.points.len().saturating_sub(1) {
|
||||
let p = nearest_on_segment(cursor_world, wp_f64(wire, i), wp_f64(wire, i + 1));
|
||||
let sp = world_to_screen(p, view_rot, eye, bounds);
|
||||
curve_d2 = curve_d2.min(dist2(sp, cursor_screen));
|
||||
}
|
||||
let screen = world_to_screen(center, view_rot, eye, bounds);
|
||||
let rank = snap_priority(SnapType::Center);
|
||||
if curve_d2 < radius2
|
||||
&& in_bounds(screen)
|
||||
&& (rank < best_rank || (rank == best_rank && curve_d2 < best_d2))
|
||||
{
|
||||
best_rank = rank;
|
||||
best_d2 = curve_d2;
|
||||
best = Some(SnapResult {
|
||||
world: center,
|
||||
screen,
|
||||
snap_type: SnapType::Center,
|
||||
tangent_obj: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
best
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user