forked from 1b-agent/opencadstudio-upstream
Merge pull request #717 from gianlucafiore/fix/716-perpendicular-tracking
Fix perpendicular and OTRACK snap interactions
This commit is contained in:
2 files changed
+50
-31
No files matched your search
@@ -1097,10 +1097,8 @@ impl OpenCADStudio {
|
||||
// Grip edits use the same tracking-point acquisition and OTRACK
|
||||
// resolution as normal interactive point commands.
|
||||
let otrack_hit = {
|
||||
let snap_world = snap_hit.map(|s| s.world);
|
||||
|
||||
self.snapper.update_otrack_dwell(
|
||||
snap_world,
|
||||
snap_hit,
|
||||
&snap_candidates,
|
||||
view_rot,
|
||||
eye,
|
||||
@@ -1543,9 +1541,8 @@ impl OpenCADStudio {
|
||||
// to a tracking ray (and store the alignment so a typed
|
||||
// distance can place a point along it — issue #69).
|
||||
let otrack_hit = {
|
||||
let snap_world = self.tabs[i].snap_result.map(|s| s.world);
|
||||
self.snapper.update_otrack_dwell(
|
||||
snap_world,
|
||||
self.tabs[i].snap_result,
|
||||
&snap_candidates,
|
||||
view_rot,
|
||||
eye,
|
||||
@@ -1562,7 +1559,11 @@ impl OpenCADStudio {
|
||||
bounds,
|
||||
Instant::now(),
|
||||
);
|
||||
if self.tabs[i].snap_result.is_none() {
|
||||
if self.tabs[i].snap_result.is_none()
|
||||
|| self.tabs[i]
|
||||
.snap_result
|
||||
.is_some_and(|s| s.snap_type == crate::snap::SnapType::Extension)
|
||||
{
|
||||
// A window corner is a free point, so neither the
|
||||
// Polar increment nor the Ortho lock may pull the
|
||||
// OTRACK alignment onto an axis (#291).
|
||||
@@ -2901,7 +2902,10 @@ impl OpenCADStudio {
|
||||
}
|
||||
// OTRACK alignment wins over ortho/polar; otherwise apply
|
||||
// ortho/polar relative to the last point.
|
||||
let otrack = if !world_pt_locked && snap_hit.is_none() {
|
||||
let otrack = if !world_pt_locked
|
||||
&& (snap_hit.is_none()
|
||||
|| snap_hit.is_some_and(|s| s.snap_type == crate::snap::SnapType::Extension))
|
||||
{
|
||||
let step = if self.polar_mode && !is_window_corner {
|
||||
Some(self.polar_increment_deg)
|
||||
} else {
|
||||
|
||||
+39
-24
@@ -285,7 +285,7 @@ impl Snapper {
|
||||
/// `snap_world` is the current snap result world point (if any).
|
||||
pub fn update_otrack_dwell<W: WireSource + ?Sized>(
|
||||
&mut self,
|
||||
snap_world: Option<DVec3>,
|
||||
snap: Option<SnapResult>,
|
||||
wires: &W,
|
||||
view_rot: glam::Mat4,
|
||||
eye: glam::DVec3,
|
||||
@@ -302,6 +302,24 @@ impl Snapper {
|
||||
self.dwell_acquired = false;
|
||||
return;
|
||||
}
|
||||
// Only stable geometric snap points may be acquired automatically for
|
||||
// OTRACK. Continuous/contextual snaps such as Nearest, Perpendicular,
|
||||
// Tangent and Extension can move along geometry and would otherwise
|
||||
// create arbitrary tracking points while the cursor is hovering. (#716)
|
||||
let snap_world = snap.and_then(|hit| {
|
||||
matches!(
|
||||
hit.snap_type,
|
||||
SnapType::Endpoint
|
||||
| SnapType::Midpoint
|
||||
| SnapType::Center
|
||||
| SnapType::Node
|
||||
| SnapType::Quadrant
|
||||
| SnapType::Intersection
|
||||
| SnapType::Insertion
|
||||
| SnapType::ApparentIntersection
|
||||
)
|
||||
.then_some(hit.world)
|
||||
});
|
||||
// With OTRACK off, acquisition is Extension-driven, and Extension tracks
|
||||
// a line only from a real segment endpoint — so acquire endpoints only.
|
||||
// This stops a paused cursor on an extension foot (or a midpoint/centre)
|
||||
@@ -1186,33 +1204,30 @@ impl Snapper {
|
||||
}
|
||||
|
||||
// ── Perpendicular — foot of perpendicular from the drawing base ──
|
||||
// Drop the foot from the point the command is drawing *from* (so the
|
||||
// new segment is truly perpendicular to the target). Only when there
|
||||
// is no base point — e.g. picking the very first point — does it fall
|
||||
// back to the cursor (a plain nearest-on-line). The candidate is gated
|
||||
// on its screen distance to the cursor like every other snap, so it
|
||||
// offers when the cursor is near the perpendicular foot. (#118)
|
||||
// A perpendicular snap requires a real drawing base. Without one
|
||||
// (for example while picking the first point of LINE) there is no
|
||||
// meaningful perpendicular direction, so do not offer a candidate.
|
||||
// Falling back to the cursor here would make Perpendicular behave
|
||||
// like Nearest. (#716)
|
||||
if self.is_on(SnapType::Perpendicular) {
|
||||
let q = self
|
||||
.from_point
|
||||
.map(|v| v.as_dvec3())
|
||||
.unwrap_or(cursor_world);
|
||||
if let Some(segments) = &local_segments {
|
||||
for seg in segments {
|
||||
if let Some(foot) = perp_foot(q, seg.a, seg.b) {
|
||||
try_pt(foot, SnapType::Perpendicular);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if !wire_in_range(wire) {
|
||||
continue;
|
||||
}
|
||||
for i in 0..wire.points.len().saturating_sub(1) {
|
||||
if let Some(foot) = perp_foot(q, wp_f64(wire, i), wp_f64(wire, i + 1)) {
|
||||
if let Some(q) = self.from_point.map(|v| v.as_dvec3()) {
|
||||
if let Some(segments) = &local_segments {
|
||||
for seg in segments {
|
||||
if let Some(foot) = perp_foot(q, seg.a, seg.b) {
|
||||
try_pt(foot, SnapType::Perpendicular);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if !wire_in_range(wire) {
|
||||
continue;
|
||||
}
|
||||
for i in 0..wire.points.len().saturating_sub(1) {
|
||||
if let Some(foot) = perp_foot(q, wp_f64(wire, i), wp_f64(wire, i + 1)) {
|
||||
try_pt(foot, SnapType::Perpendicular);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user