1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Gesture helper implementation |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "gesturerecogniser.h" |
|
19 |
|
20 #include <e32math.h> |
|
21 |
|
22 #include "gesturedefs.h" |
|
23 #include <rt_gestureobserver.h> |
|
24 #include "pointarray.h" |
|
25 #include "utils.h" |
|
26 |
|
27 using namespace RT_GestureHelper; |
|
28 |
|
29 /** |
|
30 * Vector class (math) |
|
31 */ |
|
32 NONSHARABLE_CLASS( TVector ) |
|
33 { |
|
34 public: |
|
35 /** |
|
36 * Constructor |
|
37 * @param aFrom starting point of the vector |
|
38 * @param aTo ending point of the vector |
|
39 */ |
|
40 TVector( const TPoint& aFrom, const TPoint& aTo ) |
|
41 : iX( aTo.iX - aFrom.iX ), |
|
42 iY( aTo.iY - aFrom.iY ) |
|
43 { |
|
44 } |
|
45 |
|
46 /** @return angle of the vector */ |
|
47 TReal Angle() const |
|
48 { |
|
49 TReal angle = 0; |
|
50 TReal length = Length(); |
|
51 if ( length != 0 ) |
|
52 { |
|
53 Math::ACos( angle, iX / Length() ); |
|
54 if ( iY < 0 ) |
|
55 { |
|
56 angle = 2 * KPi - angle; |
|
57 } |
|
58 } |
|
59 return Degrees( angle ); |
|
60 } |
|
61 |
|
62 /** @return length of the vector */ |
|
63 TReal Length() const |
|
64 { |
|
65 TReal length = 0; |
|
66 Math::Sqrt( length, iX * iX + iY * iY ); |
|
67 return length; |
|
68 } |
|
69 |
|
70 private: |
|
71 /** @return radians in degrees */ |
|
72 inline TReal Degrees( TReal aRadians ) const |
|
73 { |
|
74 return aRadians * 180 / KPi; |
|
75 } |
|
76 |
|
77 public: |
|
78 /// x coordinate that represent the vector |
|
79 TReal iX; |
|
80 /// y coordinate that represent the vector |
|
81 TReal iY; |
|
82 }; |
|
83 |
|
84 inline TPoint LastPoint( const TPointArray& aPoints ) |
|
85 { |
|
86 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
87 return aPoints[ aPoints.Count() - 1 ] ; |
|
88 } |
|
89 |
|
90 /** |
|
91 * @return Length of the gesture in points |
|
92 */ |
|
93 inline TReal GestureLength( const TPointArray& aPoints ) |
|
94 { |
|
95 return TVector( aPoints[0], LastPoint( aPoints ) ).Length(); |
|
96 } |
|
97 |
|
98 /** |
|
99 * @return ETrue if aAngleUnderTest is almost aAngle |
|
100 * Closeness of the angles is controlled by KAngleTolerance |
|
101 */ |
|
102 static TBool IsNear( TReal aAngleUnderTest, TReal aAngle ) |
|
103 { |
|
104 return aAngle - KAngleTolerance <= aAngleUnderTest && |
|
105 aAngleUnderTest <= aAngle + KAngleTolerance; |
|
106 } |
|
107 |
|
108 /** |
|
109 * @return the angle as a direction flags of TGesture |
|
110 */ |
|
111 inline TGestureCode Direction( TReal aAngle ) |
|
112 { |
|
113 TGestureCode direction = EGestureUnknown; |
|
114 |
|
115 if ( IsNear( aAngle, 90.0 ) ) |
|
116 { |
|
117 direction = EGestureSwipeDown; |
|
118 } |
|
119 else if ( IsNear( aAngle, 180.0 ) ) |
|
120 { |
|
121 direction = EGestureSwipeLeft; |
|
122 } |
|
123 else if ( IsNear( aAngle, 270.0 ) ) |
|
124 { |
|
125 direction = EGestureSwipeUp; |
|
126 } |
|
127 else if ( 360.0 - KAngleTolerance <= aAngle || aAngle <= KAngleTolerance ) |
|
128 { |
|
129 direction = EGestureSwipeRight; |
|
130 } |
|
131 else // for lint warning |
|
132 { |
|
133 // unknown angle |
|
134 } |
|
135 |
|
136 return direction; |
|
137 } |
|
138 |
|
139 /** @return direction between points */ |
|
140 inline TGestureCode Direction( const TPoint& aFromPoint, const TPoint& aToPoint ) |
|
141 { |
|
142 return Direction( TVector( aFromPoint, aToPoint ).Angle() ); |
|
143 } |
|
144 |
|
145 /** @return overall direction between points */ |
|
146 static TGestureCode GeneralDirection( const TPointArray& aPoints ) |
|
147 { |
|
148 // If the start and end points are too close to each other, direction |
|
149 // is undefined |
|
150 if ( ToleranceRect( aPoints[0] ).Contains( LastPoint( aPoints ) ) ) |
|
151 { |
|
152 return EGestureUnknown; |
|
153 } |
|
154 return Direction( aPoints[0], LastPoint( aPoints ) ); |
|
155 } |
|
156 |
|
157 // function type to get a point in the point array |
|
158 typedef TPoint (TPointArray::*PointByIndexFunc)( TInt aIndex ) const; |
|
159 |
|
160 /// @return latest point outside tolerance area or KErrNotFound if not point outside it |
|
161 TInt LatestCertainPointIndex( const TPointArray& aPoints, PointByIndexFunc aPointByIndex ) |
|
162 { |
|
163 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
164 |
|
165 int i = aPoints.Count(); |
|
166 TRect toleranceRect = ToleranceRect( (aPoints.*aPointByIndex)( aPoints.Count() - 1 ) ); |
|
167 // Find out the first point from the end of the array |
|
168 // that is not contained in the tolerance rect. |
|
169 while( 0 <= --i ) |
|
170 { |
|
171 // if the point does not belong inside tolerance rect, it is the first point |
|
172 // outside the rect |
|
173 if( !toleranceRect.Contains( (aPoints.*aPointByIndex)(i) ) ) |
|
174 { |
|
175 break; |
|
176 } |
|
177 } |
|
178 return i; |
|
179 } |
|
180 |
|
181 /** @return last direction of dragging */ |
|
182 inline TGestureCode LastDirection( const TPointArray& aPoints ) |
|
183 { |
|
184 TInt latestPointIndex = LatestCertainPointIndex( aPoints, TPointArray::operator[] ); |
|
185 if ( KErrNotFound != latestPointIndex ) |
|
186 { |
|
187 return Direction( aPoints[latestPointIndex], LastPoint( aPoints ) ); |
|
188 } |
|
189 // no points were outside the rect, and hence the direction is unknown |
|
190 return EGestureUnknown; |
|
191 } |
|
192 |
|
193 /** |
|
194 * @return ETrue if points for a tap event |
|
195 */ |
|
196 inline TBool IsTap( const TPointArray& aPoints ) |
|
197 { |
|
198 return KErrNotFound == LatestCertainPointIndex( aPoints, TPointArray::Raw ); |
|
199 } |
|
200 |
|
201 // ---------------------------------------------------------------------------- |
|
202 // Return gesture code of a gesture formed by a sequence of points |
|
203 // ---------------------------------------------------------------------------- |
|
204 // |
|
205 TGestureCode TGestureRecogniser::GestureCode( const TPointArray& aPoints ) const |
|
206 { |
|
207 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
208 |
|
209 // tap needs to be treated separately, because recognising that needs to consider |
|
210 // raw points (and not points in which x or y axis has been filtered out) |
|
211 if ( IsTap( aPoints ) ) |
|
212 { |
|
213 return EGestureTap; |
|
214 } |
|
215 |
|
216 TGestureCode direction = GeneralDirection( aPoints ); |
|
217 // if last direction is opposite of the general one, user has cancelled a swipe |
|
218 if ( direction != LastDirection( aPoints ) ) |
|
219 { |
|
220 direction = EGestureUnknown; |
|
221 } |
|
222 return direction; |
|
223 } |
|