diff -r 000000000000 -r e83bab7cf002 mulwidgets/gesturehelper/src/gesturerecogniser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mulwidgets/gesturehelper/src/gesturerecogniser.cpp Thu Dec 17 08:56:02 2009 +0200 @@ -0,0 +1,285 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Gesture helper implementation +* +*/ + +#include "gesturerecogniser.h" + +#include + +#include "gesturedefs.h" +#include "gestureobserver.h" +#include "pointarray.h" +#include "utils.h" + +#include // pointerevents + +using namespace GestureHelper; + +/** + * Vector class (math) + */ +NONSHARABLE_CLASS( TVector ) + { +public: + /** + * Constructor + * @param aFrom starting point of the vector + * @param aTo ending point of the vector + */ + TVector( const TPoint& aFrom, const TPoint& aTo ) + : iX( aTo.iX - aFrom.iX ), + iY( aTo.iY - aFrom.iY ) + { + } + + /** @return angle of the vector */ + TReal Angle() const + { + TReal angle = 0; + TReal length = Length(); + if ( length != 0 ) + { + Math::ACos( angle, iX / Length() ); + if ( iY < 0 ) + { + angle = 2 * KPi - angle; + } + } + return Degrees( angle ); + } + + /** @return length of the vector */ + TReal Length() const + { + TReal length = 0; + Math::Sqrt( length, iX * iX + iY * iY ); + return length; + } + +private: + /** @return radians in degrees */ + inline TReal Degrees( TReal aRadians ) const + { + return aRadians * 180 / KPi; + } + +public: + /// x coordinate that represent the vector + TReal iX; + /// y coordinate that represent the vector + TReal iY; + }; + +inline TPoint LastPoint( const TPointArray& aPoints ) + { + __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); + return aPoints[ aPoints.Count() - 1 ] ; + } + +/** + * @return Length of the gesture in points + */ +inline TReal GestureLength( const TPointArray& aPoints ) + { + return TVector( aPoints[0], LastPoint( aPoints ) ).Length(); + } + +/** + * @return ETrue if aAngleUnderTest is almost aAngle + * Closeness of the angles is controlled by KAngleTolerance + */ +static TBool IsNear( TReal aAngleUnderTest, TReal aAngle ) + { + return aAngle - KAngleTolerance <= aAngleUnderTest && + aAngleUnderTest <= aAngle + KAngleTolerance; + } + +/** + * @return the angle as a direction flags of TGesture + */ +inline TGestureCode Direction( TReal aAngle ) + { + TGestureCode direction = EGestureUnknown; + + if ( IsNear( aAngle, 90.0 ) ) + { + direction = EGestureSwipeDown; + } + else if ( IsNear( aAngle, 180.0 ) ) + { + direction = EGestureSwipeLeft; + } + else if ( IsNear( aAngle, 270.0 ) ) + { + direction = EGestureSwipeUp; + } + else if ( 360.0 - KAngleTolerance <= aAngle || aAngle <= KAngleTolerance ) + { + direction = EGestureSwipeRight; + } + else // for lint warning + { + // unknown angle + } + + return direction; + } + +/** @return direction between points */ +inline TGestureCode Direction( const TPoint& aFromPoint, const TPoint& aToPoint ) + { + return Direction( TVector( aFromPoint, aToPoint ).Angle() ); + } + +// function type to get a point in the point array +typedef TPoint (TPointArray::*PointByIndexFunc)( TInt aIndex ) const; + +/// @return latest point outside tolerance area or KErrNotFound if not point outside it +TInt LatestCertainPointIndex( const TPointArray& aPoints, PointByIndexFunc aPointByIndex, TRect aToleranceRect ) + { + int i = aPoints.Count(); + // Find out the first point from the end of the array + // that is not contained in the tolerance rect. + while( 0 <= --i ) + { + // if the point does not belong inside tolerance rect, it is the first point + // outside the rect + if( !aToleranceRect.Contains( (aPoints.*aPointByIndex)(i) ) ) + { + break; + } + } + return i; + } + +/** @return last direction of dragging */ +inline TGestureCode LastDirection( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) + { + __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); + + TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::operator[])(aPoints.Count() - 1), aRelevantAxis ); + + TInt latestPointIndex = LatestCertainPointIndex( aPoints, TPointArray::operator[],toleranceRect ); + if ( KErrNotFound != latestPointIndex ) + { + return Direction( aPoints[latestPointIndex], LastPoint( aPoints ) ); + } + // no points were outside the rect, and hence the direction is unknown + return EGestureUnknown; + } + +/** + * @return ETrue if points for a tap event + */ +inline TBool IsTap( const TPointArray& aPoints ) + { + __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); + + TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::Raw)(0) ); + + return KErrNotFound == LatestCertainPointIndex( aPoints, TPointArray::Raw,toleranceRect ); + } + +// ---------------------------------------------------------------------------- +// Return gesture code of a gesture formed by a sequence of points +// ---------------------------------------------------------------------------- +// +TGestureCode TGestureRecogniser::GestureCode( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) const + { + __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); + + // tap needs to be treated separately, because recognising that needs to consider + // raw points (and not points in which x or y axis has been filtered out) + if ( IsTap( aPoints ) ) + { + return EGestureTap; + } + + return LastDirection( aPoints, aRelevantAxis ); + } + +// ---------------------------------------------------------------------------- +// Return gesture code of a gesture formed by a sequence of points +// ---------------------------------------------------------------------------- +// +TGestureCode TGestureRecogniser::MultiTouchGestureCode( const TPointArray& aPoints, const TPointArray& aSecondaryPoints, + TInt aPreviousDistance, TBool aIsFirstPinch ) const + { + __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); + __ASSERT_DEBUG( aSecondaryPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); + __ASSERT_DEBUG( aPreviousDistance > 0, Panic( EGesturePanicIllegalLogic ) ); + + TInt currentDistance = TVector( LastPoint( aPoints ), LastPoint( aSecondaryPoints ) ).Length(); + + // currently gesture tolerance is used as reference to identify the pinch + // and it is same for first time recognition and also for pinch thereon + // This can be changed to an independent constant if required + // This is now implemeted. We have different tolerance for intial pinch and pinhc theron + + // We need to have different tolerance at the time of changing direction. + // When user is pinching in and then starts pinching out the tolerance should be different. + // This is implemented in CGesture class. aIsFirstPinch will take care of all this + TInt pinchTolerance = aIsFirstPinch ? KInitialPinchTolerance : KPinchTolerance; + if (Abs( currentDistance - aPreviousDistance ) >= pinchTolerance ) + { + return EGesturePinch; + } + return EGestureUnknown; + } + +// ---------------------------------------------------------------------------- +// Validate the drag formed by a sequence of points. If all the points are +// within the tolerance rect then the gesture is not recognised. +// ---------------------------------------------------------------------------- +// +TGestureCode TGestureRecogniser::ValidateDrag( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) const + { + __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); + + TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::operator[])(aPoints.Count() - 1), aRelevantAxis ); + + TInt latestPointIndex = LatestCertainPointIndex( aPoints, TPointArray::operator[],toleranceRect ); + if ( KErrNotFound != latestPointIndex ) + { + return EGestureDrag; + } + // no points were outside the rect, and hence the direction is unknown + return EGestureUnknown; + } + +// ---------------------------------------------------------------------------- +// Return the length between the given two points +// ---------------------------------------------------------------------------- +// +TInt TGestureRecogniser::Length( const TPoint aPoint, const TPoint aSecondaryPoint ) const + { + return TVector(aPoint,aSecondaryPoint).Length(); + } + +// ---------------------------------------------------------------------------- +// Return pointer number fetched from the given event +// ---------------------------------------------------------------------------- +// +TInt TGestureRecogniser::PointerNumber( const TPointerEvent& aEvent ) + { + if( aEvent.IsAdvancedPointerEvent() ) + { + return aEvent.AdvancedPointerEvent()->PointerNumber(); + } + return 0; + } +// end of file +