Don't force angles to use linear interpolation.
[synfig.git] / synfig-core / trunk / src / synfig / valuenode_animated.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file valuenode_animated.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include <vector>
34 #include <list>
35 #include <stdexcept>
36
37 #include <cmath>
38
39 #include <ETL/bezier>
40 #include <ETL/hermite>
41 #include <ETL/spline>
42 #include <ETL/handle>
43 #include <ETL/misc>
44
45 #include <algorithm>
46 #include <typeinfo>
47
48 #include "canvas.h"
49 #include "general.h"
50 #include "valuenode_animated.h"
51 #include "valuenode_const.h"
52 #include "exception.h"
53 #include "gradient.h"
54
55 #endif
56
57 /* === U S I N G =========================================================== */
58
59 using namespace std;
60 using namespace etl;
61 using namespace synfig;
62
63 /* === M A C R O S ========================================================= */
64
65 // Fast binary search implementation
66 /*
67 template<typename I, typename T> inline I
68 binary_find(I begin, I end, const T& value)
69 {
70         I iter(begin+(end-begin)/2);
71
72         while(end-begin>1 && !(*iter==value))
73         {
74                 ((*iter<value)?begin:end) = iter;
75
76                 iter = begin+(end-begin)/2;
77         }
78         return iter;
79 }
80 */
81
82 /*
83 template<typename T> String tangent_info(T a, T b, T v)
84 {
85         return "...";
86 }
87
88 String tangent_info(Vector a, Vector b, Vector v)
89 {
90         if(a==b)
91                 return strprintf("(should be zero) T=[%f,%f], Pp=[%f,%f], Pn=[%f,%f]",v[0],v[1],a[0],a[1],b[0],b[1]);
92         else
93                 return strprintf("(should NOT be zero) T=[%f,%f], Pp=[%f,%f], Pn=[%f,%f]",v[0],v[1],a[0],a[1],b[0],b[1]);
94 }
95 */
96
97 template <class T>
98 struct subtractor : public std::binary_function<T, T, T>
99 {
100         T operator()(const T &a,const T &b)const
101         {
102                 return a-b;
103         }
104 };
105
106 template <>
107 struct subtractor<Angle> : public std::binary_function<Angle, Angle, Angle>
108 {
109         Angle operator()(const Angle &a,const Angle &b)const
110         {
111                 return a.dist(b);
112         }
113 };
114
115 template <class T>
116 struct magnitude : public std::unary_function<float, T>
117 {
118         float operator()(const T &a)const
119         {
120                 return abs(a);
121         }
122 };
123
124 template <>
125 struct magnitude<Angle> : public std::unary_function<float, Angle>
126 {
127         float operator()(const Angle &a)const
128         {
129                 return abs(Angle::rad(a).get());
130         }
131 };
132
133 template <>
134 struct magnitude<Vector> : public std::unary_function<float, Vector>
135 {
136         float operator()(const Vector &a)const
137         {
138                 return a.mag();
139         }
140 };
141
142 template <>
143 struct magnitude<Color> : public std::unary_function<float, Color>
144 {
145         float operator()(const Color &a)const
146         {
147                 return abs(a.get_y());
148         }
149 };
150
151
152
153
154
155 template <class T>
156 struct is_angle_type
157 {
158         bool operator()()const
159         {
160                 return false;
161         }
162 };
163
164 #ifdef ANGLES_USE_LINEAR_INTERPOLATION
165 template <>
166 struct is_angle_type<Angle>
167 {
168         bool operator()()const
169         {
170                 return true;
171         }
172 };
173 #endif  // ANGLES_USE_LINEAR_INTERPOLATION
174
175 /* === G L O B A L S ======================================================= */
176
177 /* === C L A S S E S ======================================================= */
178
179 template<typename T>
180 class _Hermite : public synfig::ValueNode_Animated
181 {
182 public:
183         typedef T value_type;
184         affine_combo<value_type,Time> affine_combo_func;
185         subtractor<value_type>  subtract_func;
186         magnitude<value_type>   magnitude_func;
187         is_angle_type<value_type>       is_angle;
188 private:
189         struct PathSegment
190         {
191                 is_angle_type<value_type>       is_angle;
192                 subtractor<value_type>  subtract_func;
193
194                 mutable hermite<Time,Time> first;
195                 mutable hermite<value_type,Time> second;
196                 WaypointList::iterator start;
197                 WaypointList::iterator end;
198
199                 value_type resolve(const Time &t)const
200                 {
201                         bool start_static(start->is_static());
202                         bool end_static(end->is_static());
203
204                         if(!start_static || !end_static)
205                         {
206                                 //if(!start_static)
207                                         second.p1()=start->get_value(t).get(value_type());
208                                 if(start->get_after()==INTERPOLATION_CONSTANT || end->get_before()==INTERPOLATION_CONSTANT)
209                                         return second.p1();
210                                 //if(!end_static)
211                                         second.p2()=end->get_value(t).get(value_type());
212
213                                 // At the moment, the only type of non-constant interpolation
214                                 // that we support is linear.
215                                 second.t1()=
216                                 second.t2()=subtract_func(second.p2(),second.p1());
217
218                                 second.sync();
219                         }
220
221                         return second(first(t));
222                 }
223         };
224         typedef vector <
225                 PathSegment
226                 /*
227                 pair <
228                         hermite<Time,Time>,
229                         hermite<value_type,Time>
230                 >
231                 */
232         > curve_list_type;
233
234         curve_list_type curve_list;
235
236         // Bounds of this curve
237         Time r,s;
238
239 public:
240         ValueNode* clone(const GUID& deriv_guid)const
241         {
242                 { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
243                 _Hermite<T>* ret(new _Hermite<T>());
244                 ret->set_guid(get_guid()^deriv_guid);
245                 for(WaypointList::const_iterator iter=waypoint_list().begin();iter!=waypoint_list().end();++iter)
246                         ret->add(iter->clone(deriv_guid));
247                 return ret;
248         }
249
250         _Hermite()
251         {
252                 set_type(ValueBase(value_type()).get_type());
253         }
254
255         virtual WaypointList::iterator new_waypoint(Time t, ValueBase value)
256         {
257                 // Make sure we are getting data of the correct type
258                 //if(data.type!=type)
259                 //      return waypoint_list_type::iterator();
260
261                 try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
262                 Waypoint waypoint(value,t);
263                 waypoint.set_parent_value_node(this);
264
265                 waypoint_list_.push_back(waypoint);
266                 WaypointList::iterator ret=waypoint_list_.end();
267                 --ret;
268
269                 if(is_angle())
270                 {
271                         ret->set_before(INTERPOLATION_LINEAR);
272                         ret->set_after(INTERPOLATION_LINEAR);
273                 }
274
275                 changed();
276
277                 return ret;
278         }
279
280         virtual WaypointList::iterator new_waypoint(Time t, ValueNode::Handle value_node)
281         {
282                 // Make sure we are getting data of the correct type
283                 //if(data.type!=type)
284                 //      return waypoint_list_type::iterator();
285                 try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
286
287                 Waypoint waypoint(value_node,t);
288                 waypoint.set_parent_value_node(this);
289
290                 waypoint_list_.push_back(waypoint);
291                 WaypointList::iterator ret=waypoint_list_.end();
292                 --ret;
293
294                 if(is_angle())
295                 {
296                         ret->set_before(INTERPOLATION_LINEAR);
297                         ret->set_after(INTERPOLATION_LINEAR);
298                 }
299
300                 changed();
301
302                 return ret;
303         }
304
305         virtual void on_changed()
306         {
307                 ValueNode_Animated::on_changed();
308
309                 if(waypoint_list_.size()<=1)
310                         return;
311                 std::sort(waypoint_list_.begin(),waypoint_list_.end());
312                 //waypoint_list_.sort();
313
314                 r=waypoint_list_.front().get_time();
315                 s=waypoint_list_.back().get_time();
316
317                 curve_list.clear();
318
319                 WaypointList::iterator prev,iter,next=waypoint_list_.begin();
320                 int i=0;
321
322                 for(iter=next++;iter!=waypoint_list_.end() && next!=waypoint_list_.end();prev=iter,iter=next++,i++)
323                 {
324                         typename curve_list_type::value_type curve;
325                         WaypointList::iterator after_next(next);
326                         ++after_next;
327
328                         curve.start=iter;
329                         curve.end=next;
330
331                         // Set up the positions
332                         curve.first.set_rs(iter->get_time(), next->get_time());
333                         curve.second.set_rs(iter->get_time(), next->get_time());
334
335                         Waypoint::Interpolation iter_get_after(iter->get_after());
336                         Waypoint::Interpolation next_get_after(next->get_after());
337                         Waypoint::Interpolation iter_get_before(iter->get_before());
338                         Waypoint::Interpolation next_get_before(next->get_before());
339
340                         if(is_angle())
341                         {
342                                 if(iter_get_after==INTERPOLATION_TCB)
343                                         iter_get_after=INTERPOLATION_LINEAR;
344                                 if(next_get_after==INTERPOLATION_TCB)
345                                         next_get_after=INTERPOLATION_LINEAR;
346                                 if(iter_get_before==INTERPOLATION_TCB)
347                                         iter_get_before=INTERPOLATION_LINEAR;
348                                 if(next_get_before==INTERPOLATION_TCB)
349                                         next_get_before=INTERPOLATION_LINEAR;
350                         }
351
352                         if(iter->is_static() && next->is_static())
353                         {
354                                 curve.second.p1()=iter->get_value().get(T());
355                                 curve.second.p2()=next->get_value().get(T());
356                                 if(iter_get_after==INTERPOLATION_CONSTANT || next_get_before==INTERPOLATION_CONSTANT)
357                                 {
358                                         // Sections must be constant on both sides.
359                                         // NOTE: this is commented out because of some
360                                         // user interface issues. Namely, if a section is
361                                         // constant and the user turns off the constant on
362                                         // one waypoint, this will end up turning it back on.
363                                         // Confusing.
364                                         //iter->get_after()=next->get_before()=INTERPOLATION_CONSTANT;
365                                         curve.second.p1()=
366                                         curve.second.p2()=iter->get_value().get(T());
367                                         curve.second.t1()=
368                                         curve.second.t2()=subtract_func(curve.second.p1(),curve.second.p2());
369                                 }
370                                 else
371                                 {
372                                         if(iter_get_after==INTERPOLATION_TCB && iter!=waypoint_list_.begin() && !is_angle())
373                                         {
374                                                 if(iter->get_before()!=INTERPOLATION_TCB && !curve_list.empty())
375                                                 {
376                                                         curve.second.t1()=curve_list.back().second.t2();
377                                                 }
378                                                 else
379                                                 {
380
381                                                 const Real& t(iter->get_tension());             // Tension
382                                                 const Real& c(iter->get_continuity());  // Continuity
383                                                 const Real& b(iter->get_bias());                        // Bias
384
385                                                 // The following line works where the previous line fails.
386                                                 value_type Pp; Pp=curve_list.back().second.p1();        // P_{i-1}
387
388                                                 const value_type& Pc(curve.second.p1());        // P_i
389                                                 const value_type& Pn(curve.second.p2());        // P_{i+1}
390
391                                                 // TCB
392                                                 value_type vect(static_cast<value_type>(subtract_func(Pc,Pp)*(((1.0-t)*(1.0+c)*(1.0+b))/2.0)+(Pn-Pc)*(((1.0-t)*(1.0-c)*(1.0-b))/2.0)));
393
394                                                 // Tension Only
395                                                 //value_type vect=(value_type)((Pn-Pp)*(1.0-t));
396
397                                                 // Linear
398                                                 //value_type vect=(value_type)(Pn-Pc);
399
400                                                 // Debugging stuff
401                                                 //synfig::info("%d:t1: %s",i,tangent_info(Pp,Pn,vect).c_str());
402
403                                                 // Adjust for time
404                                                 //vect=value_type(vect*(curve.second.get_dt()*2.0)/(curve.second.get_dt()+curve_list.back().second.get_dt()));
405                                                 //vect=value_type(vect*(curve.second.get_dt())/(curve_list.back().second.get_dt()));
406
407                                                 curve.second.t1()=vect;
408                                                 }
409                                         }
410                                         else if(
411                                                 iter_get_after==INTERPOLATION_LINEAR || iter_get_after==INTERPOLATION_HALT ||
412                                                 (iter_get_after==INTERPOLATION_TCB && iter==waypoint_list_.begin()))
413                                         {
414                                                 curve.second.t1()=subtract_func(curve.second.p2(),curve.second.p1());
415                                         }
416
417                                         if(iter_get_before==INTERPOLATION_TCB && iter->get_after()!=INTERPOLATION_TCB && !curve_list.empty())
418                                         {
419                                                 curve_list.back().second.t2()=curve.second.t1();
420                                                 curve_list.back().second.sync();
421                                         }
422
423
424                                         if(next_get_before==INTERPOLATION_TCB && after_next!=waypoint_list_.end()  && !is_angle())
425                                         {
426                                                 const Real &t(next->get_tension());             // Tension
427                                                 const Real &c(next->get_continuity());  // Continuity
428                                                 const Real &b(next->get_bias());                        // Bias
429                                                 const value_type &Pp(curve.second.p1());        // P_{i-1}
430                                                 const value_type &Pc(curve.second.p2());        // P_i
431                                                 value_type Pn; Pn=after_next->get_value().get(T());     // P_{i+1}
432
433                                                 // TCB
434                                                 value_type vect(static_cast<value_type>(subtract_func(Pc,Pp) * (((1.0-t)*(1.0-c)*(1.0+b))/2.0) +
435                                                                                                                                                          (Pn-Pc) * (((1.0-t)*(1.0+c)*(1.0-b))/2.0)));
436
437                                                 // Tension Only
438                                                 //value_type vect((value_type)((Pn-Pp)*(1.0-t)));
439
440                                                 // Linear
441                                                 //value_type vect=(value_type)(Pc-Pp);
442
443                                                 // Debugging stuff
444                                                 //synfig::info("%d:t2: %s",i,tangent_info(Pp,Pn,vect).c_str());
445
446                                                 // Adjust for time
447                                                 //vect=value_type(vect*(curve.second.get_dt()*2.0)/(curve.second.get_dt()+(after_next->get_time()-next->get_time())));
448                                                 //vect=value_type(vect*(curve.second.get_dt()/((after_next->get_time()-next->get_time()))));
449
450                                                 curve.second.t2()=vect;
451                                         }
452                                         else if(
453                                                 next_get_before==INTERPOLATION_LINEAR || next_get_before==INTERPOLATION_HALT ||
454                                                 (next_get_before==INTERPOLATION_TCB && after_next==waypoint_list_.end()))
455                                         {
456                                                 curve.second.t2()=subtract_func(curve.second.p2(),curve.second.p1());
457                                         }
458
459                                         // Adjust for time
460                                         const float timeadjust(0.5);
461
462                                         if(iter_get_after==INTERPOLATION_HALT)
463                                                 curve.second.t1()*=0;
464                                         // if this isn't the first curve
465                                         else if(iter_get_after != INTERPOLATION_LINEAR && !curve_list.empty())
466                                                 // adjust it for the curve that came before it
467                                                 curve.second.t1() *=
468                                                         //                  (time span of this curve) * 1.5
469                                                         // -----------------------------------------------------------------
470                                                         // ((time span of this curve) * 0.5) + (time span of previous curve)
471                                                         (curve.second.get_dt()*(timeadjust+1)) /
472                                                         (curve.second.get_dt()*timeadjust + curve_list.back().second.get_dt());
473
474                                         if(next_get_before==INTERPOLATION_HALT)
475                                                 curve.second.t2()*=0;
476                                         // if this isn't the last curve
477                                         else if(next_get_before != INTERPOLATION_LINEAR && after_next!=waypoint_list_.end())
478                                                 // adjust it for the curve that came after it
479                                                 curve.second.t2() *=
480                                                         //                (time span of this curve) * 1.5
481                                                         // -------------------------------------------------------------
482                                                         // ((time span of this curve) * 0.5) + (time span of next curve)
483                                                         (curve.second.get_dt()*(timeadjust+1)) /
484                                                         (curve.second.get_dt()*timeadjust+(after_next->get_time()-next->get_time()));
485                                 } // not CONSTANT
486                         }
487
488                         // Set up the time to the default stuff
489                         curve.first.set_rs(iter->get_time(), next->get_time());
490                         curve.first.p1()=iter->get_time();
491                         curve.first.p2()=next->get_time();
492                         curve.first.t1()=(curve.first.p2()-curve.first.p1())*(1.0f-iter->get_time_tension());
493                         curve.first.t2()=(curve.first.p2()-curve.first.p1())*(1.0f-next->get_time_tension());
494
495
496                         curve.first.sync();
497                         curve.second.sync();
498
499                         curve_list.push_back(curve);
500                 }
501         }
502
503         virtual ValueBase operator()(Time t)const
504         {
505                 if(waypoint_list_.empty())
506                         return value_type();    //! \todo Perhaps we should throw something here?
507                 if(waypoint_list_.size()==1)
508                         return waypoint_list_.front().get_value(t);
509                 if(t<=r)
510                         return waypoint_list_.front().get_value(t);
511                 if(t>=s)
512                         return waypoint_list_.back().get_value(t);
513
514                 typename curve_list_type::const_iterator iter;
515
516                 // This next line will set iter to the
517                 // correct iterator for the given time.
518                 for(iter=curve_list.begin();iter<curve_list.end() && t>=iter->first.get_s();++iter)
519                         continue;
520                 if(iter==curve_list.end())
521                         return waypoint_list_.back().get_value(t);
522                 return iter->resolve(t);
523         }
524 };
525
526
527 template<typename T>
528 class _Constant : public synfig::ValueNode_Animated
529 {
530 public:
531         typedef T value_type;
532
533 private:
534
535         // Bounds of this curve
536         Time r,s;
537
538 public:
539         ValueNode* clone(const GUID& deriv_guid)const
540         {
541                 { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
542                 _Constant<T>* ret(new _Constant<T>());
543                 ret->set_guid(get_guid()^deriv_guid);
544                 for(WaypointList::const_iterator iter=waypoint_list().begin();iter!=waypoint_list().end();++iter)
545                         ret->add(iter->clone(deriv_guid));
546                 return ret;
547         }
548
549         _Constant()
550         {
551                 set_type(ValueBase(value_type()).get_type());
552         }
553
554         virtual WaypointList::iterator new_waypoint(Time t, ValueBase value)
555         {
556                 // Make sure we are getting data of the correct type
557                 //if(data.type!=type)
558                 //      return waypoint_list_type::iterator();
559                 try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
560
561                 Waypoint waypoint(value,t);
562                 waypoint.set_parent_value_node(this);
563
564                 waypoint_list_.push_back(waypoint);
565                 WaypointList::iterator ret=waypoint_list_.end();
566                 --ret;
567                 changed();
568
569                 return ret;
570         }
571
572         virtual WaypointList::iterator new_waypoint(Time t, ValueNode::Handle value_node)
573         {
574                 // Make sure we are getting data of the correct type
575                 //if(data.type!=type)
576                 //      return waypoint_list_type::iterator();
577                 try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
578
579                 Waypoint waypoint(value_node,t);
580                 waypoint.set_parent_value_node(this);
581
582                 waypoint_list_.push_back(waypoint);
583                 WaypointList::iterator ret=waypoint_list_.end();
584                 --ret;
585                 changed();
586
587                 return ret;
588         }
589
590         virtual void on_changed()
591         {
592                 ValueNode_Animated::on_changed();
593
594                 if(waypoint_list_.size()<=1)
595                         return;
596                 std::sort(waypoint_list_.begin(),waypoint_list_.end());
597                 //waypoint_list_.sort();
598                 r=waypoint_list_.front().get_time();
599                 s=waypoint_list_.back().get_time();
600
601         }
602
603         virtual ValueBase operator()(Time t)const
604         {
605                 if(waypoint_list_.size()==1)
606                         return waypoint_list_.front().get_value(t);
607                 if(waypoint_list_.empty())
608                         return value_type();
609                 if(t<=r)
610                         return waypoint_list_.front().get_value(t);
611                 if(t>=s)
612                         return waypoint_list_.back().get_value(t);
613
614                 typename WaypointList::const_iterator iter;
615                 typename WaypointList::const_iterator next;
616
617                 // This next line will set iter to the
618                 // correct iterator for the given time.
619                 for(next=waypoint_list_.begin(),iter=next++;next!=waypoint_list_.end() && t>=next->get_time();iter=next++)
620                         continue;
621
622                 return iter->get_value(t);
623         }
624 };
625
626 class _AnimBool : public synfig::ValueNode_Animated
627 {
628 public:
629         typedef bool value_type;
630
631 private:
632
633         // Bounds of this curve
634         Time r,s;
635
636 public:
637         ValueNode* clone(const GUID& deriv_guid)const
638         {
639                 { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
640                 _AnimBool* ret(new _AnimBool());
641                 ret->set_guid(get_guid()^deriv_guid);
642                 for(WaypointList::const_iterator iter=waypoint_list().begin();iter!=waypoint_list().end();++iter)
643                         ret->add(iter->clone(deriv_guid));
644                 return ret;
645         }
646
647         _AnimBool()
648         {
649                 set_type(ValueBase(value_type()).get_type());
650         }
651
652         virtual WaypointList::iterator new_waypoint(Time t, ValueBase value)
653         {
654                 // Make sure we are getting data of the correct type
655                 //if(data.type!=type)
656                 //      return waypoint_list_type::iterator();
657                 try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
658
659
660                 Waypoint waypoint(value,t);
661                 waypoint.set_parent_value_node(this);
662
663                 waypoint_list_.push_back(waypoint);
664                 WaypointList::iterator ret=waypoint_list_.end();
665                 --ret;
666                 changed();
667
668                 return ret;
669         }
670
671         virtual WaypointList::iterator new_waypoint(Time t, ValueNode::Handle value_node)
672         {
673                 // Make sure we are getting data of the correct type
674                 //if(data.type!=type)
675                 //      return waypoint_list_type::iterator();
676                 try { find(t); throw Exception::BadTime(_("A waypoint already exists at this point in time")); } catch(Exception::NotFound) { };
677
678                 Waypoint waypoint(value_node,t);
679                 waypoint.set_parent_value_node(this);
680
681                 waypoint_list_.push_back(waypoint);
682                 WaypointList::iterator ret=waypoint_list_.end();
683                 --ret;
684                 changed();
685
686                 return ret;
687         }
688
689         virtual void on_changed()
690         {
691                 ValueNode_Animated::on_changed();
692
693                 if(waypoint_list_.size()<=1)
694                         return;
695                 std::sort(waypoint_list_.begin(),waypoint_list_.end());
696                 //waypoint_list_.sort();
697                 r=waypoint_list_.front().get_time();
698                 s=waypoint_list_.back().get_time();
699
700         }
701
702         virtual ValueBase operator()(Time t)const
703         {
704                 if(waypoint_list_.size()==1)
705                         return waypoint_list_.front().get_value(t);
706                 if(waypoint_list_.empty())
707                         return false;
708                 if(t<r)
709                         return waypoint_list_.front().get_value(t);
710                 if(t>s)
711                         return waypoint_list_.back().get_value(t);
712
713                 WaypointList::const_iterator iter;
714                 WaypointList::const_iterator next;
715
716                 // This next line will set iter to the
717                 // correct iterator for the given time.
718                 for(next=waypoint_list_.begin(),iter=next++;next!=waypoint_list_.end() && t>=next->get_time();iter=next++)
719                         if(iter->get_time()==t)
720                                 return iter->get_value(t);
721
722                 if(iter->get_time()==t)
723                         return iter->get_value(t);
724
725                 if(next!=waypoint_list_.end())
726                         return iter->get_value(t).get(bool()) || next->get_value(t).get(bool());
727                 return iter->get_value(t);
728         }
729 };
730
731 /* === M E T H O D S ======================================================= */
732
733 ValueNode_Animated::ValueNode_Animated()
734 {
735         DCAST_HACK_ENABLE();
736 }
737
738 int
739 ValueNode_Animated::find(const Time& begin,const Time& end,std::vector<Waypoint*>& selected)
740 {
741         Time curr_time(begin);
742         int ret(0);
743
744         // try to grab first waypoint
745         try
746         {
747                 WaypointList::iterator iter;
748                 iter=find(curr_time);
749                 selected.push_back(&*iter);
750                 ret++;
751         }
752         catch(...) { }
753
754         try
755         {
756                 WaypointList::iterator iter;
757                 while(true)
758                 {
759                         iter=find_next(curr_time);
760                         curr_time=iter->get_time();
761                         if(curr_time>=end)
762                                 break;
763                         selected.push_back(&*iter);
764                         ret++;
765                 }
766         }
767         catch(...) { }
768
769         return ret;
770 }
771
772 /*
773 void
774 ValueNode_Animated::manipulate_time(const Time& old_begin,const Time& old_end,const Time& new_begin,const Time& new_end)
775 {
776 #define old_2_new(x)    (((x)-old_begin)/(old_end-old_begin)*(new_end-new_begin)+new_begin)
777         std::vector<Waypoint*> selected;
778         std::vector<Waypoint*>::iterator iter;
779
780         if(find(old_begin,old_end,selected))
781         {
782                 // check to make sure this operation is OK
783                 for(iter=selected.begin();iter!=selected.end();++iter)
784                 {
785                         try
786                         {
787                                 Time new_time(old_2_new((*iter)->get_time()));
788                                 if(new_time>=old_begin && new_time<old_end)
789                                         continue;
790                                 find(new_time);
791                                 // If we found a waypoint already at that time, then
792                                 // we need to abort
793                                 throw Exception::BadTime(_("Waypoint Conflict"));
794                         }
795                         catch(Exception::NotFound) { }
796
797                         selected.back()->set_time(old_2_new(selected.back()->get_time()));
798                         selected.pop_back();
799                 }
800
801
802                 while(!selected.empty())
803                 {
804                         selected.back()->set_time(old_2_new(selected.back()->get_time()));
805                         selected.pop_back();
806                 }
807
808                 changed();
809         }
810 #undef old_2_new
811 }
812 */
813
814 Waypoint
815 ValueNode_Animated::new_waypoint_at_time(const Time& time)const
816 {
817         Waypoint waypoint;
818         try
819         {
820                 // Trivial case, we are sitting on a waypoint
821                 waypoint=*find(time);
822                 waypoint.make_unique();
823         }
824         catch(...)
825         {
826                 if(waypoint_list().empty())
827                 {
828                         waypoint.set_value((*this)(time));
829                 }
830                 else
831                 {
832                         WaypointList::const_iterator prev;
833                         WaypointList::const_iterator next;
834
835                         bool has_prev(false), has_next(false);
836
837                         try { prev=find_prev(time); has_prev=true; } catch(...) { }
838                         try { next=find_next(time); has_next=true; } catch(...) { }
839
840                         /*
841                         WaypointList::const_iterator closest;
842
843                         if(has_prev&&!has_next)
844                                 closest=prev;
845                         else if(has_next&&!has_prev)
846                                 closest=next;
847                         else if(time-prev->get_time()<next->get_time()-time)
848                                 closest=prev;
849                         else
850                                 closest=next;
851
852                         for(iter=waypoint_list().begin();iter!=waypoint_list().end();++iter)
853                         {
854                                 const Real dist(abs(iter->get_time()-time));
855                                 if(dist<abs(closest->get_time()-time))
856                                         closest=iter;
857                         }
858                         */
859
860                         if(has_prev && !prev->is_static())
861                                 waypoint.set_value_node(prev->get_value_node());
862                         if(has_next && !next->is_static())
863                                 waypoint.set_value_node(next->get_value_node());
864                         else
865                                 waypoint.set_value((*this)(time));
866
867                         /*if(has_prev)
868                                 waypoint.set_after(prev->get_before());
869                         if(has_next)
870                                 waypoint.set_before(next->get_after());
871                         */
872                 }
873         }
874         waypoint.set_time(time);
875         waypoint.set_parent_value_node(const_cast<ValueNode_Animated*>(this));
876 //      synfig::info("waypoint.get_after()=set to %d",waypoint.get_after());
877 //      synfig::info("waypoint.get_before()=set to %d",waypoint.get_before());
878
879         return waypoint;
880 }
881
882 ValueNode_Animated::WaypointList::iterator
883 ValueNode_Animated::find(const UniqueID &x)
884 {
885         ValueNode_Animated::WaypointList::iterator iter;
886         iter=std::find(waypoint_list().begin(),waypoint_list().end(),x);
887         if(iter==waypoint_list().end() || iter->get_uid()!=x.get_uid())
888                 throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find UniqueID %d",x.get_uid()));
889         return iter;
890 }
891
892 ValueNode_Animated::WaypointList::const_iterator
893 ValueNode_Animated::find(const UniqueID &x)const
894 {
895         return const_cast<ValueNode_Animated*>(this)->find(x);
896         /*
897         ValueNode_Animated::WaypointList::const_iterator iter;
898         iter=std::find(waypoint_list().begin(),waypoint_list().end(),x);
899         if(iter!=waypoint_list().end() && iter->get_uid()!=x.get_uid())
900                 throw Exception::NotFound(strprintf("ValueNode_Animated::find()const: Can't find UniqueID %d",x.get_uid()));
901         return iter;
902         */
903 }
904
905 ValueNode_Animated::WaypointList::iterator
906 ValueNode_Animated::find(const Time &x)
907 {
908         WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
909
910         if(iter!=waypoint_list().end() && x.is_equal(iter->get_time()))
911                 return iter;
912
913         throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find Waypoint at %s",x.get_string().c_str()));
914 }
915
916 ValueNode_Animated::WaypointList::const_iterator
917 ValueNode_Animated::find(const Time &x)const
918 {
919         return const_cast<ValueNode_Animated*>(this)->find(x);
920         /*
921         WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
922
923         if(iter!=waypoint_list().end() && x.is_equal(iter->get_time()))
924                 return iter;
925
926         throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find Waypoint at %s",x.get_string().c_str()));
927         */
928 }
929
930 ValueNode_Animated::WaypointList::iterator
931 ValueNode_Animated::find_next(const Time &x)
932 {
933         WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
934
935         if(iter!=waypoint_list().end())
936         {
937                 if(iter->get_time().is_more_than(x))
938                         return iter;
939                 ++iter;
940                 if(iter!=waypoint_list().end() && iter->get_time().is_more_than(x))
941                         return iter;
942         }
943
944         throw Exception::NotFound(strprintf("ValueNode_Animated::find_next(): Can't find Waypoint after %s",x.get_string().c_str()));
945 }
946
947 ValueNode_Animated::WaypointList::const_iterator
948 ValueNode_Animated::find_next(const Time &x)const
949 {
950         return const_cast<ValueNode_Animated*>(this)->find_next(x);
951         /*
952         WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
953
954         if(iter!=waypoint_list().end())
955         {
956                 if(iter->get_time()-Time::epsilon()>x)
957                         return iter;
958                 ++iter;
959                 if(iter!=waypoint_list().end() && iter->get_time()-Time::epsilon()>x)
960                         return iter;
961         }
962
963         throw Exception::NotFound(strprintf("ValueNode_Animated::find_next(): Can't find Waypoint after %s",x.get_string().c_str()));
964 */
965 }
966
967 ValueNode_Animated::WaypointList::iterator
968 ValueNode_Animated::find_prev(const Time &x)
969 {
970         WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
971
972         if(iter!=waypoint_list().end())
973         {
974                 if(iter->get_time().is_less_than(x))
975                         return iter;
976                 if(iter!=waypoint_list().begin() && (--iter)->get_time().is_less_than(x))
977                         return iter;
978         }
979
980         throw Exception::NotFound(strprintf("ValueNode_Animated::find_prev(): Can't find Waypoint after %s",x.get_string().c_str()));
981 }
982
983 ValueNode_Animated::WaypointList::const_iterator
984 ValueNode_Animated::find_prev(const Time &x)const
985 {
986         return const_cast<ValueNode_Animated*>(this)->find_prev(x);
987         /*
988         WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
989
990         if(iter!=waypoint_list().end())
991         {
992                 if(iter->get_time()+Time::epsilon()<x)
993                         return iter;
994                 if(iter!=waypoint_list().begin() && (--iter)->get_time()+Time::epsilon()<x)
995                         return iter;
996         }
997         throw Exception::NotFound(strprintf("ValueNode_Animated::find_prev(): Can't find Waypoint after %s",x.get_string().c_str()));
998         */
999 }
1000
1001 void
1002 ValueNode_Animated::erase(const UniqueID &x)
1003 {
1004         waypoint_list().erase(find(x));
1005 }
1006
1007 ValueNode_Animated::WaypointList::iterator
1008 ValueNode_Animated::add(const Waypoint &x)
1009 {
1010         Waypoint waypoint(x);
1011         waypoint.set_parent_value_node(this);
1012         waypoint_list_.push_back(waypoint);
1013         //assert(waypoint_list_.back().get_parent_value_node()==this);
1014         WaypointList::iterator ret=waypoint_list_.end();
1015         --ret;
1016         changed();
1017         return ret;
1018 }
1019
1020 void
1021 ValueNode_Animated::set_type(ValueBase::Type t)
1022 {
1023         ValueNode::set_type(t);
1024 }
1025
1026 ValueNode_Animated::Handle
1027 synfig::ValueNode_Animated::create(ValueBase::Type type)
1028 {
1029         switch(type)
1030         {
1031                 case ValueBase::TYPE_TIME:
1032                         return ValueNode_Animated::Handle(new _Hermite<Time>);
1033                 case ValueBase::TYPE_REAL:
1034                         return ValueNode_Animated::Handle(new _Hermite<Vector::value_type>);
1035                 case ValueBase::TYPE_INTEGER:
1036                         return ValueNode_Animated::Handle(new _Hermite<int>);
1037                 case ValueBase::TYPE_ANGLE:
1038                         return ValueNode_Animated::Handle(new _Hermite<Angle>);
1039                 case ValueBase::TYPE_VECTOR:
1040                         return ValueNode_Animated::Handle(new _Hermite<Vector>);
1041                 case ValueBase::TYPE_COLOR:
1042                         return ValueNode_Animated::Handle(new _Hermite<Color>);
1043
1044                 case ValueBase::TYPE_STRING:
1045                         return ValueNode_Animated::Handle(new _Constant<String>);
1046                 case ValueBase::TYPE_GRADIENT:
1047                         return ValueNode_Animated::Handle(new _Hermite<Gradient>);
1048                 case ValueBase::TYPE_BOOL:
1049                         return ValueNode_Animated::Handle(new _AnimBool);
1050                 case ValueBase::TYPE_CANVAS:
1051                         return ValueNode_Animated::Handle(new _Constant<Canvas::LooseHandle>);
1052                 default:
1053                         throw
1054                                 Exception::BadType(strprintf(_("%s: You cannot use a %s in an animated ValueNode"),"synfig::ValueNode_Animated::create()",
1055                                         ValueBase::type_name(type).c_str())
1056                                 );
1057                         break;
1058         }
1059         return ValueNode_Animated::Handle();
1060 }
1061
1062 ValueNode_Animated::Handle
1063 ValueNode_Animated::create(const ValueBase& value, const Time& time)
1064 {
1065         return create(ValueNode::Handle(ValueNode_Const::create(value)),time);
1066 }
1067
1068 ValueNode_Animated::Handle
1069 ValueNode_Animated::create(ValueNode::Handle value_node, const Time& time)
1070 {
1071         ValueNode_Animated::Handle ret(create(value_node->get_type()));
1072         ret->new_waypoint(time,value_node);
1073         return ret;
1074 }
1075
1076 ValueNode_Animated::~ValueNode_Animated()
1077 {
1078 }
1079
1080 String
1081 ValueNode_Animated::get_name()const
1082 {
1083         return "animated";
1084 }
1085
1086 String
1087 ValueNode_Animated::get_local_name()const
1088 {
1089         return _("Animated");
1090 }
1091
1092 void ValueNode_Animated::get_times_vfunc(Node::time_set &set) const
1093 {
1094         //add all the way point times to the value node...
1095
1096         WaypointList::const_iterator    i = waypoint_list().begin(),
1097                                                                         end = waypoint_list().end();
1098
1099         for(; i != end; ++i)
1100         {
1101                 TimePoint t;
1102                 t.set_time(i->get_time());
1103                 t.set_before(i->get_before());
1104                 t.set_after(i->get_after());
1105                 t.set_guid(i->get_guid());
1106                 set.insert(t);
1107         }
1108 }
1109 struct timecmp
1110  {
1111         Time t;
1112
1113         timecmp(const Time &c) :t(c) {}
1114
1115         bool operator()(const Waypoint &rhs) const
1116         {
1117                 return t.is_equal(rhs.get_time());
1118         }
1119  };
1120
1121  ValueNode_Animated::findresult
1122  ValueNode_Animated::find_uid(const UniqueID &x)
1123  {
1124         findresult      f;
1125         f.second = false;
1126
1127         //search for it... and set the bool part of the return value to true if we found it!
1128         f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
1129         if(f.first != waypoint_list_.end())
1130                 f.second = true;
1131
1132         return f;
1133  }
1134
1135  ValueNode_Animated::const_findresult
1136  ValueNode_Animated::find_uid(const UniqueID &x)const
1137  {
1138         const_findresult        f;
1139         f.second = false;
1140
1141         //search for it... and set the bool part of the return value to true if we found it!
1142         f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
1143         if(f.first != waypoint_list_.end())
1144                 f.second = true;
1145
1146         return f;
1147  }
1148
1149  ValueNode_Animated::findresult
1150  ValueNode_Animated::find_time(const Time &x)
1151  {
1152         findresult      f;
1153         f.second = false;
1154
1155         //search for it... and set the bool part of the return value to true if we found it!
1156         f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
1157         if(f.first != waypoint_list_.end())
1158                 f.second = true;
1159
1160         return f;
1161  }
1162
1163 ValueNode_Animated::const_findresult
1164 ValueNode_Animated::find_time(const Time &x)const
1165 {
1166         const_findresult        f;
1167         f.second = false;
1168
1169         //search for it... and set the bool part of the return value to true if we found it!
1170         f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
1171         if(f.first != waypoint_list_.end())
1172                 f.second = true;
1173
1174         return f;
1175 }
1176
1177 void
1178 ValueNode_Animated::insert_time(const Time& location, const Time& delta)
1179 {
1180         if(!delta)
1181                 return;
1182         try
1183         {
1184                 WaypointList::iterator iter(find_next(location));
1185                 for(;iter!=waypoint_list().end();++iter)
1186                 {
1187                         iter->set_time(iter->get_time()+delta);
1188                 }
1189                 changed();
1190         }
1191         catch(Exception::NotFound) { }
1192 }