Code

Warning cleanup
[inkscape.git] / src / livarot / PathOutline.cpp
1 /*
2  *  PathOutline.cpp
3  *  nlivarot
4  *
5  *  Created by fred on Fri Nov 28 2003.
6  *
7  */
9 #include "livarot/Path.h"
10 #include "livarot/path-description.h"
11 #include <libnr/nr-point-fns.h>
13 /*
14  * the "outliner"
15  * takes a sequence of path commands and produces a set of commands that approximates the offset
16  * result is stored in dest (that paremeter is handed to all the subfunctions)
17  * not that the result is in general not mathematically correct; you can end up with unwanted holes in your
18  * beautiful offset. a better way is to do path->polyline->polygon->offset of polygon->polyline(=contours of the polygon)->path
19  * but computing offsets of the path is faster...
20  */
22 // outline of a path.
23 // computed by making 2 offsets, one of the "left" side of the path, one of the right side, and then glueing the two
24 // the left side has to be reversed to make a contour
25 void Path::Outline(Path *dest, double width, JoinType join, ButtType butt, double miter)
26 {
27     if ( descr_flags & descr_adding_bezier ) {
28         CancelBezier();
29     }
30     if ( descr_flags & descr_doing_subpath ) {
31         CloseSubpath();
32     }
33     if ( descr_cmd.size() <= 1 ) {
34         return;
35     }
36     if ( dest == NULL ) {
37         return;
38     }
40     dest->Reset();
41     dest->SetBackData(false);
43     outline_callbacks calls;
44     NR::Point endButt;
45     NR::Point endPos;
46     calls.cubicto = StdCubicTo;
47     calls.bezierto = StdBezierTo;
48     calls.arcto = StdArcTo;
50     Path *rev = new Path;
52     // we repeat the offset contour creation for each subpath
53     int curP = 0;
54     do {
55         int lastM = curP;
56         do {
57             curP++;
58             if (curP >= int(descr_cmd.size())) {
59                 break;
60             }
61             int typ = descr_cmd[curP]->getType();
62             if (typ == descr_moveto) {
63                 break;
64             }
65         } while (curP < int(descr_cmd.size()));
67         if (curP >= int(descr_cmd.size())) {
68             curP = descr_cmd.size();
69         }
71         if (curP > lastM + 1) {
72             // we have isolated a subpath, now we make a reversed version of it
73             // we do so by taking the subpath in the reverse and constructing a path as appropriate
74             // the construct is stored in "rev"
75             int curD = curP - 1;
76             NR::Point curX;
77             NR::Point nextX;
78             int firstTyp = descr_cmd[curD]->getType();
79             bool const needClose = (firstTyp == descr_close);
80             while (curD > lastM && descr_cmd[curD]->getType() == descr_close) {
81                 curD--;
82             }
84             int realP = curD + 1;
85             if (curD > lastM) {
86                 curX = PrevPoint(curD);
87                 rev->Reset ();
88                 rev->MoveTo(curX);
89                 while (curD > lastM) {
90                     int const typ = descr_cmd[curD]->getType();
91                     if (typ == descr_moveto) {
92                         //                                              rev->Close();
93                         curD--;
94                     } else if (typ == descr_forced) {
95                         //                                              rev->Close();
96                         curD--;
97                     } else if (typ == descr_lineto) {
98                         nextX = PrevPoint (curD - 1);
99                         rev->LineTo (nextX);
100                         curX = nextX;
101                         curD--;
102                     } else if (typ == descr_cubicto) {
103                         PathDescrCubicTo* nData = dynamic_cast<PathDescrCubicTo*>(descr_cmd[curD]);
104                         nextX = PrevPoint (curD - 1);
105                         NR::Point  isD=-nData->start;
106                         NR::Point  ieD=-nData->end;
107                         rev->CubicTo (nextX, ieD,isD);
108                         curX = nextX;
109                         curD--;
110                     } else if (typ == descr_arcto) {
111                         PathDescrArcTo* nData = dynamic_cast<PathDescrArcTo*>(descr_cmd[curD]);
112                         nextX = PrevPoint (curD - 1);
113                         rev->ArcTo (nextX, nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
114                         curX = nextX;
115                         curD--;
116                     } else if (typ == descr_bezierto) {
117                         nextX = PrevPoint (curD - 1);
118                         rev->LineTo (nextX);
119                         curX = nextX;
120                         curD--;
121                     }  else if (typ == descr_interm_bezier) {
122                         int nD = curD - 1;
123                         while (nD > lastM && descr_cmd[nD]->getType() != descr_bezierto) nD--;
124                         if ((descr_cmd[nD]->getType()) !=  descr_bezierto)  {
125                             // pas trouve le debut!?
126                             // Not find the start?!
127                             nextX = PrevPoint (nD);
128                             rev->LineTo (nextX);
129                             curX = nextX;
130                         } else {
131                             nextX = PrevPoint (nD - 1);
132                             rev->BezierTo (nextX);
133                             for (int i = curD; i > nD; i--) {
134                                 PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(descr_cmd[i]);
135                                 rev->IntermBezierTo (nData->p);
136                             }
137                             rev->EndBezierTo ();
138                             curX = nextX;
139                         }
140                         curD = nD - 1;
141                     } else {
142                         curD--;
143                     }
144                 }
146                 // offset the paths and glue everything
147                 // actual offseting is done in SubContractOutline()
148                 if (needClose) {
149                     rev->Close ();
150                     rev->SubContractOutline (0, rev->descr_cmd.size(),
151                                              dest, calls, 0.0025 * width * width, width,
152                                              join, butt, miter, true, false, endPos, endButt);
153                     SubContractOutline (lastM, realP + 1 - lastM,
154                                         dest, calls, 0.0025 * width * width,
155                                         width, join, butt, miter, true, false, endPos, endButt);
156                 } else {
157                     rev->SubContractOutline (0, rev->descr_cmd.size(),
158                                              dest, calls,  0.0025 * width * width, width,
159                                              join, butt, miter, false, false, endPos, endButt);
160                     NR::Point endNor=endButt.ccw();
161                     if (butt == butt_round) {
162                         dest->ArcTo (endPos+width*endNor,  1.0001 * width, 1.0001 * width, 0.0, true, true);
163                     }  else if (butt == butt_square) {
164                         dest->LineTo (endPos-width*endNor+width*endButt);
165                         dest->LineTo (endPos+width*endNor+width*endButt);
166                         dest->LineTo (endPos+width*endNor);
167                     }  else if (butt == butt_pointy) {
168                         dest->LineTo (endPos+width*endButt);
169                         dest->LineTo (endPos+width*endNor);
170                     } else {
171                         dest->LineTo (endPos+width*endNor);
172                     }
173                     SubContractOutline (lastM, realP - lastM,
174                                         dest, calls, 0.0025 * width * width,  width, join, butt,
175                                         miter, false, true, endPos, endButt);
177                     endNor=endButt.ccw();
178                     if (butt == butt_round) {
179                         dest->ArcTo (endPos+width*endNor, 1.0001 * width, 1.0001 * width, 0.0, true, true);
180                     } else if (butt == butt_square) {
181                         dest->LineTo (endPos-width*endNor+width*endButt);
182                         dest->LineTo (endPos+width*endNor+width*endButt);
183                         dest->LineTo (endPos+width*endNor);
184                     } else if (butt == butt_pointy) {
185                         dest->LineTo (endPos+width*endButt);
186                         dest->LineTo (endPos+width*endNor);
187                     } else {
188                         dest->LineTo (endPos+width*endNor);
189                     }
190                     dest->Close ();
191                 }
192             } // if (curD > lastM)
193         } // if (curP > lastM + 1)
195     } while (curP < int(descr_cmd.size()));
197     delete rev;
200 // versions for outlining closed path: they only make one side of the offset contour
201 void
202 Path::OutsideOutline (Path * dest, double width, JoinType join, ButtType butt,
203                       double miter)
205         if (descr_flags & descr_adding_bezier) {
206                 CancelBezier();
207         }
208         if (descr_flags & descr_doing_subpath) {
209                 CloseSubpath();
210         }
211         if (int(descr_cmd.size()) <= 1) return;
212         if (dest == NULL) return;
213         dest->Reset ();
214         dest->SetBackData (false);
216         outline_callbacks calls;
217         NR::Point endButt, endPos;
218         calls.cubicto = StdCubicTo;
219         calls.bezierto = StdBezierTo;
220         calls.arcto = StdArcTo;
221         SubContractOutline (0, descr_cmd.size(),
222                             dest, calls, 0.0025 * width * width, width, join, butt,
223                             miter, true, false, endPos, endButt);
226 void
227 Path::InsideOutline (Path * dest, double width, JoinType join, ButtType butt,
228                      double miter)
230         if ( descr_flags & descr_adding_bezier ) {
231                 CancelBezier();
232         }
233         if ( descr_flags & descr_doing_subpath ) {
234                 CloseSubpath();
235         }
236         if (int(descr_cmd.size()) <= 1) return;
237         if (dest == NULL) return;
238         dest->Reset ();
239         dest->SetBackData (false);
241         outline_callbacks calls;
242         NR::Point endButt, endPos;
243         calls.cubicto = StdCubicTo;
244         calls.bezierto = StdBezierTo;
245         calls.arcto = StdArcTo;
247         Path *rev = new Path;
249         int curP = 0;
250         do {
251                 int lastM = curP;
252                 do {
253                         curP++;
254                         if (curP >= int(descr_cmd.size())) break;
255                         int typ = descr_cmd[curP]->getType();
256                         if (typ == descr_moveto) break;
257                 } while (curP < int(descr_cmd.size()));
258                 if (curP >= int(descr_cmd.size()))  curP = descr_cmd.size();
259                 if (curP > lastM + 1) {
260                         // Otherwise there's only one point.  (tr: or "only a point")
261                         // [sinon il n'y a qu'un point]
262                         int curD = curP - 1;
263                         NR::Point curX;
264                         NR::Point nextX;
265                         while (curD > lastM && (descr_cmd[curD]->getType()) == descr_close) curD--;
266                         if (curD > lastM) {
267                                 curX = PrevPoint (curD);
268                                 rev->Reset ();
269                                 rev->MoveTo (curX);
270                                 while (curD > lastM) {
271                                         int typ = descr_cmd[curD]->getType();
272                                         if (typ == descr_moveto) {
273                                                 rev->Close ();
274                                                 curD--;
275                                         } else if (typ == descr_forced) {
276                                                 curD--;
277                                         } else if (typ == descr_lineto) {
278                                                 nextX = PrevPoint (curD - 1);
279                                                 rev->LineTo (nextX);
280                                                 curX = nextX;
281                                                 curD--;
282                                         }  else if (typ == descr_cubicto) {
283                                             PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo*>(descr_cmd[curD]);
284                                                 nextX = PrevPoint (curD - 1);
285                                                 NR::Point  isD=-nData->start;
286                                                 NR::Point  ieD=-nData->end;
287                                                 rev->CubicTo (nextX, ieD,isD);
288                                                 curX = nextX;
289                                                 curD--;
290                                         } else if (typ == descr_arcto) {
291                                             PathDescrArcTo* nData = dynamic_cast<PathDescrArcTo*>(descr_cmd[curD]);
292                                                 nextX = PrevPoint (curD - 1);
293                                                 rev->ArcTo (nextX, nData->rx,nData->ry,nData->angle,nData->large,nData->clockwise);
294                                                 curX = nextX;
295                                                 curD--;
296                                         } else if (typ == descr_bezierto) {
297                                                 nextX = PrevPoint (curD - 1);
298                                                 rev->LineTo (nextX);
299                                                 curX = nextX;
300                                                 curD--;
301                                         } else if (typ == descr_interm_bezier) {
302                                                 int nD = curD - 1;
303                                                 while (nD > lastM && (descr_cmd[nD]->getType()) != descr_bezierto) nD--;
304                                                 if (descr_cmd[nD]->getType() != descr_bezierto) {
305                                                         // pas trouve le debut!?
306                                                         nextX = PrevPoint (nD);
307                                                         rev->LineTo (nextX);
308                                                         curX = nextX;
309                                                 } else {
310                                                         nextX = PrevPoint (nD - 1);
311                                                         rev->BezierTo (nextX);
312                                                         for (int i = curD; i > nD; i--) {
313                                                             PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(descr_cmd[i]);
314                                                                 rev->IntermBezierTo (nData->p);
315                                                         }
316                                                         rev->EndBezierTo ();
317                                                         curX = nextX;
318                                                 }
319                                                 curD = nD - 1;
320                                         } else {
321                                                 curD--;
322                                         }
323                                 }
324                                 rev->Close ();
325                                 rev->SubContractOutline (0, rev->descr_cmd.size(),
326                                                          dest, calls, 0.0025 * width * width,
327                                                          width, join, butt, miter, true, false,
328                                                          endPos, endButt);
329                         }
330                 }
331         }  while (curP < int(descr_cmd.size()));
333         delete rev;
337 // the offset
338 // take each command and offset it.
339 // the bezier spline is split in a sequence of bezier curves, and these are transformed in cubic bezier (which is
340 // not hard since they are quadratic bezier)
341 // joins are put where needed
342 void Path::SubContractOutline(int off, int num_pd,
343                               Path *dest, outline_callbacks & calls,
344                               double tolerance, double width, JoinType join,
345                               ButtType /*butt*/, double miter, bool closeIfNeeded,
346                               bool skipMoveto, NR::Point &lastP, NR::Point &lastT)
348     outline_callback_data callsData;
350     callsData.orig = this;
351     callsData.dest = dest;
352     int curP = 1;
354     // le moveto
355     NR::Point curX;
356     {
357         int firstTyp = descr_cmd[off]->getType();
358         if ( firstTyp != descr_moveto ) {
359             curX[0] = curX[1] = 0;
360             curP = 0;
361         } else {
362             PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo*>(descr_cmd[off]);
363             curX = nData->p;
364         }
365     }
366     NR::Point curT(0, 0);
368     bool doFirst = true;
369     NR::Point firstP(0, 0);
370     NR::Point firstT(0, 0);
372         // et le reste, 1 par 1
373         while (curP < num_pd)
374         {
375             int curD = off + curP;
376                 int nType = descr_cmd[curD]->getType();
377                 NR::Point nextX;
378                 NR::Point stPos, enPos, stTgt, enTgt, stNor, enNor;
379                 double stRad, enRad, stTle, enTle;
380                 if (nType == descr_forced)  {
381                         curP++;
382                 } else if (nType == descr_moveto) {
383                         PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo*>(descr_cmd[curD]);
384                         nextX = nData->p;
385                         // et on avance
386                         if (doFirst) {
387                         } else {
388                                 if (closeIfNeeded) {
389                                         if ( NR::LInfty (curX- firstP) < 0.0001 ) {
390                                                 OutlineJoin (dest, firstP, curT, firstT, width, join,
391                                                                          miter);
392                                                 dest->Close ();
393                                         }  else {
394                                             PathDescrLineTo temp(firstP);
396                                                 TangentOnSegAt (0.0, curX, temp, stPos, stTgt,
397                                                                                 stTle);
398                                                 TangentOnSegAt (1.0, curX, temp, enPos, enTgt,
399                                                                                 enTle);
400                                                 stNor=stTgt.cw();
401                                                 enNor=enTgt.cw();
403                                                 // jointure
404                                                 {
405                                                         NR::Point pos;
406                                                         pos = curX;
407                                                         OutlineJoin (dest, pos, curT, stNor, width, join,
408                                                                                  miter);
409                                                 }
410                                                 dest->LineTo (enPos+width*enNor);
412                                                 // jointure
413                                                 {
414                                                         NR::Point pos;
415                                                         pos = firstP;
416                                                         OutlineJoin (dest, enPos, enNor, firstT, width, join,
417                                                                                  miter);
418                                                         dest->Close ();
419                                                 }
420                                         }
421                                 }
422                         }
423                         firstP = nextX;
424                         curP++;
425                 }
426                 else if (nType == descr_close)
427                 {
428                         if (doFirst == false)
429                         {
430                                 if (NR::LInfty (curX - firstP) < 0.0001)
431                                 {
432                                         OutlineJoin (dest, firstP, curT, firstT, width, join,
433                                                                  miter);
434                                         dest->Close ();
435                                 }
436                                 else
437                                 {
438                                     PathDescrLineTo temp(firstP);
439                                         nextX = firstP;
441                                         TangentOnSegAt (0.0, curX, temp, stPos, stTgt, stTle);
442                                         TangentOnSegAt (1.0, curX, temp, enPos, enTgt, enTle);
443                                         stNor=stTgt.cw();
444                                         enNor=enTgt.cw();
446                                         // jointure
447                                         {
448                                                 OutlineJoin (dest, stPos, curT, stNor, width, join,
449                                                                          miter);
450                                         }
452                                         dest->LineTo (enPos+width*enNor);
454                                         // jointure
455                                         {
456                                                 OutlineJoin (dest, enPos, enNor, firstT, width, join,
457                                                                          miter);
458                                                 dest->Close ();
459                                         }
460                                 }
461                         }
462                         doFirst = true;
463                         curP++;
464                 }
465                 else if (nType == descr_lineto)
466                 {
467                         PathDescrLineTo* nData = dynamic_cast<PathDescrLineTo*>(descr_cmd[curD]);
468                         nextX = nData->p;
469                         // test de nullité du segment
470                         if (IsNulCurve (descr_cmd, curD, curX))
471                         {
472                                 curP++;
473                                 continue;
474                         }
475                         // et on avance
476                         TangentOnSegAt (0.0, curX, *nData, stPos, stTgt, stTle);
477                         TangentOnSegAt (1.0, curX, *nData, enPos, enTgt, enTle);
478                         stNor=stTgt.cw();
479                         enNor=enTgt.cw();
481                         lastP = enPos;
482                         lastT = enTgt;
484                         if (doFirst)
485                         {
486                                 doFirst = false;
487                                 firstP = stPos;
488                                 firstT = stNor;
489                                 if (skipMoveto)
490                                 {
491                                         skipMoveto = false;
492                                 }
493                                 else
494                                         dest->MoveTo (curX+width*stNor);
495                         }
496                         else
497                         {
498                                 // jointure
499                                 NR::Point pos;
500                                 pos = curX;
501                                 OutlineJoin (dest, pos, curT, stNor, width, join, miter);
502                         }
504                         int n_d = dest->LineTo (nextX+width*enNor);
505                         if (n_d >= 0)
506                         {
507                                 dest->descr_cmd[n_d]->associated = curP;
508                                 dest->descr_cmd[n_d]->tSt = 0.0;
509                                 dest->descr_cmd[n_d]->tEn = 1.0;
510                         }
511                         curP++;
512                 }
513                 else if (nType == descr_cubicto)
514                 {
515                         PathDescrCubicTo* nData = dynamic_cast<PathDescrCubicTo*>(descr_cmd[curD]);
516                         nextX = nData->p;
517                         // test de nullite du segment
518                         if (IsNulCurve (descr_cmd, curD, curX))
519                         {
520                                 curP++;
521                                 continue;
522                         }
523                         // et on avance
524                         TangentOnCubAt (0.0, curX, *nData, false, stPos, stTgt,
525                                                         stTle, stRad);
526                         TangentOnCubAt (1.0, curX, *nData, true, enPos, enTgt,
527                                                         enTle, enRad);
528                         stNor=stTgt.cw();
529                         enNor=enTgt.cw();
531                         lastP = enPos;
532                         lastT = enTgt;
534                         if (doFirst)
535                         {
536                                 doFirst = false;
537                                 firstP = stPos;
538                                 firstT = stNor;
539                                 if (skipMoveto)
540                                 {
541                                         skipMoveto = false;
542                                 }
543                                 else
544                                         dest->MoveTo (curX+width*stNor);
545                         }
546                         else
547                         {
548                                 // jointure
549                                 NR::Point pos;
550                                 pos = curX;
551                                 OutlineJoin (dest, pos, curT, stNor, width, join, miter);
552                         }
554                         callsData.piece = curP;
555                         callsData.tSt = 0.0;
556                         callsData.tEn = 1.0;
557                         callsData.x1 = curX[0];
558                         callsData.y1 = curX[1];
559                         callsData.x2 = nextX[0];
560                         callsData.y2 = nextX[1];
561                         callsData.d.c.dx1 = nData->start[0];
562                         callsData.d.c.dy1 = nData->start[1];
563                         callsData.d.c.dx2 = nData->end[0];
564                         callsData.d.c.dy2 = nData->end[1];
565                         (calls.cubicto) (&callsData, tolerance, width);
567                         curP++;
568                 }
569                 else if (nType == descr_arcto)
570                 {
571                         PathDescrArcTo* nData = dynamic_cast<PathDescrArcTo*>(descr_cmd[curD]);
572                         nextX = nData->p;
573                         // test de nullité du segment
574                         if (IsNulCurve (descr_cmd, curD, curX))
575                         {
576                                 curP++;
577                                 continue;
578                         }
579                         // et on avance
580                         TangentOnArcAt (0.0, curX, *nData, stPos, stTgt, stTle,
581                                                         stRad);
582                         TangentOnArcAt (1.0, curX, *nData, enPos, enTgt, enTle,
583                                                         enRad);
584                         stNor=stTgt.cw();
585                         enNor=enTgt.cw();
587                         lastP = enPos;
588                         lastT = enTgt;  // tjs definie
590                         if (doFirst)
591                         {
592                                 doFirst = false;
593                                 firstP = stPos;
594                                 firstT = stNor;
595                                 if (skipMoveto)
596                                 {
597                                         skipMoveto = false;
598                                 }
599                                 else
600                                         dest->MoveTo (curX+width*stNor);
601                         }
602                         else
603                         {
604                                 // jointure
605                                 NR::Point pos;
606                                 pos = curX;
607                                 OutlineJoin (dest, pos, curT, stNor, width, join, miter);
608                         }
610                         callsData.piece = curP;
611                         callsData.tSt = 0.0;
612                         callsData.tEn = 1.0;
613                         callsData.x1 = curX[0];
614                         callsData.y1 = curX[1];
615                         callsData.x2 = nextX[0];
616                         callsData.y2 = nextX[1];
617                         callsData.d.a.rx = nData->rx;
618                         callsData.d.a.ry = nData->ry;
619                         callsData.d.a.angle = nData->angle;
620                         callsData.d.a.clock = nData->clockwise;
621                         callsData.d.a.large = nData->large;
622                         (calls.arcto) (&callsData, tolerance, width);
624                         curP++;
625                 }
626                 else if (nType == descr_bezierto)
627                 {
628                         PathDescrBezierTo* nBData = dynamic_cast<PathDescrBezierTo*>(descr_cmd[curD]);
629                         int nbInterm = nBData->nb;
630                         nextX = nBData->p;
632                         if (IsNulCurve (descr_cmd, curD, curX)) {
633                                 curP += nbInterm + 1;
634                                 continue;
635                         }
637                         curP++;
639                         curD = off + curP;
640                         int ip = curD;
641                         PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(descr_cmd[ip]);
643                         if (nbInterm <= 0) {
644                                 // et on avance
645                             PathDescrLineTo temp(nextX);
646                                 TangentOnSegAt (0.0, curX, temp, stPos, stTgt, stTle);
647                                 TangentOnSegAt (1.0, curX, temp, enPos, enTgt, enTle);
648                                 stNor=stTgt.cw();
649                                 enNor=enTgt.cw();
651                                 lastP = enPos;
652                                 lastT = enTgt;
654                                 if (doFirst) {
655                                         doFirst = false;
656                                         firstP = stPos;
657                                         firstT = stNor;
658                                         if (skipMoveto) {
659                                                 skipMoveto = false;
660                                         } else dest->MoveTo (curX+width*stNor);
661                                 } else {
662                                         // jointure
663                                         NR::Point pos;
664                                         pos = curX;
665                                         if (stTle > 0) OutlineJoin (dest, pos, curT, stNor, width, join, miter);
666                                 }
667                                 int n_d = dest->LineTo (nextX+width*enNor);
668                                 if (n_d >= 0) {
669                                         dest->descr_cmd[n_d]->associated = curP - 1;
670                                         dest->descr_cmd[n_d]->tSt = 0.0;
671                                         dest->descr_cmd[n_d]->tEn = 1.0;
672                                 }
673                         } else if (nbInterm == 1) {
674                                 NR::Point  midX;
675                                 midX = nData->p;
676                                 // et on avance
677                                 TangentOnBezAt (0.0, curX, *nData, *nBData, false, stPos, stTgt, stTle, stRad);
678                                 TangentOnBezAt (1.0, curX, *nData, *nBData, true, enPos, enTgt, enTle, enRad);
679                                 stNor=stTgt.cw();
680                                 enNor=enTgt.cw();
682                                 lastP = enPos;
683                                 lastT = enTgt;
685                                 if (doFirst) {
686                                         doFirst = false;
687                                         firstP = stPos;
688                                         firstT = stNor;
689                                         if (skipMoveto) {
690                                                 skipMoveto = false;
691                                         } else dest->MoveTo (curX+width*stNor);
692                                 }  else {
693                                         // jointure
694                                         NR::Point pos;
695                                         pos = curX;
696                                         OutlineJoin (dest, pos, curT, stNor, width, join, miter);
697                                 }
699                                 callsData.piece = curP;
700                                 callsData.tSt = 0.0;
701                                 callsData.tEn = 1.0;
702                                 callsData.x1 = curX[0];
703                                 callsData.y1 = curX[1];
704                                 callsData.x2 = nextX[0];
705                                 callsData.y2 = nextX[1];
706                                 callsData.d.b.mx = midX[0];
707                                 callsData.d.b.my = midX[1];
708                                 (calls.bezierto) (&callsData, tolerance, width);
710                         } else if (nbInterm > 1) {
711                                 NR::Point  bx=curX;
712                                 NR::Point cx=curX;
713                                 NR::Point dx=curX;
715                                 dx = nData->p;
716                                 TangentOnBezAt (0.0, curX, *nData, *nBData, false, stPos, stTgt, stTle, stRad);
717                                 stNor=stTgt.cw();
719                                 ip++;
720                                 nData = dynamic_cast<PathDescrIntermBezierTo*>(descr_cmd[ip]);
721                                 // et on avance
722                                 if (stTle > 0) {
723                                         if (doFirst) {
724                                                 doFirst = false;
725                                                 firstP = stPos;
726                                                 firstT = stNor;
727                                                 if (skipMoveto) {
728                                                         skipMoveto = false;
729                                                 } else  dest->MoveTo (curX+width*stNor);
730                                         } else {
731                                                 // jointure
732                                                 NR::Point pos=curX;
733                                                 OutlineJoin (dest, pos, stTgt, stNor, width, join,  miter);
734                                                 //                                              dest->LineTo(curX+width*stNor.x,curY+width*stNor.y);
735                                         }
736                                 }
738                                 cx = 2 * bx - dx;
740                                 for (int k = 0; k < nbInterm - 1; k++) {
741                                         bx = cx;
742                                         cx = dx;
744                                         dx = nData->p;
745                                         ip++;
746                                         nData = dynamic_cast<PathDescrIntermBezierTo*>(descr_cmd[ip]);
747                                         NR::Point stx = (bx + cx) / 2;
748                                         //                                      double  stw=(bw+cw)/2;
750                                         PathDescrBezierTo tempb((cx + dx) / 2, 1);
751                                         PathDescrIntermBezierTo tempi(cx);
752                                         TangentOnBezAt (1.0, stx, tempi, tempb, true, enPos, enTgt, enTle, enRad);
753                                         enNor=enTgt.cw();
755                                         lastP = enPos;
756                                         lastT = enTgt;
758                                         callsData.piece = curP + k;
759                                         callsData.tSt = 0.0;
760                                         callsData.tEn = 1.0;
761                                         callsData.x1 = stx[0];
762                                         callsData.y1 = stx[1];
763                                         callsData.x2 = (cx[0] + dx[0]) / 2;
764                                         callsData.y2 = (cx[1] + dx[1]) / 2;
765                                         callsData.d.b.mx = cx[0];
766                                         callsData.d.b.my = cx[1];
767                                         (calls.bezierto) (&callsData, tolerance, width);
768                                 }
769                                 {
770                                         bx = cx;
771                                         cx = dx;
773                                         dx = nextX;
774                                         dx = 2 * dx - cx;
776                                         NR::Point stx = (bx + cx) / 2;
777                                         //                                      double  stw=(bw+cw)/2;
779                                         PathDescrBezierTo tempb((cx + dx) / 2, 1);
780                                         PathDescrIntermBezierTo tempi(cx);
781                                         TangentOnBezAt (1.0, stx, tempi, tempb, true, enPos,
782                                                                         enTgt, enTle, enRad);
783                                         enNor=enTgt.cw();
785                                         lastP = enPos;
786                                         lastT = enTgt;
788                                         callsData.piece = curP + nbInterm - 1;
789                                         callsData.tSt = 0.0;
790                                         callsData.tEn = 1.0;
791                                         callsData.x1 = stx[0];
792                                         callsData.y1 = stx[1];
793                                         callsData.x2 = (cx[0] + dx[0]) / 2;
794                                         callsData.y2 = (cx[1] + dx[1]) / 2;
795                                         callsData.d.b.mx = cx[0];
796                                         callsData.d.b.my = cx[1];
797                                         (calls.bezierto) (&callsData, tolerance, width);
799                                 }
800                         }
802                         // et on avance
803                         curP += nbInterm;
804                 }
805                 curX = nextX;
806                 curT = enNor;           // sera tjs bien definie
807         }
808         if (closeIfNeeded)
809         {
810                 if (doFirst == false)
811                 {
812                 }
813         }
817 /*
818  *
819  * utilitaires pour l'outline
820  *
821  */
823 // like the name says: check whether the path command is actually more than a dumb point.
824 bool
825 Path::IsNulCurve (std::vector<PathDescr*> const &cmd, int curD, NR::Point const &curX)
827         switch(cmd[curD]->getType()) {
828     case descr_lineto:
829     {
830                 PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo*>(cmd[curD]);
831                 if (NR::LInfty(nData->p - curX) < 0.00001) {
832                         return true;
833                 }
834                 return false;
835     }
836         case descr_cubicto:
837     {
838                 PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo*>(cmd[curD]);
839                 NR::Point A = nData->start + nData->end + 2*(curX - nData->p);
840                 NR::Point B = 3*(nData->p - curX) - 2*nData->start - nData->end;
841                 NR::Point C = nData->start;
842                 if (NR::LInfty(A) < 0.0001
843                         && NR::LInfty(B) < 0.0001
844                         && NR::LInfty (C) < 0.0001) {
845                         return true;
846                 }
847                 return false;
848     }
849     case descr_arcto:
850     {
851                 PathDescrArcTo* nData = dynamic_cast<PathDescrArcTo*>(cmd[curD]);
852                 if ( NR::LInfty(nData->p - curX) < 0.00001) {
853                         if ((nData->large == false)
854                                 || (fabs (nData->rx) < 0.00001
855                                         || fabs (nData->ry) < 0.00001)) {
856                                 return true;
857                         }
858                 }
859                 return false;
860     }
861     case descr_bezierto:
862     {
863                 PathDescrBezierTo* nBData = dynamic_cast<PathDescrBezierTo*>(cmd[curD]);
864                 if (nBData->nb <= 0)
865                 {
866                         if (NR::LInfty(nBData->p - curX) < 0.00001) {
867                                 return true;
868                         }
869                         return false;
870                 }
871                 else if (nBData->nb == 1)
872                 {
873                         if (NR::LInfty(nBData->p - curX) < 0.00001) {
874                                 int ip = curD + 1;
875                                 PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(cmd[ip]);
876                                 if (NR::LInfty(nData->p - curX) < 0.00001) {
877                                         return true;
878                                 }
879                         }
880                         return false;
881                 } else if (NR::LInfty(nBData->p - curX) < 0.00001) {
882                         for (int i = 1; i <= nBData->nb; i++) {
883                                 int ip = curD + i;
884                                 PathDescrIntermBezierTo* nData = dynamic_cast<PathDescrIntermBezierTo*>(cmd[ip]);
885                                 if (NR::LInfty(nData->p - curX) > 0.00001) {
886                                         return false;
887                                 }
888                         }
889                         return true;
890                 }
891     }
892     default:
893                 return true;
894         }
897 // tangents and cuvarture computing, for the different path command types.
898 // the need for tangent is obvious: it gives the normal, along which we offset points
899 // curvature is used to do strength correction on the length of the tangents to the offset (see
900 // cubic offset)
902 /**
903  *    \param at Distance along a tangent (0 <= at <= 1).
904  *    \param iS Start point.
905  *    \param fin LineTo description containing end point.
906  *    \param pos Filled in with the position of `at' on the segment.
907  *    \param tgt Filled in with the normalised tangent vector.
908  *    \param len Filled in with the length of the segment.
909  */
911 void Path::TangentOnSegAt(double at, NR::Point const &iS, PathDescrLineTo const &fin,
912                           NR::Point &pos, NR::Point &tgt, double &len)
914     NR::Point const iE = fin.p;
915     NR::Point const seg = iE - iS;
916     double const l = L2(seg);
917     if (l <= 0.000001) {
918         pos = iS;
919         tgt = NR::Point(0, 0);
920         len = 0;
921     } else {
922         tgt = seg / l;
923         pos = (1 - at) * iS + at * iE; // in other words, pos = iS + at * seg
924         len = l;
925     }
928 // barf
929 void Path::TangentOnArcAt(double at, const NR::Point &iS, PathDescrArcTo const &fin,
930                           NR::Point &pos, NR::Point &tgt, double &len, double &rad)
932         NR::Point const iE  = fin.p;
933         double const rx = fin.rx;
934         double const ry = fin.ry;
935         double const angle = fin.angle;
936         bool const large = fin.large;
937         bool const wise = fin.clockwise;
939         pos = iS;
940         tgt[0] = tgt[1] = 0;
941         if (rx <= 0.0001 || ry <= 0.0001)
942                 return;
944         double const sex = iE[0] - iS[0], sey = iE[1] - iS[1];
945         double const ca = cos (angle), sa = sin (angle);
946         double csex =  ca * sex + sa * sey;
947         double csey = -sa * sex + ca * sey;
948         csex /= rx;
949         csey /= ry;
950         double l = csex * csex + csey * csey;
951         if (l >= 4)
952                 return;
953         double const d = sqrt(std::max(1 - l / 4, 0.0));
954         double csdx = csey;
955         double csdy = -csex;
956         l = sqrt(l);
957         csdx /= l;
958         csdy /= l;
959         csdx *= d;
960         csdy *= d;
962         double sang;
963         double eang;
964         double rax = -csdx - csex / 2;
965         double ray = -csdy - csey / 2;
966         if (rax < -1)
967         {
968                 sang = M_PI;
969         }
970         else if (rax > 1)
971         {
972                 sang = 0;
973         }
974         else
975         {
976                 sang = acos (rax);
977                 if (ray < 0)
978                         sang = 2 * M_PI - sang;
979         }
980         rax = -csdx + csex / 2;
981         ray = -csdy + csey / 2;
982         if (rax < -1)
983         {
984                 eang = M_PI;
985         }
986         else if (rax > 1)
987         {
988                 eang = 0;
989         }
990         else
991         {
992                 eang = acos (rax);
993                 if (ray < 0)
994                         eang = 2 * M_PI - eang;
995         }
997         csdx *= rx;
998         csdy *= ry;
999         double drx = ca * csdx - sa * csdy;
1000         double dry = sa * csdx + ca * csdy;
1002         if (wise)
1003         {
1004                 if (large == true)
1005                 {
1006                         drx = -drx;
1007                         dry = -dry;
1008                         double swap = eang;
1009                         eang = sang;
1010                         sang = swap;
1011                         eang += M_PI;
1012                         sang += M_PI;
1013                         if (eang >= 2 * M_PI)
1014                                 eang -= 2 * M_PI;
1015                         if (sang >= 2 * M_PI)
1016                                 sang -= 2 * M_PI;
1017                 }
1018         }
1019         else
1020         {
1021                 if (large == false)
1022                 {
1023                         drx = -drx;
1024                         dry = -dry;
1025                         double swap = eang;
1026                         eang = sang;
1027                         sang = swap;
1028                         eang += M_PI;
1029                         sang += M_PI;
1030                         if (eang >= 2 * M_PI)
1031                                 eang -= 2 * M_PI;
1032                         if (sang >= 2 * M_PI)
1033                                 sang -= 2 * M_PI;
1034                 }
1035         }
1036         drx += (iS[0] + iE[0]) / 2;
1037         dry += (iS[1] + iE[1]) / 2;
1039         if (wise) {
1040                 if (sang < eang)
1041                         sang += 2 * M_PI;
1042                 double b = sang * (1 - at) + eang * at;
1043                 double cb = cos (b), sb = sin (b);
1044                 pos[0] = drx + ca * rx * cb - sa * ry * sb;
1045                 pos[1] = dry + sa * rx * cb + ca * ry * sb;
1046                 tgt[0] = ca * rx * sb + sa * ry * cb;
1047                 tgt[1] = sa * rx * sb - ca * ry * cb;
1048                 NR::Point dtgt;
1049                 dtgt[0] = -ca * rx * cb + sa * ry * sb;
1050                 dtgt[1] = -sa * rx * cb - ca * ry * sb;
1051                 len = L2(tgt);
1052                 rad = len * dot(tgt, tgt) / (tgt[0] * dtgt[1] - tgt[1] * dtgt[0]);
1053                 tgt /= len;
1054         }
1055         else
1056         {
1057                 if (sang > eang)
1058                         sang -= 2 * M_PI;
1059                 double b = sang * (1 - at) + eang * at;
1060                 double cb = cos (b), sb = sin (b);
1061                 pos[0] = drx + ca * rx * cb - sa * ry * sb;
1062                 pos[1] = dry + sa * rx * cb + ca * ry * sb;
1063                 tgt[0] = ca * rx * sb + sa * ry * cb;
1064                 tgt[1] = sa * rx * sb - ca * ry * cb;
1065                 NR::Point dtgt;
1066                 dtgt[0] = -ca * rx * cb + sa * ry * sb;
1067                 dtgt[1] = -sa * rx * cb - ca * ry * sb;
1068                 len = L2(tgt);
1069                 rad = len * dot(tgt, tgt) / (tgt[0] * dtgt[1] - tgt[1] * dtgt[0]);
1070                 tgt /= len;
1071         }
1073 void
1074 Path::TangentOnCubAt (double at, NR::Point const &iS, PathDescrCubicTo const &fin, bool before,
1075                       NR::Point &pos, NR::Point &tgt, double &len, double &rad)
1077         const NR::Point E = fin.p;
1078         const NR::Point Sd = fin.start;
1079         const NR::Point Ed = fin.end;
1081         pos = iS;
1082         tgt = NR::Point(0,0);
1083         len = rad = 0;
1085         const NR::Point A = Sd + Ed - 2*E + 2*iS;
1086         const NR::Point B = 0.5*(Ed - Sd);
1087         const NR::Point C = 0.25*(6*E - 6*iS - Sd - Ed);
1088         const NR::Point D = 0.125*(4*iS + 4*E - Ed + Sd);
1089         const double atb = at - 0.5;
1090         pos = (atb * atb * atb)*A + (atb * atb)*B + atb*C + D;
1091         const NR::Point der = (3 * atb * atb)*A  + (2 * atb)*B + C;
1092         const NR::Point dder = (6 * atb)*A + 2*B;
1093         const NR::Point ddder = 6 * A;
1095         double l = NR::L2 (der);
1096   // lots of nasty cases. inversion points are sadly too common...
1097         if (l <= 0.0001) {
1098                 len = 0;
1099                 l = L2(dder);
1100                 if (l <= 0.0001) {
1101                         l = L2(ddder);
1102                         if (l <= 0.0001) {
1103                                 // pas de segment....
1104                                 return;
1105                         }
1106                         rad = 100000000;
1107                         tgt = ddder / l;
1108                         if (before) {
1109                                 tgt = -tgt;
1110                         }
1111                         return;
1112                 }
1113                 rad = -l * (dot(dder,dder)) / (cross(ddder,dder));
1114                 tgt = dder / l;
1115                 if (before) {
1116                         tgt = -tgt;
1117                 }
1118                 return;
1119         }
1120         len = l;
1122         rad = -l * (dot(der,der)) / (cross(dder,der));
1124         tgt = der / l;
1127 void
1128 Path::TangentOnBezAt (double at, NR::Point const &iS,
1129                       PathDescrIntermBezierTo & mid,
1130                       PathDescrBezierTo & fin, bool before, NR::Point & pos,
1131                       NR::Point & tgt, double &len, double &rad)
1133         pos = iS;
1134         tgt = NR::Point(0,0);
1135         len = rad = 0;
1137         const NR::Point A = fin.p + iS - 2*mid.p;
1138         const NR::Point B = 2*mid.p - 2 * iS;
1139         const NR::Point C = iS;
1141         pos = at * at * A + at * B + C;
1142         const NR::Point der = 2 * at * A + B;
1143         const NR::Point dder = 2 * A;
1144         double l = NR::L2(der);
1146         if (l <= 0.0001) {
1147                 l = NR::L2(dder);
1148                 if (l <= 0.0001) {
1149                         // pas de segment....
1150                         // Not a segment.
1151                         return;
1152                 }
1153                 rad = 100000000; // Why this number?
1154                 tgt = dder / l;
1155                 if (before) {
1156                         tgt = -tgt;
1157                 }
1158                 return;
1159         }
1160         len = l;
1161         rad = -l * (dot(der,der)) / (cross(dder,der));
1163         tgt = der / l;
1166 void
1167 Path::OutlineJoin (Path * dest, NR::Point pos, NR::Point stNor, NR::Point enNor, double width,
1168                    JoinType join, double miter)
1170         const double angSi = cross (enNor,stNor);
1171         const double angCo = dot (stNor, enNor);
1172         // 1/1000 is very big/ugly, but otherwise it stuffs things up a little...
1173         // 1/1000 est tres grossier, mais sinon ca merde tout azimut
1174         if ((width >= 0 && angSi > -0.001)
1175             || (width < 0 && angSi < 0.001)) {
1176                 if (angCo > 0.999) {
1177                         // straight ahead
1178                         // tout droit
1179                 } else if (angCo < -0.999) {
1180                         // half turn
1181                         // demit-tour
1182                         dest->LineTo (pos + width*enNor);
1183                 } else {
1184                         dest->LineTo (pos);
1185                         dest->LineTo (pos + width*enNor);
1186                 }
1187         } else {
1188                 if (join == join_round) {
1189                         // Use the ends of the cubic: approximate the arc at the
1190                         // point where .., and support better the rounding of
1191                         // coordinates of the end points.
1193                         // utiliser des bouts de cubique: approximation de l'arc (au point ou on en est...), et supporte mieux
1194                         // l'arrondi des coordonnees des extremites
1195                         /* double   angle=acos(angCo);
1196                            if ( angCo >= 0 ) {
1197                            NR::Point   stTgt,enTgt;
1198                            RotCCWTo(stNor,stTgt);
1199                            RotCCWTo(enNor,enTgt);
1200                            dest->CubicTo(pos.x+width*enNor.x,pos.y+width*enNor.y,
1201                            angle*width*stTgt.x,angle*width*stTgt.y,
1202                            angle*width*enTgt.x,angle*width*enTgt.y);
1203                            } else {
1204                            NR::Point   biNor;
1205                            NR::Point   stTgt,enTgt,biTgt;
1206                            biNor.x=stNor.x+enNor.x;
1207                            biNor.y=stNor.y+enNor.y;
1208                            double  biL=sqrt(biNor.x*biNor.x+biNor.y*biNor.y);
1209                            biNor.x/=biL;
1210                            biNor.y/=biL;
1211                            RotCCWTo(stNor,stTgt);
1212                            RotCCWTo(enNor,enTgt);
1213                            RotCCWTo(biNor,biTgt);
1214                            dest->CubicTo(pos.x+width*biNor.x,pos.y+width*biNor.y,
1215                            angle*width*stTgt.x,angle*width*stTgt.y,
1216                            angle*width*biTgt.x,angle*width*biTgt.y);
1217                            dest->CubicTo(pos.x+width*enNor.x,pos.y+width*enNor.y,
1218                            angle*width*biTgt.x,angle*width*biTgt.y,
1219                            angle*width*enTgt.x,angle*width*enTgt.y);
1220                            }*/
1221                         if (width > 0) {
1222                                 dest->ArcTo (pos + width*enNor,
1223                                                          1.0001 * width, 1.0001 * width, 0.0, false, true);
1224                         } else {
1225                                 dest->ArcTo (pos + width*enNor,
1226                                                          -1.0001 * width, -1.0001 * width, 0.0, false,
1227                                                          false);
1228                         }
1229                 } else if (join == join_pointy) {
1230                         NR::Point const biss = unit_vector(NR::rot90( stNor - enNor ));
1231                         double c2 = NR::dot (biss, enNor);
1232                         double l = width / c2;
1233                         if ( fabs(l) > miter) {
1234                                 dest->LineTo (pos + width*enNor);
1235                         } else {
1236                                 dest->LineTo (pos+l*biss);
1237                                 dest->LineTo (pos+width*enNor);
1238                         }
1239                 } else {
1240                         dest->LineTo (pos + width*enNor);
1241                 }
1242         }
1245 // les callbacks
1247 // see http://www.home.unix-ag.org/simon/sketch/pathstroke.py to understand what's happening here
1249 void
1250 Path::RecStdCubicTo (outline_callback_data * data, double tol, double width,
1251                      int lev)
1253         NR::Point stPos, miPos, enPos;
1254         NR::Point stTgt, enTgt, miTgt, stNor, enNor, miNor;
1255         double stRad, miRad, enRad;
1256         double stTle, miTle, enTle;
1257         // un cubic
1258         {
1259             PathDescrCubicTo temp(NR::Point(data->x2, data->y2),
1260                                     NR::Point(data->d.c.dx1, data->d.c.dy1),
1261                                     NR::Point(data->d.c.dx2, data->d.c.dy2));
1263                 NR::Point initial_point(data->x1, data->y1);
1264                 TangentOnCubAt (0.0, initial_point, temp, false, stPos, stTgt, stTle,
1265                                                 stRad);
1266                 TangentOnCubAt (0.5, initial_point, temp, false, miPos, miTgt, miTle,
1267                                                 miRad);
1268                 TangentOnCubAt (1.0, initial_point, temp, true, enPos, enTgt, enTle,
1269                                                 enRad);
1270                 stNor=stTgt.cw();
1271                 miNor=miTgt.cw();
1272                 enNor=enTgt.cw();
1273         }
1275         double stGue = 1, miGue = 1, enGue = 1;
1276   // correction of the lengths of the tangent to the offset
1277   // if you don't see why i wrote that, draw a little figure and everything will be clear
1278         if (fabs (stRad) > 0.01)
1279                 stGue += width / stRad;
1280         if (fabs (miRad) > 0.01)
1281                 miGue += width / miRad;
1282         if (fabs (enRad) > 0.01)
1283                 enGue += width / enRad;
1284         stGue *= stTle;
1285         miGue *= miTle;
1286         enGue *= enTle;
1289         if (lev <= 0) {
1290                 int n_d = data->dest->CubicTo (enPos + width*enNor,
1291                                                                            stGue*stTgt,
1292                                                                            enGue*enTgt);
1293                 if (n_d >= 0) {
1294                         data->dest->descr_cmd[n_d]->associated = data->piece;
1295                         data->dest->descr_cmd[n_d]->tSt = data->tSt;
1296                         data->dest->descr_cmd[n_d]->tEn = data->tEn;
1297                 }
1298                 return;
1299         }
1301         NR::Point chk;
1302         const NR::Point req = miPos + width * miNor;
1303         {
1304             PathDescrCubicTo temp(enPos + width * enNor,
1305                                     stGue * stTgt,
1306                                     enGue * enTgt);
1307                 double chTle, chRad;
1308                 NR::Point chTgt;
1309                 TangentOnCubAt (0.5, stPos+width*stNor,
1310                                                 temp, false, chk, chTgt, chTle, chRad);
1311         }
1312         const NR::Point diff = req - chk;
1313         const double err = dot(diff,diff);
1314         if (err <= tol ) {  // tolerance is given as a quadratic value, no need to use tol*tol here
1315 //    printf("%f <= %f %i\n",err,tol,lev);
1316                 int n_d = data->dest->CubicTo (enPos + width*enNor,
1317                                                                            stGue*stTgt,
1318                                                                            enGue*enTgt);
1319                 if (n_d >= 0) {
1320                         data->dest->descr_cmd[n_d]->associated = data->piece;
1321                         data->dest->descr_cmd[n_d]->tSt = data->tSt;
1322                         data->dest->descr_cmd[n_d]->tEn = data->tEn;
1323                 }
1324         } else {
1325                 outline_callback_data desc = *data;
1327                 desc.tSt = data->tSt;
1328                 desc.tEn = (data->tSt + data->tEn) / 2;
1329                 desc.x1 = data->x1;
1330                 desc.y1 = data->y1;
1331                 desc.x2 = miPos[0];
1332                 desc.y2 = miPos[1];
1333                 desc.d.c.dx1 = 0.5 * stTle * stTgt[0];
1334                 desc.d.c.dy1 = 0.5 * stTle * stTgt[1];
1335                 desc.d.c.dx2 = 0.5 * miTle * miTgt[0];
1336                 desc.d.c.dy2 = 0.5 * miTle * miTgt[1];
1337                 RecStdCubicTo (&desc, tol, width, lev - 1);
1339                 desc.tSt = (data->tSt + data->tEn) / 2;
1340                 desc.tEn = data->tEn;
1341                 desc.x1 = miPos[0];
1342                 desc.y1 = miPos[1];
1343                 desc.x2 = data->x2;
1344                 desc.y2 = data->y2;
1345                 desc.d.c.dx1 = 0.5 * miTle * miTgt[0];
1346                 desc.d.c.dy1 = 0.5 * miTle * miTgt[1];
1347                 desc.d.c.dx2 = 0.5 * enTle * enTgt[0];
1348                 desc.d.c.dy2 = 0.5 * enTle * enTgt[1];
1349                 RecStdCubicTo (&desc, tol, width, lev - 1);
1350         }
1353 void
1354 Path::StdCubicTo (Path::outline_callback_data * data, double tol, double width)
1356 //      fflush (stdout);
1357         RecStdCubicTo (data, tol, width, 8);
1360 void
1361 Path::StdBezierTo (Path::outline_callback_data * data, double tol, double width)
1363     PathDescrBezierTo tempb(NR::Point(data->x2, data->y2), 1);
1364     PathDescrIntermBezierTo tempi(NR::Point(data->d.b.mx, data->d.b.my));
1365         NR::Point stPos, enPos, stTgt, enTgt;
1366         double stRad, enRad, stTle, enTle;
1367         NR::Point  tmp(data->x1,data->y1);
1368         TangentOnBezAt (0.0, tmp, tempi, tempb, false, stPos, stTgt,
1369                                         stTle, stRad);
1370         TangentOnBezAt (1.0, tmp, tempi, tempb, true, enPos, enTgt,
1371                                         enTle, enRad);
1372         data->d.c.dx1 = stTle * stTgt[0];
1373         data->d.c.dy1 = stTle * stTgt[1];
1374         data->d.c.dx2 = enTle * enTgt[0];
1375         data->d.c.dy2 = enTle * enTgt[1];
1376         RecStdCubicTo (data, tol, width, 8);
1379 void
1380 Path::RecStdArcTo (outline_callback_data * data, double tol, double width,
1381                    int lev)
1383         NR::Point stPos, miPos, enPos;
1384         NR::Point stTgt, enTgt, miTgt, stNor, enNor, miNor;
1385         double stRad, miRad, enRad;
1386         double stTle, miTle, enTle;
1387         // un cubic
1388         {
1389             PathDescrArcTo temp(NR::Point(data->x2, data->y2),
1390                                   data->d.a.rx, data->d.a.ry,
1391                                   data->d.a.angle, data->d.a.large, data->d.a.clock);
1393                 NR::Point tmp(data->x1,data->y1);
1394                 TangentOnArcAt (data->d.a.stA, tmp, temp, stPos, stTgt,
1395                                                 stTle, stRad);
1396                 TangentOnArcAt ((data->d.a.stA + data->d.a.enA) / 2, tmp,
1397                                                 temp, miPos, miTgt, miTle, miRad);
1398                 TangentOnArcAt (data->d.a.enA, tmp, temp, enPos, enTgt,
1399                                                 enTle, enRad);
1400                 stNor=stTgt.cw();
1401                 miNor=miTgt.cw();
1402                 enNor=enTgt.cw();
1403         }
1405         double stGue = 1, miGue = 1, enGue = 1;
1406         if (fabs (stRad) > 0.01)
1407                 stGue += width / stRad;
1408         if (fabs (miRad) > 0.01)
1409                 miGue += width / miRad;
1410         if (fabs (enRad) > 0.01)
1411                 enGue += width / enRad;
1412         stGue *= stTle;
1413         miGue *= miTle;
1414         enGue *= enTle;
1415         double sang, eang;
1416         {
1417                 NR::Point  tms(data->x1,data->y1),tme(data->x2,data->y2);
1418                 ArcAngles (tms,tme, data->d.a.rx,
1419                                    data->d.a.ry, data->d.a.angle, data->d.a.large, !data->d.a.clock,
1420                                    sang, eang);
1421         }
1422         double scal = eang - sang;
1423         if (scal < 0)
1424                 scal += 2 * M_PI;
1425         if (scal > 2 * M_PI)
1426                 scal -= 2 * M_PI;
1427         scal *= data->d.a.enA - data->d.a.stA;
1429         if (lev <= 0)
1430         {
1431                 int n_d = data->dest->CubicTo (enPos + width*enNor,
1432                                                                            stGue*scal*stTgt,
1433                                                                            enGue*scal*enTgt);
1434                 if (n_d >= 0) {
1435                         data->dest->descr_cmd[n_d]->associated = data->piece;
1436                         data->dest->descr_cmd[n_d]->tSt = data->d.a.stA;
1437                         data->dest->descr_cmd[n_d]->tEn = data->d.a.enA;
1438                 }
1439                 return;
1440         }
1442         NR::Point chk;
1443         const NR::Point req = miPos + width*miNor;
1444         {
1445             PathDescrCubicTo temp(enPos + width * enNor, stGue * scal * stTgt, enGue * scal * enTgt);
1446                 double chTle, chRad;
1447                 NR::Point chTgt;
1448                 TangentOnCubAt (0.5, stPos+width*stNor,
1449                                                 temp, false, chk, chTgt, chTle, chRad);
1450         }
1451         const NR::Point diff = req - chk;
1452         const double err = (dot(diff,diff));
1453         if (err <= tol * tol)
1454         {
1455                 int n_d = data->dest->CubicTo (enPos + width*enNor,
1456                                                                            stGue*scal*stTgt,
1457                                                                            enGue*scal*enTgt);
1458                 if (n_d >= 0) {
1459                         data->dest->descr_cmd[n_d]->associated = data->piece;
1460                         data->dest->descr_cmd[n_d]->tSt = data->d.a.stA;
1461                         data->dest->descr_cmd[n_d]->tEn = data->d.a.enA;
1462                 }
1463         } else {
1464                 outline_callback_data desc = *data;
1466                 desc.d.a.stA = data->d.a.stA;
1467                 desc.d.a.enA = (data->d.a.stA + data->d.a.enA) / 2;
1468                 RecStdArcTo (&desc, tol, width, lev - 1);
1470                 desc.d.a.stA = (data->d.a.stA + data->d.a.enA) / 2;
1471                 desc.d.a.enA = data->d.a.enA;
1472                 RecStdArcTo (&desc, tol, width, lev - 1);
1473         }
1476 void
1477 Path::StdArcTo (Path::outline_callback_data * data, double tol, double width)
1479         data->d.a.stA = 0.0;
1480         data->d.a.enA = 1.0;
1481         RecStdArcTo (data, tol, width, 8);
1484 /*
1485   Local Variables:
1486   mode:c++
1487   c-file-style:"stroustrup"
1488   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1489   indent-tabs-mode:nil
1490   fill-column:99
1491   End:
1492 */
1493 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :