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