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