more updates
[synfig.git] / synfig-core / trunk / src / synfig / valuenode_bline.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file valuenode_bline.cpp
3 **      \brief Template File
4 **
5 **      $Id: valuenode_bline.cpp,v 1.1.1.1 2005/01/04 01:23:15 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
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.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "valuenode_bline.h"
32 #include "valuenode_const.h"
33 #include "valuenode_composite.h"
34 #include "general.h"
35 #include "exception.h"
36 #include "blinepoint.h"
37 #include <vector>
38 #include <list>
39 #include <algorithm>
40 #include <ETL/hermite>
41 #include <ETL/calculus>
42 #include "segment.h"
43
44 #endif
45
46 /* === U S I N G =========================================================== */
47
48 using namespace std;
49 using namespace etl;
50 using namespace sinfg;
51
52 /* === M A C R O S ========================================================= */
53
54 /* === G L O B A L S ======================================================= */
55
56 /* === P R O C E D U R E S ================================================= */
57
58 inline Vector
59 linear_interpolation(const Vector& a, const Vector& b, float c)
60 { return (b-a)*c+a; }
61
62 inline Vector
63 radial_interpolation(const Vector& a, const Vector& b, float c)
64 {
65         affine_combo<Real,float> mag_combo;
66         affine_combo<Angle,float> ang_combo;
67         
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));
70         
71         return Point( mag*Angle::cos(ang).get(),mag*Angle::sin(ang).get() );
72 }
73
74
75
76 ValueBase
77 sinfg::convert_bline_to_segment_list(const ValueBase& bline)
78 {
79         std::vector<Segment> ret;
80         
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;
85
86         BLinePoint prev,first;
87         
88         //start with prev = first and iter on the second...
89         
90         if(list.empty()) return ValueBase(ret,bline.get_loop());
91         first = prev = list.front();
92         
93         for(iter=++list.begin();iter!=list.end();++iter)
94         {
95                 ret.push_back(
96                         Segment(
97                                 prev.get_vertex(),
98                                 prev.get_tangent2(),
99                                 iter->get_vertex(),
100                                 iter->get_tangent1()
101                         )
102                 );
103                 prev=*iter;
104         }               
105         if(bline.get_loop())
106         {
107                 ret.push_back(
108                         Segment(
109                                 prev.get_vertex(),
110                                 prev.get_tangent2(),
111                                 first.get_vertex(),
112                                 first.get_tangent1()
113                         )
114                 );
115         }
116         return ValueBase(ret,bline.get_loop());
117 }
118
119 ValueBase
120 sinfg::convert_bline_to_width_list(const ValueBase& bline)
121 {
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;
127         
128         if(bline.empty())
129                 return ValueBase(ValueBase::TYPE_LIST);
130         
131         for(iter=list.begin();iter!=list.end();++iter)
132                 ret.push_back(iter->get_width());
133
134         if(bline.get_loop())
135                 ret.push_back(list.front().get_width());
136
137         return ValueBase(ret,bline.get_loop());
138 }
139
140
141 /* === M E T H O D S ======================================================= */
142
143
144 ValueNode_BLine::ValueNode_BLine():
145         ValueNode_DynamicList(ValueBase::TYPE_BLINEPOINT)
146 {
147 }
148
149 ValueNode_BLine::~ValueNode_BLine()
150 {
151 }
152
153 ValueNode_BLine*
154 ValueNode_BLine::create(const ValueBase &value)
155 {
156         if(value.get_type()!=ValueBase::TYPE_LIST)
157                 return 0;
158         
159         ValueNode_BLine* value_node(new ValueNode_BLine());
160
161         if(!value.empty())
162         {
163                 switch(value.get_contained_type())
164                 {
165                 case ValueBase::TYPE_BLINEPOINT:
166                 {
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;
171
172                         for(iter=bline_points.begin();iter!=bline_points.end();iter++)
173                         {       
174                                 value_node->add(ValueNode::Handle(ValueNode_Composite::create(*iter)));
175                         }
176                         value_node->set_loop(value.get_loop());
177                 }
178                         break;
179                 case ValueBase::TYPE_SEGMENT:
180                 {
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
184                         // smooth.
185                         
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());
191                         --last;
192                         ValueNode_Const::Handle prev,first;
193                         
194                         for(iter=segments.begin();iter!=segments.end();iter++)
195                         {       
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())
200                                 {
201                                         prev=ValueNode_Const::create(ValueBase::TYPE_BLINEPOINT);
202                                         {
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);
210                                         }
211                                         first=prev;
212                                         value_node->add(ValueNode::Handle(prev));
213                                         
214                                 }
215                                 if(iter==last && iter->p2.is_equal_to(FIRST_POINT.get_vertex()))
216                                 {
217                                         value_node->set_loop(true);
218                                         if(!iter->t2.is_equal_to(FIRST_POINT.get_tangent1()))
219                                         {
220                                                 BLinePoint first_point(FIRST_POINT);
221                                                 first_point.set_tangent1(iter->t2);
222                                                 first->set_value(first_point);
223                                         }
224                                         continue;
225                                 }
226                                         
227                                 ValueNode_Const::Handle curr;
228                                 curr=ValueNode_Const::create(ValueBase::TYPE_BLINEPOINT);
229                                 {
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);
237                                 }
238                                 if(!PREV_POINT.get_tangent1().is_equal_to(iter->t1))
239                                 {
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);
244                                 }
245                                 value_node->add(ValueNode::Handle(curr));
246                                 prev=curr;
247                         }
248                         
249                 }
250                         break;
251                 default:
252                         // We got a list of who-knows-what. We don't have any idea
253                         // what to do with it.
254                         return 0;
255                         break;
256                 }
257         }
258         
259         
260         return value_node;
261 }
262
263 ValueNode_BLine::ListEntry
264 ValueNode_BLine::create_list_entry(int index, Time time, Real origin)
265 {
266         ValueNode_BLine::ListEntry ret;
267
268         
269         sinfg::BLinePoint prev,next;
270
271         int prev_i,next_i;
272
273         index=index%link_count();
274
275         assert(index>=0);
276         ret.index=index;
277         ret.set_parent_value_node(this);
278
279         if(!list[index].status_at_time(time))
280                 next_i=find_next_valid_entry(index,time);
281         else
282                 next_i=index;
283         prev_i=find_prev_valid_entry(index,time);
284         
285         sinfg::info("index=%d, next_i=%d, prev_i=%d",index,next_i,prev_i);
286         
287         next=(*list[next_i].value_node)(time);
288         prev=(*list[prev_i].value_node)(time);
289         
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);
292
293         sinfg::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);
300         
301         ret.value_node=ValueNode_Composite::create(bline_point);
302         
303         return ret;
304 }
305
306 ValueBase
307 ValueNode_BLine::operator()(Time t)const
308 {
309         std::vector<BLinePoint> ret_list;
310         
311         std::vector<ListEntry>::const_iterator iter,first_iter;
312         bool first_flag(true);
313         bool rising;
314         int index(0);
315         float next_scale(1.0f);
316         
317         BLinePoint prev,first;
318         first.set_origin(100.0f);
319         
320         for(iter=list.begin();iter!=list.end();++iter,index++)
321         {
322                 float amount(iter->amount_at_time(t,&rising));
323                 
324                 assert(amount>=0.0f);
325                 assert(amount<=1.0f);
326                 
327                 if(amount==1.0f)
328                 {
329                         if(first_flag)
330                         {
331                                 first_iter=iter;
332                                 first=prev=(*iter->value_node)(t).get(prev);
333                                 first_flag=false;
334                                 ret_list.push_back(first);
335                                 continue;
336                         }
337                         
338                         BLinePoint curr;
339                         curr=(*iter->value_node)(t).get(prev);
340                         
341                         if(next_scale!=1.0f)
342                         {
343                                 ret_list.back().set_split_tangent_flag(true);
344                                 ret_list.back().set_tangent2(prev.get_tangent2()*next_scale);
345
346                                 ret_list.push_back(curr);
347
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);
351
352                                 next_scale=1.0f;
353                         }
354                         else
355                         {
356                                 ret_list.push_back(curr);
357
358                         }
359                         
360                         prev=curr;
361                 }
362                 else
363                 if(amount>0.0f)
364                 {
365                         std::vector<ListEntry>::const_iterator begin_iter,end_iter;
366                         
367                         // This is where the interesting stuff happens
368                         // We need to seek forward in the list to see what the next
369                         // active point is
370                         
371                         BLinePoint curr;
372                         BLinePoint begin;       // begin of dynamic group
373                         BLinePoint end;         // End of dynamic group
374                         Time blend_time;
375                         int dist_from_begin(0), dist_from_end(0);
376                         BLinePoint ret;
377                         
378                         Time begin_time;
379                         Time end_time;
380                         
381                         if(!rising)
382                         {
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(); }
387                         }
388                         else
389                         {
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(); }
394                         }
395                         blend_time=begin_time;
396                         curr=(*iter->value_node)(end_time).get(curr);                           
397
398 //                      curr=(*iter->value_node)(t).get(curr);
399                         
400                         // Find "end" of dynamic group
401                         end_iter=iter;
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)
405                                 {
406                                         end=(*end_iter->value_node)(blend_time).get(prev);
407                                         break;
408                                 }
409                         
410                         // If we did not find an end of the dynamic group...
411                         if(end_iter==list.end())
412                         {
413                                 if(get_loop())
414                                 {
415                                         end_iter=first_iter;
416                                         end=(*end_iter->value_node)(blend_time).get(prev);
417 //                                      end=first;
418                                 }
419                                 else
420                                 {
421                                         // Writeme!
422                                         end_iter=first_iter;
423                                         end=(*end_iter->value_node)(blend_time).get(prev);
424 //                                      end=first;
425                                 }
426                         }
427
428                         // Find "begin" of dynamic group
429                         begin_iter=iter;
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
431                         do
432                         {
433                                 if(begin_iter==list.begin())
434                                 {
435                                         if(get_loop())
436                                                 begin_iter=list.end();
437                                         else
438                                                 break;
439                                 }
440                                 
441                                 --begin_iter;
442                                 dist_from_begin++;
443                                 
444                                 if(begin_iter==iter)
445                                         break;
446
447                                 if(begin_iter->amount_at_time(t)>amount)
448                                 {
449                                         begin=(*begin_iter->value_node)(blend_time).get(prev);
450                                         break;
451                                 }
452                         }while(begin_iter!=iter);
453                         
454                         // If we did not find a begin
455                         if(begin.get_origin()==100.0f)
456                         {
457                                 if(get_loop())
458                                 {
459                                         begin_iter=first_iter;
460                                         begin=(*begin_iter->value_node)(blend_time).get(prev);
461 //                                      begin=first;
462                                 }
463                                 else
464                                 {
465                                         // Writeme!
466                                         begin_iter=first_iter;
467                                         begin=(*begin_iter->value_node)(blend_time).get(prev);
468 //                                      begin=first;
469                                 }
470                         }
471                         
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);
474         
475                         ret.set_vertex(curve(curr.get_origin()));
476
477                         ret.set_width((end.get_width()-begin.get_width())*curr.get_origin()+begin.get_width());
478
479                         ret.set_tangent1(deriv(curr.get_origin()));
480                         ret.set_tangent2(deriv(curr.get_origin()));
481                         
482                         float prev_tangent_scalar(1.0f);
483                         float next_tangent_scalar(1.0f);
484                         
485                         //sinfg::info("index_%d:dist_from_begin=%d",index,dist_from_begin);
486                         //sinfg::info("index_%d:dist_from_end=%d",index,dist_from_end);
487                         
488                         // If we are the next to the begin
489                         if(begin_iter==--std::vector<ListEntry>::const_iterator(iter) || dist_from_begin==1)
490                         {
491                                 prev_tangent_scalar=(1.0f-curr.get_origin())*amount+curr.get_origin();
492                         }
493                         else
494                         {
495                                 float origin=curr.get_origin()-prev.get_origin();
496                                 prev_tangent_scalar=(1.0f-origin)*amount+origin;                                
497                         }
498
499                         // If we are the next to the end
500                         if(end_iter==++std::vector<ListEntry>::const_iterator(iter) || dist_from_end==1)
501                         {
502                                 float origin=1.0-curr.get_origin();
503                                 next_tangent_scalar=(1.0f-origin)*amount+origin;
504                         }
505                         else
506                         if(list.end()!=++std::vector<ListEntry>::const_iterator(iter))
507                         {
508                                 BLinePoint next;
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;                                
512                         }
513                         next_scale=next_tangent_scalar;
514                         
515                         //ret.set_vertex((curr.get_vertex()-ret.get_vertex())*amount+ret.get_vertex());
516                         if(false)
517                         {
518                                 // My first try
519                                 Point ref_point_begin(
520                                         (
521                                                 (*begin_iter->value_node)(begin_time).get(prev).get_vertex() +
522                                                 (*end_iter->value_node)(begin_time).get(prev).get_vertex()
523                                         ) * 0.5
524                                 );
525                                 Point ref_point_end(
526                                         (
527                                                 (*begin_iter->value_node)(end_time).get(prev).get_vertex() +
528                                                 (*end_iter->value_node)(end_time).get(prev).get_vertex()
529                                         ) * 0.5
530                                 );
531                                 Point ref_point_now(
532                                         (
533                                                 (*begin_iter->value_node)(t).get(prev).get_vertex() +
534                                                 (*end_iter->value_node)(t).get(prev).get_vertex()
535                                         ) * 0.5
536                                 );
537                                 Point ref_point_linear((ref_point_end-ref_point_begin)*amount+ref_point_begin);
538
539                                 ret.set_vertex(
540                                         (curr.get_vertex()-ret.get_vertex())*amount+ret.get_vertex() +
541                                         (ref_point_now-ref_point_linear)
542                                 );
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());
547                         }
548                         else
549                         {
550                                 // My second try
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;
554                                 
555                                 {
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();
561                                 }
562                                 {
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();
568                                 }
569                                 {
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();
575                                 }
576                                 
577                                 /*
578                                 end_cord_origin=(*end_iter->value_node)(end_time).get(prev).get_vertex();
579                                 end_cord_sys[0]=(
580                                         (*begin_iter->value_node)(end_time).get(prev).get_vertex() -
581                                         end_cord_origin
582                                 ).norm();
583                                 end_cord_sys[1]=end_cord_sys[0].perp();
584                                 
585                                 curr_cord_origin=(*end_iter->value_node)(t).get(prev).get_vertex();
586                                 curr_cord_sys[0]=(
587                                         (*begin_iter->value_node)(t).get(prev).get_vertex() -
588                                         curr_cord_origin
589                                 ).norm();
590                                 curr_cord_sys[1]=curr_cord_sys[0].perp();
591                                 */
592                                 
593                                 // Convert start point
594                                 Point a;
595                                 Vector at1,at2;
596                                 {
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
601                                         
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];
606                                         
607                                         if(curr.get_split_tangent_flag())
608                                         {
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];
612                                         }
613 #endif
614                                 }
615                                 
616                                 // Convert finish point
617                                 Point b;
618                                 Vector bt1,bt2;
619                                 {
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];
623                                         
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];
628
629                                         if(curr.get_split_tangent_flag())
630                                         {
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];
634                                         }
635 #endif
636                                 }
637                                                                 
638                                 // Convert current point
639                                 Point c;
640                                 Vector ct1,ct2;
641                                 {
642                                         // Transpose (invert)
643                                         swap(curr_cord_sys[0][1],curr_cord_sys[1][0]);
644
645                                         Point tmp((b-a)*amount+a);
646                                         c[0]=tmp*curr_cord_sys[0];
647                                         c[1]=tmp*curr_cord_sys[1];
648                                         c+=curr_cord_origin;
649
650 #define INTERP_FUNCTION         radial_interpolation
651 //#define INTERP_FUNCTION               linear_interpolation
652                                         
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;
658                                         ct1-=c;
659                                         
660                                         if(curr.get_split_tangent_flag())
661                                         {
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;
666                                                 ct2-=c;
667                                         }
668 #endif
669                                 }
670
671                                 ret.set_vertex(c);
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));
677 #else                           
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);
682 #endif
683                         }
684                         
685                         ret.set_origin(curr.get_origin());
686                         ret.set_width((curr.get_width()-ret.get_width())*amount+ret.get_width());
687                         
688
689                         // Handle the case where we are the first vertex
690                         if(first_flag)
691                         {
692                                 ret.set_tangent1(ret.get_tangent1()*prev_tangent_scalar);
693                                 first_iter=iter;
694                                 first=prev=ret;
695                                 first_flag=false;
696                                 ret_list.push_back(ret);
697                                 continue;
698                         }
699
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);
706
707                         prev=ret;
708                 }
709         }
710         
711         if(next_scale!=1.0f)
712         {
713                 ret_list.back().set_split_tangent_flag(true);
714                 ret_list.back().set_tangent2(prev.get_tangent2()*next_scale);
715         }
716
717 /*
718         if(get_loop() && !first_flag)
719         {
720                 ret_list.push_back(
721                         Segment(
722                         prev.get_vertex(),
723                         prev.get_tangent2(),
724                         first.get_vertex(),
725                         first.get_tangent1()
726                         )
727                 );
728         }
729 */
730         
731         if(list.empty())
732                 sinfg::warning(string("ValueNode_BLine::operator()():")+_("No entries in list"));
733         else
734         if(ret_list.empty())
735                 sinfg::warning(string("ValueNode_BLine::operator()():")+_("No entries in ret_list"));
736
737         return ValueBase(ret_list,get_loop());
738 }
739
740 String
741 ValueNode_BLine::link_local_name(int i)const
742 {
743         assert(i>=0 && (unsigned)i<list.size());
744         return etl::strprintf(_("Vertex %03d"),i+1);
745 }       
746
747 ValueNode*
748 ValueNode_BLine::clone(const GUID& deriv_guid)const
749 {
750         { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
751
752         ValueNode_BLine* ret=new ValueNode_BLine();
753         ret->set_guid(get_guid()^deriv_guid);
754         
755         std::vector<ListEntry>::const_iterator iter;
756
757         for(iter=list.begin();iter!=list.end();++iter)
758         {
759                 if(iter->value_node->is_exported())
760                         ret->add(*iter);
761                 else
762                 {
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();
769                 }
770         }
771         ret->set_loop(get_loop());
772         
773         return ret;
774 }
775
776 String
777 ValueNode_BLine::get_name()const
778 {
779         return "bline";
780 }
781
782 String
783 ValueNode_BLine::get_local_name()const
784 {
785         return _("BLine");
786 }
787
788 LinkableValueNode*
789 ValueNode_BLine::create_new()const
790 {
791         assert(0);
792         return 0;
793 }
794
795 bool
796 ValueNode_BLine::check_type(ValueBase::Type type)
797 {
798         return type==ValueBase::TYPE_LIST;
799 }