QPolygonF polygonFromPath(potrace_path_t *path,
                          int bezierPrecision)
{
  QPolygonF poly;
  if(!path) return poly;

  int n = path->curve.n;
  int *tag = path->curve.tag;
  potrace_dpoint_t (*c)[3] = path->curve.c;
  for(int i = 0; i < n; ++i)
  {
    switch (tag[i])
    {
    case POTRACE_CORNER:
      poly << QPointF(c[i][1].x, c[i][1].y)
           << QPointF(c[i][2].x, c[i][2].y);
      break;
    case POTRACE_CURVETO:
    {
      QPointF pa, pb, pc, pd;
      pa = poly.isEmpty()? QPointF(c[n-1][2].x, c[n-1][2].y) :
                           poly.last();
      pb = QPointF(c[i][0].x, c[i][0].y);
      pc = QPointF(c[i][1].x, c[i][1].y);
      pd = QPointF(c[i][2].x, c[i][2].y);
      for(int i = 1; i <= bezierPrecision; ++i)
      {
        poly << bezier(pa, pb, pc, pd, static_cast<qreal>(i)/bezierPrecision);
      }
    }
      break;
    }
  }

  if(!poly.isEmpty() && poly.first() == poly.last())
  {
    poly.remove(poly.size()-1);
  }

  return poly;
}
int main() {
    int x, y, i;
    potrace_bitmap_t *bm;
    potrace_param_t *param;
    potrace_path_t *p;
    potrace_state_t *st;
    int n, *tag;
    potrace_dpoint_t(*c)[3];

    /* create a bitmap */
    bm = bm_new(WIDTH, HEIGHT);
    if (!bm) {
        fprintf(stderr, "Error allocating bitmap: %s\n", strerror(errno));
        return 1;
    }

    /* fill the bitmap with some pattern */
    for (y = 0; y < HEIGHT; y++) {
        for (x = 0; x < WIDTH; x++) {
            BM_PUT(bm, x, y, ((x * x + y * y * y) % 10000 < 5000) ? 1 : 0);
        }
    }

    /* set tracing parameters, starting from defaults */
    param = potrace_param_default();
    if (!param) {
        fprintf(stderr, "Error allocating parameters: %s\n", strerror(errno));
        return 1;
    }
    param->turdsize = 0;

    /* trace the bitmap */
    st = potrace_trace(param, bm);
    if (!st || st->status != POTRACE_STATUS_OK) {
        fprintf(stderr, "Error tracing bitmap: %s\n", strerror(errno));
        return 1;
    }
    bm_free(bm);

    /* output vector data, e.g. as a rudimentary EPS file */
    printf("%%!PS-Adobe-3.0 EPSF-3.0\n");
    printf("%%%%BoundingBox: 0 0 %d %d\n", WIDTH, HEIGHT);
    printf("gsave\n");

    /* draw each curve */
    p = st->plist;
    while (p != NULL) {
        n = p->curve.n;
        tag = p->curve.tag;
        c = p->curve.c;
        printf("%f %f moveto\n", c[n - 1][2].x, c[n - 1][2].y);
        for (i = 0; i < n; i++) {
            switch (tag[i]) {
            case POTRACE_CORNER:
                printf("%f %f lineto\n", c[i][1].x, c[i][1].y);
                printf("%f %f lineto\n", c[i][2].x, c[i][2].y);
                break;
            case POTRACE_CURVETO:
                printf("%f %f %f %f %f %f curveto\n", c[i][0].x, c[i][0].y, c[i][1].x, c[i][1].y,
                       c[i][2].x, c[i][2].y);
                break;
            }
        }
        /* at the end of a group of a positive path and its negative
           children, fill. */
        if (p->next == NULL || p->next->sign == '+') {
            printf("0 setgray fill\n");
        }
        p = p->next;
    }
    printf("grestore\n");
    printf("%%EOF\n");

    potrace_state_free(st);
    potrace_param_free(param);

    return 0;
}
void BITMAPCONV_INFO::CreateOutputFile( BMP2CMP_MOD_LAYER aModLayer )
{
    std::vector <potrace_dpoint_t> cornersBuffer;

    // polyset_areas is a set of polygon to draw
    SHAPE_POLY_SET polyset_areas;

    // polyset_holes is the set of holes inside polyset_areas outlines
    SHAPE_POLY_SET polyset_holes;

    potrace_dpoint_t( *c )[3];

    LOCALE_IO toggle;   // Temporary switch the locale to standard C to r/w floats

    // The layer name has meaning only for .kicad_mod files.
    // For these files the header creates 2 invisible texts: value and ref
    // (needed but not usefull) on silk screen layer
    OuputFileHeader( getBrdLayerName( MOD_LYR_FSILKS ) );

    bool main_outline = true;

    /* draw each as a polygon with no hole.
     * Bezier curves are approximated by a polyline
     */
    potrace_path_t* paths = m_Paths;    // the list of paths
    while( paths != NULL )
    {
        int cnt  = paths->curve.n;
        int* tag = paths->curve.tag;
        c = paths->curve.c;
        potrace_dpoint_t startpoint = c[cnt - 1][2];
        for( int i = 0; i < cnt; i++ )
        {
            switch( tag[i] )
            {
            case POTRACE_CORNER:
                cornersBuffer.push_back( c[i][1] );
                cornersBuffer.push_back( c[i][2] );
                startpoint = c[i][2];
                break;

            case POTRACE_CURVETO:
                BezierToPolyline( cornersBuffer, startpoint, c[i][0], c[i][1], c[i][2] );
                startpoint = c[i][2];
                break;
            }
        }

        // Store current path
        if( main_outline )
        {
            main_outline = false;

            // build the current main polygon
            polyset_areas.NewOutline();
            for( unsigned int i = 0; i < cornersBuffer.size(); i++ )
            {
                polyset_areas.Append( int( cornersBuffer[i].x * m_ScaleX ),
                                      int( cornersBuffer[i].y * m_ScaleY ) );
            }
        }
        else
        {
            // Add current hole in polyset_holes
            polyset_holes.NewOutline();
            for( unsigned int i = 0; i < cornersBuffer.size(); i++ )
            {
                polyset_holes.Append( int( cornersBuffer[i].x * m_ScaleX ),
                                      int( cornersBuffer[i].y * m_ScaleY ) );
            }
        }

        cornersBuffer.clear();

        /* at the end of a group of a positive path and its negative children, fill.
         */
        if( paths->next == NULL || paths->next->sign == '+' )
        {
            // Substract holes to main polygon:
            polyset_areas.Simplify( SHAPE_POLY_SET::PM_FAST );
            polyset_holes.Simplify( SHAPE_POLY_SET::PM_FAST );
            polyset_areas.BooleanSubtract( polyset_holes, SHAPE_POLY_SET::PM_FAST );
            polyset_areas.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );

            // Output current resulting polygon(s)
            for( int ii = 0; ii < polyset_areas.OutlineCount(); ii++ )
            {
                SHAPE_LINE_CHAIN& poly = polyset_areas.Outline( ii );
                OuputOnePolygon(poly, getBrdLayerName( aModLayer ) );
            }

            polyset_areas.RemoveAllContours();
            polyset_holes.RemoveAllContours();
            main_outline = true;
        }
        paths = paths->next;
    }

    OuputFileEnd();
}