A quick fix for the mysterious non working isnan on macosx builds.
[synfig.git] / synfig-core / trunk / src / synfig / time.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file time.cpp
3 **      \brief Template File
4 **
5 **      $Id: time.cpp,v 1.1.1.1 2005/01/04 01:23:15 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "time.h"
33 #include <ETL/stringf>
34 #include <ETL/misc>
35 #include "general.h"
36 #include <cmath>
37 #include <cassert>
38 #include <ctype.h>
39 #include <math.h>
40
41
42 #ifdef WIN32
43 #include <float.h>
44 #ifndef isnan
45 extern "C" { int _isnan(double x); }
46 #define isnan _isnan
47 #endif
48 #endif
49
50 // For some reason isnan() isn't working on macosx any more.
51 // This is a quick fix.
52 #if defined(__APPLE__) && !defined(SYNFIG_ISNAN_FIX)
53 #ifdef isnan
54 #undef isnan
55 #endif
56 inline bool isnan(double x) { return x != x; }
57 inline bool isnan(float x) { return x != x; }
58 #define SYNFIG_ISNAN_FIX 1
59 #endif
60
61
62 #endif
63
64 /* === U S I N G =========================================================== */
65
66 using namespace std;
67 using namespace etl;
68 using namespace synfig;
69
70 #define tolower ::tolower
71
72 /* === M A C R O S ========================================================= */
73
74 /* === G L O B A L S ======================================================= */
75
76 /* === M E T H O D S ======================================================= */
77
78 Time::Time(const String &str_, float fps):
79         value_(0)
80 {
81         String str(str_);
82         std::transform(str.begin(),str.end(),str.begin(),&tolower);
83
84         // Start/Begin Of Time
85         if(str=="sot" || str=="bot")
86         {
87                 operator=(begin());
88                 return;
89         }
90         // End Of Time
91         if(str=="eot")
92         {
93                 operator=(end());
94                 return;
95         }
96
97
98         unsigned int pos=0;
99         int read;
100         float amount;
101         
102         // Now try to read it in the letter-abreviated format
103         while(pos<str.size() && sscanf(String(str,pos).c_str(),"%f%n",&amount,&read))
104         {
105                 pos+=read;
106                 if(pos>=str.size() || read==0)
107                 {
108                         // Throw up a warning if there are no units
109                         // and the amount isn't zero. There is no need
110                         // to warn about units if the value is zero
111                         // it is the only case where units are irrelevant.
112                         if(amount!=0)
113                                 synfig::warning("Time(): No unit provided in time code, assuming SECONDS (\"%s\")",str.c_str());
114                         value_+=amount;
115                         return;
116                 }
117                 switch(str[pos])
118                 {
119                         case 'h':
120                         case 'H':
121                                 value_+=amount*3600;
122                                 break;
123                         case 'm':
124                         case 'M':
125                                 value_+=amount*60;
126                                 break;
127                         case 's':
128                         case 'S':
129                                 value_+=amount;
130                                 break;
131                         case 'f':
132                         case 'F':
133                                 if(fps)
134                                         value_+=amount/fps;
135                                 else
136                                         synfig::warning("Time(): Individual frames referenced, but frame rate is unknown");
137                                 break;
138                         case ':':
139                                 // try to read it in as a traditional time format
140                                 {
141                                         int hour,minute,second;
142                                         float frame;
143                                         if(fps && sscanf(str.c_str(),"%d:%d:%d.%f",&hour,&minute,&second,&frame)==4)
144                                         {
145                                                         value_=frame/fps+(hour*3600+minute*60+second);
146                                                         return;
147                                         }
148                         
149                                         if(sscanf(str.c_str(),"%d:%d:%d",&hour,&minute,&second)==3)
150                                         {
151                                                 value_=hour*3600+minute*60+second;
152                                                 return;
153                                         }
154                                 }
155                                 synfig::warning("Time(): Bad time format");
156                                 break;
157
158                         default:
159                                 value_+=amount;
160                                 synfig::warning("Time(): Unexpected character '%c' when parsing time string \"%s\"",str[pos],str.c_str());
161                                 break;
162                 }
163                 pos++;
164                 amount=0;
165         }
166 }
167
168 String
169 Time::get_string(float fps, Time::Format format)const
170 {
171         Time time(*this);
172         
173         if(time<=begin())
174                 return "SOT";   // Start Of Time
175         if(time>=end())
176                 return "EOT";   // End Of Time
177         
178         if(fps<0)fps=0;
179         
180         if(ceil(time.value_)-time.value_<epsilon_())
181                 time.value_=ceil(time.value_);
182         
183         int hour,minute;
184         
185         hour=time/3600;time-=hour*3600;
186         minute=time/60;time-=minute*60;
187         
188         if(format<=FORMAT_VIDEO)
189         {
190                 int second;
191                 second=time;time-=second;
192
193                 if(fps)
194                 {
195                         int frame;
196                         frame=round_to_int(time*fps);
197
198                         return strprintf("%02d:%02d:%02d.%02d",hour,minute,second,frame);
199                 }
200                 else
201                         return strprintf("%02d:%02d:%02d",hour,minute,second);
202         }
203         
204         String ret;
205
206         if(format<=FORMAT_FULL || hour)
207                 ret+=strprintf(format<=FORMAT_NOSPACES?"%dh":"%dh ",hour);
208         
209         if(format<=FORMAT_FULL || hour || minute)
210                 ret+=strprintf(format<=FORMAT_NOSPACES?"%dm":"%dm ",minute);
211         
212         if(fps)
213         {
214                 int second;
215                 float frame;
216                 second=time;time-=second;
217                 frame=time*fps;
218                 if(format<=FORMAT_FULL || second)
219                         ret+=strprintf(format<=FORMAT_NOSPACES?"%ds":"%ds ",(int)second);
220                 
221                 if(abs(frame-floor(frame)>=epsilon_()))
222                         ret+=strprintf("%0.3ff",frame);
223                 else
224                         ret+=strprintf("%0.0ff",frame);
225         }
226         else
227         {
228                 float second;
229                 second=time;
230                 if(abs(second-floor(second))>=epsilon_())
231                         ret+=strprintf("%0.8fs",second);
232                 else
233                         ret+=strprintf("%0.0fs",second);
234         }
235         
236         return ret;
237 }
238
239 Time
240 Time::round(float fps)const
241 {
242         assert(fps>0);
243
244         value_type time(*this);
245
246         time*=fps;
247
248         if(abs(time-floor(time))<0.5)
249                 return floor(time)/fps;
250         else
251                 return ceil(time)/fps;
252 }
253
254 //! \writeme
255 bool
256 Time::is_valid()const
257 {
258         return !isnan(value_);
259 }