From 2be26e9e2e3f09f60c940c527149081ba35f66b9 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 19 Jun 2026 00:05:41 +0300 Subject: [PATCH] fix(snap): object snap takes precedence over ortho/polar When drawing with Ortho (or Polar) on, a point that snapped to an object (e.g. an Endpoint) was still pulled onto the ortho axis, so you couldn't close a shape exactly on an existing vertex. Skip the ortho/polar constraint while an object snap is locked, in both the preview and commit paths. Grid snap is positional rather than an object snap, so it still combines with ortho/polar. (#132) Co-Authored-By: Claude Opus 4.8 --- src/app/update.rs | 63 +++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/src/app/update.rs b/src/app/update.rs index 60dfa7617..07033aa99 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -2760,18 +2760,27 @@ impl OpenCADStudio { .snap_result .map(|s| self.tabs[i].scene.paper_to_model(s.world)) .unwrap_or(cursor_world); - if let Some(base) = self.last_point { - if self.ortho_mode { - pt = ortho_constrain(pt, base); - } else if self.polar_mode { - pt = polar_constrain_near( - pt, - base, - self.polar_increment_deg, - view_proj, - bounds, - self.snapper.osnap_radius_px, - ); + // Object snap wins over ortho/polar: a snapped point + // is taken as-is so it isn't pulled onto the ortho + // axis. Grid snap is positional, not an object snap, + // so it still combines with ortho/polar. (#132) + let osnap_locked = self.tabs[i] + .snap_result + .is_some_and(|s| s.snap_type != crate::snap::SnapType::Grid); + if !osnap_locked { + if let Some(base) = self.last_point { + if self.ortho_mode { + pt = ortho_constrain(pt, base); + } else if self.polar_mode { + pt = polar_constrain_near( + pt, + base, + self.polar_increment_deg, + view_proj, + bounds, + self.snapper.osnap_radius_px, + ); + } } } pt @@ -3360,18 +3369,24 @@ impl OpenCADStudio { if self.tabs[i].active_ucs.is_none() { pt.z = 0.0; } - } else if let Some(base) = self.last_point { - if self.ortho_mode { - pt = ortho_constrain(pt, base); - } else if self.polar_mode { - pt = polar_constrain_near( - pt, - base, - self.polar_increment_deg, - vp_mat, - bounds, - self.snapper.osnap_radius_px, - ); + } else if !snap_hit + .is_some_and(|s| s.snap_type != crate::snap::SnapType::Grid) + { + // Object snap wins over ortho/polar — a snapped point + // commits as-is. Grid snap still combines. (#132) + if let Some(base) = self.last_point { + if self.ortho_mode { + pt = ortho_constrain(pt, base); + } else if self.polar_mode { + pt = polar_constrain_near( + pt, + base, + self.polar_increment_deg, + vp_mat, + bounds, + self.snapper.osnap_radius_px, + ); + } } } pt