Logo Search packages:      
Sourcecode: inkscape version File versions  Download package

PathConversion.cpp

/*
 *  PathConversion.cpp
 *  nlivarot
 *
 *  Created by fred on Mon Nov 03 2003.
 *
 */

#include "Path.h"
#include "Shape.h"
#include "livarot/path-description.h"

#include <libnr/nr-point-fns.h>
#include <libnr/nr-matrix.h>
#include <libnr/nr-rotate-ops.h>
#include <libnr/nr-scale-ops.h>

/*
 * path description -> polyline
 * and Path -> Shape (the Fill() function at the bottom)
 * nathing fancy here: take each command and append an approximation of it to the polyline
 */

void Path::ConvertWithBackData(double treshhold)
{
    if ( descr_flags & descr_adding_bezier ) {
        CancelBezier();
    }
    
    if ( descr_flags & descr_doing_subpath ) {
        CloseSubpath();
    }
    
    SetBackData(true);
    ResetPoints();
    if ( descr_cmd.empty() ) {
        return;
    }
    
    NR::Point curX;
    int curP = 1;
    int lastMoveTo = -1;
      
    // le moveto
    {
        int const firstTyp = descr_cmd[0]->getType();
        if ( firstTyp == descr_moveto ) {
            curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
        } else {
            curP = 0;
            curX[NR::X] = curX[NR::Y] = 0;
        }
        lastMoveTo = AddPoint(curX, 0, 0.0, true);
    }
    
    // et le reste, 1 par 1
    while ( curP < int(descr_cmd.size()) ) {

        int nType = descr_cmd[curP]->getType();
        NR::Point nextX;

        if ( nType == descr_forced ) {

            AddForcedPoint(curX, curP, 1.0);
            curP++;

        } else if ( nType == descr_moveto ) {
            
            PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo*>(descr_cmd[curP]);
            nextX = nData->p;
            lastMoveTo = AddPoint(nextX, curP, 0.0, true);
            // et on avance
            curP++;
            
        } else if ( nType == descr_close ) {

            nextX = pts[lastMoveTo].p;
            AddPoint(nextX, curP, 1.0, false);
            curP++;
            
        } else if ( nType == descr_lineto ) {

            PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
            nextX = nData->p;
            AddPoint(nextX,curP,1.0,false);
            // et on avance
            curP++;
            
        } else if ( nType == descr_cubicto ) {
            PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
            nextX = nData->p;
            RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 0.0, 1.0, curP);
            AddPoint(nextX, curP, 1.0, false);
            // et on avance
            curP++;
            
        } else if ( nType == descr_arcto ) {
            PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
            nextX = nData->p;
            DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold, curP);
            AddPoint(nextX, curP, 1.0, false);
            // et on avance
            curP++;
            
        } else if ( nType == descr_bezierto ) {
            PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
            int nbInterm = nBData->nb;
            nextX = nBData->p;
                  
            int ip = curP + 1;
            PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                  
            if ( nbInterm >= 1 ) {
                NR::Point bx = curX;
                NR::Point cx = curX;
                NR::Point dx = curX;
        
                dx = nData->p;
                ip++;
                nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                
                cx = 2 * bx - dx;
        
                for (int k = 0; k < nbInterm - 1; k++) {
                    bx = cx;
                    cx = dx;
          
                    dx = nData->p;
                    ip++;
                    nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
          
                    NR::Point stx;
                    stx = (bx + cx) / 2;
                    if ( k > 0 ) {
                        AddPoint(stx,curP - 1+k,1.0,false);
                    }
          
                    {
                        NR::Point mx;
                        mx = (cx + dx) / 2;
                        RecBezierTo(cx, stx, mx, treshhold, 8, 0.0, 1.0, curP + k);
                    }
                }
                {
                    bx = cx;
                    cx = dx;
                    
                    dx = nextX;
                    dx = 2 * dx - cx;
          
                    NR::Point stx;
                    stx = (bx + cx) / 2;
          
                    if ( nbInterm > 1 ) {
                        AddPoint(stx, curP + nbInterm - 2, 1.0, false);
                    }
          
                    {
                        NR::Point mx;
                        mx = (cx + dx) / 2;
                        RecBezierTo(cx, stx, mx, treshhold, 8, 0.0, 1.0, curP + nbInterm - 1);
                    }
                }
                
            }
                  
                  
            AddPoint(nextX, curP - 1 + nbInterm, 1.0, false);
                  
            // et on avance
            curP += 1 + nbInterm;
        }
        curX = nextX;
    }
}


void Path::Convert(double treshhold)
{
    if ( descr_flags & descr_adding_bezier ) {
        CancelBezier();
    }
    
    if ( descr_flags & descr_doing_subpath ) {
        CloseSubpath();
    }
    
    SetBackData(false);
    ResetPoints();
    if ( descr_cmd.empty() ) {
        return;
    }
    
    NR::Point curX;
    int curP = 1;
    int lastMoveTo = 0;
      
    // le moveto
    {
        int const firstTyp = descr_cmd[0]->getType();
        if ( firstTyp == descr_moveto ) {
            curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
        } else {
            curP = 0;
            curX[0] = curX[1] = 0;
        }
        lastMoveTo = AddPoint(curX, true);
    }
    descr_cmd[0]->associated = lastMoveTo;
      
    // et le reste, 1 par 1
    while ( curP < int(descr_cmd.size()) ) {
        
        int const nType = descr_cmd[curP]->getType();
        NR::Point nextX;

        if ( nType == descr_forced ) {

            descr_cmd[curP]->associated = AddForcedPoint(curX);
            curP++;
            
        } else if ( nType == descr_moveto ) {

            PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
            nextX = nData->p;
            lastMoveTo = AddPoint(nextX, true);
            descr_cmd[curP]->associated = lastMoveTo;

            // et on avance
            curP++;
            
        } else if ( nType == descr_close ) {
            
            nextX = pts[lastMoveTo].p;
            descr_cmd[curP]->associated = AddPoint(nextX, false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }
            curP++;
            
        } else if ( nType == descr_lineto ) {

            PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
            nextX = nData->p;
            descr_cmd[curP]->associated = AddPoint(nextX, false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }
            // et on avance
            curP++;
            
        } else if ( nType == descr_cubicto ) {
            PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
            nextX = nData->p;
            RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8);
            descr_cmd[curP]->associated = AddPoint(nextX,false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }
            // et on avance
            curP++;
            
        } else if ( nType == descr_arcto ) {
            
            PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
            nextX = nData->p;
            DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
            descr_cmd[curP]->associated = AddPoint(nextX, false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }
            // et on avance
            curP++;
            
        } else if ( nType == descr_bezierto ) {
            PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
            int nbInterm = nBData->nb;
            nextX = nBData->p;
            int curBD = curP;
                  
            curP++;
            int ip = curP;
            PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                  
            if ( nbInterm == 1 ) {
                NR::Point const midX = nData->p;
                RecBezierTo(midX, curX, nextX, treshhold, 8);
            } else if ( nbInterm > 1 ) {
                NR::Point bx = curX;
                NR::Point cx = curX;
                NR::Point dx = curX;
                                                
                dx = nData->p;
                ip++;
                nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                        
                cx = 2 * bx - dx;
                        
                for (int k = 0; k < nbInterm - 1; k++) {
                    bx = cx;
                    cx = dx;
                              
                    dx = nData->p;
                    ip++;
                    nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                              
                    NR::Point stx = (bx + cx) / 2;
                    if ( k > 0 ) {
                        descr_cmd[ip - 2]->associated = AddPoint(stx, false);
                        if ( descr_cmd[ip - 2]->associated < 0 ) {
                            if ( curP == 0 ) {
                                descr_cmd[ip - 2]->associated = 0;
                            } else {
                                descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
                            }
                        }
                    }
                    
                    {
                        NR::Point const mx = (cx + dx) / 2;
                        RecBezierTo(cx, stx, mx, treshhold, 8);
                    }
                }
                
                {
                    bx = cx;
                    cx = dx;
                              
                    dx = nextX;
                    dx = 2 * dx - cx;
                              
                    NR::Point stx = (bx + cx) / 2;
                              
                    descr_cmd[ip - 1]->associated = AddPoint(stx, false);
                    if ( descr_cmd[ip - 1]->associated < 0 ) {
                        if ( curP == 0 ) {
                            descr_cmd[ip - 1]->associated = 0;
                        } else {
                            descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
                        }
                    }
                    
                    {
                        NR::Point mx = (cx + dx) / 2;
                        RecBezierTo(cx, stx, mx, treshhold, 8);
                    }
                }
            }

            descr_cmd[curBD]->associated = AddPoint(nextX, false);
            if ( descr_cmd[curBD]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curBD]->associated = 0;
                } else {
                    descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
                }
            }
            
            // et on avance
            curP += nbInterm;
        }
        
        curX = nextX;
    }
}



void Path::ConvertEvenLines(double treshhold)
{
    if ( descr_flags & descr_adding_bezier ) {
        CancelBezier();
    }
    
    if ( descr_flags & descr_doing_subpath ) {
        CloseSubpath();
    }
    
    SetBackData(false);
    ResetPoints();
    if ( descr_cmd.empty() ) {
        return;
    }
    
    NR::Point curX;
    int curP = 1;
    int lastMoveTo = 0;
      
    // le moveto
    {
        int const firstTyp = descr_cmd[0]->getType();
        if ( firstTyp == descr_moveto ) {
            curX = dynamic_cast<PathDescrMoveTo *>(descr_cmd[0])->p;
        } else {
            curP = 0;
            curX[0] = curX[1] = 0;
        }
        lastMoveTo = AddPoint(curX, true);
    }
    descr_cmd[0]->associated = lastMoveTo;
      
    // et le reste, 1 par 1
    while ( curP < int(descr_cmd.size()) ) {
        
        int const nType = descr_cmd[curP]->getType();
        NR::Point nextX;
        
        if ( nType == descr_forced ) {
            
            descr_cmd[curP]->associated = AddForcedPoint(curX);
            curP++;
            
        } else if ( nType == descr_moveto ) {
            
            PathDescrMoveTo* nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[curP]);
            nextX = nData->p;
            lastMoveTo = AddPoint(nextX,true);
            descr_cmd[curP]->associated = lastMoveTo;

            // et on avance
            curP++;
            
        } else if ( nType == descr_close ) {
            
            nextX = pts[lastMoveTo].p;
            {
                NR::Point nexcur;
                nexcur = nextX - curX;
                const double segL = NR::L2(nexcur);
                if ( segL > treshhold ) {
                    for (double i = treshhold; i < segL; i += treshhold) {
                        NR::Point nX;
                        nX = (segL - i) * curX + i * nextX;
                        nX /= segL;
                        AddPoint(nX);
                    }
                }
            }
            
            descr_cmd[curP]->associated = AddPoint(nextX,false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }
            
            curP++;
            
        } else if ( nType == descr_lineto ) {

            PathDescrLineTo* nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[curP]);
            nextX = nData->p;
            NR::Point nexcur = nextX - curX;
            const double segL = L2(nexcur);
            if ( segL > treshhold ) {
                for (double i = treshhold; i < segL; i += treshhold) {
                    NR::Point nX = ((segL - i) * curX + i * nextX) / segL;
                    AddPoint(nX);
                }
            }
            
            descr_cmd[curP]->associated = AddPoint(nextX,false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }
            // et on avance
            curP++;
            
        } else if ( nType == descr_cubicto ) {
            
            PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[curP]);
            nextX = nData->p;
            RecCubicTo(curX, nData->start, nextX, nData->end, treshhold, 8, 4 * treshhold);
            descr_cmd[curP]->associated = AddPoint(nextX, false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }
            // et on avance
            curP++;
            
        } else if ( nType == descr_arcto ) {

            PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[curP]);
            nextX = nData->p;
            DoArc(curX, nextX, nData->rx, nData->ry, nData->angle, nData->large, nData->clockwise, treshhold);
            descr_cmd[curP]->associated =AddPoint(nextX, false);
            if ( descr_cmd[curP]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curP]->associated = 0;
                } else {
                    descr_cmd[curP]->associated = descr_cmd[curP - 1]->associated;
                }
            }

            // et on avance
            curP++;

        } else if ( nType == descr_bezierto ) {
            PathDescrBezierTo *nBData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[curP]);
            int nbInterm = nBData->nb;
            nextX = nBData->p;
            int curBD = curP;
                  
            curP++;
            int ip = curP;
            PathDescrIntermBezierTo *nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                  
            if ( nbInterm == 1 ) {
                NR::Point const midX = nData->p;
                RecBezierTo(midX, curX, nextX, treshhold, 8, 4 * treshhold);
            } else if ( nbInterm > 1 ) {
                NR::Point bx = curX;
                NR::Point cx = curX;
                NR::Point dx = curX;
                                                
                dx = nData->p;
                ip++;
                nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                
                cx = 2 * bx - dx;
                        
                for (int k = 0; k < nbInterm - 1; k++) {
                    bx = cx;
                    cx = dx;
                    dx = nData->p;

                    ip++;
                    nData = dynamic_cast<PathDescrIntermBezierTo *>(descr_cmd[ip]);
                              
                    NR::Point stx = (bx+cx) / 2;
                    if ( k > 0 ) {
                        descr_cmd[ip - 2]->associated = AddPoint(stx, false);
                        if ( descr_cmd[ip - 2]->associated < 0 ) {
                            if ( curP == 0 ) {
                                descr_cmd[ip- 2]->associated = 0;
                            } else {
                                descr_cmd[ip - 2]->associated = descr_cmd[ip - 3]->associated;
                            }
                        }
                    }
                    
                    {
                        NR::Point const mx = (cx + dx) / 2;
                        RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
                    }
                }
                
                {
                    bx = cx;
                    cx = dx;
                              
                    dx = nextX;
                    dx = 2 * dx - cx;
                              
                    NR::Point const stx = (bx + cx) / 2;
                              
                    descr_cmd[ip - 1]->associated = AddPoint(stx, false);
                    if ( descr_cmd[ip - 1]->associated < 0 ) {
                        if ( curP == 0 ) {
                            descr_cmd[ip - 1]->associated = 0;
                        } else {
                            descr_cmd[ip - 1]->associated = descr_cmd[ip - 2]->associated;
                        }
                    }
                    
                    {
                        NR::Point const mx = (cx + dx) / 2;
                        RecBezierTo(cx, stx, mx, treshhold, 8, 4 * treshhold);
                    }
                }
            }
            
            descr_cmd[curBD]->associated = AddPoint(nextX, false);
            if ( descr_cmd[curBD]->associated < 0 ) {
                if ( curP == 0 ) {
                    descr_cmd[curBD]->associated = 0;
                } else {
                    descr_cmd[curBD]->associated = descr_cmd[curBD - 1]->associated;
                }
            }
            
            // et on avance
            curP += nbInterm;
        }
        if ( NR::LInfty(curX - nextX) > 0.00001 ) {
            curX = nextX;
        }
    }
}

const NR::Point Path::PrevPoint(int i) const
{
    /* TODO: I suspect this should assert `(unsigned) i < descr_nb'.  We can probably change
       the argument to unsigned.  descr_nb should probably be changed to unsigned too. */
    g_assert( i >= 0 );
    switch ( descr_cmd[i]->getType() ) {
        case descr_moveto: {
            PathDescrMoveTo *nData = dynamic_cast<PathDescrMoveTo *>(descr_cmd[i]);
            return nData->p;
        }
        case descr_lineto: {
            PathDescrLineTo *nData = dynamic_cast<PathDescrLineTo *>(descr_cmd[i]);
            return nData->p;
        }
        case descr_arcto: {
            PathDescrArcTo *nData = dynamic_cast<PathDescrArcTo *>(descr_cmd[i]);
            return nData->p;
        }
        case descr_cubicto: {
            PathDescrCubicTo *nData = dynamic_cast<PathDescrCubicTo *>(descr_cmd[i]);
            return nData->p;
        }
        case descr_bezierto: {
            PathDescrBezierTo *nData = dynamic_cast<PathDescrBezierTo *>(descr_cmd[i]);
            return nData->p;
        }
        case descr_interm_bezier:
        case descr_close:
        case descr_forced:
            return PrevPoint(i - 1);
        default:
            g_assert_not_reached();
            return NR::Point(0, 0);
    }
}

// utilitaries: given a quadratic bezier curve (start point, control point, end point, ie that's a clamped curve),
// and an abcissis on it, get the point with that abcissis.
// warning: it's NOT a curvilign abcissis (or whatever you call that in english), so "t" is NOT the length of "start point"->"result point"
void Path::QuadraticPoint(double t, NR::Point &oPt, 
                          const NR::Point &iS, const NR::Point &iM, const NR::Point &iE)
{
    NR::Point const ax = iE - 2 * iM + iS;
    NR::Point const bx = 2 * iM - 2 * iS;
    NR::Point const cx = iS;
      
    oPt = t * t * ax + t * bx + cx;
}
// idem for cubic bezier patch
void Path::CubicTangent(double t, NR::Point &oPt, const NR::Point &iS, const NR::Point &isD,
                        const NR::Point &iE, const NR::Point &ieD)
{
    NR::Point const ax = ieD - 2 * iE + 2 * iS + isD;
    NR::Point const bx = 3 * iE - ieD - 2 * isD - 3 * iS;
    NR::Point const cx = isD;
      
    oPt = 3 * t * t * ax + 2 * t * bx + cx;
}

// extract interesting info of a SVG arc description
static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
                         double rx, double ry, double angle,
                         bool large, bool wise,
                         double &sang, double &eang, NR::Point &dr);

void Path::ArcAngles(const NR::Point &iS, const NR::Point &iE,
                     double rx, double ry, double angle, bool large, bool wise, double &sang, double &eang)
{
    NR::Point dr;
    ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
}

/* N.B. If iS == iE then sang,eang,dr each become NaN.  Probably a bug. */
static void ArcAnglesAndCenter(NR::Point const &iS, NR::Point const &iE,
                               double rx, double ry, double angle,
                               bool large, bool wise,
                               double &sang, double &eang, NR::Point &dr)
{
    NR::Point se = iE - iS;
    NR::Point ca(cos(angle), sin(angle));
    NR::Point cse(dot(se, ca), cross(se, ca));
    cse[0] /= rx;
    cse[1] /= ry;
    double const lensq = dot(cse,cse);
    NR::Point csd = ( ( lensq < 4
                        ? sqrt( 1/lensq - .25 )
                        : 0.0 )
                      * cse.ccw() );

    NR::Point ra = -csd - 0.5 * cse;
    if ( ra[0] <= -1 ) {
        sang = M_PI;
    } else if ( ra[0] >= 1 ) {
        sang = 0;
    } else {
        sang = acos(ra[0]);
        if ( ra[1] < 0 ) {
            sang = 2 * M_PI - sang;
        }
    }

    ra = -csd + 0.5 * cse;
    if ( ra[0] <= -1 ) {
        eang = M_PI;
    } else if ( ra[0] >= 1 ) {
        eang = 0;
    } else {
        eang = acos(ra[0]);
        if ( ra[1] < 0 ) {
            eang = 2 * M_PI - eang;
        }
    }
      
    csd[0] *= rx;
    csd[1] *= ry;
    ca[1] = -ca[1]; // because it's the inverse rotation

    dr[0] = dot(csd, ca);
    dr[1] = cross(csd, ca);

    ca[1] = -ca[1];
      
    if ( wise ) {

        if (large) {
            dr = -dr;
            double swap = eang;
            eang = sang;
            sang = swap;
            eang += M_PI;
            sang += M_PI;
            if ( eang >= 2*M_PI ) {
                eang -= 2*M_PI;
            }
            if ( sang >= 2*M_PI ) {
                sang -= 2*M_PI;
            }
        }
        
    } else {
        if (!large) {
            dr = -dr;
            double swap = eang;
            eang = sang;
            sang = swap;
            eang += M_PI;
            sang += M_PI;
            if ( eang >= 2*M_PI ) {
                eang -= 2 * M_PI;
            }
            if ( sang >= 2*M_PI ) {
                sang -= 2 * M_PI;
            }
        }
    }
    
    dr += 0.5 * (iS + iE);
}



void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
                 double const rx, double const ry, double const angle,
                 bool const large, bool const wise, double const /*tresh*/)
{
    /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
       apart than the diameter.  Also check that we do the right thing for negative radius.
       (Same for the other DoArc functions in this file.) */
    if ( rx <= 0.0001 || ry <= 0.0001 ) {
        return;
        // We always add a lineto afterwards, so this is fine.
        // [on ajoute toujours un lineto apres, donc c bon]
    }

    double sang;
    double eang;
    NR::Point dr;
    ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
    /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
       the case of low curvature (i.e. very large radius). */

    NR::scale const ar(rx, ry);
    NR::rotate cb( angle + sang );
    if (wise) {

        double const incr = -0.1;
        if ( sang < eang ) {
            sang += 2*M_PI;
        }
        NR::rotate const omega(incr);
        for (double b = sang + incr ; b > eang ; b += incr) {
            cb = omega * cb;
            AddPoint( cb.vec * ar + dr );
        }
        
    } else {
        
        double const incr = 0.1;
        if ( sang > eang ) {
            sang -= 2*M_PI;
        }
        NR::rotate const omega(incr);
        for (double b = sang + incr ; b < eang ; b += incr) {
            cb = omega * cb;
            AddPoint( cb.vec * ar + dr);
        }
    }
}


void Path::RecCubicTo( NR::Point const &iS, NR::Point const &isD, 
                       NR::Point const &iE, NR::Point const &ieD,
                       double tresh, int lev, double maxL)
{
    NR::Point se = iE - iS;
    const double dC = NR::L2(se);
    if ( dC < 0.01 ) {

        const double sC = dot(isD,isD);
        const double eC = dot(ieD,ieD);
        if ( sC < tresh && eC < tresh ) {
            return;
        }
        
    } else {
        const double sC = fabs(cross(se, isD)) / dC;
        const double eC = fabs(cross(se, ieD)) / dC;
        if ( sC < tresh && eC < tresh ) {
            // presque tt droit -> attention si on nous demande de bien subdiviser les petits segments
            if ( maxL > 0 && dC > maxL ) {
                if ( lev <= 0 ) {
                    return;
                }
                NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
                NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
                        
                NR::Point hisD = 0.5 * isD;
                NR::Point hieD = 0.5 * ieD;
                        
                RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
                AddPoint(m);
                RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
            }
            return;
        }
    }
      
    if ( lev <= 0 ) {
        return;
    }
    
    {
        NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
        NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
                        
        NR::Point hisD = 0.5 * isD;
        NR::Point hieD = 0.5 * ieD;
    
        RecCubicTo(iS, hisD, m, md, tresh, lev - 1, maxL);
        AddPoint(m);
        RecCubicTo(m, md, iE, hieD, tresh, lev - 1,maxL);
    }
}



void Path::RecBezierTo(const NR::Point &iP,
                       const NR::Point &iS,
                       const NR::Point &iE,
                       double tresh, int lev, double maxL)
{
    if ( lev <= 0 ) {
        return;
    }
    
    NR::Point ps = iS - iP;
    NR::Point pe = iE - iP;
    NR::Point se = iE - iS;
    double s = fabs(cross(pe, ps));
    if ( s < tresh ) {
        const double l = L2(se);
        if ( maxL > 0 && l > maxL ) {
            const NR::Point m = 0.25 * (iS + iE + 2 * iP);
            NR::Point md = 0.5 * (iS + iP);
            RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
            AddPoint(m);
            md = 0.5 * (iP + iE);
            RecBezierTo(md, m, iE, tresh, lev - 1, maxL);   
        }
        return;
    }
    
    {
        const NR::Point m = 0.25 * (iS + iE + 2 * iP);
        NR::Point md = 0.5 * (iS + iP);
        RecBezierTo(md, iS, m, tresh, lev - 1, maxL);
        AddPoint(m);
        md = 0.5 * (iP + iE);
        RecBezierTo(md, m, iE, tresh, lev - 1, maxL); 
    }
}


void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
                 double const rx, double const ry, double const angle,
                 bool const large, bool const wise, double const /*tresh*/, int const piece)
{
    /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
       apart than the diameter.  Also check that we do the right thing for negative radius.
       (Same for the other DoArc functions in this file.) */
    if ( rx <= 0.0001 || ry <= 0.0001 ) {
        return;
        // We always add a lineto afterwards, so this is fine.
        // [on ajoute toujours un lineto apres, donc c bon]
    }

    double sang;
    double eang;
    NR::Point dr;
    ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
    /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
       the case of low curvature (i.e. very large radius). */
    
    NR::scale const ar(rx, ry);
    NR::rotate cb(angle + sang);
    if (wise) {
        
        double const incr = -0.1;
        if ( sang < eang ) {
            sang += 2*M_PI;
        }
        NR::rotate const omega(incr);
        for (double b = sang + incr; b > eang; b += incr) {
            cb = omega * cb;
            AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
        }
        
    } else {
        
        double const incr = 0.1;
        if ( sang > eang ) {
            sang -= 2 * M_PI;
        }
        NR::rotate const omega(incr);
        for (double b = sang + incr ; b < eang ; b += incr) {
            cb = omega * cb;
            AddPoint(cb.vec * ar + dr, piece, (b - sang) / (eang - sang));
        }
    }
}

void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD, 
                      NR::Point const &iE, NR::Point const &ieD,
                      double tresh, int lev, double st, double et, int piece)
{
    const NR::Point se = iE - iS;
    const double dC = NR::L2(se);
    if ( dC < 0.01 ) {
        const double sC = dot(isD, isD);
        const double eC = dot(ieD, ieD);
        if ( sC < tresh && eC < tresh ) {
            return;
        }
    } else {
        const double sC = fabs(cross(se, isD)) / dC;
        const double eC = fabs(cross(se, ieD)) / dC;
        if ( sC < tresh && eC < tresh ) {
            return;
        }
    }
      
    if ( lev <= 0 ) {
        return;
    }
      
    NR::Point m = 0.5 * (iS + iE) + 0.125 * (isD - ieD);
    NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
    double mt = (st + et) / 2;
      
    NR::Point hisD = 0.5 * isD;
    NR::Point hieD = 0.5 * ieD;
    
    RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece);
    AddPoint(m, piece, mt);
    RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece);
      
}



void Path::RecBezierTo(NR::Point const &iP,
                       NR::Point const &iS,
                       NR::Point const &iE,
                       double tresh, int lev, double st, double et, int piece)
{
    if ( lev <= 0 ) {
        return;
    }
    
    NR::Point ps = iS - iP;
    NR::Point pe = iE - iP;
    const double s = fabs(cross(pe, ps));
    if ( s < tresh ) {
        return;
    }
      
    {
        const double mt = (st + et) / 2;
        const NR::Point m = 0.25 * (iS + iE + 2 * iP);
        RecBezierTo(0.5 * (iS + iP), iS, m, tresh, lev - 1, st, mt, piece);
        AddPoint(m, piece, mt);
        RecBezierTo(0.5 * (iP + iE), m, iE, tresh, lev - 1, mt, et, piece);   
    }
}



void Path::DoArc(NR::Point const &iS, NR::Point const &iE,
                 double const rx, double const ry, double const angle,
                 bool const large, bool const wise, double const /*tresh*/,
                 int const piece, offset_orig &/*orig*/)
{
    // Will never arrive here, as offsets are made of cubics.
    // [on n'arrivera jamais ici, puisque les offsets sont fait de cubiques]
    /* TODO: Check that our behaviour is standards-conformant if iS and iE are (much) further
       apart than the diameter.  Also check that we do the right thing for negative radius.
       (Same for the other DoArc functions in this file.) */
    if ( rx <= 0.0001 || ry <= 0.0001 ) {
        return;
        // We always add a lineto afterwards, so this is fine.
        // [on ajoute toujours un lineto apres, donc c bon]
    }
    
    double sang;
    double eang;
    NR::Point dr;
    ArcAnglesAndCenter(iS, iE, rx, ry, angle, large, wise, sang, eang, dr);
    /* TODO: This isn't as good numerically as treating iS and iE as primary.  E.g. consider
       the case of low curvature (i.e. very large radius). */
    
    NR::scale const ar(rx, ry);
    NR::rotate cb(angle + sang);
    if (wise) {
        
        double const incr = -0.1;
        if ( sang < eang ) {
            sang += 2*M_PI;
        }
        NR::rotate const omega(incr);
        for (double b = sang + incr; b > eang ;b += incr) {
            cb = omega * cb;
            AddPoint(cb.vec * ar + dr, piece, (sang - b) / (sang - eang));
        }
        
    } else {
        double const incr = 0.1;
        if ( sang > eang ) {
            sang -= 2*M_PI;
        }
        NR::rotate const omega(incr);
        for (double b = sang + incr ; b < eang ; b += incr) {
            cb = omega * cb;
            AddPoint(cb.vec * ar + dr, piece, (b - sang) / (eang - sang));
        }
    }
}


void Path::RecCubicTo(NR::Point const &iS, NR::Point const &isD, 
                      NR::Point const &iE, NR::Point const &ieD,
                      double tresh, int lev, double st, double et,
                      int piece, offset_orig &orig)
{
    const NR::Point se = iE - iS;
    const double dC = NR::L2(se);
    bool doneSub = false;
    if ( dC < 0.01 ) {
        const double sC = dot(isD, isD);
        const double eC = dot(ieD, ieD);
        if ( sC < tresh && eC < tresh ) {
            return;
        }
    } else {
        const double sC = fabs(cross(se, isD)) / dC;
        const double eC = fabs(cross(se, ieD)) / dC;
        if ( sC < tresh && eC < tresh ) {
            doneSub = true;
        }
    }
      
    if ( lev <= 0 ) {
        doneSub = true;
    }
      
    // test des inversions
    bool stInv = false;
    bool enInv = false;
    {
        NR::Point os_pos;
        NR::Point os_tgt;
        NR::Point oe_pos;
        NR::Point oe_tgt;
        
        orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
        orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
            
    
        NR::Point n_tgt = isD;
        double si = dot(n_tgt, os_tgt);
        if ( si < 0 ) {
            stInv = true;
        }
        n_tgt = ieD;
        si = dot(n_tgt, oe_tgt);
        if ( si < 0 ) {
            enInv = true;
        }
        if ( stInv && enInv ) {

            AddPoint(os_pos, -1, 0.0);
            AddPoint(iE, piece, et);
            AddPoint(iS, piece, st);
            AddPoint(oe_pos, -1, 0.0);
            return;
            
        } else if ( ( stInv && !enInv ) || ( !stInv && enInv ) ) {
            return;
        }

    }
    
    if ( ( !stInv && !enInv && doneSub ) || lev <= 0 ) {
        return;
    }
      
    {
        const NR::Point m = 0.5 * (iS+iE) + 0.125 * (isD - ieD);
        const NR::Point md = 0.75 * (iE - iS) - 0.125 * (isD + ieD);
        const double mt = (st + et) / 2;
        const NR::Point hisD = 0.5 * isD;
        const NR::Point hieD = 0.5 * ieD;
    
        RecCubicTo(iS, hisD, m, md, tresh, lev - 1, st, mt, piece, orig);
        AddPoint(m, piece, mt);
        RecCubicTo(m, md, iE, hieD, tresh, lev - 1, mt, et, piece, orig);
    }
}



void Path::RecBezierTo(NR::Point const &iP, NR::Point const &iS,NR::Point const &iE,
                       double tresh, int lev, double st, double et,
                       int piece, offset_orig& orig)
{
    bool doneSub = false;
    if ( lev <= 0 ) {
        return;
    }

    const NR::Point ps = iS - iP;
    const NR::Point pe = iE - iP;
    const double s = fabs(cross(pe, ps));
    if ( s < tresh ) {
        doneSub = true ;
    }
  
    // test des inversions
    bool stInv = false;
    bool enInv = false;
    {
        NR::Point os_pos;
        NR::Point os_tgt;
        NR::Point oe_pos;
        NR::Point oe_tgt;
        NR::Point n_tgt;
        NR::Point n_pos;
        
        double n_len;
        double n_rad;
        PathDescrIntermBezierTo mid(iP);
        PathDescrBezierTo fin(iE, 1);
            
        TangentOnBezAt(0.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
        orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - st) + orig.tEn * st, os_pos, os_tgt);
        double si = dot(n_tgt, os_tgt);
        if ( si < 0 ) {
            stInv = true;
        }
            
        TangentOnBezAt(1.0, iS, mid, fin, false, n_pos, n_tgt, n_len, n_rad);
        orig.orig->PointAndTangentAt(orig.piece, orig.tSt * (1 - et) + orig.tEn * et, oe_pos, oe_tgt);
        si = dot(n_tgt, oe_tgt);
        if ( si < 0 ) {
            enInv = true;
        }
            
        if ( stInv && enInv ) {
            AddPoint(os_pos, -1, 0.0);
            AddPoint(iE, piece, et);
            AddPoint(iS, piece, st);
            AddPoint(oe_pos, -1, 0.0);
            return;
            //          } else if ( ( stInv && !enInv ) || ( !stInv && enInv ) ) {
            //                return;
        }
    }
    
    if ( !stInv && !enInv && doneSub ) {
        return;
    }
  
    {
        double mt = (st + et) / 2;
        NR::Point m = 0.25 * (iS + iE + 2 * iP);
        NR::Point md = 0.5 * (iS + iP);
        RecBezierTo(md, iS, m, tresh, lev - 1, st, mt, piece, orig);
        AddPoint(m, piece, mt);
        md = 0.5 * (iP + iE);
        RecBezierTo(md, m, iE, tresh, lev - 1, mt, et, piece, orig);    
    }
}


/*
 * put a polyline in a Shape instance, for further fun
 * pathID is the ID you want this Path instance to be associated with, for when you're going to recompose the polyline
 * in a path description ( you need to have prepared the back data for that, of course)
 */

void Path::Fill(Shape* dest, int pathID, bool justAdd, bool closeIfNeeded, bool invert)
{
    if ( dest == NULL ) {
        return;
    }
    
    if ( justAdd == false ) {
        dest->Reset(pts.size(), pts.size());
    }
    
    if ( pts.size() <= 1 ) {
        return;
    }
    
    int first = dest->numberOfPoints();
  //  bool  startIsEnd = false;
      
    if ( back ) {
        dest->MakeBackData(true);
    }
      
    if ( invert ) {
        if ( back ) {
            {
                // invert && back && !weighted
                for (int i = 0; i < int(pts.size()); i++) {
                    dest->AddPoint(pts[i].p);
                }
                int lastM = 0;
                int curP = 1;
                int pathEnd = 0;
                bool closed = false;
                int lEdge = -1;
                
                while ( curP < int(pts.size()) ) {
                    int sbp = curP;
                    int lm = lastM;
                    int prp = pathEnd;
                    
                    if ( pts[sbp].isMoveTo == polyline_moveto ) {

                        if ( closeIfNeeded ) {
                            if ( closed && lEdge >= 0 ) {
                                dest->DisconnectStart(lEdge);
                                dest->ConnectStart(first + lastM, lEdge);
                            } else {
                                lEdge = dest->AddEdge(first + lastM, first+pathEnd);
                                if ( lEdge >= 0 ) {
                                    dest->ebData[lEdge].pathID = pathID;
                                    dest->ebData[lEdge].pieceID = pts[lm].piece;
                                    dest->ebData[lEdge].tSt = 1.0;
                                    dest->ebData[lEdge].tEn = 0.0;
                                }
                            }
                        }
                        
                        lastM = curP;
                        pathEnd = curP;
                        closed = false;
                        lEdge = -1;
                        
                    } else {
                        
                        if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
                            lEdge = dest->AddEdge(first + curP, first + pathEnd);
                            if ( lEdge >= 0 ) {
                                dest->ebData[lEdge].pathID = pathID;
                                dest->ebData[lEdge].pieceID = pts[sbp].piece;
                                if ( pts[sbp].piece == pts[prp].piece ) {
                                    dest->ebData[lEdge].tSt = pts[sbp].t;
                                    dest->ebData[lEdge].tEn = pts[prp].t;
                                } else {
                                    dest->ebData[lEdge].tSt = pts[sbp].t;
                                    dest->ebData[lEdge].tEn = 0.0;
                                }
                            }
                            pathEnd = curP;
                            if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
                                closed = true;
                            } else {
                                closed = false;
                            }
                        }
                    }
                    
                    curP++;
                }
                
                if ( closeIfNeeded ) {
                    if ( closed && lEdge >= 0 ) {
                        dest->DisconnectStart(lEdge);
                        dest->ConnectStart(first + lastM, lEdge);
                    } else {
                        int lm = lastM;
                        lEdge = dest->AddEdge(first + lastM, first + pathEnd);
                        if ( lEdge >= 0 ) {
                            dest->ebData[lEdge].pathID = pathID;
                            dest->ebData[lEdge].pieceID = pts[lm].piece;
                            dest->ebData[lEdge].tSt = 1.0;
                            dest->ebData[lEdge].tEn = 0.0;
                        }
                    }
                }
            }
            
        } else {
            
            {
                // invert && !back && !weighted
                for (int i = 0; i < int(pts.size()); i++) {
                    dest->AddPoint(pts[i].p);
                }
                int lastM = 0;
                int curP = 1;
                int pathEnd = 0;
                bool closed = false;
                int lEdge = -1;
                while ( curP < int(pts.size()) ) {
                    int sbp = curP;
                    int lm = lastM;
                    int prp = pathEnd;
                    if ( pts[sbp].isMoveTo == polyline_moveto ) {
                        if ( closeIfNeeded ) {
                            if ( closed && lEdge >= 0 ) {
                                dest->DisconnectStart(lEdge);
                                dest->ConnectStart(first + lastM, lEdge);
                            } else {
                                dest->AddEdge(first + lastM, first + pathEnd);
                            }
                        }
                        lastM = curP;
                        pathEnd = curP;
                        closed = false;
                        lEdge = -1;
                    } else {
                        if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
                            lEdge = dest->AddEdge(first+curP, first+pathEnd);
                            pathEnd = curP;
                            if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
                                closed = true;
                            } else {
                                closed = false;
                            }
                        }
                    }
                    curP++;
                }
                
                if ( closeIfNeeded ) {
                    if ( closed && lEdge >= 0 ) {
                        dest->DisconnectStart(lEdge);
                        dest->ConnectStart(first + lastM, lEdge);
                    } else {
                        dest->AddEdge(first + lastM, first + pathEnd);
                    }
                }
                
            }
        }
        
    } else {
        
        if ( back ) {
            {
                // !invert && back && !weighted
                for (int i = 0; i < int(pts.size()); i++) {
                    dest->AddPoint(pts[i].p);
                }
                
                int lastM = 0;
                int curP = 1;
                int pathEnd = 0;
                bool closed = false;
                int lEdge = -1;
                while ( curP < int(pts.size()) ) {
                    int sbp = curP;
                    int lm = lastM;
                    int prp = pathEnd;
                    if ( pts[sbp].isMoveTo == polyline_moveto ) {
                        if ( closeIfNeeded ) {
                            if ( closed && lEdge >= 0 ) {
                                dest->DisconnectEnd(lEdge);
                                dest->ConnectEnd(first + lastM, lEdge);
                            } else {
                                lEdge = dest->AddEdge(first + pathEnd, first+lastM);
                                if ( lEdge >= 0 ) {
                                    dest->ebData[lEdge].pathID = pathID;
                                    dest->ebData[lEdge].pieceID = pts[lm].piece;
                                    dest->ebData[lEdge].tSt = 0.0;
                                    dest->ebData[lEdge].tEn = 1.0;
                                }
                            }
                        }
                        lastM = curP;
                        pathEnd = curP;
                        closed = false;
                        lEdge = -1;
                    } else {
                        if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
                            lEdge = dest->AddEdge(first + pathEnd, first + curP);
                            dest->ebData[lEdge].pathID = pathID;
                            dest->ebData[lEdge].pieceID = pts[sbp].piece;
                            if ( pts[sbp].piece == pts[prp].piece ) {
                                dest->ebData[lEdge].tSt = pts[prp].t;
                                dest->ebData[lEdge].tEn = pts[sbp].t;
                            } else {
                                dest->ebData[lEdge].tSt = 0.0;
                                dest->ebData[lEdge].tEn = pts[sbp].t;
                            }
                            pathEnd = curP;
                            if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
                                closed = true;
                            } else {
                                closed = false;
                            }
                        }
                    }
                    curP++;
                }
                
                if ( closeIfNeeded ) {
                    if ( closed && lEdge >= 0 ) {
                        dest->DisconnectEnd(lEdge);
                        dest->ConnectEnd(first + lastM, lEdge);
                    } else {
                        int lm = lastM;
                        lEdge = dest->AddEdge(first + pathEnd, first + lastM);
                        if ( lEdge >= 0 ) {
                            dest->ebData[lEdge].pathID = pathID;
                            dest->ebData[lEdge].pieceID = pts[lm].piece;
                            dest->ebData[lEdge].tSt = 0.0;
                            dest->ebData[lEdge].tEn = 1.0;
                        }
                    }
                }
            }
            
        } else {
            {
                // !invert && !back && !weighted
                for (int i = 0;i < int(pts.size()); i++) {
                    dest->AddPoint(pts[i].p);
                }
                
                int lastM = 0;
                int curP = 1;
                int pathEnd = 0;
                bool closed = false;
                int lEdge = -1;
                while ( curP < int(pts.size()) ) {
                    int sbp = curP;
                    int lm = lastM;
                    int prp = pathEnd;
                    if ( pts[sbp].isMoveTo == polyline_moveto ) {
                        if ( closeIfNeeded ) {
                            if ( closed && lEdge >= 0 ) {
                                dest->DisconnectEnd(lEdge);
                                dest->ConnectEnd(first + lastM, lEdge);
                            } else {
                                dest->AddEdge(first + pathEnd, first + lastM);
                            }
                        }
                        lastM = curP;
                        pathEnd = curP;
                        closed = false;
                        lEdge = -1;
                    } else {
                        if ( NR::LInfty(pts[sbp].p - pts[prp].p) >= 0.00001 ) {
                            lEdge = dest->AddEdge(first+pathEnd, first+curP);
                            pathEnd = curP;
                            if ( NR::LInfty(pts[sbp].p - pts[lm].p) < 0.00001 ) {
                                closed = true;
                            } else {
                                closed = false;
                            }
                        }
                    }
                    curP++;
                }
                
                if ( closeIfNeeded ) {
                    if ( closed && lEdge >= 0 ) {
                        dest->DisconnectEnd(lEdge);
                        dest->ConnectEnd(first + lastM, lEdge);
                    } else {
                        dest->AddEdge(first + pathEnd, first + lastM);
                    }
                }
                
            }
        }
    }
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :

Generated by  Doxygen 1.6.0   Back to index