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