MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
interpolator.h
Go to the documentation of this file.
1 // © Copyright 2010 - 2014 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _interpolator_h
41 #define _interpolator_h
42 
43 /// @file
44 /// @brief Helper classes to assist in generating data points between two other data points.
45 
46 #include "datatypes.h"
47 #include "exception.h"
48 #include "cubicspline.h"
49 
50 #ifndef SWIG // STD headers are bad for Swig
51  #include <cmath>
52  #include <iterator>
53 
54  #include <iostream>
55  #include <typeinfo>
56 #endif
57 
58 namespace Mezzanine
59 {
60 
61  // Forward declaration
62  template <typename InterpolatableType, typename InterpolatorType> class TrackStorage;
63 
64  /// @brief A simple functor for interpolating data points in a simple way.
65  /// @details This interpolator provides certain guarantees.
66  /// - All data points will be valid interpolated values.
67  /// - There are "corners".
68  /// - Interpolation will be constant/O(1) time (and as fast as reasonable).
69  /// - This shape defined by interpolating a set of these will not leave a Convex Hull(or Axis Aligned Bounding Box) that could contain the data
70  /// Corners can be thought of as any non-smooth change, and may not be intuitively in some interpolatable
71  /// types.
72  template <typename T>
74  {
75  public:
76  /// @brief The type this will interpolate
77  /// @note All Interpolators need to declare an InterpolatableType
78  typedef T InterpolatableType;
79  /// @brief The storage to use with thison tracks
80  typedef std::vector<InterpolatableType> Storage;
81 
82  /// @brief Get a value at a given location between exactly two others.
83  /// @param Begin The data point at one end of line segment
84  /// @param End The data point at the other end of line segment
85  /// @param Location A value between 0.0 and 1.0 indicate what point on the line segment defined by Begin and End you want.
86  /// @return A Value equal to Begin if 0.0 is passed, equal to End if 1.0 is passed equal to a point exactly in the middle if 0.5 is passed.
87  static T InterpolateMath(T Begin, T End, Real Location)
88  { return ((End-Begin)*Location)+Begin; }
89 
90  /// @brief Handles Interpolation of multiple points.
91  /// @details This will treat each data point as if it were equidistant from its
92  /// neighbors and find the datasegment the desired point resides in. Then it will
93  /// return a data point partway through that data segment. For example if you have
94  /// three Vector2's defining two data segments as follows:
95  /// @n 0,0 - 1,1 - 2,0
96  /// @n @n
97  /// Requesting the following locations would return the following data points:
98  /// @n 0.0 = 0,0
99  /// @n 0.5 = 1,1
100  /// @n 1.0 = 2,0
101  /// @n
102  /// @n 0.25 = 0.5,0.5
103  /// @n 0.75 = 1.5,0.5
104  /// @n @n Any floating point location between 0 and 1 could be requested following
105  /// this pattern.
106  /// @n @n Should the data segments not actually be equal in size that they will each
107  /// still be treated as an equal length when calcuting size. For example if you
108  /// have 2 data segments like the previous example, then .25 will be halfway through
109  /// the first segment and .75 will be halfwy through the second. If you are
110  /// interpolating a series of points through segment like these the larger data
111  /// segment will be traversed faster. For example consider the following Real value
112  /// values as data points:
113  /// @n -5, 0, 100
114  /// Requesting the following locations would return the following data points:
115  /// @n 0.0 = -5
116  /// @n 0.5 = 0
117  /// @n 1.0 = 100
118  /// @n
119  /// @n 0.25 = -2.5
120  /// @n 0.75 = 50
121  /// @n
122  /// @n 0.0 = -5
123  /// @n 0.1 = -4
124  /// @n 0.2 = -3
125  /// @n 0.3 = -2
126  /// @n 0.4 = -1
127  /// @n 0.5 = 0
128  /// @n 0.6 = 20
129  /// @n 0.7 = 40
130  /// @n 0.8 = 60
131  /// @n 0.9 = 80
132  /// @n 1.0 = 100
133  /// @n @n Note how even though the location increase by only 0.1 each step
134  /// the resulting interpolated data point move relative to the length of the
135  /// segment.
136  /// @param Begin An iterator at the beginning of a rande of data point
137  /// @param End An iterator one past the end of the data range to interpolate.
138  /// @param Location A value between 0.0 and 1.0 that represents
139  /// @return A T at a location along the data segments defined by Begin and End.
140  template<typename TIterator>
141  static T GetInterpolatedFromMultiple(TIterator Begin, TIterator End, Real Location)
142  {
143  Whole DataPointCount = std::distance(Begin,End);
144  Whole LineSegmentCount = DataPointCount-1;
145 
146  if(LineSegmentCount<1)
147  { MEZZ_EXCEPTION(Exception::PARAMETERS_RANGE_EXCEPTION,"Cannot GetPercentageThroughSegment in GenericLinearInterpolator without a data segment. There must be two or more data points."); }
148  if(1==LineSegmentCount)
149  { return InterpolateMath(*(Begin), *(Begin+1), Location); }
150 
151  Whole UsingLineSegment = Location * Real(LineSegmentCount); // Pick a Line Segment
152  if(UsingLineSegment>=LineSegmentCount) // We are past or at the end of the line segments
153  { return *(End-1); }
154 
155  Real LocalPercentage = std::fmod(PreciseReal(Location), PreciseReal(1.0/PreciseReal(LineSegmentCount)))*LineSegmentCount;
156 
157  return InterpolateMath(*(Begin+UsingLineSegment), // The first point of the line segment
158  *(Begin+UsingLineSegment+1),
159  LocalPercentage); // The percentage we are through this line segment
160  }
161 
162  /// @brief This will interpolates data points with GetInterpolatedFromMultiple or InterpolateMath a required
163  /// @details read about GetInterpolatedFromMultiple or InterpolateMath to see what kinds of results this
164  /// can produce.
165  /// @param Begin An iterator at the beginning of a range of data point
166  /// @param End An iterator one past the end of the data range to interpolate.
167  /// @param Location A value between 0.0 and 1.0 that represents
168  /// @return A T at a location along the data segments defined by Begin and End.
169  template<typename TIterator>
170  static T Interpolate(TIterator Begin, TIterator End, Real Location)
171  {
172  if(Begin==End)
173  { MEZZ_EXCEPTION(Exception::PARAMETERS_RANGE_EXCEPTION,"Requires at least 2 data points for linear interpolation, was provided 0."); }
174  if(Begin+1==End)
175  { MEZZ_EXCEPTION(Exception::PARAMETERS_RANGE_EXCEPTION,"Requires at least 2 data points for linear interpolation, was provided 1."); }
176 
177  if(Begin+2==End)
178  { return InterpolateMath(*Begin, *(Begin+1), Location); }
179 
180  return GetInterpolatedFromMultiple(Begin, End, Location);
181  }
182  };
183 
184  /// @brief A simple functor for interpolating data points in a simple way.
185  /// @details This interpolator provides different guarantees different from the linear one:
186  /// - Data points, might not be valid interpolated values
187  /// - There are no "Corners".
188  /// - Execution could be as bad as O^N.
189  /// - This shape defined by interpolating a set of these will not leave a Convex Hull(or Axis Aligned Bounding Box) that could contain the data.
190  /// - Will be able to provide interpolated values for a small set of data points.
191  /// There might be corners when connecting 2 different bezier curves if not careful, any
192  /// bezier implementation taking a finite amount of points cannot help this.
193  template <typename T>
195  {
196  public:
197  /// @brief The type this will interpolate
198  /// @note All Interpolators need to declare an InterpolatableType
200  /// @brief The storage to use with thison tracks
201  typedef std::vector<InterpolatableType> Storage;
202 
203  /// @brief Get a value at a given location between two others.
204  /// @details This uses Linear interpolation recursively to produce a single curve
205  /// following Bézier's curve algorithm. For example if interpolating the location 0.5
206  /// on a set of 3 data points A,B,C and therefor 2 data segments AB and BC, you can imagine this as
207  /// getting the point halfway down AB and the point halfway down down BC. Then this will
208  /// get return the halfway between each of those points. This produces smooth curves but could
209  /// perform slowly. For more details see the wikiedia pages on Bézier curves:
210  /// http://en.wikipedia.org/wiki/Bézier_curve or http://en.wikipedia.org/wiki/B%C3%A9zier_curve
211  /// @param Begin An Iterator to the begining of the range of the instances of the type to be Interpolated
212  /// @param End The end (not one past the end) of the range that Begin started.
213  /// @param A value between 0.0 and 1.0 indicate what point on the beziear spline defined by Begin and End you want.
214  /// @return A Value equal or near to Begin if 0.0 is passed, equal to or near to End if 1.0 is passed equal to a point exactly in the middle if 0.5 is passed.
215  /// @warning This is implemented as a recursive function with the only termination condition being the Edn iterator.
216  template<typename TIterator>
217  static T Interpolate(TIterator Begin, TIterator End, Real Location)
218  {
219  if(Begin==End || Begin+1==End)
220  { MEZZ_EXCEPTION(Exception::PARAMETERS_RANGE_EXCEPTION,"Requires at least 1 data points for bezier interpolation."); }
221 
222  if(Begin+2==End)
223  { return LinearInterpolator<T>::Interpolate(Begin,End,Location); }
224 
225  std::vector<T> SubSection;
226  for(TIterator Iter=Begin; Iter!=End-1; Iter++)
227  { SubSection.push_back(LinearInterpolator<T>::Interpolate(Iter,(Iter+2),Location)); }
228  return Interpolate(SubSection.begin(),SubSection.end(),Location);
229  }
230  };
231 
232  /// @brief If something specifically needs the linear interpolator for T they should use this.
233  /// @details This is with be a cubic spline where applicable, and will be
234  /// more smooth that the others, and be at least as intuitive as the linear version:
235  /// - Data points, will be valid interpolated values.
236  /// - There are no "Corners".
237  /// - Execution time is O^N.
238  /// - This shape defined by interpolating a set of these *will* leave a Convex Hull(or Axis Aligned Bounding Box) that could contain the data.
239  /// - Will be able to interpolated arbitrary sets of data points.
240  template <typename T>
242  {
243  public:
244  /// @brief The type this will interpolate
245  /// @note All Interpolators need to declare an InterpolatableType
247  /// @brief The storage for type for a cubic spline
249 
250  /// @brief Calculates the desired location on a cubic spline
251  /// @param Begin An iterator to the beginning of points to interpolate
252  /// @param End An iterator to the end of a data series, not one passed it.
253  /// @param Location A value between 0 and 1, that indicate how far along the curve the data point to retrieve is
254  /// @return This will return an value along a curve that passes smoothly through all the points passed.
255  template<typename TIterator>
256  static T Interpolate(TIterator Begin, TIterator End, Real Location)
257  {
258  /*std::vector<T> Points;
259  std::cout << "Unknown Type : " << typeid(TIterator).name() << std::endl
260  << "Vector<T> : " << typeid(std::vector<T>).name() << std::endl
261  << "Vector<T>::iterator : " << typeid(typename std::vector<T>::iterator).name() << std::endl
262  << "Storage : " << typeid(Storage).name() << std::endl
263  << "Storage::iterator : " << typeid(typename Storage::iterator).name() << std::endl
264  << "Storage::const_iterator : " << typeid(typename Storage::const_iterator).name() << std::endl
265  << "Is the unknown type a Storage::const_iterator? " << (typeid(typename Storage::const_iterator)==typeid(TIterator)) << std::endl
266  ;
267  Points.insert(Points.end(),Begin,End);// */
268  std::vector<T> Points(Begin, End);
269  std::vector<Real> Spacing(Points.size());
270  Real JumpSize = 1/PreciseReal(Points.size()-1);
271  Real CurrentJump=0;
272  for(std::vector<Real>::iterator Iter=Spacing.begin();
273  Iter!=Spacing.end();
274  Iter++)
275  {
276  *Iter=CurrentJump;
277  CurrentJump+=JumpSize;
278  }
279 
280  CubicSpline<Real,T> Spliney(Spacing,Points);
281  return Spliney.interpolate(Location);
282  }
283  };
284 
285 
286 } // /namespace Mezzanine
287 
288 #endif // Include guard