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