1 /* === S Y N F I G ========================================================= */
2 /*! \file valuenode_bline.cpp
3 ** \brief Template File
5 ** $Id: valuenode_bline.cpp,v 1.1.1.1 2005/01/04 01:23:15 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
31 #include "valuenode_bline.h"
32 #include "valuenode_const.h"
33 #include "valuenode_composite.h"
35 #include "exception.h"
36 #include "blinepoint.h"
40 #include <ETL/hermite>
41 #include <ETL/calculus>
46 /* === U S I N G =========================================================== */
50 using namespace synfig;
52 /* === M A C R O S ========================================================= */
54 /* === G L O B A L S ======================================================= */
56 /* === P R O C E D U R E S ================================================= */
59 linear_interpolation(const Vector& a, const Vector& b, float c)
63 radial_interpolation(const Vector& a, const Vector& b, float c)
65 affine_combo<Real,float> mag_combo;
66 affine_combo<Angle,float> ang_combo;
68 Real mag(mag_combo(a.mag(),b.mag(),c));
69 Angle ang(ang_combo(Angle::tan(a[1],a[0]),Angle::tan(b[1],b[0]),c));
71 return Point( mag*Angle::cos(ang).get(),mag*Angle::sin(ang).get() );
77 synfig::convert_bline_to_segment_list(const ValueBase& bline)
79 std::vector<Segment> ret;
81 // std::vector<BLinePoint> list(bline.operator std::vector<BLinePoint>());
82 //std::vector<BLinePoint> list(bline);
83 std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end());
84 std::vector<BLinePoint>::const_iterator iter;
86 BLinePoint prev,first;
88 //start with prev = first and iter on the second...
90 if(list.empty()) return ValueBase(ret,bline.get_loop());
91 first = prev = list.front();
93 for(iter=++list.begin();iter!=list.end();++iter)
116 return ValueBase(ret,bline.get_loop());
120 synfig::convert_bline_to_width_list(const ValueBase& bline)
122 std::vector<Real> ret;
123 // std::vector<BLinePoint> list(bline.operator std::vector<BLinePoint>());
124 //std::vector<BLinePoint> list(bline);
125 std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end());
126 std::vector<BLinePoint>::const_iterator iter;
129 return ValueBase(ValueBase::TYPE_LIST);
131 for(iter=list.begin();iter!=list.end();++iter)
132 ret.push_back(iter->get_width());
135 ret.push_back(list.front().get_width());
137 return ValueBase(ret,bline.get_loop());
141 /* === M E T H O D S ======================================================= */
144 ValueNode_BLine::ValueNode_BLine():
145 ValueNode_DynamicList(ValueBase::TYPE_BLINEPOINT)
149 ValueNode_BLine::~ValueNode_BLine()
154 ValueNode_BLine::create(const ValueBase &value)
156 if(value.get_type()!=ValueBase::TYPE_LIST)
159 ValueNode_BLine* value_node(new ValueNode_BLine());
163 switch(value.get_contained_type())
165 case ValueBase::TYPE_BLINEPOINT:
167 // std::vector<BLinePoint> bline_points(value.operator std::vector<BLinePoint>());
168 //std::vector<BLinePoint> bline_points(value);
169 std::vector<BLinePoint> bline_points(value.get_list().begin(),value.get_list().end());
170 std::vector<BLinePoint>::const_iterator iter;
172 for(iter=bline_points.begin();iter!=bline_points.end();iter++)
174 value_node->add(ValueNode::Handle(ValueNode_Composite::create(*iter)));
176 value_node->set_loop(value.get_loop());
179 case ValueBase::TYPE_SEGMENT:
181 // Here, we want to convert a list of segments
182 // into a list of BLinePoints. We make an assumption
183 // that the segment list is continuous(sp), but not necessarily
186 value_node->set_loop(false);
187 // std::vector<Segment> segments(value.operator std::vector<Segment>());
188 // std::vector<Segment> segments(value);
189 std::vector<Segment> segments(value.get_list().begin(),value.get_list().end());
190 std::vector<Segment>::const_iterator iter,last(segments.end());
192 ValueNode_Const::Handle prev,first;
194 for(iter=segments.begin();iter!=segments.end();iter++)
196 #define PREV_POINT prev->get_value().get(BLinePoint())
197 #define FIRST_POINT first->get_value().get(BLinePoint())
198 #define CURR_POINT curr->get_value().get(BLinePoint())
199 if(iter==segments.begin())
201 prev=ValueNode_Const::create(ValueBase::TYPE_BLINEPOINT);
203 BLinePoint prev_point(PREV_POINT);
204 prev_point.set_vertex(iter->p1);
205 prev_point.set_tangent1(iter->t1);
206 prev_point.set_width(0.01);
207 prev_point.set_origin(0.5);
208 prev_point.set_split_tangent_flag(false);
209 prev->set_value(prev_point);
212 value_node->add(ValueNode::Handle(prev));
215 if(iter==last && iter->p2.is_equal_to(FIRST_POINT.get_vertex()))
217 value_node->set_loop(true);
218 if(!iter->t2.is_equal_to(FIRST_POINT.get_tangent1()))
220 BLinePoint first_point(FIRST_POINT);
221 first_point.set_tangent1(iter->t2);
222 first->set_value(first_point);
227 ValueNode_Const::Handle curr;
228 curr=ValueNode_Const::create(ValueBase::TYPE_BLINEPOINT);
230 BLinePoint curr_point(CURR_POINT);
231 curr_point.set_vertex(iter->p2);
232 curr_point.set_tangent1(iter->t2);
233 curr_point.set_width(0.01);
234 curr_point.set_origin(0.5);
235 curr_point.set_split_tangent_flag(false);
236 curr->set_value(curr_point);
238 if(!PREV_POINT.get_tangent1().is_equal_to(iter->t1))
240 BLinePoint prev_point(PREV_POINT);
241 prev_point.set_split_tangent_flag(true);
242 prev_point.set_tangent2(iter->t1);
243 prev->set_value(prev_point);
245 value_node->add(ValueNode::Handle(curr));
252 // We got a list of who-knows-what. We don't have any idea
253 // what to do with it.
263 ValueNode_BLine::ListEntry
264 ValueNode_BLine::create_list_entry(int index, Time time, Real origin)
266 ValueNode_BLine::ListEntry ret;
269 synfig::BLinePoint prev,next;
273 index=index%link_count();
277 ret.set_parent_value_node(this);
279 if(!list[index].status_at_time(time))
280 next_i=find_next_valid_entry(index,time);
283 prev_i=find_prev_valid_entry(index,time);
285 synfig::info("index=%d, next_i=%d, prev_i=%d",index,next_i,prev_i);
287 next=(*list[next_i].value_node)(time);
288 prev=(*list[prev_i].value_node)(time);
290 etl::hermite<Vector> curve(prev.get_vertex(),next.get_vertex(),prev.get_tangent2(),next.get_tangent1());
291 etl::derivative< etl::hermite<Vector> > deriv(curve);
293 synfig::BLinePoint bline_point;
294 bline_point.set_vertex(curve(origin));
295 bline_point.set_width((next.get_width()-prev.get_width())*origin+prev.get_width());
296 bline_point.set_tangent1(deriv(origin)*min(1.0-origin,origin));
297 bline_point.set_tangent2(bline_point.get_tangent1());
298 bline_point.set_split_tangent_flag(false);
299 bline_point.set_origin(origin);
301 ret.value_node=ValueNode_Composite::create(bline_point);
307 ValueNode_BLine::operator()(Time t)const
309 std::vector<BLinePoint> ret_list;
311 std::vector<ListEntry>::const_iterator iter,first_iter;
312 bool first_flag(true);
315 float next_scale(1.0f);
317 BLinePoint prev,first;
318 first.set_origin(100.0f);
320 for(iter=list.begin();iter!=list.end();++iter,index++)
322 float amount(iter->amount_at_time(t,&rising));
324 assert(amount>=0.0f);
325 assert(amount<=1.0f);
332 first=prev=(*iter->value_node)(t).get(prev);
334 ret_list.push_back(first);
339 curr=(*iter->value_node)(t).get(prev);
343 ret_list.back().set_split_tangent_flag(true);
344 ret_list.back().set_tangent2(prev.get_tangent2()*next_scale);
346 ret_list.push_back(curr);
348 ret_list.back().set_split_tangent_flag(true);
349 ret_list.back().set_tangent2(curr.get_tangent2());
350 ret_list.back().set_tangent1(curr.get_tangent1()*next_scale);
356 ret_list.push_back(curr);
365 std::vector<ListEntry>::const_iterator begin_iter,end_iter;
367 // This is where the interesting stuff happens
368 // We need to seek forward in the list to see what the next
372 BLinePoint begin; // begin of dynamic group
373 BLinePoint end; // End of dynamic group
375 int dist_from_begin(0), dist_from_end(0);
383 try{ end_time=iter->find_prev(t)->get_time(); }
384 catch(...) { end_time=Time::begin(); }
385 try{ begin_time=iter->find_next(t)->get_time(); }
386 catch(...) { begin_time=Time::end(); }
390 try{ begin_time=iter->find_prev(t)->get_time(); }
391 catch(...) { begin_time=Time::begin(); }
392 try{ end_time=iter->find_next(t)->get_time(); }
393 catch(...) { end_time=Time::end(); }
395 blend_time=begin_time;
396 curr=(*iter->value_node)(end_time).get(curr);
398 // curr=(*iter->value_node)(t).get(curr);
400 // Find "end" of dynamic group
402 // for(++end_iter;begin_iter!=list.end();++end_iter)
403 for(++end_iter;end_iter!=list.end();++end_iter)
404 if(end_iter->amount_at_time(t)>amount)
406 end=(*end_iter->value_node)(blend_time).get(prev);
410 // If we did not find an end of the dynamic group...
411 if(end_iter==list.end())
416 end=(*end_iter->value_node)(blend_time).get(prev);
423 end=(*end_iter->value_node)(blend_time).get(prev);
428 // Find "begin" of dynamic group
430 begin.set_origin(100.0f); // set the origin to 100 (which is crazy) so that we can check to see if it was found
433 if(begin_iter==list.begin())
436 begin_iter=list.end();
447 if(begin_iter->amount_at_time(t)>amount)
449 begin=(*begin_iter->value_node)(blend_time).get(prev);
452 }while(begin_iter!=iter);
454 // If we did not find a begin
455 if(begin.get_origin()==100.0f)
459 begin_iter=first_iter;
460 begin=(*begin_iter->value_node)(blend_time).get(prev);
466 begin_iter=first_iter;
467 begin=(*begin_iter->value_node)(blend_time).get(prev);
472 etl::hermite<Vector> curve(begin.get_vertex(),end.get_vertex(),begin.get_tangent2(),end.get_tangent1());
473 etl::derivative< etl::hermite<Vector> > deriv(curve);
475 ret.set_vertex(curve(curr.get_origin()));
477 ret.set_width((end.get_width()-begin.get_width())*curr.get_origin()+begin.get_width());
479 ret.set_tangent1(deriv(curr.get_origin()));
480 ret.set_tangent2(deriv(curr.get_origin()));
482 float prev_tangent_scalar(1.0f);
483 float next_tangent_scalar(1.0f);
485 //synfig::info("index_%d:dist_from_begin=%d",index,dist_from_begin);
486 //synfig::info("index_%d:dist_from_end=%d",index,dist_from_end);
488 // If we are the next to the begin
489 if(begin_iter==--std::vector<ListEntry>::const_iterator(iter) || dist_from_begin==1)
491 prev_tangent_scalar=(1.0f-curr.get_origin())*amount+curr.get_origin();
495 float origin=curr.get_origin()-prev.get_origin();
496 prev_tangent_scalar=(1.0f-origin)*amount+origin;
499 // If we are the next to the end
500 if(end_iter==++std::vector<ListEntry>::const_iterator(iter) || dist_from_end==1)
502 float origin=1.0-curr.get_origin();
503 next_tangent_scalar=(1.0f-origin)*amount+origin;
506 if(list.end()!=++std::vector<ListEntry>::const_iterator(iter))
509 next=((*(++std::vector<ListEntry>::const_iterator(iter))->value_node)(t).get(prev));
510 float origin=next.get_origin()-curr.get_origin();
511 next_tangent_scalar=(1.0f-origin)*amount+origin;
513 next_scale=next_tangent_scalar;
515 //ret.set_vertex((curr.get_vertex()-ret.get_vertex())*amount+ret.get_vertex());
519 Point ref_point_begin(
521 (*begin_iter->value_node)(begin_time).get(prev).get_vertex() +
522 (*end_iter->value_node)(begin_time).get(prev).get_vertex()
527 (*begin_iter->value_node)(end_time).get(prev).get_vertex() +
528 (*end_iter->value_node)(end_time).get(prev).get_vertex()
533 (*begin_iter->value_node)(t).get(prev).get_vertex() +
534 (*end_iter->value_node)(t).get(prev).get_vertex()
537 Point ref_point_linear((ref_point_end-ref_point_begin)*amount+ref_point_begin);
540 (curr.get_vertex()-ret.get_vertex())*amount+ret.get_vertex() +
541 (ref_point_now-ref_point_linear)
543 ret.set_tangent1((curr.get_tangent1()-ret.get_tangent1())*amount+ret.get_tangent1());
544 ret.set_split_tangent_flag(curr.get_split_tangent_flag());
545 if(ret.get_split_tangent_flag())
546 ret.set_tangent2((curr.get_tangent2()-ret.get_tangent2())*amount+ret.get_tangent2());
551 Point begin_cord_sys[2], begin_cord_origin;
552 Point end_cord_sys[2], end_cord_origin;
553 Point curr_cord_sys[2], curr_cord_origin;
556 const Point a((*end_iter->value_node)(begin_time).get(prev).get_vertex());
557 const Point b((*begin_iter->value_node)(begin_time).get(prev).get_vertex());
558 begin_cord_origin=(a+b)/2;
559 begin_cord_sys[0]=( b - a ).norm();
560 begin_cord_sys[1]=begin_cord_sys[0].perp();
563 const Point a((*end_iter->value_node)(end_time).get(prev).get_vertex());
564 const Point b((*begin_iter->value_node)(end_time).get(prev).get_vertex());
565 end_cord_origin=(a+b)/2;
566 end_cord_sys[0]=( b - a ).norm();
567 end_cord_sys[1]=end_cord_sys[0].perp();
570 const Point a((*end_iter->value_node)(t).get(prev).get_vertex());
571 const Point b((*begin_iter->value_node)(t).get(prev).get_vertex());
572 curr_cord_origin=(a+b)/2;
573 curr_cord_sys[0]=( b - a ).norm();
574 curr_cord_sys[1]=curr_cord_sys[0].perp();
578 end_cord_origin=(*end_iter->value_node)(end_time).get(prev).get_vertex();
580 (*begin_iter->value_node)(end_time).get(prev).get_vertex() -
583 end_cord_sys[1]=end_cord_sys[0].perp();
585 curr_cord_origin=(*end_iter->value_node)(t).get(prev).get_vertex();
587 (*begin_iter->value_node)(t).get(prev).get_vertex() -
590 curr_cord_sys[1]=curr_cord_sys[0].perp();
593 // Convert start point
597 Point tmp(ret.get_vertex()-begin_cord_origin);
598 a[0]=tmp*begin_cord_sys[0];
599 a[1]=tmp*begin_cord_sys[1];
600 #define COORD_SYS_RADIAL_TAN_INTERP 1
602 #ifdef COORD_SYS_RADIAL_TAN_INTERP
603 tmp=ret.get_tangent1()+ret.get_vertex()-begin_cord_origin;
604 at1[0]=tmp*begin_cord_sys[0];
605 at1[1]=tmp*begin_cord_sys[1];
607 if(curr.get_split_tangent_flag())
609 tmp=ret.get_tangent2()+ret.get_vertex()-begin_cord_origin;
610 at2[0]=tmp*begin_cord_sys[0];
611 at2[1]=tmp*begin_cord_sys[1];
616 // Convert finish point
620 Point tmp(curr.get_vertex()-end_cord_origin);
621 b[0]=tmp*end_cord_sys[0];
622 b[1]=tmp*end_cord_sys[1];
624 #ifdef COORD_SYS_RADIAL_TAN_INTERP
625 tmp=curr.get_tangent1()+curr.get_vertex()-end_cord_origin;
626 bt1[0]=tmp*end_cord_sys[0];
627 bt1[1]=tmp*end_cord_sys[1];
629 if(curr.get_split_tangent_flag())
631 tmp=curr.get_tangent2()+curr.get_vertex()-end_cord_origin;
632 bt2[0]=tmp*end_cord_sys[0];
633 bt2[1]=tmp*end_cord_sys[1];
638 // Convert current point
642 // Transpose (invert)
643 swap(curr_cord_sys[0][1],curr_cord_sys[1][0]);
645 Point tmp((b-a)*amount+a);
646 c[0]=tmp*curr_cord_sys[0];
647 c[1]=tmp*curr_cord_sys[1];
650 #define INTERP_FUNCTION radial_interpolation
651 //#define INTERP_FUNCTION linear_interpolation
653 #ifdef COORD_SYS_RADIAL_TAN_INTERP
654 tmp=INTERP_FUNCTION(at1,bt1,amount);
655 ct1[0]=tmp*curr_cord_sys[0];
656 ct1[1]=tmp*curr_cord_sys[1];
657 ct1+=curr_cord_origin;
660 if(curr.get_split_tangent_flag())
662 tmp=INTERP_FUNCTION(at2,bt2,amount);
663 ct2[0]=tmp*curr_cord_sys[0];
664 ct2[1]=tmp*curr_cord_sys[1];
665 ct2+=curr_cord_origin;
672 #ifndef COORD_SYS_RADIAL_TAN_INTERP
673 ret.set_tangent1(radial_interpolation(ret.get_tangent1(),curr.get_tangent1(),amount));
674 ret.set_split_tangent_flag(curr.get_split_tangent_flag());
675 if(ret.get_split_tangent_flag())
676 ret.set_tangent2(radial_interpolation(ret.get_tangent2(),curr.get_tangent2(),amount));
678 ret.set_tangent1(ct1);
679 ret.set_split_tangent_flag(curr.get_split_tangent_flag());
680 if(ret.get_split_tangent_flag())
681 ret.set_tangent2(ct2);
685 ret.set_origin(curr.get_origin());
686 ret.set_width((curr.get_width()-ret.get_width())*amount+ret.get_width());
689 // Handle the case where we are the first vertex
692 ret.set_tangent1(ret.get_tangent1()*prev_tangent_scalar);
696 ret_list.push_back(ret);
700 ret_list.back().set_split_tangent_flag(true);
701 ret_list.back().set_tangent2(prev.get_tangent2()*prev_tangent_scalar);
702 ret_list.push_back(ret);
703 ret_list.back().set_split_tangent_flag(true);
704 //ret_list.back().set_tangent2(ret.get_tangent1());
705 ret_list.back().set_tangent1(ret.get_tangent1()*prev_tangent_scalar);
713 ret_list.back().set_split_tangent_flag(true);
714 ret_list.back().set_tangent2(prev.get_tangent2()*next_scale);
718 if(get_loop() && !first_flag)
732 synfig::warning(string("ValueNode_BLine::operator()():")+_("No entries in list"));
735 synfig::warning(string("ValueNode_BLine::operator()():")+_("No entries in ret_list"));
737 return ValueBase(ret_list,get_loop());
741 ValueNode_BLine::link_local_name(int i)const
743 assert(i>=0 && (unsigned)i<list.size());
744 return etl::strprintf(_("Vertex %03d"),i+1);
748 ValueNode_BLine::clone(const GUID& deriv_guid)const
750 { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
752 ValueNode_BLine* ret=new ValueNode_BLine();
753 ret->set_guid(get_guid()^deriv_guid);
755 std::vector<ListEntry>::const_iterator iter;
757 for(iter=list.begin();iter!=list.end();++iter)
759 if(iter->value_node->is_exported())
763 ListEntry list_entry(*iter);
764 //list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
765 //if(!list_entry.value_node)
766 list_entry.value_node=iter->value_node->clone(deriv_guid);
767 ret->add(list_entry);
768 //ret->list.back().value_node=iter->value_node.clone();
771 ret->set_loop(get_loop());
777 ValueNode_BLine::get_name()const
783 ValueNode_BLine::get_local_name()const
789 ValueNode_BLine::create_new()const
796 ValueNode_BLine::check_type(ValueBase::Type type)
798 return type==ValueBase::TYPE_LIST;