MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
trackiterator.h
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 _trackiterator_h
41 #define _trackiterator_h
42 
43 #include "countedptr.h"
44 
45 #ifndef SWIG // STD headers are bad for Swig
46  #include <cmath>
47  #include <limits>
48 
49  #include "crossplatform.h"
50 #endif
51 
52 
53 namespace Mezzanine
54 {
55  // Forward declation
56  template <typename InterpolatableType> class TrackBase;
57 
58  /// @brief An Iterator that can take an arbitrary amount of steps through a track.
59  /// @details This stores a value between 0.0 and 1.0 as the current location on a
60  /// track, and another value between 0.0 an 1.0 as how muc to move when
61  /// incremented. Everytime this is dereferenced it makes a call against the
62  /// track it targets and gets the point on the track that corresponds with is current
63  /// location. For example, presume SomeTrack is a valid track instance:
64  /// @code
65  /// SmoothTrackIterator< LinearInterpolator<Vector3> > Iter(&SomeTrack,0.0,1.0/200.0);
66  ///
67  /// for(Whole Counter = 0; Counter<200; Counter++
68  /// {
69  /// std::cout << *Iter << std::endl;
70  /// }
71  /// @endcode
72  /// This code will output 200 Vector3's lying on the path define by the track, which
73  /// are each separated b approximately 0.5% ofthe tracks full length. If the track is
74  /// small this could look pretty smooth
75  template<typename InterpolatorType>
77  {
78  public:
79  /// @brief The type the interpolator this works with uses.
80  typedef typename InterpolatorType::InterpolatableType InterpolatableType;
81  /// @brief What type is this iterator working with.
83  /// @brief When doing iterator math what is the type of math results
85  /// @brief The type of a pointer to the iterated type
87  /// @brief The type of a reference to the iterated type
89  /// @brief This almost supports random access iteration, it does not support any kind of writing to the container
90  typedef std::random_access_iterator_tag iterator_category;
91  /// @brief What kind of track with this iterate over
93  /// @brief The kind of this iterator.
95 
96  protected:
97  /// @brief The track this works against.
99  /// @brief Where on the track are we?
101  /// @brief How far should this
103 
104  /// @brief Move the iterator in the direction of the step.
105  void Increment()
106  { Location += Step; }
107  /// @brief Move the iterator in the opposite direction from the step.
108  void Decrement()
109  { Location -= Step; }
110  /// @brief Move the iterator a multiple (including negative multiples) of the step.
111  void StepAdjust(Integer Steps)
112  { Location += Step * PreciseReal(Steps); }
113 
114  public:
115  /// @brief The constructor for an iterator that can take an arbitrary amount steps through a series of data points
116  /// @details If default constructed this cannot be dereferenced and is only useful for comparisons
117  /// @param TrackToIterate Which track with this work against.
118  /// @param WhereToStart Where on the track (range 0 to 1) Should iteration start.
119  /// @param Increment When incremented how much should the location change? Defaults to .01 to create 100 steps.
120  SmoothTrackIterator(const TargetTrackType* const TrackToIterate = 0, Real WhereToStart = 0.0, Real Increment = 0.01)
121  : TargetTrack(TrackToIterate), Location(WhereToStart), Step(Increment)
122  {}
123  /// @brief Create a copy of an SmoothTrackIterator.
124  /// @param Copy The SmoothTrackIterator to copy.
126  : TargetTrack(Copy.TargetTrack), Location(Copy.Location), Step(Copy.Step)
127  {}
128 
129  /// @brief Change this SmoothTrackIterator to match another (Except for Track)
130  /// @param Other The SmoothTrackIterator to copy, except for its target track
131  /// @return A SmoothTrackIterator<InterpolatableType>
133  {
134  Location=Other.Location;
135  Step=Other.Step;
136  return *this;
137  }
138 
139  /// @brief Is this SmoothTrackIterator on the same track and in the same place as another.
140  /// @param Other The Other SmoothTrackIterator to compare this one too.
141  /// @return True if the track is the same and the location on the track is close enough to be within 1 epsilon.
142  bool operator==(const ThisType& Other) const
143  {
144  return //TargetTrack==Other.TargetTrack &&
145  (Other.Location-std::numeric_limits<Real>::epsilon())<=Location &&
146  Location<=(Other.Location+std::numeric_limits<Real>::epsilon());
147  }
148  /// @brief Is this SmoothTrackIterator not on the same track and in the same place as another.
149  /// @param Other The Other SmoothTrackIterator to compare this one too.
150  /// @return False if the track is the same and the location on the track is close enough to be within 1 epsilon.
151  bool operator!=(const ThisType& Other) const
152  { return !operator==(Other); }
153 
154  /// @brief Get the current location on the SmoothTrackIterator
155  /// @return An instance of InterpolatableType that is read only
156  /// @warning Most iterators return a reference, to allow changes in the underlying container. This returns points that are not stored, so they cannot be changed.
157  /// @note Everytime this is called this it calls the interpolator in the Target Track, This should run in constant time, but is much slower than normal pointer dereferences.
159  { return TargetTrack->GetInterpolated(Location); }
160  /// @brief Derefernce this with the syntax for pointer member access.
161  /// @return A Counted pointer to a temporary InterpolatableType instance.
162  /// @warning This is read only because it is not stored anywhere.
163  /// @note Everytime this is called it calls the interpolator in the Target Track.
166 
167  /// @brief Move the SmoothTrackIterator backwards on the track by on step.
168  /// @details The iterator is moved to a new position by subtracting the
169  /// step from the current location.
170  /// @return A Reference to this iterator after the change has been made.
172  {
173  Decrement();
174  return *this;
175  }
176  /// @brief Move the SmoothTrackIterator backwards on the track and get a copy of its location before
177  /// @details Like the prefix -- this moves the iterator, but this returns a copy
178  /// of the iterator before being increment.
179  /// @return An iterator that is a copy of this one before the decrement.
180  /// @note Even though the results of this could be assignable doing so is useless without storing the results in a new iterator so this is made const.
181  const ThisType operator--(int)
182  {
183  ThisType Results(*this);
184  Decrement();
185  return Results;
186  }
187 
188  /// @brief Move the SmoothTrackIterator forwards on the track by on step.
189  /// @details The iterator is moved to a new position by adding the
190  /// step from the current location.
191  /// @return A Reference to this iterator after the change has been made.
193  {
194  Increment();
195  return *this;
196  }
197  /// @brief Move the SmoothTrackIterator forwards on the track and get a copy of its location before
198  /// @details Like the prefix ++ this moves the iterator, but this returns a copy
199  /// of the iterator before being incremented.
200  /// @return An iterator that is a copy of this one before the decrement.
201  /// @note Even though the results of this could be assignable doing so is useless without storing the results in a new iterator so this is made const.
202  const ThisType operator++(int)
203  {
204  ThisType Results(*this);
205  Increment();
206  return Results;
207  }
208 
209  /// @brief Is the Iterator inside the track?
210  /// @return This returns 0 if iterator is in the bounds of the track, -1 if before and 1 if after the bounds of the track.
212  {
213  if(1.0 < Location)
214  { return 1; }
215  if(0.0 > Location)
216  { return -1; }
217  return 0;
218  }
219  /// @brief If this is iterator is beyond the bounds of the track it target *wrap* it around to the other side
220  /// @details Since the location on the track is stored as a value between 0.0 and 1.0 as long asthe step is
221  /// less than ,subtracting or adding one will preserve the apparent offset from the last location on looped
222  /// tracks
223  /// @return True if the bounds where outside the track and false if they where not.
225  {
226  Real Original = Location;
227  while(1.0<Location)
228  { Location--; }
229  while(0.0>Location)
230  { Location++; }
231  return Original!=Location;
232  }
233 
234  /// @brief Move a copy of this iterator a multiple of steps relative to the amount added
235  /// @return A reference to this iterator to allow multiple math operations.
236  /// @note Even though the results of this could be assignable doing so is useless without storing the results in a new iterator so this is made const.
238  {
239  ThisType Results(*this);
240  Results.StepAdjust(Steps);
241  return Results;
242  }
243  /// @brief Move a copy this iterator a negativemultiple of steps relative to the amount subtract
244  /// @return A reference to this iterator to allow multiple math operations.
245  /// @note Even though the results of this could be assignable doing so is useless without storing the results in a new iterator so this is made const.
247  {
248  ThisType Results(*this);
249  Results.StepAdjust(-Steps);
250  return Results;
251  }
252 
253  /// @brief Move this iterator a given amount of steps forward
254  /// @return A reference to this iterator so it could be used in other operations
256  {
257  StepAdjust(Steps);
258  return *this;
259  }
260  /// @brief Move this iterator a given amount of steps backwards
261  /// @return A reference to this iterator so it could be used in other operations
263  {
264  StepAdjust(-Steps);
265  return *this;
266  }
267 
268  /// @brief Compare which iterator is further along the track
269  /// @note The target track and the step size are ignored. This allows for potentially non-sensensical comparison.
270  /// @param Right The value on the right of the <.
271  /// @return true if this iterator is closer to the start of its track than right one, false otherwise.
272  bool operator<(const ThisType& Right)
273  { return Location < Right.Location; }
274  /// @brief Compare which iterator is further toward the track beginning.
275  /// @note The target track and the step size are ignored. This allows for potentially non-sensensical comparison.
276  /// @param Right The value on the right of the >.
277  /// @return true if the other iterator is closer to the start of its track than right one, false otherwise.
278  bool operator>(const ThisType& Right)
279  { return Location > Right.Location; }
280  /// @brief Compare which iterator is further along the track
281  /// @note The target track and the step size are ignored. This allows for potentially non-sensensical comparison.
282  /// @param Right The value on the right of the <=.
283  /// @return true if this iterator is closer to the start of its track than right one(or they are equidistant), false otherwise.
284  bool operator<=(const ThisType& Right)
285  { return Location <= Right.Location; }
286  /// @brief Compare which iterator is further toward the track beginning.
287  /// @note The target track and the step size are ignored. This allows for potentially non-sensensical comparison.
288  /// @param Right The value on the right of the >=.
289  /// @return true if the other iterator is closer to the start of its track than right one(or they are equidistant), false otherwise.
290  bool operator>=(const ThisType& Right)
291  { return Location >= Right.Location; }
292 
293  /// @brief Get an iterator an arbitrary number of steps forward or backwards.
294  /// @note Even though the results of this could be assignable doing so is useless without storing the results in a new iterator so this is made const.
295  /// @param Steps How many times to increment or decrement the iterator.
297  { return *this + Steps; }
298  };
299 
300  /// @brief This allows for addition with and an Integer on the Left hand side, such as: 2 + Iter
301  /// @param Steps The Integer on the left.
302  /// @param Iter The SmoothTrackIterator on the right.
303  template<typename InterpolatableType>
305  { return Iter + Steps; }
306  /// @brief This allows for subtraction with and an Integer on the Left hand side, such as: 2 + Iter
307  /// @param Steps The Integer on the left.
308  /// @param Iter The SmoothTrackIterator on the right.
309  template<typename InterpolatableType>
311  { return Iter - Steps; }
312 
313 
314 
315 
316  /// @brief This will take the same amount of clock time to iterate over a range.
317  /// @details This will spread movement over a range of a track evenly throughout
318  /// a period of time. For example if you have a track of Real values ranging
319  /// from 0.0 to 10.0, interpolating the point at 0.0 will return 0.0 and the
320  /// point 1.0 will return 10.0. Continuing this example if we were to define an
321  /// iterator over this range that will take exactly 1,000 milliseconds to
322  /// complete its journey, if we increment and dereference this 500 milliseconds
323  /// after it was instantiated it will return 5.0. This is the point halfway
324  /// through the range of the track because the time is halfway consumed.
325  /// @n @n
326  /// This iterator must be bounds checked to be safe to use. If incremented before
327  /// its start time its current location is set to its start time, if incremented
328  /// past its end time its current location becoms its end time.
329  /// @n @n
330  /// Here is a code sample that takes 3/4 of a second to iterate over the first
331  /// quarter of the data in a track.
332  /// @code
333  /// TimedTrackIterator< LinearInterpolator<Vector3> > Iter(&SomeTrack,0.0,0.25,750);
334  ///
335  /// bool SimulationIsStillRunning = true;
336  /// While(SimulationIsStillRunning)
337  /// {
338  /// // This does not increment the iterator like normal iterators, it
339  /// // just updates an internal record of time
340  /// Iter++;
341  ///
342  /// // When de-referencing the time is update
343  /// std::cout << *Iter << std::endl;
344  ///
345  /// // DoOtherSimulationStuff will return false when the simulation end, and
346  /// // presumably it does all the other stuff
347  /// SimulationIsStillRunning = DoOtherSimulationStuff();
348  /// }
349  /// @endcode
350  /// This code will emit to the standard output at least one Vector3 to the standard
351  /// output. All output will be between(inclusive) 0.0 and 0.25 with times closer to
352  /// the iterator creation time being near 0.0 and times closer to 750
353  template<typename InterpolatorType>
355  {
356  public:
357  /// @brief The type the interpolator this works with uses.
358  typedef typename InterpolatorType::InterpolatableType InterpolatableType;
359  /// @brief What type is this iterator working with.
361  /// @brief The type of a pointer to the iterated type
363  /// @brief The type of a reference to the iterated type
365  /// @brief This almost supports random access iteration, it does not support any kind of writing to the container
366  typedef std::input_iterator_tag iterator_category;
367  /// @brief What kind of track with this iterate over
369  /// @brief The kind of this iterator.
371 
372  protected:
373  /// @brief What Time does iteration start at
375  /// Where is this iterator now.
377  /// @brief What Time does iteration ed at
379 
380  /// @brief The track this works against.
382 
383  /// @brief Where Should Iteration Start
385  /// @brief Where should iteration stop
387 
388  /// @brief Update the current location of this iterator based on the current time
390  {
391  CurrentTime=Now;
392  if(Now<StartTime)
393  { CurrentTime = StartTime; }
394  if(EndTime<Now)
395  { CurrentTime = EndTime; }
396  }
397 
398  /// @brief Do the math for determining where/when the iterator is.
399  /// @return A value on the track corresponding to how far through time
401  {
402  MaxInt Length(EndTime - StartTime);
403  MaxInt Progress(CurrentTime - StartTime);
404  Real RangeLength(EndRange - StartRange);
405 
406  Real AdjustedProgress( PreciseReal((Progress)/PreciseReal(Length)) * PreciseReal(RangeLength) + PreciseReal(StartRange) );
407  return TargetTrack->GetInterpolated(AdjustedProgress);
408  }
409 
410  public:
411  /// @brief The constructor for and iterator
412  /// @details Tracks
413  /// @param TrackToIterate Which track with this work against.
414  /// @param StartOnTrack In the range of 0.0 to 1.0 Where on the track should iteration start. Defaults to 0.0.
415  /// @param EndOnTrack In the range of 0.0 to 1.0 Where on the track should iteration end. Defaults to 1.0.
416  /// @param Duration In microseconds how long should traversing the range of the track take. Defaults to 1 second.
417  /// @param WhenToStart The time iteration should start. Defaults to now.
418  TimedTrackIterator(const TargetTrackType* const TrackToIterate = 0,
419  Real StartOnTrack = 0.0,
420  Real EndOnTrack = 1.0,
421  MaxInt Duration = 1000000,
422  MaxInt WhenToStart = crossplatform::GetTimeStamp())
423  : StartTime(WhenToStart),
424  EndTime(Duration+WhenToStart),
425  TargetTrack(TrackToIterate),
426  StartRange(StartOnTrack),
427  EndRange(EndOnTrack)
428  { Update(WhenToStart); }
429  /// @brief Create a copy of an TimedTrackIterator.
430  /// @param Copy The TimedTrackIterator to copy.
432  : StartTime(Copy.StartTime),
433  CurrentTime(Copy.CurrentTime),
434  EndTime(Copy.EndTime),
435  TargetTrack(Copy.TargetTrack),
436  StartRange(Copy.StartRange),
437  EndRange(Copy.EndRange)
438  { }
439  /// @brief Change this TimedTrackIterator to match another (Except for Track)
440  /// @param Other The TimedTrackIterator to copy, except for its target track
441  /// @return A TimedTrackIterator<InterpolatableType>
443  {
444  StartRange=Other.StartRange;
445  EndRange=Other.EndRange;
446  StartTime=Other.StartTime;
447  CurrentTime=Other.CurrentTime;
448  EndTime=Other.EndTime;
449  return *this;
450  }
451 
452  /// @brief Is this TimedTrackIterator on the same track and in the same place as another.
453  /// @param Other The Other TimedTrackIterator to compare this one too.
454  /// @return True if the track is the same and the location on the same track.
455  bool operator== (const ThisType& Other) const
456  {
457  return TargetTrack==Other.TargetTrack &&
458  StartRange==Other.StartRange &&
459  EndRange==Other.EndRange &&
460  StartTime==Other.StartTime &&
461  CurrentTime==Other.CurrentTime &&
462  EndTime==Other.EndTime;
463  }
464  /// @brief Is this TimedTrackIterator not on the same track and in the same place as another.
465  /// @param Other The Other TimedTrackIterator to compare this one too.
466  /// @return False if the track is the same and the location on the same track.
467  bool operator!= (const ThisType& Other) const
468  { return !operator==(Other); }
469 
470  /// @brief Get the location on track from the last time it was incremented
471  /// @return An instance of InterpolatableType that is read only
472  /// @warning Most iterators return a reference, to allow changes in the underlying container. This returns points that are not stored, so they cannot be changed.
473  /// @note Everytime this is called this it calls the interpolator in the Target Track, This should run in constant time, but is much slower than normal pointer dereferences.
475  { return GetDereferenced(); }
476  /// @brief Dereference this with the syntax for pointer member access.
477  /// @return A Counted pointer to a temporary InterpolatableType instance.
478  /// @warning This is read only because it is not stored anywhere.
479  /// @note Everytime this is called it calls the interpolator in the Target Track.
482 
483  /// @brief Move the TimedTrackIterator forwards on the track by an amount proportionate to time elapsed.
484  /// @return A Reference to this iterator after the change has been made.
486  {
487  Update();
488  return *this;
489  }
490  /// @brief Move the TimedTrackIterator forwards on the track by an amount proportionate to time elapsed.
491  /// @details Like the prefix ++ this moves the iterator, but this returns a copy
492  /// of the iterator before being incremented.
493  /// @return An iterator that is a copy of this one before the decrement.
494  /// @note Even though the results of this could be assignable doing so is useless without storing the results in a new iterator so this is made const.
495  const ThisType operator++(int)
496  {
497  ThisType Results(*this);
498  Update();
499  return Results;
500  }
501 
502  /// @brief Is this iterator at the end of its range on the track
503  /// @return True if the iterator has been incremented to its bounds
504  bool AtEnd() const
505  { return EndTime == CurrentTime; }
506 
507  /// @brief Is this iterator at the beginning of its range on the track
508  /// @return True if the iterator has not been incremented or its time has not yet come.
509  bool AtStart() const
510  { return StartTime == CurrentTime; }
511  };
512 
513 
514 
515 
516 }//Mezzanine
517 
518 #endif
519