@@ -72,6 +72,9 @@ const BEAM_MISS_LENGTH: f32 = 1.0;
7272/// `weapon_muzzle`'s, shared with dark_explorer).
7373const AIM_LINE_HALO : f32 = 0.004 ;
7474const AIM_LINE_CORE : f32 = 0.0012 ;
75+ /// A test-hold nudge let go within this of where it started stages nothing.
76+ const NUDGE_MIN_MM : f32 = 0.1 ;
77+ const NUDGE_MIN_DEG : f32 = 0.01 ;
7578
7679/// Whether a hand's controller is held, so aims the panel ray. The runtime
7780/// must track it; the posing hand's is set down once that hand is tracked.
@@ -564,11 +567,8 @@ impl GripPoseTool {
564567 self . triggers = [ panel:: TriggerArbiter :: new ( ) ; 2 ] ;
565568 self . requested = true ;
566569 self . pinch_lost = true ;
567- self . squeezed = true ;
570+ self . cancel_nudge ( ) ;
568571 self . turning = None ;
569- if let Some ( hold) = self . test_hold . as_mut ( ) {
570- hold. nudge = None ;
571- }
572572 self . stick_armed = false ;
573573 self . poke = Default :: default ( ) ;
574574 // Frames from before the pause are not part of a steady window now.
@@ -749,12 +749,22 @@ impl GripPoseTool {
749749 self . squeezed = squeeze;
750750 }
751751
752+ /// Drop a nudge in progress unstaged (pausing, discarding); the squeeze
753+ /// acts again only once let go.
754+ pub fn cancel_nudge ( & mut self ) {
755+ if let Some ( hold) = self . test_hold . as_mut ( ) {
756+ hold. nudge = None ;
757+ }
758+ self . squeezed = true ;
759+ }
760+
752761 /// Test hold's nudge: from the leading edge of the free controller's
753762 /// squeeze (`controller`, its world pose, `None` while it aims no ray)
754763 /// the item, at `item` as held now, keeps its pose relative to that
755764 /// controller. Returns where the item is as the squeeze lets go, for the
756- /// grip to hold it there. Losing either controller drops the nudge
757- /// unstaged, and the squeeze is disarmed until let go in hand.
765+ /// grip to hold it there, unless that is still where it is held (a
766+ /// squeeze without a move is no edit). Losing either controller drops
767+ /// the nudge unstaged, and the squeeze is disarmed until let go in hand.
758768 pub fn nudge_with (
759769 & mut self ,
760770 controller : Option < GripPose > ,
@@ -776,7 +786,15 @@ impl GripPoseTool {
776786 }
777787 None
778788 } else {
779- hold. nudge . take ( ) . map ( |nudge| nudge. item ( ) )
789+ hold. nudge
790+ . take ( )
791+ . map ( |nudge| nudge. item ( ) )
792+ . filter ( |released| {
793+ millimetres ( ( released. position - item. position ) . magnitude ( ) ) > NUDGE_MIN_MM
794+ || crate :: weapon_muzzle:: turn_deg (
795+ item. rotation . normalize ( ) . conjugate ( ) * released. rotation ,
796+ ) > NUDGE_MIN_DEG
797+ } )
780798 } ;
781799 self . squeezed = squeeze;
782800 released
@@ -2139,6 +2157,11 @@ mod tests {
21392157 let released = tool. nudge_with ( Some ( moved) , item, false ) . expect ( "released" ) ;
21402158 assert ! ( close( released, expected) ) ;
21412159 assert ! ( tool. test_hold. unwrap( ) . nudge. is_none( ) ) ;
2160+ // A squeeze let go without a move is no edit.
2161+ assert ! ( tool. nudge_with( Some ( moved) , expected, true ) . is_none( ) ) ;
2162+ assert ! ( tool. test_hold. unwrap( ) . nudge. is_some( ) ) ;
2163+ assert ! ( tool. nudge_with( Some ( moved) , expected, false ) . is_none( ) ) ;
2164+ assert ! ( tool. test_hold. unwrap( ) . nudge. is_none( ) ) ;
21422165 }
21432166
21442167 /// Losing either controller mid-nudge drops it with nothing to stage,
0 commit comments