Commented out unused code.
[synfig.git] / synfig-studio / trunk / src / synfigapp / blineconvert.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file blineconvert.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "blineconvert.h"
33 #include <vector>
34 #include <ETL/gaussian>
35 #include <ETL/hermite>
36 #include <ETL/clock>
37 #include <float.h>
38 #include <algorithm>
39 #include <synfig/general.h>
40 #include <cassert>
41
42
43
44 #endif
45
46 /* === U S I N G =========================================================== */
47
48 using namespace std;
49 using namespace etl;
50 using namespace synfig;
51
52 /* === M A C R O S ========================================================= */
53
54 #define EPSILON         (1e-10)
55
56 /* === G L O B A L S ======================================================= */
57
58 /* === P R O C E D U R E S ================================================= */
59
60 /* === M E T H O D S ======================================================= */
61
62
63 //Derivative Functions for numerical approximation
64
65 //bias == 0 will get F' at f3, bias < 0 will get F' at f1, and bias > 0 will get F' at f5
66 template < class T >
67 inline void FivePointdt(T &df, const T &f1, const T &f2, const T &f3, const T &f4, const T &f5, int bias)
68 {
69         if(bias == 0)
70         {
71                 //middle
72                 df = (f1 - f2*8 + f4*8 - f5)*(1/12.0f);
73         }else if(bias < 0)
74         {
75                 //left
76                 df = (-f1*25 + f2*48 - f3*36 + f4*16 - f5*3)*(1/12.0f);
77         }else
78         {
79                 //right
80                 df = (f1*3 - f2*16 + f3*36 - f4*48 + f5*25)*(1/12.0f);
81         }
82 }
83
84 template < class T >
85 inline void ThreePointdt(T &df, const T &f1, const T &f2, const T &f3, int bias)
86 {
87         if(bias == 0)
88         {
89                 //middle
90                 df = (-f1 + f3)*(1/2.0f);
91         }else if(bias < 0)
92         {
93                 //left
94                 df = (-f1*3 + f2*4 - f3)*(1/2.0f);
95         }else
96         {
97                 //right
98                 df = (f1 - f2*4 + f3*3)*(1/2.0f);
99         }
100 }
101
102 // template < class T >
103 // inline void ThreePointddt(T &df, const T &f1, const T &f2, const T &f3, int bias)
104 // {
105 //      // a 3 point approximation pretends to have constant acceleration,
106 //      // so only one algorithm needed for left, middle, or right
107 //      df = (f1 -f2*2 + f3)*(1/2.0f);
108 // }
109 // 
110 // // WARNING -- totally broken
111 // template < class T >
112 // inline void FivePointddt(T &df, const T &f1, const T &f2, const T &f3, int bias)
113 // {
114 //      if(bias == 0)
115 //      {
116 //              assert(0); // !?
117 //              //middle
118 //              //df = (- f1 + f2*16 - f3*30 +  f4*16 - f5)*(1/12.0f);
119 //      }/*else if(bias < 0)
120 //      {
121 //              //left
122 //              df = (f1*7 - f2*26*4 + f3*19*6 - f4*14*4 + f5*11)*(1/12.0f);
123 //      }else
124 //      {
125 //              //right
126 //              df = (f1*3 - f2*16 + f3*36 - f4*48 + f5*25)*(1/12.0f);
127 //      }*/
128 //      //side ones don't work, use 3 point
129 // }
130 // 
131 // //implement an arbitrary derivative
132 // //dumb algorithm
133 // template < class T >
134 // void DerivativeApprox(T &df, const T f[], const Real t[], int npoints, int indexval)
135 // {
136 //      /*
137 //      Lj(x) = PI_i!=j (x - xi) / PI_i!=j (xj - xi)
138 // 
139 //      so Lj'(x) = SUM_k PI_i!=j|k (x - xi) / PI_i!=j (xj - xi)
140 //      */
141 // 
142 //      unsigned int i,j,k,i0,i1;
143 // 
144 //      Real Lpj,mult,div,tj;
145 //      Real tval = t[indexval];
146 // 
147 //      //sum k
148 //      for(j=0;j<npoints;++j)
149 //      {
150 //              Lpj = 0;
151 //              div = 1;
152 //              tj = t[j];
153 // 
154 //              for(k=0;k<npoints;++k)
155 //              {
156 //                      if(k != j) //because there is no summand for k == j, since that term is missing from the original equation
157 //                      {
158 //                              //summation for k
159 //                              for(i=0;i<npoints;++i)
160 //                              {
161 //                                      if(i != k)
162 //                                      {
163 //                                              mult *= tval - t[i];
164 //                                      }
165 //                              }
166 // 
167 //                              Lpj += mult; //add into the summation
168 // 
169 //                              //since the ks follow the exact pattern we need for the divisor (use that too)
170 //                              div *= tj - t[k];
171 //                      }
172 //              }
173 // 
174 //              //get the actual coefficient
175 //              Lpj /= div;
176 // 
177 //              //add it in to the equation
178 //              df += f[j]*Lpj;
179 //      }
180 // }
181
182 //END numerical derivatives
183
184 // template < class T >
185 // inline int sign(T f, T tol)
186 // {
187 //      if(f < -tol) return -1;
188 //      if(f > tol) return 1;
189 //      return 0;
190 // }
191
192 void GetFirstDerivatives(const std::vector<synfig::Point> &f, unsigned int left, unsigned int right, char *out, unsigned int dfstride)
193 {
194         unsigned int current = left;
195
196         if(right - left < 2)
197                 return;
198         else if(right - left < 3)
199         {
200                 synfig::Vector v = f[left+1] - f[left];
201
202                 //set both to the one we want
203                 *(synfig::Vector*)out = v;
204                 out += dfstride;
205                 *(synfig::Vector*)out = v;
206                 out += dfstride;
207         }
208         else if(right - left < 6/*5*/) //should use 3 point
209         {
210                 //left then middle then right
211                 ThreePointdt(*(synfig::Vector*)out,f[left+0], f[left+1], f[left+2], -1);
212                 current += 1;
213                 out += dfstride;
214
215                 for(;current < right-1; current++, out += dfstride)
216                 {
217                         ThreePointdt(*(synfig::Vector*)out,f[current-1], f[current], f[current+1], 0);
218                 }
219
220                 ThreePointdt(*(synfig::Vector*)out,f[right-3], f[right-2], f[right-1], 1);
221                 current++;
222                 out += dfstride;
223
224         }else //can use 5 point
225         {
226                 //left 2 then middle bunch then right two
227                 //may want to use 3 point for inner edge ones
228
229                 FivePointdt(*(synfig::Vector*)out,f[left+0], f[left+1], f[left+2], f[left+3], f[left+4], -2);
230                 out += dfstride;
231                 FivePointdt(*(synfig::Vector*)out,f[left+1], f[left+2], f[left+3], f[left+4], f[left+5], -1);
232                 out += dfstride;
233                 current += 2;
234
235                 for(;current < right-2; current++, out += dfstride)
236                 {
237                         FivePointdt(*(synfig::Vector*)out,f[current-2], f[current-1], f[current], f[current+1], f[current+2], 0);
238                 }
239
240                 FivePointdt(*(synfig::Vector*)out,f[right-5], f[right-4], f[right-3], f[right-2], f[right-1], 1);
241                 out += dfstride;
242                 FivePointdt(*(synfig::Vector*)out,f[right-6], f[right-5], f[right-4], f[right-3], f[right-2], 2);
243                 out += dfstride;
244                 current += 2;
245         }
246 }
247
248 void GetSimpleDerivatives(const std::vector<synfig::Point> &f, int left, int right,
249                                                         std::vector<synfig::Point> &df, int outleft,
250                                                         const std::vector<synfig::Real> &/*di*/)
251 {
252         int i1,i2,i;
253         int offset = 2; //df = 1/2 (f[i+o]-f[i-o])
254
255         assert((int)df.size() >= right-left+outleft); //must be big enough
256
257         for(i = left; i < right; ++i)
258         {
259                 //right now indices (figure out distance later)
260                 i1 = std::max(left,i-offset);
261                 i2 = std::max(left,i+offset);
262
263                 df[outleft++] = (f[i2] - f[i1])*0.5f;
264         }
265 }
266
267 //get the curve error from the double sample list of work points (hopefully that's enough)
268 Real CurveError(const synfig::Point *pts, unsigned int n, std::vector<synfig::Point> &work, int left, int right)
269 {
270         if(right-left < 2) return -1;
271
272         int i,j;
273
274         //get distances to each point
275         Real d,dtemp,dsum;
276         //synfig::Vector v,vt;
277         //synfig::Point p1,p2;
278         synfig::Point pi;
279         std::vector<synfig::Point>::const_iterator it;//,end = work.begin()+right;
280
281         //unsigned int size = work.size();
282
283         //for each line, get distance
284         d = 0; //starts at 0
285         for(i = 0; i < (int)n; ++i)
286         {
287                 pi = pts[i];
288
289                 dsum = FLT_MAX;
290
291                 it = work.begin()+left;
292                 //p2 = *it++; //put it at left+1
293                 for(j = left/*+1*/; j < right; ++j,++it)
294                 {
295                         /*p1 = p2;
296                         p2 = *it;
297
298                         v = p2 - p1;
299                         vt = pi - p1;
300
301                         dtemp = v.mag_squared() > 1e-12 ? (vt*v)/v.mag_squared() : 0; //get the projected time value for the current line
302
303                         //get distance to line segment with the time value clamped 0-1
304                         if(dtemp >= 1)  //use p+v
305                         {
306                                 vt += v; //makes it pp - (p+v)
307                         }else if(dtemp > 0)     //use vt-proj
308                         {
309                                 vt -= v*dtemp; // vt - proj_v(vt)       //must normalize the projection vector to work
310                         }
311
312                         //else use p
313                         dtemp = vt.mag_squared();*/
314
315                         dtemp = (pi - *it).mag_squared();
316                         if(dtemp < dsum)
317                                 dsum = dtemp;
318                 }
319
320                 //accumulate the points' min distance from the curve
321                 d += sqrt(dsum);
322         }
323
324         return d;
325 }
326
327 typedef synfigapp::BLineConverter::cpindex cpindex;
328
329 //has the index data and the tangent scale data (relevant as it may be)
330 int tessellate_curves(const std::vector<cpindex> &inds, const std::vector<Point> &f, const std::vector<synfig::Vector> &df, std::vector<Point> &work)
331 {
332         if(inds.size() < 2)
333                 return 0;
334
335         etl::hermite<Point>     curve;
336         int ntess = 0;
337
338         std::vector<cpindex>::const_iterator j = inds.begin(),j2, end = inds.end();
339
340         unsigned int ibase = inds[0].curind;
341
342         j2 = j++;
343         for(; j != end; j2 = j++)
344         {
345                 //if this curve has invalid error (in j) then retessellate its work points (requires reparametrization, etc.)
346                 if(j->error < 0)
347                 {
348                         //get the stepsize etc. for the number of points in here
349                         unsigned int n = j->curind - j2->curind + 1; //thats the number of points in the span
350                         unsigned int k, kend, i0, i3;
351                         //so reset the right chunk
352
353                         Real t, dt = 1/(Real)(n*2-2); //assuming that they own only n points
354
355                         //start at first intermediate
356                         t = 0;
357
358                         i0 = j2->curind; i3 = j->curind;
359                         k = (i0-ibase)*2; //start on first intermediary point (2x+1)
360                         kend = (i3-ibase)*2; //last point to set (not intermediary)
361
362                         //build hermite curve, it's easier
363                         curve.p1() = f[i0];
364                         curve.p2() = f[i3];
365                         curve.t1() = df[i0-ibase] * (df[i0-ibase].mag_squared() > 1e-4
366                                                                                  ? j2->tangentscale/df[i0-ibase].mag()
367                                                                                  : j2->tangentscale);
368                         curve.t2() = df[i3-ibase] * (df[i3-ibase].mag_squared() > 1e-4
369                                                                                  ? j->tangentscale/df[i3-ibase].mag()
370                                                                                  : j->tangentscale);
371                         curve.sync();
372
373                         //MUST include the end point (since we are ignoring left one)
374                         for(; k < kend; ++k, t += dt)
375                         {
376                                 work[k] = curve(t);
377                         }
378
379                         work[k] = curve(1); //k == kend, t == 1 -> c(t) == p2
380                         ++ntess;
381                 }
382         }
383
384         return ntess;
385 }
386
387 synfigapp::BLineConverter::BLineConverter()
388 {
389         pixelwidth = 1;
390         smoothness = 0.70f;
391         width = 0;
392 };
393
394 void
395 synfigapp::BLineConverter::clear()
396 {
397         f.clear();
398         f_w.clear();
399         ftemp.clear();
400         df.clear();
401         cvt.clear();
402         brk.clear();
403         di.clear();
404         d_i.clear();
405         work.clear();
406         curind.clear();
407 }
408
409 void
410 synfigapp::BLineConverter::operator () (std::list<synfig::BLinePoint> &out, const std::list<synfig::Point> &in,const std::list<synfig::Real> &in_w)
411 {
412         //Profiling information
413         /*etl::clock::value_type initialprocess=0, curveval=0, breakeval=0, disteval=0;
414         etl::clock::value_type preproceval=0, tesseval=0, erroreval=0, spliteval=0;
415         unsigned int                    numpre=0, numtess=0, numerror=0, numsplit=0;
416         etl::clock_realtime timer,total;*/
417
418         //total.reset();
419         if(in.size()<=1)
420                 return;
421
422         clear();
423
424         //removing digitization error harder than expected
425
426         //intended to fix little pen errors caused by the way people draw (tiny juts in opposite direction)
427         //Different solutions
428         //      Average at both end points (will probably eliminate many points at each end of the samples)
429         //      Average after the break points are found (weird points would still affect the curve)
430         //      Just always get rid of breaks at the beginning and end if they are a certain distance apart
431         //              This is will be current approach so all we do now is try to remove duplicate points
432
433         //remove duplicate points - very bad for fitting
434
435         //timer.reset();
436
437         {
438                 std::list<synfig::Point>::const_iterator i = in.begin(), end = in.end();
439                 std::list<synfig::Real>::const_iterator iw = in_w.begin();
440                 synfig::Point   c;
441
442                 if(in.size() == in_w.size())
443                 {
444                         for(;i != end; ++i,++iw)
445                         {
446                                 //eliminate duplicate points
447                                 if(*i != c)
448                                 {
449                                         f.push_back(c = *i);
450                                         f_w.push_back(*iw);
451                                 }
452                         }
453                 }else
454                 {
455                         for(;i != end; ++i)
456                         {
457                                 //eliminate duplicate points
458                                 if(*i != c)
459                                 {
460                                         f.push_back(c = *i);
461                                 }
462                         }
463                 }
464         }
465         //initialprocess = timer();
466
467         if(f.size()<=6)
468                 return;
469
470         //get curvature information
471         //timer.reset();
472
473         {
474                 int i,i0,i1;
475                 synfig::Vector v1,v2;
476
477                 cvt.resize(f.size());
478
479                 cvt.front() = 1;
480                 cvt.back() = 1;
481
482                 for(i = 1; i < (int)f.size()-1; ++i)
483                 {
484                         i0 = std::max(0,i - 2);
485                         i1 = std::min((int)(f.size()-1),i + 2);
486
487                         v1 = f[i] - f[i0];
488                         v2 = f[i1] - f[i];
489
490                         cvt[i] = (v1*v2)/(v1.mag()*v2.mag());
491                 }
492         }
493
494         //curveval = timer();
495         //synfig::info("calculated curvature");
496
497         //find corner points and interpolate inside those
498         //timer.reset();
499         {
500                 //break at sharp derivative points
501                 //TODO tolerance should be set based upon digitization resolution (length dependent index selection)
502                 Real    tol = 0;                //break tolerance, for the cosine of the change in angle (really high curvature or something)
503                 Real    fixdistsq = 4*width*width; //the distance to ignore breaks at the end points (for fixing stuff)
504                 unsigned int i = 0;
505
506                 int             maxi = -1, last=0;
507                 Real    minc = 1;
508
509                 brk.push_back(0);
510
511                 for(i = 1; i < cvt.size()-1; ++i)
512                 {
513                         //insert if too sharp (we need to break the tangents to insert onto the break list)
514
515                         if(cvt[i] < tol)
516                         {
517                                 if(cvt[i] < minc)
518                                 {
519                                         minc = cvt[i];
520                                         maxi = i;
521                                 }
522                         }else if(maxi >= 0)
523                         {
524                                 if(maxi >= last + 8)
525                                 {
526                                         //synfig::info("break: %d-%d",maxi+1,cvt.size());
527                                         brk.push_back(maxi);
528                                         last = maxi;
529                                 }
530                                 maxi = -1;
531                                 minc = 1;
532                         }
533                 }
534
535                 brk.push_back(i);
536
537                 //postprocess for breaks too close to each other
538                 Real d = 0;
539                 Point p = f[brk.front()];
540
541                 //first set
542                 for(i = 1; i < brk.size()-1; ++i) //do not want to include end point...
543                 {
544                         d = (f[brk[i]] - p).mag_squared();
545                         if(d > fixdistsq) break; //don't want to group breaks if we ever get over the dist...
546                 }
547                 //want to erase all points before...
548                 if(i != 1)
549                         brk.erase(brk.begin(),brk.begin()+i-1);
550
551                 //end set
552                 p = f[brk.back()];
553                 for(i = brk.size()-2; i > 0; --i) //start at one in from the end
554                 {
555                         d = (f[brk[i]] - p).mag_squared();
556                         if(d > fixdistsq) break; //don't want to group breaks if we ever get over the dist
557                 }
558                 if(i != brk.size()-2)
559                         brk.erase(brk.begin()+i+2,brk.end()); //erase all points that we found... found none if i has not advanced
560                 //must not include the one we ended up on
561         }
562         //breakeval = timer();
563         //synfig::info("found break points: %d",brk.size());
564
565         //get the distance calculation of the entire curve (for tangent scaling)
566
567         //timer.reset();
568         {
569                 synfig::Point p1,p2;
570
571                 p1=p2=f[0];
572
573                 di.resize(f.size()); d_i.resize(f.size());
574                 Real d = 0;
575                 for(unsigned int i = 0; i < f.size();)
576                 {
577                         d += (d_i[i] = (p2-p1).mag());
578                         di[i] = d;
579
580                         p1=p2;
581                         p2=f[++i];
582                 }
583         }
584         //disteval = timer();
585         //synfig::info("calculated distance");
586
587         //now break at every point - calculate new derivatives each time
588
589         //TODO
590         //must be sure that the break points are 3 or more apart
591         //then must also store the breaks which are not smooth, etc.
592         //and figure out tangents between there
593
594         //for each pair of break points (as long as they are far enough apart) recursively subdivide stuff
595         //ignore the detected intermediate points
596         {
597                 unsigned int i0=0,i3=0,is=0;
598                 int i=0,j=0;
599
600                 bool done = false;
601
602                 Real errortol = smoothness*pixelwidth; //???? what the hell should this value be
603
604                 BLinePoint a;
605                 synfig::Vector v;
606
607                 //intemp = f; //don't want to smooth out the corners
608
609                 bool breaktan = false, setwidth;
610                 a.set_split_tangent_flag(false);
611                 //a.set_width(width);
612                 a.set_width(1.0f);
613
614                 setwidth = (f.size() == f_w.size());
615
616                 for(j = 0; j < (int)brk.size() - 1; ++j)
617                 {
618                         //for b[j] to b[j+1] subdivide and stuff
619                         i0 = brk[j];
620                         i3 = brk[j+1];
621
622                         unsigned int size = i3-i0+1; //must include the end points
623
624                         //new derivatives
625                         //timer.reset();
626                         ftemp.assign(f.begin()+i0, f.begin()+i3+1);
627                         for(i=0;i<20;++i)
628                                 gaussian_blur_3(ftemp.begin(),ftemp.end(),false);
629
630                         df.resize(size);
631                         GetFirstDerivatives(ftemp,0,size,(char*)&df[0],sizeof(df[0]));
632                         //GetSimpleDerivatives(ftemp,0,size,df,0,di);
633                         //< don't have to worry about indexing stuff as it is all being taken car of right now
634                         //preproceval += timer();
635                         //numpre++;
636
637                         work.resize(size*2-1); //guarantee that all points will be tessellated correctly (one point in between every 2 adjacent points)
638
639                         //if size of work is size*2-1, the step size should be 1/(size*2 - 2)
640                         //Real step = 1/(Real)(size*2 - 1);
641
642                         //start off with break points as indices
643                         curind.clear();
644                         curind.push_back(cpindex(i0,di[i3]-di[i0],0)); //0 error because no curve on the left
645                         curind.push_back(cpindex(i3,di[i3]-di[i0],-1)); //error needs to be reevaluated
646                         done = false; //we want to loop
647
648                         unsigned int dcount = 0;
649
650                         //while there are still enough points between us, and the error is too high subdivide (and invalidate neighbors that share tangents)
651                         while(!done)
652                         {
653                                 //tessellate all curves with invalid error values
654                                 work[0] = f[i0];
655
656                                 //timer.reset();
657                                 /*numtess += */tessellate_curves(curind,f,df,work);
658                                 //tesseval += timer();
659
660                                 //now get all error values
661                                 //timer.reset();
662                                 for(i = 1; i < (int)curind.size(); ++i)
663                                 {
664                                         if(curind[i].error < 0) //must have been retessellated, so now recalculate error value
665                                         {
666                                                 //evaluate error from points (starting at current index)
667                                                 int size = curind[i].curind - curind[i-1].curind + 1;
668                                                 curind[i].error = CurveError(&f[curind[i-1].curind], size,
669                                                                                                          work,(curind[i-1].curind - i0)*2,(curind[i].curind - i0)*2+1);
670
671                                                 /*if(curind[i].error > 1.0e5)
672                                                 {
673                                                         synfig::info("Holy crap %d-%d error %f",curind[i-1].curind,curind[i].curind,curind[i].error);
674                                                         curind[i].error = -1;
675                                                         numtess += tessellate_curves(curind,f,df,work);
676                                                         curind[i].error = CurveError(&f[curind[i-1].curind], size,
677                                                                                                          work,0,work.size());//(curind[i-1].curind - i0)*2,(curind[i].curind - i0)*2+1);
678                                                 }*/
679                                                 //numerror++;
680                                         }
681                                 }
682                                 //erroreval += timer();
683
684                                 //assume we're done
685                                 done = true;
686
687                                 //check each error to see if it's too big, if so, then subdivide etc.
688                                 int indsize = (int)curind.size();
689                                 Real maxrelerror = 0;
690                                 int maxi = -1;//, numpoints;
691
692                                 //timer.reset();
693                                 //get the maximum error and split there
694                                 for(i = 1; i < indsize; ++i)
695                                 {
696                                         //numpoints = curind[i].curind - curind[i-1].curind + 1;
697
698                                         if(curind[i].error > maxrelerror && curind[i].curind - curind[i-1].curind > 2) //only accept if it's valid
699                                         {
700                                                 maxrelerror = curind[i].error;
701                                                 maxi = i;
702                                         }
703                                 }
704
705                                 //split if error is too great
706                                 if(maxrelerror > errortol)
707                                 {
708                                         //add one to the left etc
709                                         unsigned int    ibase = curind[maxi-1].curind, itop = curind[maxi].curind,
710                                                                         ibreak = (ibase + itop)/2;
711                                         Real scale, scale2;
712
713                                         assert(ibreak < f.size());
714
715                                         //synfig::info("Split %d -%d- %d, error: %f", ibase,ibreak,itop,maxrelerror);
716
717                                         if(ibase != itop)
718                                         {
719                                                 //invalidate current error of the changed tangents and add an extra segment
720                                                 //enforce minimum tangents property
721                                                 curind[maxi].error = -1;
722                                                 curind[maxi-1].error = -1;
723                                                 if(maxi+1 < indsize) curind[maxi+1].error = -1; //if there is a curve segment beyond this it will be effected as well
724
725                                                 scale = di[itop] - di[ibreak];
726                                                 scale2 = maxi+1 < indsize ? di[curind[maxi+1].curind] - di[itop] : scale; //to the right valid?
727                                                 curind[maxi].tangentscale = std::min(scale, scale2);
728
729                                                 scale = di[ibreak] - di[ibase];
730                                                 scale2 = maxi >= 2 ? di[ibase] - di[curind[maxi-2].curind] : scale; // to the left valid -2 ?
731                                                 curind[maxi-1].tangentscale = std::min(scale, scale2);
732
733                                                 scale = std::min(di[ibreak] - di[ibase], di[itop] - di[ibreak]);
734
735                                                 curind.insert(curind.begin()+maxi,cpindex(ibreak, scale, -1));
736                                                 //curind.push_back(cpindex(ibreak, scale, -1));
737                                                 //std::sort(curind.begin(), curind.end());
738
739                                                 done = false;
740                                                 //numsplit++;
741                                         }
742                                 }
743                                 //spliteval += timer();
744
745                                 dcount++;
746                         }
747
748                         //insert the last point too (just set tangent for now
749                         is = curind[0].curind;
750
751                         //first point inherits current tangent status
752                         v = df[is - i0];
753                         if(v.mag_squared() > EPSILON)
754                                 v *= (curind[0].tangentscale/v.mag());
755
756                         if(!breaktan)
757                                 a.set_tangent(v);
758                         else a.set_tangent2(v);
759
760                         a.set_vertex(f[is]);
761                         if(setwidth)a.set_width(f_w[is]);
762
763                         out.push_back(a);
764                         a.set_split_tangent_flag(false); //won't need to break anymore
765                         breaktan = false;
766
767                         for(i = 1; i < (int)curind.size()-1; ++i)
768                         {
769                                 is = curind[i].curind;
770
771                                 //first point inherits current tangent status
772                                 v = df[is-i0];
773                                 if(v.mag_squared() > EPSILON)
774                                         v *= (curind[i].tangentscale/v.mag());
775
776                                 a.set_tangent(v); // always inside, so guaranteed to be smooth
777                                 a.set_vertex(f[is]);
778                                 if(setwidth)a.set_width(f_w[is]);
779
780                                 out.push_back(a);
781                         }
782
783                         //set the last point's data
784                         is = curind.back().curind; //should already be this
785
786                         v = df[is-i0];
787                         if(v.mag_squared() > EPSILON)
788                                 v *= (curind.back().tangentscale/v.mag());
789
790                         a.set_tangent1(v);
791                         a.set_split_tangent_flag(true);
792                         breaktan = true;
793
794                         //will get the vertex and tangent 2 from next round
795                 }
796
797                 a.set_vertex(f[i3]);
798                 a.set_split_tangent_flag(false);
799                 if(setwidth)
800                         a.set_width(f_w[i3]);
801                 out.push_back(a);
802
803                 /*etl::clock::value_type totaltime = total(),
804                                                            misctime = totaltime - initialprocess - curveval - breakeval - disteval
805                                                                           - preproceval - tesseval - erroreval - spliteval;
806
807                 synfig::info(
808                         "Curve Convert Profile:\n"
809                         "\tInitial Preprocess:    %f\n"
810                         "\tCurvature Calculation: %f\n"
811                         "\tBreak Calculation:     %f\n"
812                         "\tDistance Calculation:  %f\n"
813                         "  Algorithm: (numtimes,totaltime)\n"
814                         "\tPreprocess step:      (%d,%f)\n"
815                         "\tTessellation step:    (%d,%f)\n"
816                         "\tError step:           (%d,%f)\n"
817                         "\tSplit step:           (%d,%f)\n"
818                         "  Num Input: %d, Num Output: %d\n"
819                         "  Total time: %f, Misc time: %f\n",
820                         initialprocess, curveval,breakeval,disteval,
821                         numpre,preproceval,numtess,tesseval,numerror,erroreval,numsplit,spliteval,
822                         in.size(),out.size(),
823                         totaltime,misctime);*/
824
825                 return;
826         }
827 }
828
829 void synfigapp::BLineConverter::EnforceMinWidth(std::list<synfig::BLinePoint> &bline, synfig::Real min_pressure)
830 {
831         std::list<synfig::BLinePoint>::iterator i = bline.begin(),
832                                                                                         end = bline.end();
833
834         for(i = bline.begin(); i != end; ++i)
835         {
836                 if(i->get_width() < min_pressure)
837                 {
838                         i->set_width(min_pressure);
839                 }
840         }
841 }