Code

fix bug !
[inkscape.git] / src / livarot / PathStroke.cpp
1 /*
2  *  PathStroke.cpp
3  *  nlivarot
4  *
5  *  Created by fred on Tue Jun 17 2003.
6  *
7  */
9 #include "Path.h"
10 #include "Shape.h"
11 #include <2geom/transforms.h>
13 /*
14  * stroking polylines into a Shape instance
15  * grunt work.
16  * if the goal is to raster the stroke, polyline stroke->polygon->uncrossed polygon->raster is grossly
17  * inefficient (but reuse the intersector, so that's what a lazy programmer like me does). the correct way would be
18  * to set up a supersampled buffer, raster each polyline stroke's part (one part per segment in the polyline, plus 
19  * each join) because these are all convex polygons, then transform in alpha values
20  */
22 // until i find something better
23 Geom::Point StrokeNormalize(const Geom::Point value) {
24     double length = L2(value); 
25     if ( length < 0.0000001 ) { 
26         return Geom::Point(0, 0);
27     } else { 
28         return value/length; 
29     }
30 }
32 // faster version if length is known
33 Geom::Point StrokeNormalize(const Geom::Point value, double length) {
34     if ( length < 0.0000001 ) { 
35         return Geom::Point(0, 0);
36     } else { 
37         return value/length; 
38     }
39 }
41 void Path::Stroke(Shape *dest, bool doClose, double width, JoinType join,
42         ButtType butt, double miter, bool justAdd)
43 {
44     if (dest == NULL) {
45         return;
46     }
48     if (justAdd == false) {
49         dest->Reset(3 * pts.size(), 3 * pts.size());
50     }
52     dest->MakeBackData(false);
54     int lastM = 0;
55     while (lastM < int(pts.size())) {
57         int lastP = lastM + 1;
58         while (lastP < int(pts.size()) // select one subpath
59                 && (pts[lastP].isMoveTo == polyline_lineto
60                     || pts[lastP].isMoveTo == polyline_forced))
61         {
62             lastP++;
63         }
65         if ( lastP > lastM+1 ) {
66             if ( pts[lastP - 1].closed ) {
67                 DoStroke(lastM, lastP - lastM, dest, true, width, join, butt, miter, true);
68             } else {
69                 DoStroke(lastM, lastP - lastM, dest, doClose, width, join, butt, miter, true);
70             }
71         } else if (butt == butt_round) {       // special case: zero length round butt is a circle
72             int last[2] = { -1, -1 };
73             Geom::Point dir;
74             dir[0] = 1;
75             dir[1] = 0;
76             Geom::Point pos = pts[lastM].p;
77             DoButt(dest, width, butt, pos, dir, last[RIGHT], last[LEFT]);
78             int end[2];
79             dir = -dir;
80             DoButt(dest, width, butt, pos, dir, end[LEFT], end[RIGHT]);
81             dest->AddEdge (end[LEFT], last[LEFT]);
82             dest->AddEdge (last[RIGHT], end[RIGHT]);
83         }
84         lastM = lastP;
85     }
86 }
88 void Path::DoStroke(int off, int N, Shape *dest, bool doClose, double width, JoinType join,
89                     ButtType butt, double miter, bool /*justAdd*/)
90 {
91     if (N <= 1) {
92         return;
93     }
95     Geom::Point prevP, nextP;
96     int prevI, nextI;
97     int upTo;
99     int curI = 0;
100     Geom::Point curP = pts[off].p;
102     if (doClose) {
104         prevI = N - 1;
105         while (prevI > 0) {
106             prevP = pts[off + prevI].p;
107             Geom::Point diff = curP - prevP;
108             double dist = dot(diff, diff);
109             if (dist > 0.001) {
110                 break;
111             }
112             prevI--;
113         }
114         if (prevI <= 0) {
115             return;
116         }
117         upTo = prevI;
119     } else {
121         prevP = curP;
122         prevI = curI;
123         upTo = N - 1;
124     }
126     {
127         nextI = 1;
128         while (nextI <= upTo) {
129             nextP = pts[off + nextI].p;
130             Geom::Point diff = curP - nextP;
131             double dist = dot(diff, diff);
132             if (dist > 0.0) { // more tolerance for the first distance, to give the cap the right direction
133                 break;
134             }
135             nextI++;
136         }
137         if (nextI > upTo) {
138             if (butt == butt_round) {  // special case: zero length round butt is a circle
139                 int last[2] = { -1, -1 };
140                 Geom::Point dir;
141                 dir[0] = 1;
142                 dir[1] = 0;
143                 DoButt(dest, width, butt, curP, dir, last[RIGHT], last[LEFT]);
144                 int end[2];
145                 dir = -dir;
146                 DoButt(dest, width, butt, curP, dir, end[LEFT], end[RIGHT]);
147                 dest->AddEdge (end[LEFT], last[LEFT]);
148                 dest->AddEdge (last[RIGHT], end[RIGHT]);
149             }
150             return;
151         }
152     }
154     int start[2] = { -1, -1 };
155     int last[2] = { -1, -1 };
156     Geom::Point prevD = curP - prevP;
157     Geom::Point nextD = nextP - curP;
158     double prevLe = Geom::L2(prevD);
159     double nextLe = Geom::L2(nextD);
160     prevD = StrokeNormalize(prevD, prevLe);
161     nextD = StrokeNormalize(nextD, nextLe);
163     if (doClose) {
164         DoJoin(dest,  width, join, curP, prevD, nextD, miter, prevLe, nextLe, start, last);
165     } else {
166         nextD = -nextD;
167         DoButt(dest,  width, butt, curP, nextD, last[RIGHT], last[LEFT]);
168         nextD = -nextD;
169     }
171     do {
172         prevP = curP;
173         prevI = curI;
174         curP = nextP;
175         curI = nextI;
176         prevD = nextD;
177         prevLe = nextLe;
178         nextI++;
179         while (nextI <= upTo) {
180             nextP = pts[off + nextI].p;
181             Geom::Point diff = curP - nextP;
182             double dist = dot(diff, diff);
183             if (dist > 0.001 || (nextI == upTo && dist > 0.0)) { // more tolerance for the last distance too, for the right cap direction
184                 break;
185             }
186             nextI++;
187         }
188         if (nextI > upTo) {
189             break;
190         }
192         nextD = nextP - curP;
193         nextLe = Geom::L2(nextD);
194         nextD = StrokeNormalize(nextD, nextLe);
195         int nSt[2] = { -1, -1 };
196         int nEn[2] = { -1, -1 };
197         DoJoin(dest, width, join, curP, prevD, nextD, miter, prevLe, nextLe, nSt, nEn);
198         dest->AddEdge(nSt[LEFT], last[LEFT]);
199         last[LEFT] = nEn[LEFT];
200         dest->AddEdge(last[RIGHT], nSt[RIGHT]);
201         last[RIGHT] = nEn[RIGHT];
202     } while (nextI <= upTo);
204     if (doClose) {
205         /*              prevP=curP;
206                         prevI=curI;
207                         curP=nextP;
208                         curI=nextI;
209                         prevD=nextD;*/
210         nextP = pts[off].p;
212         nextD = nextP - curP;
213         nextLe = Geom::L2(nextD);
214         nextD = StrokeNormalize(nextD, nextLe);
215         int nSt[2] = { -1, -1 };
216         int nEn[2] = { -1, -1 };
217         DoJoin(dest,  width, join, curP, prevD, nextD, miter, prevLe, nextLe, nSt, nEn);
218         dest->AddEdge (nSt[LEFT], last[LEFT]);
219         last[LEFT] = nEn[LEFT];
220         dest->AddEdge (last[RIGHT], nSt[RIGHT]);
221         last[RIGHT] = nEn[RIGHT];
223         dest->AddEdge (start[LEFT], last[LEFT]);
224         dest->AddEdge (last[RIGHT], start[RIGHT]);
226     } else {
228         int end[2];
229         DoButt (dest,  width, butt, curP, prevD, end[LEFT], end[RIGHT]);
230         dest->AddEdge (end[LEFT], last[LEFT]);
231         dest->AddEdge (last[RIGHT], end[RIGHT]);
232     }
236 void Path::DoButt(Shape *dest, double width, ButtType butt, Geom::Point pos, Geom::Point dir,
237         int &leftNo, int &rightNo)
239     Geom::Point nor;
240     nor = dir.ccw();
242     if (butt == butt_square)
243     {
244         Geom::Point x;
245         x = pos + width * dir + width * nor;
246         int bleftNo = dest->AddPoint (x);
247         x = pos + width * dir - width * nor;
248         int brightNo = dest->AddPoint (x);
249         x = pos + width * nor;
250         leftNo = dest->AddPoint (x);
251         x = pos - width * nor;
252         rightNo = dest->AddPoint (x);
253         dest->AddEdge (rightNo, brightNo);
254         dest->AddEdge (brightNo, bleftNo);
255         dest->AddEdge (bleftNo, leftNo);
256     }
257     else if (butt == butt_pointy)
258     {
259         leftNo = dest->AddPoint (pos + width * nor);
260         rightNo = dest->AddPoint (pos - width * nor);
261         int mid = dest->AddPoint (pos + width * dir);
262         dest->AddEdge (rightNo, mid);
263         dest->AddEdge (mid, leftNo);
264     }
265     else if (butt == butt_round)
266     {
267         const Geom::Point sx = pos + width * nor;
268         const Geom::Point ex = pos - width * nor;
269         leftNo = dest->AddPoint (sx);
270         rightNo = dest->AddPoint (ex);
272         RecRound (dest, rightNo, leftNo, ex, sx, -nor, nor, pos, width);
273     }
274     else
275     {
276         leftNo = dest->AddPoint (pos + width * nor);
277         rightNo = dest->AddPoint (pos - width * nor);
278         dest->AddEdge (rightNo, leftNo);
279     }
283 void Path::DoJoin (Shape *dest, double width, JoinType join, Geom::Point pos, Geom::Point prev,
284         Geom::Point next, double miter, double /*prevL*/, double /*nextL*/,
285         int *stNo, int *enNo)
287     Geom::Point pnor = prev.ccw();
288     Geom::Point nnor = next.ccw();
289     double angSi = cross(next, prev);
291     /* FIXED: this special case caused bug 1028953 */
292     if (angSi > -0.0001 && angSi < 0.0001) {
293         double angCo = dot (prev, next);
294         if (angCo > 0.9999) {
295             // tout droit
296             stNo[LEFT] = enNo[LEFT] = dest->AddPoint(pos + width * pnor);
297             stNo[RIGHT] = enNo[RIGHT] = dest->AddPoint(pos - width * pnor);
298         } else {
299             // demi-tour
300             const Geom::Point sx = pos + width * pnor;
301             const Geom::Point ex = pos - width * pnor;
302             stNo[LEFT] = enNo[RIGHT] = dest->AddPoint (sx);
303             stNo[RIGHT] = enNo[LEFT] = dest->AddPoint (ex);
304             if (join == join_round) {
305                 RecRound (dest, enNo[LEFT], stNo[LEFT], ex, sx, -pnor, pnor, pos, width);
306                 dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);
307             } else {
308                 dest->AddEdge(enNo[LEFT], stNo[LEFT]);
309                 dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);        // two times because both are crossing each other
310             }
311         }
312         return;
313     }
315     if (angSi < 0) {
316         int midNo = dest->AddPoint(pos);
317         stNo[LEFT] = dest->AddPoint(pos + width * pnor);
318         enNo[LEFT] = dest->AddPoint(pos + width * nnor);
319         dest->AddEdge(enNo[LEFT], midNo);
320         dest->AddEdge(midNo, stNo[LEFT]);
322         if (join == join_pointy) {
324             stNo[RIGHT] = dest->AddPoint(pos - width * pnor);
325             enNo[RIGHT] = dest->AddPoint(pos - width * nnor);
327             const Geom::Point biss = StrokeNormalize(prev - next);
328             double c2 = dot(biss, nnor);
329             double l = width / c2;
330             double emiter = width * c2;
331             if (emiter < miter) {
332                 emiter = miter;
333             }
335             if (fabs(l) < miter) {
336                 int const n = dest->AddPoint(pos - l * biss);
337                 dest->AddEdge(stNo[RIGHT], n);
338                 dest->AddEdge(n, enNo[RIGHT]);
339             } else {
340                 dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);
341             }
343         } else if (join == join_round) {
344             Geom::Point sx = pos - width * pnor;
345             stNo[RIGHT] = dest->AddPoint(sx);
346             Geom::Point ex = pos - width * nnor;
347             enNo[RIGHT] = dest->AddPoint(ex);
349             RecRound(dest, stNo[RIGHT], enNo[RIGHT], 
350                     sx, ex, -pnor, -nnor, pos, width);
352         } else {
353             stNo[RIGHT] = dest->AddPoint(pos - width * pnor);
354             enNo[RIGHT] = dest->AddPoint(pos - width * nnor);
355             dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);
356         }
358     } else {
360         int midNo = dest->AddPoint(pos);
361         stNo[RIGHT] = dest->AddPoint(pos - width * pnor);
362         enNo[RIGHT] = dest->AddPoint(pos - width * nnor);
363         dest->AddEdge(stNo[RIGHT], midNo);
364         dest->AddEdge(midNo, enNo[RIGHT]);
366         if (join == join_pointy) {
368             stNo[LEFT] = dest->AddPoint(pos + width * pnor);
369             enNo[LEFT] = dest->AddPoint(pos + width * nnor);
371             const Geom::Point biss = StrokeNormalize(next - prev);
372             double c2 = dot(biss, nnor);
373             double l = width / c2;
374             double emiter = width * c2;
375             if (emiter < miter) {
376                 emiter = miter;
377             }
378             if ( fabs(l) < miter) {
379                 int const n = dest->AddPoint (pos + l * biss);
380                 dest->AddEdge (enNo[LEFT], n);
381                 dest->AddEdge (n, stNo[LEFT]);
382             }
383             else
384             {
385                 dest->AddEdge (enNo[LEFT], stNo[LEFT]);
386             }
388         } else if (join == join_round) {
390             Geom::Point sx = pos + width * pnor;
391             stNo[LEFT] = dest->AddPoint(sx);
392             Geom::Point ex = pos + width * nnor;
393             enNo[LEFT] = dest->AddPoint(ex);
395             RecRound(dest, enNo[LEFT], stNo[LEFT], 
396                     ex, sx, nnor, pnor, pos, width);
398         } else {
399             stNo[LEFT] = dest->AddPoint(pos + width * pnor);
400             enNo[LEFT] = dest->AddPoint(pos + width * nnor);
401             dest->AddEdge(enNo[LEFT], stNo[LEFT]);
402         }
403     }
406     void
407 Path::DoLeftJoin (Shape * dest, double width, JoinType join, Geom::Point pos,
408         Geom::Point prev, Geom::Point next, double miter, double /*prevL*/, double /*nextL*/,
409         int &leftStNo, int &leftEnNo,int pathID,int pieceID,double tID)
411     Geom::Point pnor=prev.ccw();
412     Geom::Point nnor=next.ccw();
413     double angSi = cross (next, prev);
414     if (angSi > -0.0001 && angSi < 0.0001)
415     {
416         double angCo = dot (prev, next);
417         if (angCo > 0.9999)
418         {
419             // tout droit
420             leftEnNo = leftStNo = dest->AddPoint (pos + width * pnor);
421         }
422         else
423         {
424             // demi-tour
425             leftStNo = dest->AddPoint (pos + width * pnor);
426             leftEnNo = dest->AddPoint (pos - width * pnor);
427             int nEdge=dest->AddEdge (leftEnNo, leftStNo);
428             if ( dest->hasBackData() ) {
429                 dest->ebData[nEdge].pathID=pathID;
430                 dest->ebData[nEdge].pieceID=pieceID;
431                 dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
432             }
433         }
434         return;
435     }
436     if (angSi < 0)
437     {
438         /*              Geom::Point     biss;
439                         biss.x=next.x-prev.x;
440                         biss.y=next.y-prev.y;
441                         double   c2=cross(biss,next);
442                         double   l=width/c2;
443                         double          projn=l*(dot(biss,next));
444                         double          projp=-l*(dot(biss,prev));
445                         if ( projp <= 0.5*prevL && projn <= 0.5*nextL ) {
446                         double   x,y;
447                         x=pos.x+l*biss.x;
448                         y=pos.y+l*biss.y;
449                         leftEnNo=leftStNo=dest->AddPoint(x,y);
450                         } else {*/
451         leftStNo = dest->AddPoint (pos + width * pnor);
452         leftEnNo = dest->AddPoint (pos + width * nnor);
453         int midNo = dest->AddPoint (pos);
454         int nEdge=dest->AddEdge (leftEnNo, midNo);
455         if ( dest->hasBackData() ) {
456             dest->ebData[nEdge].pathID=pathID;
457             dest->ebData[nEdge].pieceID=pieceID;
458             dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
459         }
460         nEdge=dest->AddEdge (midNo, leftStNo);
461         if ( dest->hasBackData() ) {
462             dest->ebData[nEdge].pathID=pathID;
463             dest->ebData[nEdge].pieceID=pieceID;
464             dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
465         }
466         //              }
467     }
468     else
469     {
470         if (join == join_pointy)
471         {
472             leftStNo = dest->AddPoint (pos + width * pnor);
473             leftEnNo = dest->AddPoint (pos + width * nnor);
475             const Geom::Point biss = StrokeNormalize (pnor + nnor);
476             double c2 = dot (biss, nnor);
477             double l = width / c2;
478             double emiter = width * c2;
479             if (emiter < miter)
480                 emiter = miter;
481             if (l <= emiter)
482             {
483                 int nleftStNo = dest->AddPoint (pos + l * biss);
484                 int nEdge=dest->AddEdge (leftEnNo, nleftStNo);
485                 if ( dest->hasBackData() ) {
486                     dest->ebData[nEdge].pathID=pathID;
487                     dest->ebData[nEdge].pieceID=pieceID;
488                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
489                 }
490                 nEdge=dest->AddEdge (nleftStNo, leftStNo);
491                 if ( dest->hasBackData() ) {
492                     dest->ebData[nEdge].pathID=pathID;
493                     dest->ebData[nEdge].pieceID=pieceID;
494                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
495                 }
496             }
497             else
498             {
499                 double s2 = cross (biss, nnor);
500                 double dec = (l - emiter) * c2 / s2;
501                 const Geom::Point tbiss=biss.ccw();
503                 int nleftStNo = dest->AddPoint (pos + emiter * biss + dec * tbiss);
504                 int nleftEnNo = dest->AddPoint (pos + emiter * biss - dec * tbiss);
505                 int nEdge=dest->AddEdge (nleftEnNo, nleftStNo);
506                 if ( dest->hasBackData() ) {
507                     dest->ebData[nEdge].pathID=pathID;
508                     dest->ebData[nEdge].pieceID=pieceID;
509                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
510                 }
511                 nEdge=dest->AddEdge (leftEnNo, nleftEnNo);
512                 if ( dest->hasBackData() ) {
513                     dest->ebData[nEdge].pathID=pathID;
514                     dest->ebData[nEdge].pieceID=pieceID;
515                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
516                 }
517                 nEdge=dest->AddEdge (nleftStNo, leftStNo);
518                 if ( dest->hasBackData() ) {
519                     dest->ebData[nEdge].pathID=pathID;
520                     dest->ebData[nEdge].pieceID=pieceID;
521                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
522                 }
523             }
524         }
525         else if (join == join_round)
526         {
527             const Geom::Point sx = pos + width * pnor;
528             leftStNo = dest->AddPoint (sx);
529             const Geom::Point ex = pos + width * nnor;
530             leftEnNo = dest->AddPoint (ex);
532             RecRound(dest, leftEnNo, leftStNo, 
533                     sx, ex, pnor, nnor ,pos, width);
535         }
536         else
537         {
538             leftStNo = dest->AddPoint (pos + width * pnor);
539             leftEnNo = dest->AddPoint (pos + width * nnor);
540             int nEdge=dest->AddEdge (leftEnNo, leftStNo);
541             if ( dest->hasBackData() ) {
542                 dest->ebData[nEdge].pathID=pathID;
543                 dest->ebData[nEdge].pieceID=pieceID;
544                 dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
545             }
546         }
547     }
549     void
550 Path::DoRightJoin (Shape * dest, double width, JoinType join, Geom::Point pos,
551         Geom::Point prev, Geom::Point next, double miter, double /*prevL*/,
552         double /*nextL*/, int &rightStNo, int &rightEnNo,int pathID,int pieceID,double tID)
554     const Geom::Point pnor=prev.ccw();
555     const Geom::Point nnor=next.ccw();
556     double angSi = cross (next,prev);
557     if (angSi > -0.0001 && angSi < 0.0001)
558     {
559         double angCo = dot (prev, next);
560         if (angCo > 0.9999)
561         {
562             // tout droit
563             rightEnNo = rightStNo = dest->AddPoint (pos - width*pnor);
564         }
565         else
566         {
567             // demi-tour
568             rightEnNo = dest->AddPoint (pos + width*pnor);
569             rightStNo = dest->AddPoint (pos - width*pnor);
570             int nEdge=dest->AddEdge (rightStNo, rightEnNo);
571             if ( dest->hasBackData() ) {
572                 dest->ebData[nEdge].pathID=pathID;
573                 dest->ebData[nEdge].pieceID=pieceID;
574                 dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
575             }
576         }
577         return;
578     }
579     if (angSi < 0)
580     {
581         if (join == join_pointy)
582         {
583             rightStNo = dest->AddPoint (pos - width*pnor);
584             rightEnNo = dest->AddPoint (pos - width*nnor);
586             const Geom::Point biss = StrokeNormalize (pnor + nnor);
587             double c2 = dot (biss, nnor);
588             double l = width / c2;
589             double emiter = width * c2;
590             if (emiter < miter)
591                 emiter = miter;
592             if (l <= emiter)
593             {
594                 int nrightStNo = dest->AddPoint (pos - l * biss);
595                 int nEdge=dest->AddEdge (rightStNo, nrightStNo);
596                 if ( dest->hasBackData() ) {
597                     dest->ebData[nEdge].pathID=pathID;
598                     dest->ebData[nEdge].pieceID=pieceID;
599                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
600                 }
601                 nEdge=dest->AddEdge (nrightStNo, rightEnNo);
602                 if ( dest->hasBackData() ) {
603                     dest->ebData[nEdge].pathID=pathID;
604                     dest->ebData[nEdge].pieceID=pieceID;
605                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
606                 }
607             }
608             else
609             {
610                 double s2 = cross (biss, nnor);
611                 double dec = (l - emiter) * c2 / s2;
612                 const Geom::Point tbiss=biss.ccw();
614                 int nrightStNo = dest->AddPoint (pos - emiter*biss - dec*tbiss);
615                 int nrightEnNo = dest->AddPoint (pos - emiter*biss + dec*tbiss);
616                 int nEdge=dest->AddEdge (rightStNo, nrightStNo);
617                 if ( dest->hasBackData() ) {
618                     dest->ebData[nEdge].pathID=pathID;
619                     dest->ebData[nEdge].pieceID=pieceID;
620                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
621                 }
622                 nEdge=dest->AddEdge (nrightStNo, nrightEnNo);
623                 if ( dest->hasBackData() ) {
624                     dest->ebData[nEdge].pathID=pathID;
625                     dest->ebData[nEdge].pieceID=pieceID;
626                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
627                 }
628                 nEdge=dest->AddEdge (nrightEnNo, rightEnNo);
629                 if ( dest->hasBackData() ) {
630                     dest->ebData[nEdge].pathID=pathID;
631                     dest->ebData[nEdge].pieceID=pieceID;
632                     dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
633                 }
634             }
635         }
636         else if (join == join_round)
637         {
638             const Geom::Point sx = pos - width * pnor;
639             rightStNo = dest->AddPoint (sx);
640             const Geom::Point ex = pos - width * nnor;
641             rightEnNo = dest->AddPoint (ex);
643             RecRound(dest, rightStNo, rightEnNo, 
644                     sx, ex, -pnor, -nnor ,pos, width);
645         }
646         else
647         {
648             rightStNo = dest->AddPoint (pos - width * pnor);
649             rightEnNo = dest->AddPoint (pos - width * nnor);
650             int nEdge=dest->AddEdge (rightStNo, rightEnNo);
651             if ( dest->hasBackData() ) {
652                 dest->ebData[nEdge].pathID=pathID;
653                 dest->ebData[nEdge].pieceID=pieceID;
654                 dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
655             }
656         }
657     }
658     else
659     {
660         /*              Geom::Point     biss;
661                         biss=next.x-prev.x;
662                         biss.y=next.y-prev.y;
663                         double   c2=cross(next,biss);
664                         double   l=width/c2;
665                         double          projn=l*(dot(biss,next));
666                         double          projp=-l*(dot(biss,prev));
667                         if ( projp <= 0.5*prevL && projn <= 0.5*nextL ) {
668                         double   x,y;
669                         x=pos.x+l*biss.x;
670                         y=pos.y+l*biss.y;
671                         rightEnNo=rightStNo=dest->AddPoint(x,y);
672                         } else {*/
673         rightStNo = dest->AddPoint (pos - width*pnor);
674         rightEnNo = dest->AddPoint (pos - width*nnor);
675         int midNo = dest->AddPoint (pos);
676         int nEdge=dest->AddEdge (rightStNo, midNo);
677         if ( dest->hasBackData() ) {
678             dest->ebData[nEdge].pathID=pathID;                                  
679             dest->ebData[nEdge].pieceID=pieceID;
680             dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
681         }
682         nEdge=dest->AddEdge (midNo, rightEnNo);
683         if ( dest->hasBackData() ) {
684             dest->ebData[nEdge].pathID=pathID;
685             dest->ebData[nEdge].pieceID=pieceID;
686             dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
687         }
688         //              }
689     }
693 // a very ugly way to produce round joins: doing one (or two, depend on the angle of the join) quadratic bezier curves
694 // but since most joins are going to be small, nobody will notice -- but somebody noticed and now the ugly stuff is gone! so:
696 // a very nice way to produce round joins, caps or dots
697 void Path::RecRound(Shape *dest, int sNo, int eNo, // start and end index
698         Geom::Point const &iS, Geom::Point const &iE, // start and end point
699         Geom::Point const &nS, Geom::Point const &nE, // start and end normal vector
700         Geom::Point &origine, float width) // center and radius of round
702     //Geom::Point diff = iS - iE;
703     //double dist = dot(diff, diff);
704     if (width < 0.5 || dot(iS - iE, iS - iE)/width < 2.0) {
705         dest->AddEdge(sNo, eNo);
706         return;
707     }
708     double ang, sia, lod;
709     if (nS == -nE) {
710         ang = M_PI;
711         sia = 1;
712     } else {
713         double coa = dot(nS, nE);
714         sia = cross(nS, nE);
715         ang = acos(coa);
716         if ( coa >= 1 ) {
717             ang = 0;
718         }
719         if ( coa <= -1 ) {
720             ang = M_PI;
721         }
722     }
723     lod = 0.02 + 10 / (10 + width); // limit detail to about 2 degrees (180 * 0.02/Pi degrees)
724     ang /= lod;
726     int nbS = (int) floor(ang);
727     Geom::Rotate omega(((sia > 0) ? -lod : lod));
728     Geom::Point cur = iS - origine;
729     //  StrokeNormalize(cur);
730     //  cur*=width;
731     int lastNo = sNo;
732     for (int i = 0; i < nbS; i++) {
733         cur = cur * omega;
734         Geom::Point m = origine + cur;
735         int mNo = dest->AddPoint(m);
736         dest->AddEdge(lastNo, mNo);
737         lastNo = mNo;
738     }
739     dest->AddEdge(lastNo, eNo);
742 /*
743    Local Variables:
744 mode:c++
745 c-file-style:"stroustrup"
746 c-file-offsets:((innamespace . 0)(inline-open . 0))
747 indent-tabs-mode:nil
748 fill-column:99
749 End:
750  */
751 // vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :