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