License conversion from Flora to Apache 2.0
[platform/core/uifw/dali-core.git] / dali / internal / update / touch / history.h
1 #ifndef __DALI_INTERNAL_HISTORY_H__
2 #define __DALI_INTERNAL_HISTORY_H__
3
4 /*
5  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/set-wrapper.h>
26 #include <dali/public-api/common/dali-common.h>
27 #include <dali/public-api/math/vector2.h>
28
29 namespace Dali
30 {
31
32 namespace Internal
33 {
34
35 /**
36  * HistoryPair
37  * represents a key-value element in the HistoryContainer
38  */
39 template<class T>
40 struct HistoryPairType
41 {
42 public:
43
44   HistoryPairType(float firstValue)
45   : first(firstValue)
46   {
47   }
48
49   HistoryPairType(float firstValue, T secondValue)
50   : first(firstValue),
51     second(secondValue)
52   {
53   }
54
55   bool operator<(const HistoryPairType& rhs) const
56   {
57     return first < rhs.first;
58   }
59
60   float first;
61   T second;
62 };
63
64 /**
65  * History container.
66  * This container is used for keeping a list of element pairs while providing an API that can
67  * generate interpolated values of requested elements that lie between two stored elements.
68  *
69  * e.g. stored values:
70  *
71  * 1.0 - 10
72  * 2.0 - 30
73  * 3.0 - 50
74  *
75  * Requesting value at key 1.5 will use the adjacent stored keys (1.0 and 2.0) to return an
76  * interpolated value of 20.0 (i.e. 0.5 of the way between 10 and 30).
77  *
78  * Requesting value at key 2.9 will use the adjacent stored keys (2.0 and 3.0) to return an
79  * interpolated value of 48.0 (i.e. 0.9 of the way between 30 and 50)
80  */
81 class History
82 {
83   typedef HistoryPairType<Vector2> HistoryPair;
84   typedef std::set<HistoryPair> HistoryContainer;
85   typedef HistoryContainer::iterator HistoryContainerIter;
86
87 public:
88
89   /**
90    * History constructor
91    */
92   History()
93   : mMaxSize(std::numeric_limits<size_t>::max())
94   {
95   }
96
97   /**
98    * History destructor
99    */
100   ~History()
101   {
102   }
103
104   /**
105    * Sets the maximum size of the history container in terms of elements stored, default is no limit
106    * @param[in] maxSize The maximum number of elements stored in container
107    */
108   void SetMaxSize(size_t maxSize)
109   {
110     mMaxSize = maxSize;
111
112     if(mHistory.size() > mMaxSize)
113     {
114       // determine reduction in history size, and remove these elements
115       size_t reduction = mHistory.size() - mMaxSize;
116
117       while(reduction--)
118       {
119         mHistory.erase(mHistory.begin() );
120       }
121     }
122   }
123
124   void Clear()
125   {
126     mHistory.clear();
127   }
128
129   /**
130    * Adds an element (y) to the container at position (x)
131    *
132    * @param[in] x Key position value to add
133    * @param[in] y Value to add at Key.
134    */
135   void Add(float x, const Vector2& y)
136   {
137     if(mHistory.size() >= mMaxSize)
138     {
139       RemoveTail();
140     }
141
142     mHistory.insert(HistoryPair(x,y));
143   }
144
145   /**
146    * Removes first element in the container
147    */
148   void RemoveTail()
149   {
150     mHistory.erase(mHistory.begin());
151   }
152
153   /**
154    * Retrieves value from the history using key (x).
155    * If the requested key (x) lies between two points, a linearly interpolated value between the two
156    * points is returned.
157    *
158    * @param[in] x Key position to retrieve
159    *
160    * @return The interpolated Value is returned for this position.
161    */
162   Vector2 Get(float x) const
163   {
164     HistoryContainerIter i = mHistory.lower_bound(x);
165
166     if(i == mHistory.end())
167     {
168       --i;
169     }
170
171     // For samples based on first point, just return position.
172     if(i == mHistory.begin())
173     {
174       return i->second;
175     }
176
177     // within begin() ... end() range
178     float x2 = i->first;
179     Vector2 y2 = i->second;
180
181     --i;
182     float x1 = i->first;
183     Vector2 y1 = i->second;
184
185     // For samples based on first 2 points, just use linear interpolation
186     // TODO: Should really perform quadratic interpolation whenever there are 3+
187     // points.
188     if(i == mHistory.begin())
189     {
190       return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
191     }
192
193     // For samples based elsewhere, always use quadratic interpolation.
194     --i;
195     float x0 = i->first;
196     Vector2 y0 = i->second;
197
198     if(i != mHistory.begin())
199     {
200       --i;
201       float xn = i->first;
202       Vector2 yn = i->second;
203
204       x2 = (x2 + x1) * 0.5f;
205       x1 = (x1 + x0) * 0.5f;
206       x0 = (xn + x0) * 0.5f;
207
208       y2 = (y2 + y1) * 0.5f;
209       y1 = (y1 + y0) * 0.5f;
210       y0 = (yn + y0) * 0.5f;
211     }
212     // Quadratic equation:
213
214     // y = ax^2 + bx + c
215     // by making touches relative to x0, y0 (i.e. x0 = 0, y0 = 0)
216     // we get c = 0, and equation becomes:
217     // y = ax^2 + bx
218     // 1) Y1 = a . X1^2 + b X1
219     // 2) Y2 = a . X2^2 + b X2
220     // solving simulatenous equations gets:
221
222     // make time (x) & position (y) relative to x0, y0
223     y1 -= y0;
224     y2 -= y0;
225     x1 -= x0;
226     x2 -= x0;
227
228     x -= x0;
229
230     Vector2 a = ( y1 - (y2 * x1) / x2 ) / (x1 * (x1 - x2) );
231     Vector2 b = ( y1 / x1 ) - (a * x1);
232
233     return a * x * x + b * x + y0;
234   }
235
236   /**
237    * Retrieves a value from the history relative to the head.
238    *
239    * @note If the Keys (x) in the history decrease in value the further back you go. Then a
240    * negative deltaX value should be supplied to refer to these keys relative to the head key.
241    *
242    * @param[in] deltaX Key position to retrieve relative to head key
243    *
244    * @return The interpolated Value is returned for this relative position.
245    */
246   Vector2 GetRelativeToHead(float deltaX) const
247   {
248     HistoryContainerIter i = mHistory.end();
249     --i;
250     return Get(i->first + deltaX);
251   }
252
253   /**
254    * Retrieves the head time value.
255    *
256    * @retrun The head time value.
257    */
258   float GetHeadTime() const
259   {
260     HistoryContainerIter i = mHistory.end();
261     if(i==mHistory.begin())
262     {
263       return 0.0f;
264     }
265     --i;
266     return i->first;
267   }
268
269   /**
270    * Retrieves the head value.
271    *
272    * @return The head value.
273    */
274   Vector2 GetHead() const
275   {
276     HistoryContainerIter i = mHistory.end();
277     if(i==mHistory.begin())
278     {
279       return Vector2();
280     }
281     --i;
282     return i->second;
283   }
284
285 private:
286
287   HistoryContainer mHistory;                ///< History container
288   size_t mMaxSize;                          ///< Current maximum size of container
289
290 };
291
292 } // namespace Internal
293
294 } // namespace Dali
295
296 #endif // __DALI_INTERNAL_HISTORY_H__