@@ -302,45 +302,43 @@ void Trackball::apply(TouchDownEvent& touchDown)
302302 if (!eventRelevant (touchDown)) return ;
303303
304304 _previousTouches[touchDown.id ] = &touchDown;
305-
306- // First touch - simulate button press for rotation
307- if (_previousTouches.size () == 1 )
305+ switch (touchDown.id )
308306 {
309- vsg::ref_ptr<vsg::Window> w = touchDown.window ;
310- vsg::ref_ptr<vsg::ButtonPressEvent> evt = vsg::ButtonPressEvent::create (
311- w,
312- touchDown.time ,
313- touchDown.x ,
314- touchDown.y ,
315- touchMappedToButtonMask,
316- touchDown.id );
317- apply (*evt.get ());
307+ case 0 : {
308+ if (_previousTouches.size () == 1 )
309+ {
310+ vsg::ref_ptr<vsg::Window> w = touchDown.window ;
311+ vsg::ref_ptr<vsg::ButtonPressEvent> evt = vsg::ButtonPressEvent::create (
312+ w,
313+ touchDown.time ,
314+ touchDown.x ,
315+ touchDown.y ,
316+ touchMappedToButtonMask,
317+ touchDown.id );
318+ apply (*evt.get ());
319+ }
320+ break ;
321+ }
322+ case 1 : {
323+ _prevZoomTouchDistance = 0.0 ;
324+ if (touchDown.id == 0 && _previousTouches.count (1 ))
325+ {
326+ const auto & prevTouch1 = _previousTouches[1 ];
327+ auto a = std::abs (static_cast <double >(prevTouch1->x ) - touchDown.x );
328+ auto b = std::abs (static_cast <double >(prevTouch1->y ) - touchDown.y );
329+ if (a > 0 || b > 0 )
330+ _prevZoomTouchDistance = sqrt (a * a + b * b);
331+ }
332+ break ;
318333 }
319- // Second touch - initialize zoom distance
320- else if (_previousTouches.size () == 2 )
321- {
322- // Calculate initial distance between the two touches
323- auto it = _previousTouches.begin ();
324- const TouchEvent* touch1 = it->second ;
325- ++it;
326- const TouchEvent* touch2 = it->second ;
327-
328- auto a = std::abs (static_cast <double >(touch1->x ) - static_cast <double >(touch2->x ));
329- auto b = std::abs (static_cast <double >(touch1->y ) - static_cast <double >(touch2->y ));
330- _prevZoomTouchDistance = sqrt (a * a + b * b);
331-
332- // Reset zoom state to establish a stable baseline
333- // This prevents immediate zoom when second finger touches
334- _zoomPreviousRatio = 0.0 ;
335334 }
336335}
337336
338337void Trackball::apply (TouchUpEvent& touchUp)
339338{
340339 if (!eventRelevant (touchUp)) return ;
341340
342- // If this is the last touch, simulate button release
343- if (_previousTouches.size () == 1 )
341+ if (touchUp.id == 0 && _previousTouches.size () == 1 )
344342 {
345343 vsg::ref_ptr<vsg::Window> w = touchUp.window ;
346344 vsg::ref_ptr<vsg::ButtonReleaseEvent> evt = vsg::ButtonReleaseEvent::create (
@@ -374,73 +372,24 @@ void Trackball::apply(TouchMoveEvent& touchMove)
374372 break ;
375373 }
376374 case 2 : {
377- // Two touches - Zoom by pinch
378- // Find the other touch (not the current moving one)
379- const TouchEvent* otherTouch = nullptr ;
380-
381- // Iterate through the map to find the touch that isn't the current one
382- for (const auto & [id, touch] : _previousTouches)
375+ if (touchMove.id == 0 && _previousTouches.count (0 ))
383376 {
384- if (id != touchMove.id )
377+ // Zoom
378+ const auto & prevTouch1 = _previousTouches[1 ];
379+ auto a = std::abs (static_cast <double >(prevTouch1->x ) - touchMove.x );
380+ auto b = std::abs (static_cast <double >(prevTouch1->y ) - touchMove.y );
381+ if (a > 0 || b > 0 )
385382 {
386- otherTouch = touch;
387- break ;
388- }
389- }
390-
391- if (otherTouch)
392- {
393- // Calculate current distance between two touches
394- auto a = std::abs (static_cast <double >(otherTouch->x ) - touchMove.x );
395- auto b = std::abs (static_cast <double >(otherTouch->y ) - touchMove.y );
396- auto currentDistance = sqrt (a * a + b * b);
397-
398- // Only process zoom if we have a valid previous distance
399- if (_prevZoomTouchDistance > 0 && currentDistance > 0 )
400- {
401- // Calculate the distance change
402- auto distanceChange = std::abs (currentDistance - _prevZoomTouchDistance);
403-
404- // Minimum threshold to prevent jitter (e.g., 5 pixels)
405- // Adjust this value based on screen DPI and desired sensitivity
406- constexpr double MIN_ZOOM_THRESHOLD = 5.0 ;
407-
408- if (distanceChange >= MIN_ZOOM_THRESHOLD)
383+ auto touchZoomDistance = sqrt (a * a + b * b);
384+ if (_prevZoomTouchDistance && touchZoomDistance > 0 )
409385 {
410- // Calculate zoom ratio
411- auto zoomRatio = currentDistance / _prevZoomTouchDistance;
412-
413- // Dead zone: ignore tiny changes near 1.0 (e.g., 0.98-1.02)
414- constexpr double DEAD_ZONE_MIN = 0.98 ;
415- constexpr double DEAD_ZONE_MAX = 1.02 ;
416-
417- if (zoomRatio < DEAD_ZONE_MIN || zoomRatio > DEAD_ZONE_MAX)
418- {
419- // Clamp extreme zoom values to prevent sudden jumps
420- // Limit to 0.5x - 2.0x per frame
421- constexpr double MIN_ZOOM_RATIO = 0.5 ;
422- constexpr double MAX_ZOOM_RATIO = 2.0 ;
423- zoomRatio = std::clamp (zoomRatio, MIN_ZOOM_RATIO, MAX_ZOOM_RATIO);
424-
425- // Convert ratio to zoom level
426- auto zoomLevel = zoomRatio;
427- if (zoomLevel < 1.0 )
428- zoomLevel = -(1.0 / zoomLevel);
429-
430- // Apply zoom with damping factor (0.1 = 10% of calculated zoom)
431- // This makes zoom feel smoother and more controllable
432- zoomLevel *= 0.1 ;
433- zoom (zoomLevel);
434- vsg::debug (" zoom event - distanceChange: " , distanceChange, " , zoomRatio: " , zoomRatio, " , zoomLevel: " , zoomLevel);
435- // Update previous distance for next frame
436- _prevZoomTouchDistance = currentDistance;
437- }
386+ auto zoomLevel = touchZoomDistance / _prevZoomTouchDistance;
387+ if (zoomLevel < 1 )
388+ zoomLevel = -(1 / zoomLevel);
389+ zoomLevel *= 0.1 ;
390+ zoom (zoomLevel);
438391 }
439- }
440- else
441- {
442- // First valid measurement, just store the distance
443- _prevZoomTouchDistance = currentDistance;
392+ _prevZoomTouchDistance = touchZoomDistance;
444393 }
445394 }
446395 break ;
0 commit comments