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