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