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 "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 "gestureobserver.h" |
|
24 #include "pointarray.h" |
|
25 #include "utils.h" |
|
26 |
|
27 #include <w32std.h> // pointerevents |
|
28 |
|
29 using namespace GestureHelper; |
|
30 |
|
31 /** |
|
32 * Vector class (math) |
|
33 */ |
|
34 NONSHARABLE_CLASS( TVector ) |
|
35 { |
|
36 public: |
|
37 /** |
|
38 * Constructor |
|
39 * @param aFrom starting point of the vector |
|
40 * @param aTo ending point of the vector |
|
41 */ |
|
42 TVector( const TPoint& aFrom, const TPoint& aTo ) |
|
43 : iX( aTo.iX - aFrom.iX ), |
|
44 iY( aTo.iY - aFrom.iY ) |
|
45 { |
|
46 } |
|
47 |
|
48 /** @return angle of the vector */ |
|
49 TReal Angle() const |
|
50 { |
|
51 TReal angle = 0; |
|
52 TReal length = Length(); |
|
53 if ( length != 0 ) |
|
54 { |
|
55 Math::ACos( angle, iX / Length() ); |
|
56 if ( iY < 0 ) |
|
57 { |
|
58 angle = 2 * KPi - angle; |
|
59 } |
|
60 } |
|
61 return Degrees( angle ); |
|
62 } |
|
63 |
|
64 /** @return length of the vector */ |
|
65 TReal Length() const |
|
66 { |
|
67 TReal length = 0; |
|
68 Math::Sqrt( length, iX * iX + iY * iY ); |
|
69 return length; |
|
70 } |
|
71 |
|
72 private: |
|
73 /** @return radians in degrees */ |
|
74 inline TReal Degrees( TReal aRadians ) const |
|
75 { |
|
76 return aRadians * 180 / KPi; |
|
77 } |
|
78 |
|
79 public: |
|
80 /// x coordinate that represent the vector |
|
81 TReal iX; |
|
82 /// y coordinate that represent the vector |
|
83 TReal iY; |
|
84 }; |
|
85 |
|
86 inline TPoint LastPoint( const TPointArray& aPoints ) |
|
87 { |
|
88 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
89 return aPoints[ aPoints.Count() - 1 ] ; |
|
90 } |
|
91 |
|
92 /** |
|
93 * @return Length of the gesture in points |
|
94 */ |
|
95 inline TReal GestureLength( const TPointArray& aPoints ) |
|
96 { |
|
97 return TVector( aPoints[0], LastPoint( aPoints ) ).Length(); |
|
98 } |
|
99 |
|
100 /** |
|
101 * @return ETrue if aAngleUnderTest is almost aAngle |
|
102 * Closeness of the angles is controlled by KAngleTolerance |
|
103 */ |
|
104 static TBool IsNear( TReal aAngleUnderTest, TReal aAngle ) |
|
105 { |
|
106 return aAngle - KAngleTolerance <= aAngleUnderTest && |
|
107 aAngleUnderTest <= aAngle + KAngleTolerance; |
|
108 } |
|
109 |
|
110 /** |
|
111 * @return the angle as a direction flags of TGesture |
|
112 */ |
|
113 inline TGestureCode Direction( TReal aAngle ) |
|
114 { |
|
115 TGestureCode direction = EGestureUnknown; |
|
116 |
|
117 if ( IsNear( aAngle, 90.0 ) ) |
|
118 { |
|
119 direction = EGestureSwipeDown; |
|
120 } |
|
121 else if ( IsNear( aAngle, 180.0 ) ) |
|
122 { |
|
123 direction = EGestureSwipeLeft; |
|
124 } |
|
125 else if ( IsNear( aAngle, 270.0 ) ) |
|
126 { |
|
127 direction = EGestureSwipeUp; |
|
128 } |
|
129 else if ( 360.0 - KAngleTolerance <= aAngle || aAngle <= KAngleTolerance ) |
|
130 { |
|
131 direction = EGestureSwipeRight; |
|
132 } |
|
133 else // for lint warning |
|
134 { |
|
135 // unknown angle |
|
136 } |
|
137 |
|
138 return direction; |
|
139 } |
|
140 |
|
141 /** @return direction between points */ |
|
142 inline TGestureCode Direction( const TPoint& aFromPoint, const TPoint& aToPoint ) |
|
143 { |
|
144 return Direction( TVector( aFromPoint, aToPoint ).Angle() ); |
|
145 } |
|
146 |
|
147 // function type to get a point in the point array |
|
148 typedef TPoint (TPointArray::*PointByIndexFunc)( TInt aIndex ) const; |
|
149 |
|
150 /// @return latest point outside tolerance area or KErrNotFound if not point outside it |
|
151 TInt LatestCertainPointIndex( const TPointArray& aPoints, PointByIndexFunc aPointByIndex, TRect aToleranceRect ) |
|
152 { |
|
153 int i = aPoints.Count(); |
|
154 // Find out the first point from the end of the array |
|
155 // that is not contained in the tolerance rect. |
|
156 while( 0 <= --i ) |
|
157 { |
|
158 // if the point does not belong inside tolerance rect, it is the first point |
|
159 // outside the rect |
|
160 if( !aToleranceRect.Contains( (aPoints.*aPointByIndex)(i) ) ) |
|
161 { |
|
162 break; |
|
163 } |
|
164 } |
|
165 return i; |
|
166 } |
|
167 |
|
168 /** @return last direction of dragging */ |
|
169 inline TGestureCode LastDirection( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) |
|
170 { |
|
171 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
172 |
|
173 TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::operator[])(aPoints.Count() - 1), aRelevantAxis ); |
|
174 |
|
175 TInt latestPointIndex = LatestCertainPointIndex( aPoints, TPointArray::operator[],toleranceRect ); |
|
176 if ( KErrNotFound != latestPointIndex ) |
|
177 { |
|
178 return Direction( aPoints[latestPointIndex], LastPoint( aPoints ) ); |
|
179 } |
|
180 // no points were outside the rect, and hence the direction is unknown |
|
181 return EGestureUnknown; |
|
182 } |
|
183 |
|
184 /** |
|
185 * @return ETrue if points for a tap event |
|
186 */ |
|
187 inline TBool IsTap( const TPointArray& aPoints ) |
|
188 { |
|
189 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
190 |
|
191 TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::Raw)(0) ); |
|
192 |
|
193 return KErrNotFound == LatestCertainPointIndex( aPoints, TPointArray::Raw,toleranceRect ); |
|
194 } |
|
195 |
|
196 // ---------------------------------------------------------------------------- |
|
197 // Return gesture code of a gesture formed by a sequence of points |
|
198 // ---------------------------------------------------------------------------- |
|
199 // |
|
200 TGestureCode TGestureRecogniser::GestureCode( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) const |
|
201 { |
|
202 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
203 |
|
204 // tap needs to be treated separately, because recognising that needs to consider |
|
205 // raw points (and not points in which x or y axis has been filtered out) |
|
206 if ( IsTap( aPoints ) ) |
|
207 { |
|
208 return EGestureTap; |
|
209 } |
|
210 |
|
211 return LastDirection( aPoints, aRelevantAxis ); |
|
212 } |
|
213 |
|
214 // ---------------------------------------------------------------------------- |
|
215 // Return gesture code of a gesture formed by a sequence of points |
|
216 // ---------------------------------------------------------------------------- |
|
217 // |
|
218 TGestureCode TGestureRecogniser::MultiTouchGestureCode( const TPointArray& aPoints, const TPointArray& aSecondaryPoints, |
|
219 TInt aPreviousDistance, TBool aIsFirstPinch ) const |
|
220 { |
|
221 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
222 __ASSERT_DEBUG( aSecondaryPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
223 __ASSERT_DEBUG( aPreviousDistance > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
224 |
|
225 TInt currentDistance = TVector( LastPoint( aPoints ), LastPoint( aSecondaryPoints ) ).Length(); |
|
226 |
|
227 // currently gesture tolerance is used as reference to identify the pinch |
|
228 // and it is same for first time recognition and also for pinch thereon |
|
229 // This can be changed to an independent constant if required |
|
230 // This is now implemeted. We have different tolerance for intial pinch and pinhc theron |
|
231 |
|
232 // We need to have different tolerance at the time of changing direction. |
|
233 // When user is pinching in and then starts pinching out the tolerance should be different. |
|
234 // This is implemented in CGesture class. aIsFirstPinch will take care of all this |
|
235 TInt pinchTolerance = aIsFirstPinch ? KInitialPinchTolerance : KPinchTolerance; |
|
236 if (Abs( currentDistance - aPreviousDistance ) >= pinchTolerance ) |
|
237 { |
|
238 return EGesturePinch; |
|
239 } |
|
240 return EGestureUnknown; |
|
241 } |
|
242 |
|
243 // ---------------------------------------------------------------------------- |
|
244 // Validate the drag formed by a sequence of points. If all the points are |
|
245 // within the tolerance rect then the gesture is not recognised. |
|
246 // ---------------------------------------------------------------------------- |
|
247 // |
|
248 TGestureCode TGestureRecogniser::ValidateDrag( const TPointArray& aPoints, MGestureEvent::TAxis aRelevantAxis ) const |
|
249 { |
|
250 __ASSERT_DEBUG( aPoints.Count() > 0, Panic( EGesturePanicIllegalLogic ) ); |
|
251 |
|
252 TRect toleranceRect = ToleranceRect( (aPoints.TPointArray::operator[])(aPoints.Count() - 1), aRelevantAxis ); |
|
253 |
|
254 TInt latestPointIndex = LatestCertainPointIndex( aPoints, TPointArray::operator[],toleranceRect ); |
|
255 if ( KErrNotFound != latestPointIndex ) |
|
256 { |
|
257 return EGestureDrag; |
|
258 } |
|
259 // no points were outside the rect, and hence the direction is unknown |
|
260 return EGestureUnknown; |
|
261 } |
|
262 |
|
263 // ---------------------------------------------------------------------------- |
|
264 // Return the length between the given two points |
|
265 // ---------------------------------------------------------------------------- |
|
266 // |
|
267 TInt TGestureRecogniser::Length( const TPoint aPoint, const TPoint aSecondaryPoint ) const |
|
268 { |
|
269 return TVector(aPoint,aSecondaryPoint).Length(); |
|
270 } |
|
271 |
|
272 // ---------------------------------------------------------------------------- |
|
273 // Return pointer number fetched from the given event |
|
274 // ---------------------------------------------------------------------------- |
|
275 // |
|
276 TInt TGestureRecogniser::PointerNumber( const TPointerEvent& aEvent ) |
|
277 { |
|
278 if( aEvent.IsAdvancedPointerEvent() ) |
|
279 { |
|
280 return aEvent.AdvancedPointerEvent()->PointerNumber(); |
|
281 } |
|
282 return 0; |
|
283 } |
|
284 // end of file |
|
285 |
|