1 // timeline.cpp
2 //
3 // Object timelines.
4 //
5 // Copyright (C) 2008, the Celestia Development Team
6 // Initial version by Chris Laurel, claurel@gmail.com
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 
13 #include "celengine/timeline.h"
14 #include "celengine/timelinephase.h"
15 #include "celengine/frametree.h"
16 #include "celengine/frame.h"
17 
18 using namespace std;
19 
20 
21 /*! A Timeline is a list of TimelinePhases that covers a continuous
22  *  interval of time.
23  */
24 
Timeline()25 Timeline::Timeline()
26 {
27 }
28 
29 
~Timeline()30 Timeline::~Timeline()
31 {
32     for (vector<TimelinePhase*>::iterator iter = phases.begin(); iter != phases.end(); iter++)
33     {
34         // Remove the phase from whatever phase tree contains it.
35         TimelinePhase* phase = *iter;
36         phase->getFrameTree()->removeChild(phase);
37 
38         phase->release();
39     }
40 }
41 
42 
43 bool
appendPhase(TimelinePhase * phase)44 Timeline::appendPhase(TimelinePhase* phase)
45 {
46     // Validate start and end times. If there are existing phases in the timeline,
47     // startTime must be equal to endTime of the previous phases so that there are
48     // no gaps and no overlaps.
49     if (!phases.empty())
50     {
51         if (phase->startTime() != phases.back()->endTime())
52             return false;
53     }
54 
55     phase->addRef();
56     phases.push_back(phase);
57 
58     return true;
59 }
60 
61 
62 const TimelinePhase*
findPhase(double t) const63 Timeline::findPhase(double t) const
64 {
65     // Find the phase containing time t. The overwhelming common case is
66     // nPhases = 1, so we special case that. Otherwise, we do a simple linear search,
67     // as the number of phases in a timeline should always be quite small.
68     if (phases.size() == 1)
69     {
70         return phases[0];
71     }
72     else
73     {
74         for (vector<TimelinePhase*>::const_iterator iter = phases.begin(); iter != phases.end(); iter++)
75         {
76             if (t < (*iter)->endTime())
77                 return *iter;
78         }
79 
80         // Time is greater than the end time of the final phase. Just return the final phase.
81         return phases.back();
82     }
83 }
84 
85 
86 /*! Get the phase at the specified index.
87  */
88 const TimelinePhase*
getPhase(unsigned int n) const89 Timeline::getPhase(unsigned int n) const
90 {
91     return phases.at(n);
92 }
93 
94 
95 /*! Get the number of phases in this timeline.
96  */
97 unsigned int
phaseCount() const98 Timeline::phaseCount() const
99 {
100     return phases.size();
101 }
102 
103 
104 double
startTime() const105 Timeline::startTime() const
106 {
107     return phases.front()->startTime();
108 }
109 
110 
111 double
endTime() const112 Timeline::endTime() const
113 {
114     return phases.back()->endTime();
115 }
116 
117 
118 /*! Check whether the timeline covers the specified time t. True if
119  *  startTime <= t <= endTime. Note that this is deliberately different
120  *  than the TimelinePhase::includes function, which is only true if
121  *  t is strictly less than the end time.
122  */
123 bool
includes(double t) const124 Timeline::includes(double t) const
125 {
126     return phases.front()->startTime() <= t && t <= phases.back()->endTime();
127 }
128 
129 
130 void
markChanged()131 Timeline::markChanged()
132 {
133     if (phases.size() == 1)
134     {
135         phases[0]->getFrameTree()->markChanged();
136     }
137     else
138     {
139         for (vector<TimelinePhase*>::iterator iter = phases.begin(); iter != phases.end(); iter++)
140             (*iter)->getFrameTree()->markChanged();
141     }
142 }
143