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