1 /*
2 * PathCutting.cpp
3 * nlivarot
4 *
5 * Created by fred on someday in 2004.
6 * public domain
7 *
8 * Additional Code by Authors:
9 * Richard Hughes <cyreve@users.sf.net>
10 *
11 * Copyright (C) 2005 Richard Hughes
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #include <cstring>
17 #include <string>
18 #include <cstdio>
19 #include <typeinfo>
20 #include "Path.h"
21 #include "style.h"
22 #include "livarot/path-description.h"
23 #include "libnr/nr-point-matrix-ops.h"
24 #include "libnr/nr-convert2geom.h"
25 #include <2geom/pathvector.h>
26 #include <2geom/point.h>
27 #include <2geom/matrix.h>
28 #include <2geom/sbasis-to-bezier.h>
29 #include "../display/canvas-bpath.h"
31 void Path::DashPolyline(float head,float tail,float body,int nbD,float *dashs,bool stPlain,float stOffset)
32 {
33 if ( nbD <= 0 || body <= 0.0001 ) return; // pas de tirets, en fait
35 std::vector<path_lineto> orig_pts = pts;
36 pts.clear();
38 int lastMI=-1;
39 int curP = 0;
40 int lastMP = -1;
42 for (int i = 0; i < int(orig_pts.size()); i++) {
43 if ( orig_pts[curP].isMoveTo == polyline_moveto ) {
44 if ( lastMI >= 0 && lastMI < i-1 ) { // au moins 2 points
45 DashSubPath(i-lastMI,lastMP, orig_pts, head,tail,body,nbD,dashs,stPlain,stOffset);
46 }
47 lastMI=i;
48 lastMP=curP;
49 }
50 curP++;
51 }
52 if ( lastMI >= 0 && lastMI < int(orig_pts.size()) - 1 ) {
53 DashSubPath(orig_pts.size() - lastMI, lastMP, orig_pts, head, tail, body, nbD, dashs, stPlain, stOffset);
54 }
55 }
57 void Path::DashPolylineFromStyle(SPStyle *style, float scale, float min_len)
58 {
59 if (style->stroke_dash.n_dash) {
61 double dlen = 0.0;
62 for (int i = 0; i < style->stroke_dash.n_dash; i++) {
63 dlen += style->stroke_dash.dash[i] * scale;
64 }
65 if (dlen >= min_len) {
66 NRVpathDash dash;
67 dash.offset = style->stroke_dash.offset * scale;
68 dash.n_dash = style->stroke_dash.n_dash;
69 dash.dash = g_new(double, dash.n_dash);
70 for (int i = 0; i < dash.n_dash; i++) {
71 dash.dash[i] = style->stroke_dash.dash[i] * scale;
72 }
73 int nbD=dash.n_dash;
74 float *dashs=(float*)malloc((nbD+1)*sizeof(float));
75 while ( dash.offset >= dlen ) dash.offset-=dlen;
76 dashs[0]=dash.dash[0];
77 for (int i=1; i<nbD; i++) {
78 dashs[i]=dashs[i-1]+dash.dash[i];
79 }
80 // modulo dlen
81 this->DashPolyline(0.0, 0.0, dlen, nbD, dashs, true, dash.offset);
82 free(dashs);
83 g_free(dash.dash);
84 }
85 }
86 }
89 void Path::DashSubPath(int spL, int spP, std::vector<path_lineto> const &orig_pts, float head,float tail,float body,int nbD,float *dashs,bool stPlain,float stOffset)
90 {
91 if ( spL <= 0 || spP == -1 ) return;
93 double totLength=0;
94 NR::Point lastP;
95 lastP = orig_pts[spP].p;
96 for (int i=1;i<spL;i++) {
97 NR::Point const n = orig_pts[spP + i].p;
98 NR::Point d=n-lastP;
99 double nl=NR::L2(d);
100 if ( nl > 0.0001 ) {
101 totLength+=nl;
102 lastP=n;
103 }
104 }
106 if ( totLength <= head+tail ) return; // tout mange par la tete et la queue
108 double curLength=0;
109 double dashPos=0;
110 int dashInd=0;
111 bool dashPlain=false;
112 double lastT=0;
113 int lastPiece=-1;
114 lastP = orig_pts[spP].p;
115 for (int i=1;i<spL;i++) {
116 NR::Point n;
117 int nPiece=-1;
118 double nT=0;
119 if ( back ) {
120 n = orig_pts[spP + i].p;
121 nPiece = orig_pts[spP + i].piece;
122 nT = orig_pts[spP + i].t;
123 } else {
124 n = orig_pts[spP + i].p;
125 }
126 NR::Point d=n-lastP;
127 double nl=NR::L2(d);
128 if ( nl > 0.0001 ) {
129 double stLength=curLength;
130 double enLength=curLength+nl;
131 // couper les bouts en trop
132 if ( curLength <= head && curLength+nl > head ) {
133 nl-=head-curLength;
134 curLength=head;
135 dashInd=0;
136 dashPos=stOffset;
137 bool nPlain=stPlain;
138 while ( dashs[dashInd] < stOffset ) {
139 dashInd++;
140 nPlain=!(nPlain);
141 if ( dashInd >= nbD ) {
142 dashPos=0;
143 dashInd=0;
144 break;
145 }
146 }
147 if ( nPlain == true && dashPlain == false ) {
148 NR::Point p=(enLength-curLength)*lastP+(curLength-stLength)*n;
149 p/=(enLength-stLength);
150 if ( back ) {
151 double pT=0;
152 if ( nPiece == lastPiece ) {
153 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
154 } else {
155 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
156 }
157 AddPoint(p,nPiece,pT,true);
158 } else {
159 AddPoint(p,true);
160 }
161 } else if ( nPlain == false && dashPlain == true ) {
162 }
163 dashPlain=nPlain;
164 }
165 // faire les tirets
166 if ( curLength >= head /*&& curLength+nl <= totLength-tail*/ ) {
167 while ( curLength <= totLength-tail && nl > 0 ) {
168 if ( enLength <= totLength-tail ) nl=enLength-curLength; else nl=totLength-tail-curLength;
169 double leftInDash=body-dashPos;
170 if ( dashInd < nbD ) {
171 leftInDash=dashs[dashInd]-dashPos;
172 }
173 if ( leftInDash <= nl ) {
174 bool nPlain=false;
175 if ( dashInd < nbD ) {
176 dashPos=dashs[dashInd];
177 dashInd++;
178 if ( dashPlain ) nPlain=false; else nPlain=true;
179 } else {
180 dashInd=0;
181 dashPos=0;
182 //nPlain=stPlain;
183 nPlain=dashPlain;
184 }
185 if ( nPlain == true && dashPlain == false ) {
186 NR::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
187 p/=(enLength-stLength);
188 if ( back ) {
189 double pT=0;
190 if ( nPiece == lastPiece ) {
191 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
192 } else {
193 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
194 }
195 AddPoint(p,nPiece,pT,true);
196 } else {
197 AddPoint(p,true);
198 }
199 } else if ( nPlain == false && dashPlain == true ) {
200 NR::Point p=(enLength-curLength-leftInDash)*lastP+(curLength+leftInDash-stLength)*n;
201 p/=(enLength-stLength);
202 if ( back ) {
203 double pT=0;
204 if ( nPiece == lastPiece ) {
205 pT=(lastT*(enLength-curLength-leftInDash)+nT*(curLength+leftInDash-stLength))/(enLength-stLength);
206 } else {
207 pT=(nPiece*(curLength+leftInDash-stLength))/(enLength-stLength);
208 }
209 AddPoint(p,nPiece,pT,false);
210 } else {
211 AddPoint(p,false);
212 }
213 }
214 dashPlain=nPlain;
216 curLength+=leftInDash;
217 nl-=leftInDash;
218 } else {
219 dashPos+=nl;
220 curLength+=nl;
221 nl=0;
222 }
223 }
224 if ( dashPlain ) {
225 if ( back ) {
226 AddPoint(n,nPiece,nT,false);
227 } else {
228 AddPoint(n,false);
229 }
230 }
231 nl=enLength-curLength;
232 }
233 if ( curLength <= totLength-tail && curLength+nl > totLength-tail ) {
234 nl=totLength-tail-curLength;
235 dashInd=0;
236 dashPos=0;
237 bool nPlain=false;
238 if ( nPlain == true && dashPlain == false ) {
239 } else if ( nPlain == false && dashPlain == true ) {
240 NR::Point p=(enLength-curLength)*lastP+(curLength-stLength)*n;
241 p/=(enLength-stLength);
242 if ( back ) {
243 double pT=0;
244 if ( nPiece == lastPiece ) {
245 pT=(lastT*(enLength-curLength)+nT*(curLength-stLength))/(enLength-stLength);
246 } else {
247 pT=(nPiece*(curLength-stLength))/(enLength-stLength);
248 }
249 AddPoint(p,nPiece,pT,false);
250 } else {
251 AddPoint(p,false);
252 }
253 }
254 dashPlain=nPlain;
255 }
256 // continuer
257 curLength=enLength;
258 lastP=n;
259 lastPiece=nPiece;
260 lastT=nT;
261 }
262 }
263 }
265 Geom::PathVector *
266 Path::MakePathVector()
267 {
268 Geom::PathVector *pv = new Geom::PathVector();
269 Geom::Path * currentpath = NULL;
271 NR::Point lastP,bezSt,bezEn;
272 int bezNb=0;
273 for (int i=0;i<int(descr_cmd.size());i++) {
274 int const typ = descr_cmd[i]->getType();
275 switch ( typ ) {
276 case descr_close:
277 {
278 currentpath->close(true);
279 }
280 break;
282 case descr_lineto:
283 {
284 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
285 currentpath->appendNew<Geom::LineSegment>(Geom::Point(nData->p[0], nData->p[1]));
286 lastP = nData->p;
287 }
288 break;
290 case descr_moveto:
291 {
292 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
293 pv->push_back(Geom::Path());
294 currentpath = &pv->back();
295 currentpath->start(Geom::Point(nData->p[0], nData->p[1]));
296 lastP = nData->p;
297 }
298 break;
300 case descr_arcto:
301 {
302 /* TODO: add testcase for this descr_arcto case */
303 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
304 currentpath->appendNew<Geom::SVGEllipticalArc>( nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, to_2geom(nData->p) );
305 lastP = nData->p;
306 }
307 break;
309 case descr_cubicto:
310 {
311 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
312 gdouble x1=lastP[0]+0.333333*nData->start[0];
313 gdouble y1=lastP[1]+0.333333*nData->start[1];
314 gdouble x2=nData->p[0]-0.333333*nData->end[0];
315 gdouble y2=nData->p[1]-0.333333*nData->end[1];
316 gdouble x3=nData->p[0];
317 gdouble y3=nData->p[1];
318 currentpath->appendNew<Geom::CubicBezier>( Geom::Point(x1,y1) , Geom::Point(x2,y2) , Geom::Point(x3,y3) );
319 lastP = nData->p;
320 }
321 break;
323 case descr_bezierto:
324 {
325 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
326 if ( nData->nb <= 0 ) {
327 currentpath->appendNew<Geom::LineSegment>( Geom::Point(nData->p[0], nData->p[1]) );
328 bezNb=0;
329 } else if ( nData->nb == 1 ){
330 PathDescrIntermBezierTo *iData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i+1]);
331 gdouble x1=0.333333*(lastP[0]+2*iData->p[0]);
332 gdouble y1=0.333333*(lastP[1]+2*iData->p[1]);
333 gdouble x2=0.333333*(nData->p[0]+2*iData->p[0]);
334 gdouble y2=0.333333*(nData->p[1]+2*iData->p[1]);
335 gdouble x3=nData->p[0];
336 gdouble y3=nData->p[1];
337 currentpath->appendNew<Geom::CubicBezier>( Geom::Point(x1,y1) , Geom::Point(x2,y2) , Geom::Point(x3,y3) );
338 bezNb=0;
339 } else {
340 bezSt = 2*lastP-nData->p;
341 bezEn = nData->p;
342 bezNb = nData->nb;
343 }
344 lastP = nData->p;
345 }
346 break;
348 case descr_interm_bezier:
349 {
350 if ( bezNb > 0 ) {
351 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
352 NR::Point p_m=nData->p,p_s=0.5*(bezSt+p_m),p_e;
353 if ( bezNb > 1 ) {
354 PathDescrIntermBezierTo *iData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i+1]);
355 p_e=0.5*(p_m+iData->p);
356 } else {
357 p_e=bezEn;
358 }
360 NR::Point cp1=0.333333*(p_s+2*p_m),cp2=0.333333*(2*p_m+p_e);
361 gdouble x1=cp1[0];
362 gdouble y1=cp1[1];
363 gdouble x2=cp2[0];
364 gdouble y2=cp2[1];
365 gdouble x3=p_e[0];
366 gdouble y3=p_e[1];
367 currentpath->appendNew<Geom::CubicBezier>( Geom::Point(x1,y1) , Geom::Point(x2,y2) , Geom::Point(x3,y3) );
369 bezNb--;
370 }
371 }
372 break;
373 }
374 }
376 return pv;
377 }
379 void Path::AddCurve(Geom::Curve const &c)
380 {
381 if( dynamic_cast<Geom::LineSegment const*>(&c) ||
382 dynamic_cast<Geom::HLineSegment const*>(&c) ||
383 dynamic_cast<Geom::VLineSegment const*>(&c) )
384 {
385 LineTo( from_2geom(c.finalPoint()) );
386 }
387 /*
388 else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast<Geom::QuadraticBezier const *>(c)) {
389 ...
390 }
391 */
392 else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const *>(&c)) {
393 Geom::Point tmp = (*cubic_bezier)[3];
394 Geom::Point tms = 3 * ((*cubic_bezier)[1] - (*cubic_bezier)[0]);
395 Geom::Point tme = 3 * ((*cubic_bezier)[3] - (*cubic_bezier)[2]);
396 CubicTo (from_2geom(tmp), from_2geom(tms), from_2geom(tme));
397 }
398 else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc const *>(&c)) {
399 ArcTo( from_2geom(svg_elliptical_arc->finalPoint()),
400 svg_elliptical_arc->ray(0), svg_elliptical_arc->ray(1),
401 svg_elliptical_arc->rotation_angle(),
402 svg_elliptical_arc->large_arc_flag(), svg_elliptical_arc->sweep_flag() );
403 } else {
404 //this case handles sbasis as well as all other curve types
405 Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c.toSBasis(), 0.1);
407 //recurse to convert the new path resulting from the sbasis to svgd
408 for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) {
409 AddCurve(*iter);
410 }
411 }
412 }
414 /** append is false by default: it means that the path should be resetted. If it is true, the path is not resetted and Geom::Path will be appended as a new path
415 */
416 void Path::LoadPath(Geom::Path const &path, Geom::Matrix const &tr, bool doTransformation, bool append)
417 {
418 if (!append) {
419 SetBackData (false);
420 Reset();
421 }
422 if (path.empty())
423 return;
425 // TODO: this can be optimized by not generating a new path here, but doing the transform in AddCurve
426 // directly on the curve parameters
427 Geom::Path const pathtr = doTransformation ? path * tr : path;
429 MoveTo( from_2geom(pathtr.initialPoint()) );
431 for(Geom::Path::const_iterator cit = pathtr.begin(); cit != pathtr.end_default(); ++cit) {
432 AddCurve(*cit);
433 }
435 if (pathtr.closed()) {
436 Close();
437 }
438 }
440 void Path::LoadPathVector(Geom::PathVector const &pv)
441 {
442 LoadPathVector(pv, Geom::Matrix(), false);
443 }
445 void Path::LoadPathVector(Geom::PathVector const &pv, Geom::Matrix const &tr, bool doTransformation)
446 {
447 SetBackData (false);
448 Reset();
449 for(Geom::PathVector::const_iterator it = pv.begin(); it != pv.end(); ++it) {
450 LoadPath(*it, tr, doTransformation, true);
451 }
452 }
454 /**
455 * \return Length of the lines in the pts vector.
456 */
458 double Path::Length()
459 {
460 if ( pts.empty() ) {
461 return 0;
462 }
464 NR::Point lastP = pts[0].p;
466 double len = 0;
467 for (std::vector<path_lineto>::const_iterator i = pts.begin(); i != pts.end(); i++) {
469 if ( i->isMoveTo != polyline_moveto ) {
470 len += NR::L2(i->p - lastP);
471 }
473 lastP = i->p;
474 }
476 return len;
477 }
480 double Path::Surface()
481 {
482 if ( pts.empty() ) {
483 return 0;
484 }
486 NR::Point lastM = pts[0].p;
487 NR::Point lastP = lastM;
489 double surf = 0;
490 for (std::vector<path_lineto>::const_iterator i = pts.begin(); i != pts.end(); i++) {
492 if ( i->isMoveTo == polyline_moveto ) {
493 surf += NR::cross(lastM - lastP, lastM);
494 lastP = lastM = i->p;
495 } else {
496 surf += NR::cross(i->p - lastP, i->p);
497 lastP = i->p;
498 }
500 }
502 return surf;
503 }
506 Path** Path::SubPaths(int &outNb,bool killNoSurf)
507 {
508 int nbRes=0;
509 Path** res=NULL;
510 Path* curAdd=NULL;
512 for (int i=0;i<int(descr_cmd.size());i++) {
513 int const typ = descr_cmd[i]->getType();
514 switch ( typ ) {
515 case descr_moveto:
516 if ( curAdd ) {
517 if ( curAdd->descr_cmd.size() > 1 ) {
518 curAdd->Convert(1.0);
519 double addSurf=curAdd->Surface();
520 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
521 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
522 res[nbRes++]=curAdd;
523 } else {
524 delete curAdd;
525 }
526 } else {
527 delete curAdd;
528 }
529 curAdd=NULL;
530 }
531 curAdd=new Path;
532 curAdd->SetBackData(false);
533 {
534 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
535 curAdd->MoveTo(nData->p);
536 }
537 break;
538 case descr_close:
539 {
540 curAdd->Close();
541 }
542 break;
543 case descr_lineto:
544 {
545 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
546 curAdd->LineTo(nData->p);
547 }
548 break;
549 case descr_cubicto:
550 {
551 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
552 curAdd->CubicTo(nData->p,nData->start,nData->end);
553 }
554 break;
555 case descr_arcto:
556 {
557 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
558 curAdd->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
559 }
560 break;
561 case descr_bezierto:
562 {
563 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
564 curAdd->BezierTo(nData->p);
565 }
566 break;
567 case descr_interm_bezier:
568 {
569 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
570 curAdd->IntermBezierTo(nData->p);
571 }
572 break;
573 default:
574 break;
575 }
576 }
577 if ( curAdd ) {
578 if ( curAdd->descr_cmd.size() > 1 ) {
579 curAdd->Convert(1.0);
580 double addSurf=curAdd->Surface();
581 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
582 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
583 res[nbRes++]=curAdd;
584 } else {
585 delete curAdd;
586 }
587 } else {
588 delete curAdd;
589 }
590 }
591 curAdd=NULL;
593 outNb=nbRes;
594 return res;
595 }
596 Path** Path::SubPathsWithNesting(int &outNb,bool killNoSurf,int nbNest,int* nesting,int* conts)
597 {
598 int nbRes=0;
599 Path** res=NULL;
600 Path* curAdd=NULL;
601 bool increment=false;
603 for (int i=0;i<int(descr_cmd.size());i++) {
604 int const typ = descr_cmd[i]->getType();
605 switch ( typ ) {
606 case descr_moveto:
607 {
608 if ( curAdd && increment == false ) {
609 if ( curAdd->descr_cmd.size() > 1 ) {
610 // sauvegarder descr_cmd[0]->associated
611 int savA=curAdd->descr_cmd[0]->associated;
612 curAdd->Convert(1.0);
613 curAdd->descr_cmd[0]->associated=savA; // associated n'est pas utilise apres
614 double addSurf=curAdd->Surface();
615 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
616 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
617 res[nbRes++]=curAdd;
618 } else {
619 delete curAdd;
620 }
621 } else {
622 delete curAdd;
623 }
624 curAdd=NULL;
625 }
626 Path* hasDad=NULL;
627 for (int j=0;j<nbNest;j++) {
628 if ( conts[j] == i && nesting[j] >= 0 ) {
629 int dadMvt=conts[nesting[j]];
630 for (int k=0;k<nbRes;k++) {
631 if ( res[k] && res[k]->descr_cmd.empty() == false && res[k]->descr_cmd[0]->associated == dadMvt ) {
632 hasDad=res[k];
633 break;
634 }
635 }
636 }
637 if ( conts[j] > i ) break;
638 }
639 if ( hasDad ) {
640 curAdd=hasDad;
641 increment=true;
642 } else {
643 curAdd=new Path;
644 curAdd->SetBackData(false);
645 increment=false;
646 }
647 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
648 int mNo=curAdd->MoveTo(nData->p);
649 curAdd->descr_cmd[mNo]->associated=i;
650 }
651 break;
652 case descr_close:
653 {
654 curAdd->Close();
655 }
656 break;
657 case descr_lineto:
658 {
659 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
660 curAdd->LineTo(nData->p);
661 }
662 break;
663 case descr_cubicto:
664 {
665 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
666 curAdd->CubicTo(nData->p,nData->start,nData->end);
667 }
668 break;
669 case descr_arcto:
670 {
671 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
672 curAdd->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
673 }
674 break;
675 case descr_bezierto:
676 {
677 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
678 curAdd->BezierTo(nData->p);
679 }
680 break;
681 case descr_interm_bezier:
682 {
683 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
684 curAdd->IntermBezierTo(nData->p);
685 }
686 break;
687 default:
688 break;
689 }
690 }
691 if ( curAdd && increment == false ) {
692 if ( curAdd->descr_cmd.size() > 1 ) {
693 curAdd->Convert(1.0);
694 double addSurf=curAdd->Surface();
695 if ( fabs(addSurf) > 0.0001 || killNoSurf == false ) {
696 res=(Path**)g_realloc(res,(nbRes+1)*sizeof(Path*));
697 res[nbRes++]=curAdd;
698 } else {
699 delete curAdd;
700 }
701 } else {
702 delete curAdd;
703 }
704 }
705 curAdd=NULL;
707 outNb=nbRes;
708 return res;
709 }
712 void Path::ConvertForcedToVoid()
713 {
714 for (int i=0; i < int(descr_cmd.size()); i++) {
715 if ( descr_cmd[i]->getType() == descr_forced) {
716 delete descr_cmd[i];
717 descr_cmd.erase(descr_cmd.begin() + i);
718 }
719 }
720 }
723 void Path::ConvertForcedToMoveTo()
724 {
725 NR::Point lastSeen(0, 0);
726 NR::Point lastMove(0, 0);
728 {
729 NR::Point lastPos(0, 0);
730 for (int i = int(descr_cmd.size()) - 1; i >= 0; i--) {
731 int const typ = descr_cmd[i]->getType();
732 switch ( typ ) {
733 case descr_forced:
734 {
735 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
736 d->p = lastPos;
737 break;
738 }
739 case descr_close:
740 {
741 PathDescrClose *d = dynamic_cast<PathDescrClose *>(descr_cmd[i]);
742 d->p = lastPos;
743 break;
744 }
745 case descr_moveto:
746 {
747 PathDescrMoveTo *d = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
748 lastPos = d->p;
749 break;
750 }
751 case descr_lineto:
752 {
753 PathDescrLineTo *d = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
754 lastPos = d->p;
755 break;
756 }
757 case descr_arcto:
758 {
759 PathDescrArcTo *d = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
760 lastPos = d->p;
761 break;
762 }
763 case descr_cubicto:
764 {
765 PathDescrCubicTo *d = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
766 lastPos = d->p;
767 break;
768 }
769 case descr_bezierto:
770 {
771 PathDescrBezierTo *d = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
772 lastPos = d->p;
773 break;
774 }
775 case descr_interm_bezier:
776 {
777 PathDescrIntermBezierTo *d = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
778 lastPos = d->p;
779 break;
780 }
781 default:
782 break;
783 }
784 }
785 }
787 bool hasMoved = false;
788 for (int i = 0; i < int(descr_cmd.size()); i++) {
789 int const typ = descr_cmd[i]->getType();
790 switch ( typ ) {
791 case descr_forced:
792 if ( i < int(descr_cmd.size()) - 1 && hasMoved ) { // sinon il termine le chemin
794 delete descr_cmd[i];
795 descr_cmd[i] = new PathDescrMoveTo(lastSeen);
796 lastMove = lastSeen;
797 hasMoved = true;
798 }
799 break;
801 case descr_moveto:
802 {
803 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
804 lastMove = lastSeen = nData->p;
805 hasMoved = true;
806 }
807 break;
808 case descr_close:
809 {
810 lastSeen=lastMove;
811 }
812 break;
813 case descr_lineto:
814 {
815 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
816 lastSeen=nData->p;
817 }
818 break;
819 case descr_cubicto:
820 {
821 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
822 lastSeen=nData->p;
823 }
824 break;
825 case descr_arcto:
826 {
827 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
828 lastSeen=nData->p;
829 }
830 break;
831 case descr_bezierto:
832 {
833 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
834 lastSeen=nData->p;
835 }
836 break;
837 case descr_interm_bezier:
838 {
839 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
840 lastSeen=nData->p;
841 }
842 break;
843 default:
844 break;
845 }
846 }
847 }
848 static int CmpPosition(const void * p1, const void * p2) {
849 Path::cut_position *cp1=(Path::cut_position*)p1;
850 Path::cut_position *cp2=(Path::cut_position*)p2;
851 if ( cp1->piece < cp2->piece ) return -1;
852 if ( cp1->piece > cp2->piece ) return 1;
853 if ( cp1->t < cp2->t ) return -1;
854 if ( cp1->t > cp2->t ) return 1;
855 return 0;
856 }
857 static int CmpCurv(const void * p1, const void * p2) {
858 double *cp1=(double*)p1;
859 double *cp2=(double*)p2;
860 if ( *cp1 < *cp2 ) return -1;
861 if ( *cp1 > *cp2 ) return 1;
862 return 0;
863 }
866 Path::cut_position* Path::CurvilignToPosition(int nbCv, double *cvAbs, int &nbCut)
867 {
868 if ( nbCv <= 0 || pts.empty() || back == false ) {
869 return NULL;
870 }
872 qsort(cvAbs, nbCv, sizeof(double), CmpCurv);
874 cut_position *res = NULL;
875 nbCut = 0;
876 int curCv = 0;
878 double len = 0;
879 double lastT = 0;
880 int lastPiece = -1;
882 NR::Point lastM = pts[0].p;
883 NR::Point lastP = lastM;
885 for (std::vector<path_lineto>::const_iterator i = pts.begin(); i != pts.end(); i++) {
887 if ( i->isMoveTo == polyline_moveto ) {
889 lastP = lastM = i->p;
890 lastT = i->t;
891 lastPiece = i->piece;
893 } else {
895 double const add = NR::L2(i->p - lastP);
896 double curPos = len;
897 double curAdd = add;
899 while ( curAdd > 0.0001 && curCv < nbCv && curPos + curAdd >= cvAbs[curCv] ) {
900 double const theta = (cvAbs[curCv] - len) / add;
901 res = (cut_position*) g_realloc(res, (nbCut + 1) * sizeof(cut_position));
902 res[nbCut].piece = i->piece;
903 res[nbCut].t = theta * i->t + (1 - theta) * ( (lastPiece != i->piece) ? 0 : lastT);
904 nbCut++;
905 curAdd -= cvAbs[curCv] - curPos;
906 curPos = cvAbs[curCv];
907 curCv++;
908 }
910 len += add;
911 lastPiece = i->piece;
912 lastP = i->p;
913 lastT = i->t;
914 }
915 }
917 return res;
918 }
920 /*
921 Moved from Layout-TNG-OutIter.cpp
922 TODO: clean up uses of the original function and remove
924 Original Comment:
925 "this function really belongs to Path. I'll probably move it there eventually,
926 hence the Path-esque coding style"
928 */
929 template<typename T> inline static T square(T x) {return x*x;}
930 Path::cut_position Path::PointToCurvilignPosition(NR::Point const &pos, unsigned seg) const
931 {
932 // if the parameter "seg" == 0, then all segments will be considered
933 // In however e.g. "seg" == 6 , then only the 6th segment will be considered
935 unsigned bestSeg = 0;
936 double bestRangeSquared = DBL_MAX;
937 double bestT = 0.0; // you need a sentinel, or make sure that you prime with correct values.
939 for (unsigned i = 1 ; i < pts.size() ; i++) {
940 if (pts[i].isMoveTo == polyline_moveto || (seg > 0 && i != seg)) continue;
941 NR::Point p1, p2, localPos;
942 double thisRangeSquared;
943 double t;
945 if (pts[i - 1].p == pts[i].p) {
946 thisRangeSquared = square(pts[i].p[NR::X] - pos[NR::X]) + square(pts[i].p[NR::Y] - pos[NR::Y]);
947 t = 0.0;
948 } else {
949 // we rotate all our coordinates so we're always looking at a mostly vertical line.
950 if (fabs(pts[i - 1].p[NR::X] - pts[i].p[NR::X]) < fabs(pts[i - 1].p[NR::Y] - pts[i].p[NR::Y])) {
951 p1 = pts[i - 1].p;
952 p2 = pts[i].p;
953 localPos = pos;
954 } else {
955 p1 = pts[i - 1].p.cw();
956 p2 = pts[i].p.cw();
957 localPos = pos.cw();
958 }
959 double gradient = (p2[NR::X] - p1[NR::X]) / (p2[NR::Y] - p1[NR::Y]);
960 double intersection = p1[NR::X] - gradient * p1[NR::Y];
961 /*
962 orthogonalGradient = -1.0 / gradient; // you are going to have numerical problems here.
963 orthogonalIntersection = localPos[NR::X] - orthogonalGradient * localPos[NR::Y];
964 nearestY = (orthogonalIntersection - intersection) / (gradient - orthogonalGradient);
966 expand out nearestY fully :
967 nearestY = (localPos[NR::X] - (-1.0 / gradient) * localPos[NR::Y] - intersection) / (gradient - (-1.0 / gradient));
969 multiply top and bottom by gradient:
970 nearestY = (localPos[NR::X] * gradient - (-1.0) * localPos[NR::Y] - intersection * gradient) / (gradient * gradient - (-1.0));
972 and simplify to get:
973 */
974 double nearestY = (localPos[NR::X] * gradient + localPos[NR::Y] - intersection * gradient)
975 / (gradient * gradient + 1.0);
976 t = (nearestY - p1[NR::Y]) / (p2[NR::Y] - p1[NR::Y]);
977 if (t <= 0.0) {
978 thisRangeSquared = square(p1[NR::X] - localPos[NR::X]) + square(p1[NR::Y] - localPos[NR::Y]);
979 t = 0.0;
980 } else if (t >= 1.0) {
981 thisRangeSquared = square(p2[NR::X] - localPos[NR::X]) + square(p2[NR::Y] - localPos[NR::Y]);
982 t = 1.0;
983 } else {
984 thisRangeSquared = square(nearestY * gradient + intersection - localPos[NR::X]) + square(nearestY - localPos[NR::Y]);
985 }
986 }
988 if (thisRangeSquared < bestRangeSquared) {
989 bestSeg = i;
990 bestRangeSquared = thisRangeSquared;
991 bestT = t;
992 }
993 }
994 Path::cut_position result;
995 if (bestSeg == 0) {
996 result.piece = 0;
997 result.t = 0.0;
998 } else {
999 result.piece = pts[bestSeg].piece;
1000 if (result.piece == pts[bestSeg - 1].piece) {
1001 result.t = pts[bestSeg - 1].t * (1.0 - bestT) + pts[bestSeg].t * bestT;
1002 } else {
1003 result.t = pts[bestSeg].t * bestT;
1004 }
1005 }
1006 return result;
1007 }
1008 /*
1009 this one also belongs to Path
1010 returns the length of the path up to the position indicated by t (0..1)
1012 TODO: clean up uses of the original function and remove
1014 should this take a cut_position as a parameter?
1015 */
1016 double Path::PositionToLength(int piece, double t)
1017 {
1018 double length = 0.0;
1019 for (unsigned i = 1 ; i < pts.size() ; i++) {
1020 if (pts[i].isMoveTo == polyline_moveto) continue;
1021 if (pts[i].piece == piece && t < pts[i].t) {
1022 length += NR::L2((t - pts[i - 1].t) / (pts[i].t - pts[i - 1].t) * (pts[i].p - pts[i - 1].p));
1023 break;
1024 }
1025 length += NR::L2(pts[i].p - pts[i - 1].p);
1026 }
1027 return length;
1028 }
1030 void Path::ConvertPositionsToForced(int nbPos, cut_position *poss)
1031 {
1032 if ( nbPos <= 0 ) {
1033 return;
1034 }
1036 {
1037 NR::Point lastPos(0, 0);
1038 for (int i = int(descr_cmd.size()) - 1; i >= 0; i--) {
1039 int const typ = descr_cmd[i]->getType();
1040 switch ( typ ) {
1042 case descr_forced:
1043 {
1044 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
1045 d->p = lastPos;
1046 break;
1047 }
1049 case descr_close:
1050 {
1051 delete descr_cmd[i];
1052 descr_cmd[i] = new PathDescrLineTo(NR::Point(0, 0));
1054 int fp = i - 1;
1055 while ( fp >= 0 && (descr_cmd[fp]->getType()) != descr_moveto ) {
1056 fp--;
1057 }
1059 if ( fp >= 0 ) {
1060 PathDescrMoveTo *oData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[fp]);
1061 dynamic_cast<PathDescrLineTo*>(descr_cmd[i])->p = oData->p;
1062 }
1063 }
1064 break;
1066 case descr_bezierto:
1067 {
1068 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
1069 NR::Point theP = nData->p;
1070 if ( nData->nb == 0 ) {
1071 lastPos = theP;
1072 }
1073 }
1074 break;
1076 case descr_moveto:
1077 {
1078 PathDescrMoveTo *d = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
1079 lastPos = d->p;
1080 break;
1081 }
1082 case descr_lineto:
1083 {
1084 PathDescrLineTo *d = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1085 lastPos = d->p;
1086 break;
1087 }
1088 case descr_arcto:
1089 {
1090 PathDescrArcTo *d = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1091 lastPos = d->p;
1092 break;
1093 }
1094 case descr_cubicto:
1095 {
1096 PathDescrCubicTo *d = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1097 lastPos = d->p;
1098 break;
1099 }
1100 case descr_interm_bezier:
1101 {
1102 PathDescrIntermBezierTo *d = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
1103 lastPos = d->p;
1104 break;
1105 }
1106 default:
1107 break;
1108 }
1109 }
1110 }
1112 qsort(poss, nbPos, sizeof(cut_position), CmpPosition);
1114 for (int curP=0;curP<nbPos;curP++) {
1115 int cp=poss[curP].piece;
1116 if ( cp < 0 || cp >= int(descr_cmd.size()) ) break;
1117 float ct=poss[curP].t;
1118 if ( ct < 0 ) continue;
1119 if ( ct > 1 ) continue;
1121 int const typ = descr_cmd[cp]->getType();
1122 if ( typ == descr_moveto || typ == descr_forced || typ == descr_close ) {
1123 // ponctuel= rien a faire
1124 } else if ( typ == descr_lineto || typ == descr_arcto || typ == descr_cubicto ) {
1125 // facile: creation d'un morceau et d'un forced -> 2 commandes
1126 NR::Point theP;
1127 NR::Point theT;
1128 NR::Point startP;
1129 startP=PrevPoint(cp-1);
1130 if ( typ == descr_cubicto ) {
1131 double len,rad;
1132 NR::Point stD,enD,endP;
1133 {
1134 PathDescrCubicTo *oData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1135 stD=oData->start;
1136 enD=oData->end;
1137 endP=oData->p;
1138 TangentOnCubAt (ct, startP, *oData,true, theP,theT,len,rad);
1139 }
1141 theT*=len;
1143 InsertCubicTo(endP,(1-ct)*theT,(1-ct)*enD,cp+1);
1144 InsertForcePoint(cp+1);
1145 {
1146 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1147 nData->start=ct*stD;
1148 nData->end=ct*theT;
1149 nData->p=theP;
1150 }
1151 // decalages dans le tableau des positions de coupe
1152 for (int j=curP+1;j<nbPos;j++) {
1153 if ( poss[j].piece == cp ) {
1154 poss[j].piece+=2;
1155 poss[j].t=(poss[j].t-ct)/(1-ct);
1156 } else {
1157 poss[j].piece+=2;
1158 }
1159 }
1160 } else if ( typ == descr_lineto ) {
1161 NR::Point endP;
1162 {
1163 PathDescrLineTo *oData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1164 endP=oData->p;
1165 }
1167 theP=ct*endP+(1-ct)*startP;
1169 InsertLineTo(endP,cp+1);
1170 InsertForcePoint(cp+1);
1171 {
1172 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1173 nData->p=theP;
1174 }
1175 // decalages dans le tableau des positions de coupe
1176 for (int j=curP+1;j<nbPos;j++) {
1177 if ( poss[j].piece == cp ) {
1178 poss[j].piece+=2;
1179 poss[j].t=(poss[j].t-ct)/(1-ct);
1180 } else {
1181 poss[j].piece+=2;
1182 }
1183 }
1184 } else if ( typ == descr_arcto ) {
1185 NR::Point endP;
1186 double rx,ry,angle;
1187 bool clockw,large;
1188 double delta=0;
1189 {
1190 PathDescrArcTo *oData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1191 endP=oData->p;
1192 rx=oData->rx;
1193 ry=oData->ry;
1194 angle=oData->angle;
1195 clockw=oData->clockwise;
1196 large=oData->large;
1197 }
1198 {
1199 double sang,eang;
1200 ArcAngles(startP,endP,rx,ry,angle,large,clockw,sang,eang);
1202 if (clockw) {
1203 if ( sang < eang ) sang += 2*M_PI;
1204 delta=eang-sang;
1205 } else {
1206 if ( sang > eang ) sang -= 2*M_PI;
1207 delta=eang-sang;
1208 }
1209 if ( delta < 0 ) delta=-delta;
1210 }
1212 PointAt (cp,ct, theP);
1214 if ( delta*(1-ct) > M_PI ) {
1215 InsertArcTo(endP,rx,ry,angle,true,clockw,cp+1);
1216 } else {
1217 InsertArcTo(endP,rx,ry,angle,false,clockw,cp+1);
1218 }
1219 InsertForcePoint(cp+1);
1220 {
1221 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1222 nData->p=theP;
1223 if ( delta*ct > M_PI ) {
1224 nData->clockwise=true;
1225 } else {
1226 nData->clockwise=false;
1227 }
1228 }
1229 // decalages dans le tableau des positions de coupe
1230 for (int j=curP+1;j<nbPos;j++) {
1231 if ( poss[j].piece == cp ) {
1232 poss[j].piece+=2;
1233 poss[j].t=(poss[j].t-ct)/(1-ct);
1234 } else {
1235 poss[j].piece+=2;
1236 }
1237 }
1238 }
1239 } else if ( typ == descr_bezierto || typ == descr_interm_bezier ) {
1240 // dur
1241 int theBDI=cp;
1242 while ( theBDI >= 0 && (descr_cmd[theBDI]->getType()) != descr_bezierto ) theBDI--;
1243 if ( (descr_cmd[theBDI]->getType()) == descr_bezierto ) {
1244 PathDescrBezierTo theBD=*(dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]));
1245 if ( cp >= theBDI && cp < theBDI+theBD.nb ) {
1246 if ( theBD.nb == 1 ) {
1247 NR::Point endP=theBD.p;
1248 NR::Point midP;
1249 NR::Point startP;
1250 startP=PrevPoint(theBDI-1);
1251 {
1252 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[theBDI+1]);
1253 midP=nData->p;
1254 }
1255 NR::Point aP=ct*midP+(1-ct)*startP;
1256 NR::Point bP=ct*endP+(1-ct)*midP;
1257 NR::Point knotP=ct*bP+(1-ct)*aP;
1259 InsertIntermBezierTo(bP,theBDI+2);
1260 InsertBezierTo(knotP,1,theBDI+2);
1261 InsertForcePoint(theBDI+2);
1262 {
1263 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[theBDI+1]);
1264 nData->p=aP;
1265 }
1266 {
1267 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1268 nData->p=knotP;
1269 }
1270 // decalages dans le tableau des positions de coupe
1271 for (int j=curP+1;j<nbPos;j++) {
1272 if ( poss[j].piece == cp ) {
1273 poss[j].piece+=3;
1274 poss[j].t=(poss[j].t-ct)/(1-ct);
1275 } else {
1276 poss[j].piece+=3;
1277 }
1278 }
1280 } else {
1281 // decouper puis repasser
1282 if ( cp > theBDI ) {
1283 NR::Point pcP,ncP;
1284 {
1285 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp]);
1286 pcP=nData->p;
1287 }
1288 {
1289 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+1]);
1290 ncP=nData->p;
1291 }
1292 NR::Point knotP=0.5*(pcP+ncP);
1294 InsertBezierTo(knotP,theBD.nb-(cp-theBDI),cp+1);
1295 {
1296 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1297 nData->nb=cp-theBDI;
1298 }
1300 // decalages dans le tableau des positions de coupe
1301 for (int j=curP;j<nbPos;j++) {
1302 if ( poss[j].piece == cp ) {
1303 poss[j].piece+=1;
1304 } else {
1305 poss[j].piece+=1;
1306 }
1307 }
1308 curP--;
1309 } else {
1310 NR::Point pcP,ncP;
1311 {
1312 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+1]);
1313 pcP=nData->p;
1314 }
1315 {
1316 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+2]);
1317 ncP=nData->p;
1318 }
1319 NR::Point knotP=0.5*(pcP+ncP);
1321 InsertBezierTo(knotP,theBD.nb-1,cp+2);
1322 {
1323 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1324 nData->nb=1;
1325 }
1327 // decalages dans le tableau des positions de coupe
1328 for (int j=curP;j<nbPos;j++) {
1329 if ( poss[j].piece == cp ) {
1330 // poss[j].piece+=1;
1331 } else {
1332 poss[j].piece+=1;
1333 }
1334 }
1335 curP--;
1336 }
1337 }
1338 } else {
1339 // on laisse aussi tomber
1340 }
1341 } else {
1342 // on laisse tomber
1343 }
1344 }
1345 }
1346 }
1348 void Path::ConvertPositionsToMoveTo(int nbPos,cut_position* poss)
1349 {
1350 ConvertPositionsToForced(nbPos,poss);
1351 // ConvertForcedToMoveTo();
1352 // on fait une version customizee a la place
1354 Path* res=new Path;
1356 NR::Point lastP(0,0);
1357 for (int i=0;i<int(descr_cmd.size());i++) {
1358 int const typ = descr_cmd[i]->getType();
1359 if ( typ == descr_moveto ) {
1360 NR::Point np;
1361 {
1362 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
1363 np=nData->p;
1364 }
1365 NR::Point endP;
1366 bool hasClose=false;
1367 int hasForced=-1;
1368 bool doesClose=false;
1369 int j=i+1;
1370 for (;j<int(descr_cmd.size());j++) {
1371 int const ntyp = descr_cmd[j]->getType();
1372 if ( ntyp == descr_moveto ) {
1373 j--;
1374 break;
1375 } else if ( ntyp == descr_forced ) {
1376 if ( hasForced < 0 ) hasForced=j;
1377 } else if ( ntyp == descr_close ) {
1378 hasClose=true;
1379 break;
1380 } else if ( ntyp == descr_lineto ) {
1381 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[j]);
1382 endP=nData->p;
1383 } else if ( ntyp == descr_arcto ) {
1384 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[j]);
1385 endP=nData->p;
1386 } else if ( ntyp == descr_cubicto ) {
1387 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[j]);
1388 endP=nData->p;
1389 } else if ( ntyp == descr_bezierto ) {
1390 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[j]);
1391 endP=nData->p;
1392 } else {
1393 }
1394 }
1395 if ( NR::LInfty(endP-np) < 0.00001 ) {
1396 doesClose=true;
1397 }
1398 if ( ( doesClose || hasClose ) && hasForced >= 0 ) {
1399 // printf("nasty i=%i j=%i frc=%i\n",i,j,hasForced);
1400 // aghhh.
1401 NR::Point nMvtP=PrevPoint(hasForced);
1402 res->MoveTo(nMvtP);
1403 NR::Point nLastP=nMvtP;
1404 for (int k = hasForced + 1; k < j; k++) {
1405 int ntyp=descr_cmd[k]->getType();
1406 if ( ntyp == descr_moveto ) {
1407 // ne doit pas arriver
1408 } else if ( ntyp == descr_forced ) {
1409 res->MoveTo(nLastP);
1410 } else if ( ntyp == descr_close ) {
1411 // rien a faire ici; de plus il ne peut y en avoir qu'un
1412 } else if ( ntyp == descr_lineto ) {
1413 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1414 res->LineTo(nData->p);
1415 nLastP=nData->p;
1416 } else if ( ntyp == descr_arcto ) {
1417 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1418 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1419 nLastP=nData->p;
1420 } else if ( ntyp == descr_cubicto ) {
1421 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1422 res->CubicTo(nData->p,nData->start,nData->end);
1423 nLastP=nData->p;
1424 } else if ( ntyp == descr_bezierto ) {
1425 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[k]);
1426 res->BezierTo(nData->p);
1427 nLastP=nData->p;
1428 } else if ( ntyp == descr_interm_bezier ) {
1429 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[k]);
1430 res->IntermBezierTo(nData->p);
1431 } else {
1432 }
1433 }
1434 if ( doesClose == false ) res->LineTo(np);
1435 nLastP=np;
1436 for (int k=i+1;k<hasForced;k++) {
1437 int ntyp=descr_cmd[k]->getType();
1438 if ( ntyp == descr_moveto ) {
1439 // ne doit pas arriver
1440 } else if ( ntyp == descr_forced ) {
1441 res->MoveTo(nLastP);
1442 } else if ( ntyp == descr_close ) {
1443 // rien a faire ici; de plus il ne peut y en avoir qu'un
1444 } else if ( ntyp == descr_lineto ) {
1445 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1446 res->LineTo(nData->p);
1447 nLastP=nData->p;
1448 } else if ( ntyp == descr_arcto ) {
1449 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1450 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1451 nLastP=nData->p;
1452 } else if ( ntyp == descr_cubicto ) {
1453 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1454 res->CubicTo(nData->p,nData->start,nData->end);
1455 nLastP=nData->p;
1456 } else if ( ntyp == descr_bezierto ) {
1457 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[k]);
1458 res->BezierTo(nData->p);
1459 nLastP=nData->p;
1460 } else if ( ntyp == descr_interm_bezier ) {
1461 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[k]);
1462 res->IntermBezierTo(nData->p);
1463 } else {
1464 }
1465 }
1466 lastP=nMvtP;
1467 i=j;
1468 } else {
1469 // regular, just move on
1470 res->MoveTo(np);
1471 lastP=np;
1472 }
1473 } else if ( typ == descr_close ) {
1474 res->Close();
1475 } else if ( typ == descr_forced ) {
1476 res->MoveTo(lastP);
1477 } else if ( typ == descr_lineto ) {
1478 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1479 res->LineTo(nData->p);
1480 lastP=nData->p;
1481 } else if ( typ == descr_arcto ) {
1482 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1483 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1484 lastP=nData->p;
1485 } else if ( typ == descr_cubicto ) {
1486 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1487 res->CubicTo(nData->p,nData->start,nData->end);
1488 lastP=nData->p;
1489 } else if ( typ == descr_bezierto ) {
1490 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
1491 res->BezierTo(nData->p);
1492 lastP=nData->p;
1493 } else if ( typ == descr_interm_bezier ) {
1494 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
1495 res->IntermBezierTo(nData->p);
1496 } else {
1497 }
1498 }
1500 Copy(res);
1501 delete res;
1502 return;
1503 }
1505 /*
1506 Local Variables:
1507 mode:c++
1508 c-file-style:"stroustrup"
1509 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1510 indent-tabs-mode:nil
1511 fill-column:99
1512 End:
1513 */
1514 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :