1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 #include <QTextStream>
18 #include <cmath>
19
20 #include "TimeDef.h"
21
22 #define FPS 1
23 #define EPSILON 1.0e-10
24
25
Time()26 Time::Time() :
27 type_(ExactFrame),
28 frame_(0), time_(0)
29 {
30 }
31
Time(int f)32 Time::Time(int f) :
33 type_(ExactFrame),
34 frame_(f),
35 time_(f/(double)FPS)
36 {
37 }
38
Time(int f,bool justAfter)39 Time::Time(int f, bool justAfter) :
40 frame_(f),
41 time_(f/(double)FPS)
42 {
43 if(justAfter)
44 {
45 type_ = JustAfterFrame;
46 // TODO: change the implementation, use the nextafter()
47 // methods, providing in C99 or C++11
48 // e.g.: 1.0e7 + 1.0e-10 != 1.0e7
49 // but 1.0e5 + 1.0e-10 >> 1.0e5 (>> means lot of floats inbetween)
50
51 // would still be ok in normal cases, and even -1 day < t < 1 day...
52 time_ += EPSILON;
53 }
54 else
55 {
56 type_ = JustBeforeFrame;
57 time_ -= EPSILON;
58 }
59 }
60
Time(double t)61 Time::Time(double t) :
62 type_(FloatTime),
63 frame_(std::floor(t*FPS)), // by default, truncate towards negative infinite
64 time_(t)
65 {
66 double eps = 1.0e-4;
67 double rounded = std::floor(t*FPS+0.5);
68 double rest = t - rounded;
69 if( -eps<rest && rest<eps ) // unless epsilon-close to an integer (e.g., t=41.9999)
70 {
71 type_ = ExactFrame; // in which case we assume the frame is exact
72 frame_ = (int) rounded; // and truncate to nearest (e.g., 42)
73 }
74 }
75
operator <(const Time & other) const76 bool Time::operator<(const Time & other) const
77 {
78 if(type() != other.type())
79 {
80 // a robust way would not do that, but ok in normal cases
81 return floatTime() < other.floatTime();
82 }
83 else
84 {
85 switch (type())
86 {
87 case ExactFrame:
88 case JustBeforeFrame:
89 case JustAfterFrame:
90 return frame() < other.frame();
91 case FloatTime:
92 return floatTime() < other.floatTime();
93 default:
94 return false;
95 }
96 }
97 }
98
operator >(const Time & other) const99 bool Time::operator>(const Time & other) const
100 {
101 return other<*this;
102 }
103
operator >=(const Time & other) const104 bool Time::operator>=(const Time & other) const
105 {
106 return (*this > other) || (*this == other);
107 }
108
operator <=(const Time & other) const109 bool Time::operator<=(const Time & other) const
110 {
111 return (*this < other) || (*this == other);
112 }
113
operator ==(const Time & other) const114 bool Time::operator==(const Time & other) const
115 {
116 if(type() != other.type())
117 return false;
118 else
119 {
120 switch (type())
121 {
122 case ExactFrame:
123 case JustBeforeFrame:
124 case JustAfterFrame:
125 return frame() == other.frame();
126 case FloatTime:
127 return floatTime() == other.floatTime();
128 default:
129 return true;
130 }
131 }
132 }
133
operator !=(const Time & other) const134 bool Time::operator!=(const Time & other) const
135 {
136 return !( *this == other );
137 }
138
operator +(const Time & other) const139 Time Time::operator+(const Time & other) const
140 {
141 if(type() != other.type())
142 {
143 // a robust way would not do that, but ok in normal cases
144 return Time(floatTime() + other.floatTime());
145 }
146 else
147 {
148 switch (type())
149 {
150 case ExactFrame:
151 case JustBeforeFrame:
152 case JustAfterFrame:
153 return Time(frame() + other.frame());
154 case FloatTime:
155 return Time(floatTime() + other.floatTime());
156 default:
157 return Time();
158 }
159 }
160 }
161
operator -(const Time & other) const162 Time Time::operator-(const Time & other) const
163 {
164 if(type() != other.type())
165 {
166 // a robust way would not do that, but ok in normal cases
167 return Time(floatTime() - other.floatTime());
168 }
169 else
170 {
171 switch (type())
172 {
173 case ExactFrame:
174 case JustBeforeFrame:
175 case JustAfterFrame:
176 return Time(frame() - other.frame());
177 case FloatTime:
178 return Time(floatTime() - other.floatTime());
179 default:
180 return Time();
181 }
182 }
183 }
184
185
save(QTextStream & out)186 void Time::save(QTextStream & out)
187 {
188 switch (type())
189 {
190 case ExactFrame:
191 out << "ExactFrame " << frame();
192 return;
193 case JustBeforeFrame:
194 out << "JustBeforeFrame " << frame();
195 return;
196 case JustAfterFrame:
197 out << "JustAfterFrame " << frame();
198 return;
199 case FloatTime:
200 out << "FloatTime " << floatTime();
201 return;
202 default:
203 return;
204 }
205 }
206
operator <<(QTextStream & str,const Time & time)207 QTextStream & operator<<(QTextStream & str, const Time & time)
208 {
209 switch (time.type())
210 {
211 case Time::ExactFrame:
212 str << "ExactFrame " << time.frame();
213 return str;
214 case Time::JustBeforeFrame:
215 str << "JustBeforeFrame " << time.frame();
216 return str;
217 case Time::JustAfterFrame:
218 str << "JustAfterFrame " << time.frame();
219 return str;
220 case Time::FloatTime:
221 str << "FloatTime " << time.floatTime();
222 return str;
223 default:
224 return str;
225 }
226 }
227
operator >>(QTextStream & str,Time & time)228 QTextStream & operator>>(QTextStream & str, Time & time)
229 {
230 QString type;
231 str >> type;
232
233 if(type == "ExactFrame")
234 {
235 int frame;
236 str >> frame;
237 time = Time(frame);
238 }
239 else if(type == "JustBeforeFrame")
240 {
241 int frame;
242 str >> frame;
243 time = Time(frame, 0);
244 }
245 else if(type == "JustAfterFrame")
246 {
247 int frame;
248 str >> frame;
249 time = Time(frame, 1);
250 }
251 else if(type == "FloatTime")
252 {
253 double t;
254 str >> t;
255 time = Time(t);
256 }
257
258 return str;
259 }
260