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, unsigned seg) const
955 {
956 // if the parameter "seg" == 0, then all segments will be considered
957 // In however e.g. "seg" == 6 , then only the 6th segment will be considered
959 unsigned bestSeg = 0;
960 double bestRangeSquared = DBL_MAX;
961 double bestT = 0.0; // you need a sentinel, or make sure that you prime with correct values.
963 for (unsigned i = 1 ; i < pts.size() ; i++) {
964 if (pts[i].isMoveTo == polyline_moveto || (seg > 0 && i != seg)) continue;
965 NR::Point p1, p2, localPos;
966 double thisRangeSquared;
967 double t;
969 if (pts[i - 1].p == pts[i].p) {
970 thisRangeSquared = square(pts[i].p[NR::X] - pos[NR::X]) + square(pts[i].p[NR::Y] - pos[NR::Y]);
971 t = 0.0;
972 } else {
973 // we rotate all our coordinates so we're always looking at a mostly vertical line.
974 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])) {
975 p1 = pts[i - 1].p;
976 p2 = pts[i].p;
977 localPos = pos;
978 } else {
979 p1 = pts[i - 1].p.cw();
980 p2 = pts[i].p.cw();
981 localPos = pos.cw();
982 }
983 double gradient = (p2[NR::X] - p1[NR::X]) / (p2[NR::Y] - p1[NR::Y]);
984 double intersection = p1[NR::X] - gradient * p1[NR::Y];
985 /*
986 orthogonalGradient = -1.0 / gradient; // you are going to have numerical problems here.
987 orthogonalIntersection = localPos[NR::X] - orthogonalGradient * localPos[NR::Y];
988 nearestY = (orthogonalIntersection - intersection) / (gradient - orthogonalGradient);
990 expand out nearestY fully :
991 nearestY = (localPos[NR::X] - (-1.0 / gradient) * localPos[NR::Y] - intersection) / (gradient - (-1.0 / gradient));
993 multiply top and bottom by gradient:
994 nearestY = (localPos[NR::X] * gradient - (-1.0) * localPos[NR::Y] - intersection * gradient) / (gradient * gradient - (-1.0));
996 and simplify to get:
997 */
998 double nearestY = (localPos[NR::X] * gradient + localPos[NR::Y] - intersection * gradient)
999 / (gradient * gradient + 1.0);
1000 t = (nearestY - p1[NR::Y]) / (p2[NR::Y] - p1[NR::Y]);
1001 if (t <= 0.0) {
1002 thisRangeSquared = square(p1[NR::X] - localPos[NR::X]) + square(p1[NR::Y] - localPos[NR::Y]);
1003 t = 0.0;
1004 } else if (t >= 1.0) {
1005 thisRangeSquared = square(p2[NR::X] - localPos[NR::X]) + square(p2[NR::Y] - localPos[NR::Y]);
1006 t = 1.0;
1007 } else {
1008 thisRangeSquared = square(nearestY * gradient + intersection - localPos[NR::X]) + square(nearestY - localPos[NR::Y]);
1009 }
1010 }
1012 if (thisRangeSquared < bestRangeSquared) {
1013 bestSeg = i;
1014 bestRangeSquared = thisRangeSquared;
1015 bestT = t;
1016 }
1017 }
1018 Path::cut_position result;
1019 if (bestSeg == 0) {
1020 result.piece = 0;
1021 result.t = 0.0;
1022 } else {
1023 result.piece = pts[bestSeg].piece;
1024 if (result.piece == pts[bestSeg - 1].piece) {
1025 result.t = pts[bestSeg - 1].t * (1.0 - bestT) + pts[bestSeg].t * bestT;
1026 } else {
1027 result.t = pts[bestSeg].t * bestT;
1028 }
1029 }
1030 return result;
1031 }
1032 /*
1033 this one also belongs to Path
1034 returns the length of the path up to the position indicated by t (0..1)
1036 TODO: clean up uses of the original function and remove
1038 should this take a cut_position as a parameter?
1039 */
1040 double Path::PositionToLength(int piece, double t)
1041 {
1042 double length = 0.0;
1043 for (unsigned i = 1 ; i < pts.size() ; i++) {
1044 if (pts[i].isMoveTo == polyline_moveto) continue;
1045 if (pts[i].piece == piece && t < pts[i].t) {
1046 length += NR::L2((t - pts[i - 1].t) / (pts[i].t - pts[i - 1].t) * (pts[i].p - pts[i - 1].p));
1047 break;
1048 }
1049 length += NR::L2(pts[i].p - pts[i - 1].p);
1050 }
1051 return length;
1052 }
1054 void Path::ConvertPositionsToForced(int nbPos, cut_position *poss)
1055 {
1056 if ( nbPos <= 0 ) {
1057 return;
1058 }
1060 {
1061 NR::Point lastPos(0, 0);
1062 for (int i = int(descr_cmd.size()) - 1; i >= 0; i--) {
1063 int const typ = descr_cmd[i]->getType();
1064 switch ( typ ) {
1066 case descr_forced:
1067 {
1068 PathDescrForced *d = dynamic_cast<PathDescrForced *>(descr_cmd[i]);
1069 d->p = lastPos;
1070 break;
1071 }
1073 case descr_close:
1074 {
1075 delete descr_cmd[i];
1076 descr_cmd[i] = new PathDescrLineTo(NR::Point(0, 0));
1078 int fp = i - 1;
1079 while ( fp >= 0 && (descr_cmd[fp]->getType()) != descr_moveto ) {
1080 fp--;
1081 }
1083 if ( fp >= 0 ) {
1084 PathDescrMoveTo *oData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[fp]);
1085 dynamic_cast<PathDescrLineTo*>(descr_cmd[i])->p = oData->p;
1086 }
1087 }
1088 break;
1090 case descr_bezierto:
1091 {
1092 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
1093 NR::Point theP = nData->p;
1094 if ( nData->nb == 0 ) {
1095 lastPos = theP;
1096 }
1097 }
1098 break;
1100 case descr_moveto:
1101 {
1102 PathDescrMoveTo *d = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
1103 lastPos = d->p;
1104 break;
1105 }
1106 case descr_lineto:
1107 {
1108 PathDescrLineTo *d = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1109 lastPos = d->p;
1110 break;
1111 }
1112 case descr_arcto:
1113 {
1114 PathDescrArcTo *d = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1115 lastPos = d->p;
1116 break;
1117 }
1118 case descr_cubicto:
1119 {
1120 PathDescrCubicTo *d = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1121 lastPos = d->p;
1122 break;
1123 }
1124 case descr_interm_bezier:
1125 {
1126 PathDescrIntermBezierTo *d = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
1127 lastPos = d->p;
1128 break;
1129 }
1130 default:
1131 break;
1132 }
1133 }
1134 }
1136 qsort(poss, nbPos, sizeof(cut_position), CmpPosition);
1138 for (int curP=0;curP<nbPos;curP++) {
1139 int cp=poss[curP].piece;
1140 if ( cp < 0 || cp >= int(descr_cmd.size()) ) break;
1141 float ct=poss[curP].t;
1142 if ( ct < 0 ) continue;
1143 if ( ct > 1 ) continue;
1145 int const typ = descr_cmd[cp]->getType();
1146 if ( typ == descr_moveto || typ == descr_forced || typ == descr_close ) {
1147 // ponctuel= rien a faire
1148 } else if ( typ == descr_lineto || typ == descr_arcto || typ == descr_cubicto ) {
1149 // facile: creation d'un morceau et d'un forced -> 2 commandes
1150 NR::Point theP;
1151 NR::Point theT;
1152 NR::Point startP;
1153 startP=PrevPoint(cp-1);
1154 if ( typ == descr_cubicto ) {
1155 double len,rad;
1156 NR::Point stD,enD,endP;
1157 {
1158 PathDescrCubicTo *oData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1159 stD=oData->start;
1160 enD=oData->end;
1161 endP=oData->p;
1162 TangentOnCubAt (ct, startP, *oData,true, theP,theT,len,rad);
1163 }
1165 theT*=len;
1167 InsertCubicTo(endP,(1-ct)*theT,(1-ct)*enD,cp+1);
1168 InsertForcePoint(cp+1);
1169 {
1170 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[cp]);
1171 nData->start=ct*stD;
1172 nData->end=ct*theT;
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_lineto ) {
1185 NR::Point endP;
1186 {
1187 PathDescrLineTo *oData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1188 endP=oData->p;
1189 }
1191 theP=ct*endP+(1-ct)*startP;
1193 InsertLineTo(endP,cp+1);
1194 InsertForcePoint(cp+1);
1195 {
1196 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[cp]);
1197 nData->p=theP;
1198 }
1199 // decalages dans le tableau des positions de coupe
1200 for (int j=curP+1;j<nbPos;j++) {
1201 if ( poss[j].piece == cp ) {
1202 poss[j].piece+=2;
1203 poss[j].t=(poss[j].t-ct)/(1-ct);
1204 } else {
1205 poss[j].piece+=2;
1206 }
1207 }
1208 } else if ( typ == descr_arcto ) {
1209 NR::Point endP;
1210 double rx,ry,angle;
1211 bool clockw,large;
1212 double delta=0;
1213 {
1214 PathDescrArcTo *oData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1215 endP=oData->p;
1216 rx=oData->rx;
1217 ry=oData->ry;
1218 angle=oData->angle;
1219 clockw=oData->clockwise;
1220 large=oData->large;
1221 }
1222 {
1223 double sang,eang;
1224 ArcAngles(startP,endP,rx,ry,angle,large,clockw,sang,eang);
1226 if (clockw) {
1227 if ( sang < eang ) sang += 2*M_PI;
1228 delta=eang-sang;
1229 } else {
1230 if ( sang > eang ) sang -= 2*M_PI;
1231 delta=eang-sang;
1232 }
1233 if ( delta < 0 ) delta=-delta;
1234 }
1236 PointAt (cp,ct, theP);
1238 if ( delta*(1-ct) > M_PI ) {
1239 InsertArcTo(endP,rx,ry,angle,true,clockw,cp+1);
1240 } else {
1241 InsertArcTo(endP,rx,ry,angle,false,clockw,cp+1);
1242 }
1243 InsertForcePoint(cp+1);
1244 {
1245 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[cp]);
1246 nData->p=theP;
1247 if ( delta*ct > M_PI ) {
1248 nData->clockwise=true;
1249 } else {
1250 nData->clockwise=false;
1251 }
1252 }
1253 // decalages dans le tableau des positions de coupe
1254 for (int j=curP+1;j<nbPos;j++) {
1255 if ( poss[j].piece == cp ) {
1256 poss[j].piece+=2;
1257 poss[j].t=(poss[j].t-ct)/(1-ct);
1258 } else {
1259 poss[j].piece+=2;
1260 }
1261 }
1262 }
1263 } else if ( typ == descr_bezierto || typ == descr_interm_bezier ) {
1264 // dur
1265 int theBDI=cp;
1266 while ( theBDI >= 0 && (descr_cmd[theBDI]->getType()) != descr_bezierto ) theBDI--;
1267 if ( (descr_cmd[theBDI]->getType()) == descr_bezierto ) {
1268 PathDescrBezierTo theBD=*(dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]));
1269 if ( cp >= theBDI && cp < theBDI+theBD.nb ) {
1270 if ( theBD.nb == 1 ) {
1271 NR::Point endP=theBD.p;
1272 NR::Point midP;
1273 NR::Point startP;
1274 startP=PrevPoint(theBDI-1);
1275 {
1276 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[theBDI+1]);
1277 midP=nData->p;
1278 }
1279 NR::Point aP=ct*midP+(1-ct)*startP;
1280 NR::Point bP=ct*endP+(1-ct)*midP;
1281 NR::Point knotP=ct*bP+(1-ct)*aP;
1283 InsertIntermBezierTo(bP,theBDI+2);
1284 InsertBezierTo(knotP,1,theBDI+2);
1285 InsertForcePoint(theBDI+2);
1286 {
1287 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[theBDI+1]);
1288 nData->p=aP;
1289 }
1290 {
1291 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1292 nData->p=knotP;
1293 }
1294 // decalages dans le tableau des positions de coupe
1295 for (int j=curP+1;j<nbPos;j++) {
1296 if ( poss[j].piece == cp ) {
1297 poss[j].piece+=3;
1298 poss[j].t=(poss[j].t-ct)/(1-ct);
1299 } else {
1300 poss[j].piece+=3;
1301 }
1302 }
1304 } else {
1305 // decouper puis repasser
1306 if ( cp > theBDI ) {
1307 NR::Point pcP,ncP;
1308 {
1309 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp]);
1310 pcP=nData->p;
1311 }
1312 {
1313 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+1]);
1314 ncP=nData->p;
1315 }
1316 NR::Point knotP=0.5*(pcP+ncP);
1318 InsertBezierTo(knotP,theBD.nb-(cp-theBDI),cp+1);
1319 {
1320 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1321 nData->nb=cp-theBDI;
1322 }
1324 // decalages dans le tableau des positions de coupe
1325 for (int j=curP;j<nbPos;j++) {
1326 if ( poss[j].piece == cp ) {
1327 poss[j].piece+=1;
1328 } else {
1329 poss[j].piece+=1;
1330 }
1331 }
1332 curP--;
1333 } else {
1334 NR::Point pcP,ncP;
1335 {
1336 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+1]);
1337 pcP=nData->p;
1338 }
1339 {
1340 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[cp+2]);
1341 ncP=nData->p;
1342 }
1343 NR::Point knotP=0.5*(pcP+ncP);
1345 InsertBezierTo(knotP,theBD.nb-1,cp+2);
1346 {
1347 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[theBDI]);
1348 nData->nb=1;
1349 }
1351 // decalages dans le tableau des positions de coupe
1352 for (int j=curP;j<nbPos;j++) {
1353 if ( poss[j].piece == cp ) {
1354 // poss[j].piece+=1;
1355 } else {
1356 poss[j].piece+=1;
1357 }
1358 }
1359 curP--;
1360 }
1361 }
1362 } else {
1363 // on laisse aussi tomber
1364 }
1365 } else {
1366 // on laisse tomber
1367 }
1368 }
1369 }
1370 }
1372 void Path::ConvertPositionsToMoveTo(int nbPos,cut_position* poss)
1373 {
1374 ConvertPositionsToForced(nbPos,poss);
1375 // ConvertForcedToMoveTo();
1376 // on fait une version customizee a la place
1378 Path* res=new Path;
1380 NR::Point lastP(0,0);
1381 for (int i=0;i<int(descr_cmd.size());i++) {
1382 int const typ = descr_cmd[i]->getType();
1383 if ( typ == descr_moveto ) {
1384 NR::Point np;
1385 {
1386 PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
1387 np=nData->p;
1388 }
1389 NR::Point endP;
1390 bool hasClose=false;
1391 int hasForced=-1;
1392 bool doesClose=false;
1393 int j=i+1;
1394 for (;j<int(descr_cmd.size());j++) {
1395 int const ntyp = descr_cmd[j]->getType();
1396 if ( ntyp == descr_moveto ) {
1397 j--;
1398 break;
1399 } else if ( ntyp == descr_forced ) {
1400 if ( hasForced < 0 ) hasForced=j;
1401 } else if ( ntyp == descr_close ) {
1402 hasClose=true;
1403 break;
1404 } else if ( ntyp == descr_lineto ) {
1405 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[j]);
1406 endP=nData->p;
1407 } else if ( ntyp == descr_arcto ) {
1408 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[j]);
1409 endP=nData->p;
1410 } else if ( ntyp == descr_cubicto ) {
1411 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[j]);
1412 endP=nData->p;
1413 } else if ( ntyp == descr_bezierto ) {
1414 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[j]);
1415 endP=nData->p;
1416 } else {
1417 }
1418 }
1419 if ( NR::LInfty(endP-np) < 0.00001 ) {
1420 doesClose=true;
1421 }
1422 if ( ( doesClose || hasClose ) && hasForced >= 0 ) {
1423 // printf("nasty i=%i j=%i frc=%i\n",i,j,hasForced);
1424 // aghhh.
1425 NR::Point nMvtP=PrevPoint(hasForced);
1426 res->MoveTo(nMvtP);
1427 NR::Point nLastP=nMvtP;
1428 for (int k = hasForced + 1; k < j; k++) {
1429 int ntyp=descr_cmd[k]->getType();
1430 if ( ntyp == descr_moveto ) {
1431 // ne doit pas arriver
1432 } else if ( ntyp == descr_forced ) {
1433 res->MoveTo(nLastP);
1434 } else if ( ntyp == descr_close ) {
1435 // rien a faire ici; de plus il ne peut y en avoir qu'un
1436 } else if ( ntyp == descr_lineto ) {
1437 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1438 res->LineTo(nData->p);
1439 nLastP=nData->p;
1440 } else if ( ntyp == descr_arcto ) {
1441 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1442 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1443 nLastP=nData->p;
1444 } else if ( ntyp == descr_cubicto ) {
1445 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1446 res->CubicTo(nData->p,nData->start,nData->end);
1447 nLastP=nData->p;
1448 } else if ( ntyp == descr_bezierto ) {
1449 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[k]);
1450 res->BezierTo(nData->p);
1451 nLastP=nData->p;
1452 } else if ( ntyp == descr_interm_bezier ) {
1453 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[k]);
1454 res->IntermBezierTo(nData->p);
1455 } else {
1456 }
1457 }
1458 if ( doesClose == false ) res->LineTo(np);
1459 nLastP=np;
1460 for (int k=i+1;k<hasForced;k++) {
1461 int ntyp=descr_cmd[k]->getType();
1462 if ( ntyp == descr_moveto ) {
1463 // ne doit pas arriver
1464 } else if ( ntyp == descr_forced ) {
1465 res->MoveTo(nLastP);
1466 } else if ( ntyp == descr_close ) {
1467 // rien a faire ici; de plus il ne peut y en avoir qu'un
1468 } else if ( ntyp == descr_lineto ) {
1469 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[k]);
1470 res->LineTo(nData->p);
1471 nLastP=nData->p;
1472 } else if ( ntyp == descr_arcto ) {
1473 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[k]);
1474 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1475 nLastP=nData->p;
1476 } else if ( ntyp == descr_cubicto ) {
1477 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[k]);
1478 res->CubicTo(nData->p,nData->start,nData->end);
1479 nLastP=nData->p;
1480 } else if ( ntyp == descr_bezierto ) {
1481 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[k]);
1482 res->BezierTo(nData->p);
1483 nLastP=nData->p;
1484 } else if ( ntyp == descr_interm_bezier ) {
1485 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[k]);
1486 res->IntermBezierTo(nData->p);
1487 } else {
1488 }
1489 }
1490 lastP=nMvtP;
1491 i=j;
1492 } else {
1493 // regular, just move on
1494 res->MoveTo(np);
1495 lastP=np;
1496 }
1497 } else if ( typ == descr_close ) {
1498 res->Close();
1499 } else if ( typ == descr_forced ) {
1500 res->MoveTo(lastP);
1501 } else if ( typ == descr_lineto ) {
1502 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
1503 res->LineTo(nData->p);
1504 lastP=nData->p;
1505 } else if ( typ == descr_arcto ) {
1506 PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
1507 res->ArcTo(nData->p,nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
1508 lastP=nData->p;
1509 } else if ( typ == descr_cubicto ) {
1510 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
1511 res->CubicTo(nData->p,nData->start,nData->end);
1512 lastP=nData->p;
1513 } else if ( typ == descr_bezierto ) {
1514 PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
1515 res->BezierTo(nData->p);
1516 lastP=nData->p;
1517 } else if ( typ == descr_interm_bezier ) {
1518 PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[i]);
1519 res->IntermBezierTo(nData->p);
1520 } else {
1521 }
1522 }
1524 Copy(res);
1525 delete res;
1526 return;
1527 }
1529 /*
1530 Local Variables:
1531 mode:c++
1532 c-file-style:"stroustrup"
1533 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1534 indent-tabs-mode:nil
1535 fill-column:99
1536 End:
1537 */
1538 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :