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