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