1 /* === S Y N F I G ========================================================= */
2 /*! \file valuenode_animated.cpp
3 ** \brief Implementation of the "Animated" valuenode conversion.
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
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.
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.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
40 #include <ETL/hermite>
50 #include "valuenode_animated.h"
51 #include "valuenode_const.h"
52 #include "exception.h"
57 /* === U S I N G =========================================================== */
61 using namespace synfig;
63 /* === M A C R O S ========================================================= */
65 // Fast binary search implementation
67 template<typename I, typename T> inline I
68 binary_find(I begin, I end, const T& value)
70 I iter(begin+(end-begin)/2);
72 while(end-begin>1 && !(*iter==value))
74 ((*iter<value)?begin:end) = iter;
76 iter = begin+(end-begin)/2;
83 template<typename T> String tangent_info(T a, T b, T v)
88 String tangent_info(Vector a, Vector b, Vector v)
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]);
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]);
98 struct subtractor : public std::binary_function<T, T, T>
100 T operator()(const T &a,const T &b)const
107 struct subtractor<Angle> : public std::binary_function<Angle, Angle, Angle>
109 Angle operator()(const Angle &a,const Angle &b)const
116 struct magnitude : public std::unary_function<float, T>
118 float operator()(const T &a)const
125 struct magnitude<Angle> : public std::unary_function<float, Angle>
127 float operator()(const Angle &a)const
129 return abs(Angle::rad(a).get());
134 struct magnitude<Vector> : public std::unary_function<float, Vector>
136 float operator()(const Vector &a)const
143 struct magnitude<Color> : public std::unary_function<float, Color>
145 float operator()(const Color &a)const
147 return abs(a.get_y());
158 bool operator()()const
164 #ifdef ANGLES_USE_LINEAR_INTERPOLATION
166 struct is_angle_type<Angle>
168 bool operator()()const
173 #endif // ANGLES_USE_LINEAR_INTERPOLATION
175 /* === G L O B A L S ======================================================= */
177 /* === C L A S S E S ======================================================= */
180 class _Hermite : public synfig::ValueNode_Animated
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;
191 is_angle_type<value_type> is_angle;
192 subtractor<value_type> subtract_func;
194 mutable hermite<Time,Time> first;
195 mutable hermite<value_type,Time> second;
196 WaypointList::iterator start;
197 WaypointList::iterator end;
199 value_type resolve(const Time &t)const
201 bool start_static(start->is_static());
202 bool end_static(end->is_static());
204 if(!start_static || !end_static)
207 second.p1()=start->get_value(t).get(value_type());
208 if(start->get_after()==INTERPOLATION_CONSTANT || end->get_before()==INTERPOLATION_CONSTANT)
211 second.p2()=end->get_value(t).get(value_type());
213 // At the moment, the only type of non-constant interpolation
214 // that we support is linear.
216 second.t2()=subtract_func(second.p2(),second.p1());
221 return second(first(t));
229 hermite<value_type,Time>
234 curve_list_type curve_list;
236 // Bounds of this curve
240 ValueNode* clone(const synfig::GUID& deriv_guid)const
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));
252 set_type(ValueBase(value_type()).get_type());
255 virtual WaypointList::iterator new_waypoint(Time t, ValueBase value)
257 // Make sure we are getting data of the correct type
258 //if(data.type!=type)
259 // return waypoint_list_type::iterator();
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);
265 waypoint_list_.push_back(waypoint);
266 WaypointList::iterator ret=waypoint_list_.end();
271 ret->set_before(INTERPOLATION_LINEAR);
272 ret->set_after(INTERPOLATION_LINEAR);
280 virtual WaypointList::iterator new_waypoint(Time t, ValueNode::Handle value_node)
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) { };
287 Waypoint waypoint(value_node,t);
288 waypoint.set_parent_value_node(this);
290 waypoint_list_.push_back(waypoint);
291 WaypointList::iterator ret=waypoint_list_.end();
296 ret->set_before(INTERPOLATION_LINEAR);
297 ret->set_after(INTERPOLATION_LINEAR);
305 virtual void on_changed()
307 ValueNode_Animated::on_changed();
309 if(waypoint_list_.size()<=1)
311 std::sort(waypoint_list_.begin(),waypoint_list_.end());
312 //waypoint_list_.sort();
314 r=waypoint_list_.front().get_time();
315 s=waypoint_list_.back().get_time();
319 WaypointList::iterator prev,iter,next=waypoint_list_.begin();
322 for(iter=next++;iter!=waypoint_list_.end() && next!=waypoint_list_.end();prev=iter,iter=next++,i++)
324 typename curve_list_type::value_type curve;
325 WaypointList::iterator after_next(next);
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());
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());
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;
352 if(iter->is_static() && next->is_static())
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)
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.
364 //iter->get_after()=next->get_before()=INTERPOLATION_CONSTANT;
366 curve.second.p2()=iter->get_value().get(T());
368 curve.second.t2()=subtract_func(curve.second.p1(),curve.second.p2());
372 if(iter_get_after==INTERPOLATION_TCB && iter!=waypoint_list_.begin() && !is_angle())
374 if(iter->get_before()!=INTERPOLATION_TCB && !curve_list.empty())
376 curve.second.t1()=curve_list.back().second.t2();
380 const Real& t(iter->get_tension()); // Tension
381 const Real& c(iter->get_continuity()); // Continuity
382 const Real& b(iter->get_bias()); // Bias
384 // The following line works where the previous line fails.
385 value_type Pp; Pp=curve_list.back().second.p1(); // P_{i-1}
387 const value_type& Pc(curve.second.p1()); // P_i
388 const value_type& Pn(curve.second.p2()); // P_{i+1}
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)));
397 //value_type vect=(value_type)((Pn-Pp)*(1.0-t));
400 //value_type vect=(value_type)(Pn-Pc);
403 //synfig::info("%d:t1: %s",i,tangent_info(Pp,Pn,vect).c_str());
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()));
409 curve.second.t1()=vect;
413 iter_get_after==INTERPOLATION_LINEAR || iter_get_after==INTERPOLATION_HALT ||
414 (iter_get_after==INTERPOLATION_TCB && iter==waypoint_list_.begin()))
416 curve.second.t1()=subtract_func(curve.second.p2(),curve.second.p1());
419 if(iter_get_before==INTERPOLATION_TCB && iter->get_after()!=INTERPOLATION_TCB && !curve_list.empty())
421 curve_list.back().second.t2()=curve.second.t1();
422 curve_list.back().second.sync();
426 if(next_get_before==INTERPOLATION_TCB && after_next!=waypoint_list_.end() && !is_angle())
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}
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)));
440 //value_type vect((value_type)((Pn-Pp)*(1.0-t)));
443 //value_type vect=(value_type)(Pc-Pp);
446 //synfig::info("%d:t2: %s",i,tangent_info(Pp,Pn,vect).c_str());
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()))));
452 curve.second.t2()=vect;
455 next_get_before==INTERPOLATION_LINEAR || next_get_before==INTERPOLATION_HALT ||
456 (next_get_before==INTERPOLATION_TCB && after_next==waypoint_list_.end()))
458 curve.second.t2()=subtract_func(curve.second.p2(),curve.second.p1());
462 const float timeadjust(0.5);
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()));
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())));
490 // Set up the time to the default stuff
491 curve.first.set_rs(iter->get_time(), next->get_time());
492 curve.first.p1()=iter->get_time();
493 curve.first.p2()=next->get_time();
494 curve.first.t1()=(curve.first.p2()-curve.first.p1())*(1.0f-iter->get_time_tension());
495 curve.first.t2()=(curve.first.p2()-curve.first.p1())*(1.0f-next->get_time_tension());
501 curve_list.push_back(curve);
505 virtual ValueBase operator()(Time t)const
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);
512 return waypoint_list_.front().get_value(t);
514 return waypoint_list_.back().get_value(t);
516 typename curve_list_type::const_iterator iter;
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)
522 if(iter==curve_list.end())
523 return waypoint_list_.back().get_value(t);
524 return iter->resolve(t);
530 class _Constant : public synfig::ValueNode_Animated
533 typedef T value_type;
537 // Bounds of this curve
541 ValueNode* clone(const synfig::GUID& deriv_guid)const
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));
553 set_type(ValueBase(value_type()).get_type());
556 virtual WaypointList::iterator new_waypoint(Time t, ValueBase value)
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) { };
563 Waypoint waypoint(value,t);
564 waypoint.set_parent_value_node(this);
566 waypoint_list_.push_back(waypoint);
567 WaypointList::iterator ret=waypoint_list_.end();
574 virtual WaypointList::iterator new_waypoint(Time t, ValueNode::Handle value_node)
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) { };
581 Waypoint waypoint(value_node,t);
582 waypoint.set_parent_value_node(this);
584 waypoint_list_.push_back(waypoint);
585 WaypointList::iterator ret=waypoint_list_.end();
592 virtual void on_changed()
594 ValueNode_Animated::on_changed();
596 if(waypoint_list_.size()<=1)
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();
605 virtual ValueBase operator()(Time t)const
607 if(waypoint_list_.size()==1)
608 return waypoint_list_.front().get_value(t);
609 if(waypoint_list_.empty())
612 return waypoint_list_.front().get_value(t);
614 return waypoint_list_.back().get_value(t);
616 typename WaypointList::const_iterator iter;
617 typename WaypointList::const_iterator next;
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++)
624 return iter->get_value(t);
628 class _AnimBool : public synfig::ValueNode_Animated
631 typedef bool value_type;
635 // Bounds of this curve
639 ValueNode* clone(const synfig::GUID& deriv_guid)const
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));
651 set_type(ValueBase(value_type()).get_type());
654 virtual WaypointList::iterator new_waypoint(Time t, ValueBase value)
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) { };
662 Waypoint waypoint(value,t);
663 waypoint.set_parent_value_node(this);
665 waypoint_list_.push_back(waypoint);
666 WaypointList::iterator ret=waypoint_list_.end();
673 virtual WaypointList::iterator new_waypoint(Time t, ValueNode::Handle value_node)
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) { };
680 Waypoint waypoint(value_node,t);
681 waypoint.set_parent_value_node(this);
683 waypoint_list_.push_back(waypoint);
684 WaypointList::iterator ret=waypoint_list_.end();
691 virtual void on_changed()
693 ValueNode_Animated::on_changed();
695 if(waypoint_list_.size()<=1)
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();
704 virtual ValueBase operator()(Time t)const
706 if(waypoint_list_.size()==1)
707 return waypoint_list_.front().get_value(t);
708 if(waypoint_list_.empty())
711 return waypoint_list_.front().get_value(t);
713 return waypoint_list_.back().get_value(t);
715 WaypointList::const_iterator iter;
716 WaypointList::const_iterator next;
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);
724 if(iter->get_time()==t)
725 return iter->get_value(t);
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);
733 /* === M E T H O D S ======================================================= */
735 ValueNode_Animated::ValueNode_Animated()
741 ValueNode_Animated::find(const Time& begin,const Time& end,std::vector<Waypoint*>& selected)
743 Time curr_time(begin);
746 // try to grab first waypoint
749 WaypointList::iterator iter;
750 iter=find(curr_time);
751 selected.push_back(&*iter);
758 WaypointList::iterator iter;
761 iter=find_next(curr_time);
762 curr_time=iter->get_time();
765 selected.push_back(&*iter);
776 ValueNode_Animated::manipulate_time(const Time& old_begin,const Time& old_end,const Time& new_begin,const Time& new_end)
778 #define old_2_new(x) (((x)-old_begin)/(old_end-old_begin)*(new_end-new_begin)+new_begin)
779 std::vector<Waypoint*> selected;
780 std::vector<Waypoint*>::iterator iter;
782 if(find(old_begin,old_end,selected))
784 // check to make sure this operation is OK
785 for(iter=selected.begin();iter!=selected.end();++iter)
789 Time new_time(old_2_new((*iter)->get_time()));
790 if(new_time>=old_begin && new_time<old_end)
793 // If we found a waypoint already at that time, then
795 throw Exception::BadTime(_("Waypoint Conflict"));
797 catch(Exception::NotFound) { }
799 selected.back()->set_time(old_2_new(selected.back()->get_time()));
804 while(!selected.empty())
806 selected.back()->set_time(old_2_new(selected.back()->get_time()));
817 ValueNode_Animated::new_waypoint_at_time(const Time& time)const
822 // Trivial case, we are sitting on a waypoint
823 waypoint=*find(time);
824 waypoint.make_unique();
828 if(waypoint_list().empty())
830 waypoint.set_value((*this)(time));
834 WaypointList::const_iterator prev;
835 WaypointList::const_iterator next;
837 bool has_prev(false), has_next(false);
839 try { prev=find_prev(time); has_prev=true; } catch(...) { }
840 try { next=find_next(time); has_next=true; } catch(...) { }
843 WaypointList::const_iterator closest;
845 if(has_prev&&!has_next)
847 else if(has_next&&!has_prev)
849 else if(time-prev->get_time()<next->get_time()-time)
854 for(iter=waypoint_list().begin();iter!=waypoint_list().end();++iter)
856 const Real dist(abs(iter->get_time()-time));
857 if(dist<abs(closest->get_time()-time))
862 if(has_prev && !prev->is_static())
863 waypoint.set_value_node(prev->get_value_node());
864 if(has_next && !next->is_static())
865 waypoint.set_value_node(next->get_value_node());
867 waypoint.set_value((*this)(time));
870 waypoint.set_after(prev->get_before());
872 waypoint.set_before(next->get_after());
876 waypoint.set_time(time);
877 waypoint.set_parent_value_node(const_cast<ValueNode_Animated*>(this));
878 // synfig::info("waypoint.get_after()=set to %d",waypoint.get_after());
879 // synfig::info("waypoint.get_before()=set to %d",waypoint.get_before());
884 ValueNode_Animated::WaypointList::iterator
885 ValueNode_Animated::find(const UniqueID &x)
887 ValueNode_Animated::WaypointList::iterator iter;
888 iter=std::find(waypoint_list().begin(),waypoint_list().end(),x);
889 if(iter==waypoint_list().end() || iter->get_uid()!=x.get_uid())
890 throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find UniqueID %d",x.get_uid()));
894 ValueNode_Animated::WaypointList::const_iterator
895 ValueNode_Animated::find(const UniqueID &x)const
897 return const_cast<ValueNode_Animated*>(this)->find(x);
899 ValueNode_Animated::WaypointList::const_iterator iter;
900 iter=std::find(waypoint_list().begin(),waypoint_list().end(),x);
901 if(iter!=waypoint_list().end() && iter->get_uid()!=x.get_uid())
902 throw Exception::NotFound(strprintf("ValueNode_Animated::find()const: Can't find UniqueID %d",x.get_uid()));
907 ValueNode_Animated::WaypointList::iterator
908 ValueNode_Animated::find(const Time &x)
910 WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
912 if(iter!=waypoint_list().end() && x.is_equal(iter->get_time()))
915 throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find Waypoint at %s",x.get_string().c_str()));
918 ValueNode_Animated::WaypointList::const_iterator
919 ValueNode_Animated::find(const Time &x)const
921 return const_cast<ValueNode_Animated*>(this)->find(x);
923 WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
925 if(iter!=waypoint_list().end() && x.is_equal(iter->get_time()))
928 throw Exception::NotFound(strprintf("ValueNode_Animated::find(): Can't find Waypoint at %s",x.get_string().c_str()));
932 ValueNode_Animated::WaypointList::iterator
933 ValueNode_Animated::find_next(const Time &x)
935 WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
937 if(iter!=waypoint_list().end())
939 if(iter->get_time().is_more_than(x))
942 if(iter!=waypoint_list().end() && iter->get_time().is_more_than(x))
946 throw Exception::NotFound(strprintf("ValueNode_Animated::find_next(): Can't find Waypoint after %s",x.get_string().c_str()));
949 ValueNode_Animated::WaypointList::const_iterator
950 ValueNode_Animated::find_next(const Time &x)const
952 return const_cast<ValueNode_Animated*>(this)->find_next(x);
954 WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
956 if(iter!=waypoint_list().end())
958 if(iter->get_time()-Time::epsilon()>x)
961 if(iter!=waypoint_list().end() && iter->get_time()-Time::epsilon()>x)
965 throw Exception::NotFound(strprintf("ValueNode_Animated::find_next(): Can't find Waypoint after %s",x.get_string().c_str()));
969 ValueNode_Animated::WaypointList::iterator
970 ValueNode_Animated::find_prev(const Time &x)
972 WaypointList::iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
974 if(iter!=waypoint_list().end())
976 if(iter->get_time().is_less_than(x))
978 if(iter!=waypoint_list().begin() && (--iter)->get_time().is_less_than(x))
982 throw Exception::NotFound(strprintf("ValueNode_Animated::find_prev(): Can't find Waypoint after %s",x.get_string().c_str()));
985 ValueNode_Animated::WaypointList::const_iterator
986 ValueNode_Animated::find_prev(const Time &x)const
988 return const_cast<ValueNode_Animated*>(this)->find_prev(x);
990 WaypointList::const_iterator iter(binary_find(waypoint_list().begin(),waypoint_list().end(),x));
992 if(iter!=waypoint_list().end())
994 if(iter->get_time()+Time::epsilon()<x)
996 if(iter!=waypoint_list().begin() && (--iter)->get_time()+Time::epsilon()<x)
999 throw Exception::NotFound(strprintf("ValueNode_Animated::find_prev(): Can't find Waypoint after %s",x.get_string().c_str()));
1004 ValueNode_Animated::erase(const UniqueID &x)
1006 waypoint_list().erase(find(x));
1009 ValueNode_Animated::WaypointList::iterator
1010 ValueNode_Animated::add(const Waypoint &x)
1012 Waypoint waypoint(x);
1013 waypoint.set_parent_value_node(this);
1014 waypoint_list_.push_back(waypoint);
1015 //assert(waypoint_list_.back().get_parent_value_node()==this);
1016 WaypointList::iterator ret=waypoint_list_.end();
1023 ValueNode_Animated::set_type(ValueBase::Type t)
1025 ValueNode::set_type(t);
1028 ValueNode_Animated::Handle
1029 synfig::ValueNode_Animated::create(ValueBase::Type type)
1033 case ValueBase::TYPE_TIME:
1034 return ValueNode_Animated::Handle(new _Hermite<Time>);
1035 case ValueBase::TYPE_REAL:
1036 return ValueNode_Animated::Handle(new _Hermite<Vector::value_type>);
1037 case ValueBase::TYPE_INTEGER:
1038 return ValueNode_Animated::Handle(new _Hermite<int>);
1039 case ValueBase::TYPE_ANGLE:
1040 return ValueNode_Animated::Handle(new _Hermite<Angle>);
1041 case ValueBase::TYPE_VECTOR:
1042 return ValueNode_Animated::Handle(new _Hermite<Vector>);
1043 case ValueBase::TYPE_COLOR:
1044 return ValueNode_Animated::Handle(new _Hermite<Color>);
1046 case ValueBase::TYPE_STRING:
1047 return ValueNode_Animated::Handle(new _Constant<String>);
1048 case ValueBase::TYPE_GRADIENT:
1049 return ValueNode_Animated::Handle(new _Hermite<Gradient>);
1050 case ValueBase::TYPE_BOOL:
1051 return ValueNode_Animated::Handle(new _AnimBool);
1052 case ValueBase::TYPE_CANVAS:
1053 return ValueNode_Animated::Handle(new _Constant<Canvas::LooseHandle>);
1056 Exception::BadType(strprintf(_("%s: You cannot use a %s in an animated ValueNode"),"synfig::ValueNode_Animated::create()",
1057 ValueBase::type_local_name(type).c_str())
1061 return ValueNode_Animated::Handle();
1064 ValueNode_Animated::Handle
1065 ValueNode_Animated::create(const ValueBase& value, const Time& time)
1067 return create(ValueNode::Handle(ValueNode_Const::create(value)),time);
1070 ValueNode_Animated::Handle
1071 ValueNode_Animated::create(ValueNode::Handle value_node, const Time& time)
1073 ValueNode_Animated::Handle ret(create(value_node->get_type()));
1074 ret->new_waypoint(time,value_node);
1078 ValueNode_Animated::~ValueNode_Animated()
1083 ValueNode_Animated::get_name()const
1089 ValueNode_Animated::get_local_name()const
1091 return _("Animated");
1094 void ValueNode_Animated::get_times_vfunc(Node::time_set &set) const
1096 //add all the way point times to the value node...
1098 WaypointList::const_iterator i = waypoint_list().begin(),
1099 end = waypoint_list().end();
1101 for(; i != end; ++i)
1104 t.set_time(i->get_time());
1105 t.set_before(i->get_before());
1106 t.set_after(i->get_after());
1107 t.set_guid(i->get_guid());
1115 timecmp(const Time &c) :t(c) {}
1117 bool operator()(const Waypoint &rhs) const
1119 return t.is_equal(rhs.get_time());
1123 ValueNode_Animated::findresult
1124 ValueNode_Animated::find_uid(const UniqueID &x)
1129 //search for it... and set the bool part of the return value to true if we found it!
1130 f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
1131 if(f.first != waypoint_list_.end())
1137 ValueNode_Animated::const_findresult
1138 ValueNode_Animated::find_uid(const UniqueID &x)const
1143 //search for it... and set the bool part of the return value to true if we found it!
1144 f.first = std::find(waypoint_list_.begin(), waypoint_list_.end(), x);
1145 if(f.first != waypoint_list_.end())
1151 ValueNode_Animated::findresult
1152 ValueNode_Animated::find_time(const Time &x)
1157 //search for it... and set the bool part of the return value to true if we found it!
1158 f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
1159 if(f.first != waypoint_list_.end())
1165 ValueNode_Animated::const_findresult
1166 ValueNode_Animated::find_time(const Time &x)const
1171 //search for it... and set the bool part of the return value to true if we found it!
1172 f.first = std::find_if(waypoint_list_.begin(), waypoint_list_.end(), timecmp(x));
1173 if(f.first != waypoint_list_.end())
1180 ValueNode_Animated::insert_time(const Time& location, const Time& delta)
1186 WaypointList::iterator iter(find_next(location));
1187 for(;iter!=waypoint_list().end();++iter)
1189 iter->set_time(iter->get_time()+delta);
1193 catch(Exception::NotFound) { }