Remove dynamic cast hack
[synfig.git] / synfig-core / 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, 2008 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 synfig::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_temporal_tension());
495                         curve.first.t2()=(curve.first.p2()-curve.first.p1())*(1.0f-next->get_temporal_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 synfig::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 synfig::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 }
738
739 int
740 ValueNode_Animated::find(const Time& begin,const Time& end,std::vector<Waypoint*>& selected)
741 {
742         Time curr_time(begin);
743         int ret(0);
744
745         // try to grab first waypoint
746         try
747         {
748                 WaypointList::iterator iter;
749                 iter=find(curr_time);
750                 selected.push_back(&*iter);
751                 ret++;
752         }
753         catch(...) { }
754
755         try
756         {
757                 WaypointList::iterator iter;
758                 while(true)
759                 {
760                         iter=find_next(curr_time);
761                         curr_time=iter->get_time();
762                         if(curr_time>=end)
763                                 break;
764                         selected.push_back(&*iter);
765                         ret++;
766                 }
767         }
768         catch(...) { }
769
770         return ret;
771 }
772
773 /*
774 void
775 ValueNode_Animated::manipulate_time(const Time& old_begin,const Time& old_end,const Time& new_begin,const Time& new_end)
776 {
777 #define old_2_new(x)    (((x)-old_begin)/(old_end-old_begin)*(new_end-new_begin)+new_begin)
778         std::vector<Waypoint*> selected;
779         std::vector<Waypoint*>::iterator iter;
780
781         if(find(old_begin,old_end,selected))
782         {
783                 // check to make sure this operation is OK
784                 for(iter=selected.begin();iter!=selected.end();++iter)
785                 {
786                         try
787                         {
788                                 Time new_time(old_2_new((*iter)->get_time()));
789                                 if(new_time>=old_begin && new_time<old_end)
790                                         continue;
791                                 find(new_time);
792                                 // If we found a waypoint already at that time, then
793                                 // we need to abort
794                                 throw Exception::BadTime(_("Waypoint Conflict"));
795                         }
796                         catch(Exception::NotFound) { }
797
798                         selected.back()->set_time(old_2_new(selected.back()->get_time()));
799                         selected.pop_back();
800                 }
801
802
803                 while(!selected.empty())
804                 {
805                         selected.back()->set_time(old_2_new(selected.back()->get_time()));
806                         selected.pop_back();
807                 }
808
809                 changed();
810         }
811 #undef old_2_new
812 }
813 */
814
815 Waypoint
816 ValueNode_Animated::new_waypoint_at_time(const Time& time)const
817 {
818         Waypoint waypoint;
819         try
820         {
821                 // Trivial case, we are sitting on a waypoint
822                 waypoint=*find(time);
823                 waypoint.make_unique();
824         }
825         catch(...)
826         {
827                 if(waypoint_list().empty())
828                 {
829                         waypoint.set_value((*this)(time));
830                 }
831                 else
832                 {
833                         WaypointList::const_iterator prev;
834                         WaypointList::const_iterator next;
835
836                         bool has_prev(false), has_next(false);
837
838                         try { prev=find_prev(time); has_prev=true; } catch(...) { }
839                         try { next=find_next(time); has_next=true; } catch(...) { }
840
841                         /*
842                         WaypointList::const_iterator closest;
843
844                         if(has_prev&&!has_next)
845                                 closest=prev;
846                         else if(has_next&&!has_prev)
847                                 closest=next;
848                         else if(time-prev->get_time()<next->get_time()-time)
849                                 closest=prev;
850                         else
851                                 closest=next;
852
853                         for(iter=waypoint_list().begin();iter!=waypoint_list().end();++iter)
854                         {
855                                 const Real dist(abs(iter->get_time()-time));
856                                 if(dist<abs(closest->get_time()-time))
857                                         closest=iter;
858                         }
859                         */
860
861                         if(has_prev && !prev->is_static())
862                                 waypoint.set_value_node(prev->get_value_node());
863                         if(has_next && !next->is_static())
864                                 waypoint.set_value_node(next->get_value_node());
865                         else
866                                 waypoint.set_value((*this)(time));
867
868                         /*if(has_prev)
869                                 waypoint.set_after(prev->get_before());
870                         if(has_next)
871                                 waypoint.set_before(next->get_after());
872                         */
873                 }
874         }
875         waypoint.set_time(time);
876         waypoint.set_parent_value_node(const_cast<ValueNode_Animated*>(this));
877 //      synfig::info("waypoint.get_after()=set to %d",waypoint.get_after());
878 //      synfig::info("waypoint.get_before()=set to %d",waypoint.get_before());
879
880         return waypoint;
881 }
882
883 ValueNode_Animated::WaypointList::iterator
884 ValueNode_Animated::find(const UniqueID &x)
885 {
886         ValueNode_Animated::WaypointList::iterator iter;
887         iter=std::find(waypoint_list().begin(),waypoint_list().end(),x);
888         if(iter==waypoint_list().end() || iter->get_uid()!=x.get_uid())
889                 throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find UniqueID %d",x.get_uid()));
890         return iter;
891 }
892
893 ValueNode_Animated::WaypointList::const_iterator
894 ValueNode_Animated::find(const UniqueID &x)const
895 {
896         return const_cast<ValueNode_Animated*>(this)->find(x);
897         /*
898         ValueNode_Animated::WaypointList::const_iterator iter;
899         iter=std::find(waypoint_list().begin(),waypoint_list().end(),x);
900         if(iter!=waypoint_list().end() && iter->get_uid()!=x.get_uid())
901                 throw Exception::NotFound(strprintf("ValueNode_Animated::find()const: Can't find UniqueID %d",x.get_uid()));
902         return iter;
903         */
904 }
905
906 ValueNode_Animated::WaypointList::iterator
907 ValueNode_Animated::find(const Time &x)
908 {
909         WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
910
911         if(iter!=waypoint_list().end() && x.is_equal(iter->get_time()))
912                 return iter;
913
914         throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find Waypoint at %s",x.get_string().c_str()));
915 }
916
917 ValueNode_Animated::WaypointList::const_iterator
918 ValueNode_Animated::find(const Time &x)const
919 {
920         return const_cast<ValueNode_Animated*>(this)->find(x);
921         /*
922         WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
923
924         if(iter!=waypoint_list().end() && x.is_equal(iter->get_time()))
925                 return iter;
926
927         throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find Waypoint at %s",x.get_string().c_str()));
928         */
929 }
930
931 ValueNode_Animated::WaypointList::iterator
932 ValueNode_Animated::find_next(const Time &x)
933 {
934         WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
935
936         if(iter!=waypoint_list().end())
937         {
938                 if(iter->get_time().is_more_than(x))
939                         return iter;
940                 ++iter;
941                 if(iter!=waypoint_list().end() && iter->get_time().is_more_than(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 ValueNode_Animated::WaypointList::const_iterator
949 ValueNode_Animated::find_next(const Time &x)const
950 {
951         return const_cast<ValueNode_Animated*>(this)->find_next(x);
952         /*
953         WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
954
955         if(iter!=waypoint_list().end())
956         {
957                 if(iter->get_time()-Time::epsilon()>x)
958                         return iter;
959                 ++iter;
960                 if(iter!=waypoint_list().end() && iter->get_time()-Time::epsilon()>x)
961                         return iter;
962         }
963
964         throw Exception::NotFound(strprintf("ValueNode_Animated::find_next(): Can't find Waypoint after %s",x.get_string().c_str()));
965 */
966 }
967
968 ValueNode_Animated::WaypointList::iterator
969 ValueNode_Animated::find_prev(const Time &x)
970 {
971         WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
972
973         if(iter!=waypoint_list().end())
974         {
975                 if(iter->get_time().is_less_than(x))
976                         return iter;
977                 if(iter!=waypoint_list().begin() && (--iter)->get_time().is_less_than(x))
978                         return iter;
979         }
980
981         throw Exception::NotFound(strprintf("ValueNode_Animated::find_prev(): Can't find Waypoint after %s",x.get_string().c_str()));
982 }
983
984 ValueNode_Animated::WaypointList::const_iterator
985 ValueNode_Animated::find_prev(const Time &x)const
986 {
987         return const_cast<ValueNode_Animated*>(this)->find_prev(x);
988         /*
989         WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
990
991         if(iter!=waypoint_list().end())
992         {
993                 if(iter->get_time()+Time::epsilon()<x)
994                         return iter;
995                 if(iter!=waypoint_list().begin() && (--iter)->get_time()+Time::epsilon()<x)
996                         return iter;
997         }
998         throw Exception::NotFound(strprintf("ValueNode_Animated::find_prev(): Can't find Waypoint after %s",x.get_string().c_str()));
999         */
1000 }
1001
1002 void
1003 ValueNode_Animated::erase(const UniqueID &x)
1004 {
1005         waypoint_list().erase(find(x));
1006 }
1007
1008 ValueNode_Animated::WaypointList::iterator
1009 ValueNode_Animated::add(const Waypoint &x)
1010 {
1011         Waypoint waypoint(x);
1012         waypoint.set_parent_value_node(this);
1013         waypoint_list_.push_back(waypoint);
1014         //assert(waypoint_list_.back().get_parent_value_node()==this);
1015         WaypointList::iterator ret=waypoint_list_.end();
1016         --ret;
1017         changed();
1018         return ret;
1019 }
1020
1021 void
1022 ValueNode_Animated::set_type(ValueBase::Type t)
1023 {
1024         ValueNode::set_type(t);
1025 }
1026
1027 ValueNode_Animated::Handle
1028 synfig::ValueNode_Animated::create(ValueBase::Type type)
1029 {
1030         switch(type)
1031         {
1032                 case ValueBase::TYPE_TIME:
1033                         return ValueNode_Animated::Handle(new _Hermite<Time>);
1034                 case ValueBase::TYPE_REAL:
1035                         return ValueNode_Animated::Handle(new _Hermite<Vector::value_type>);
1036                 case ValueBase::TYPE_INTEGER:
1037                         return ValueNode_Animated::Handle(new _Hermite<int>);
1038                 case ValueBase::TYPE_ANGLE:
1039                         return ValueNode_Animated::Handle(new _Hermite<Angle>);
1040                 case ValueBase::TYPE_VECTOR:
1041                         return ValueNode_Animated::Handle(new _Hermite<Vector>);
1042                 case ValueBase::TYPE_COLOR:
1043                         return ValueNode_Animated::Handle(new _Hermite<Color>);
1044
1045                 case ValueBase::TYPE_STRING:
1046                         return ValueNode_Animated::Handle(new _Constant<String>);
1047                 case ValueBase::TYPE_GRADIENT:
1048                         return ValueNode_Animated::Handle(new _Hermite<Gradient>);
1049                 case ValueBase::TYPE_BOOL:
1050                         return ValueNode_Animated::Handle(new _AnimBool);
1051                 case ValueBase::TYPE_CANVAS:
1052                         return ValueNode_Animated::Handle(new _Constant<Canvas::LooseHandle>);
1053                 default:
1054                         throw
1055                                 Exception::BadType(strprintf(_("%s: You cannot use a %s in an animated ValueNode"),"synfig::ValueNode_Animated::create()",
1056                                         ValueBase::type_local_name(type).c_str())
1057                                 );
1058                         break;
1059         }
1060         return ValueNode_Animated::Handle();
1061 }
1062
1063 ValueNode_Animated::Handle
1064 ValueNode_Animated::create(const ValueBase& value, const Time& time)
1065 {
1066         return create(ValueNode::Handle(ValueNode_Const::create(value)),time);
1067 }
1068
1069 ValueNode_Animated::Handle
1070 ValueNode_Animated::create(ValueNode::Handle value_node, const Time& time)
1071 {
1072         ValueNode_Animated::Handle ret(create(value_node->get_type()));
1073         ret->new_waypoint(time,value_node);
1074         return ret;
1075 }
1076
1077 ValueNode_Animated::~ValueNode_Animated()
1078 {
1079 }
1080
1081 String
1082 ValueNode_Animated::get_name()const
1083 {
1084         return "animated";
1085 }
1086
1087 String
1088 ValueNode_Animated::get_local_name()const
1089 {
1090         return _("Animated");
1091 }
1092
1093 void ValueNode_Animated::get_times_vfunc(Node::time_set &set) const
1094 {
1095         //add all the way point times to the value node...
1096
1097         WaypointList::const_iterator    i = waypoint_list().begin(),
1098                                                                         end = waypoint_list().end();
1099
1100         for(; i != end; ++i)
1101         {
1102                 TimePoint t;
1103                 t.set_time(i->get_time());
1104                 t.set_before(i->get_before());
1105                 t.set_after(i->get_after());
1106                 t.set_guid(i->get_guid());
1107                 set.insert(t);
1108         }
1109 }
1110 struct timecmp
1111  {
1112         Time t;
1113
1114         timecmp(const Time &c) :t(c) {}
1115
1116         bool operator()(const Waypoint &rhs) const
1117         {
1118                 return t.is_equal(rhs.get_time());
1119         }
1120  };
1121
1122  ValueNode_Animated::findresult
1123  ValueNode_Animated::find_uid(const UniqueID &x)
1124  {
1125         findresult      f;
1126         f.second = false;
1127
1128         //search for it... and set the bool part of the return value to true if we found it!
1129         f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
1130         if(f.first != waypoint_list_.end())
1131                 f.second = true;
1132
1133         return f;
1134  }
1135
1136  ValueNode_Animated::const_findresult
1137  ValueNode_Animated::find_uid(const UniqueID &x)const
1138  {
1139         const_findresult        f;
1140         f.second = false;
1141
1142         //search for it... and set the bool part of the return value to true if we found it!
1143         f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
1144         if(f.first != waypoint_list_.end())
1145                 f.second = true;
1146
1147         return f;
1148  }
1149
1150  ValueNode_Animated::findresult
1151  ValueNode_Animated::find_time(const Time &x)
1152  {
1153         findresult      f;
1154         f.second = false;
1155
1156         //search for it... and set the bool part of the return value to true if we found it!
1157         f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
1158         if(f.first != waypoint_list_.end())
1159                 f.second = true;
1160
1161         return f;
1162  }
1163
1164 ValueNode_Animated::const_findresult
1165 ValueNode_Animated::find_time(const Time &x)const
1166 {
1167         const_findresult        f;
1168         f.second = false;
1169
1170         //search for it... and set the bool part of the return value to true if we found it!
1171         f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
1172         if(f.first != waypoint_list_.end())
1173                 f.second = true;
1174
1175         return f;
1176 }
1177
1178 void
1179 ValueNode_Animated::insert_time(const Time& location, const Time& delta)
1180 {
1181         if(!delta)
1182                 return;
1183         try
1184         {
1185                 WaypointList::iterator iter(find_next(location));
1186                 for(;iter!=waypoint_list().end();++iter)
1187                 {
1188                         iter->set_time(iter->get_time()+delta);
1189                 }
1190                 changed();
1191         }
1192         catch(Exception::NotFound) { }
1193 }