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(); }