Index: trunk/doc-rnd/Makefile
===================================================================
--- trunk/doc-rnd/Makefile (revision 1268)
+++ trunk/doc-rnd/Makefile (revision 1269)
@@ -4,4 +4,4 @@
all: keys.html
keys.html: $(MENU_RES) $(KEYLIST)
- $(KEYLIST) $(MENU_RES) > keys.html
\ No newline at end of file
+ $(KEYLIST) $(MENU_RES) > keys.html
Index: trunk/doc-rnd/TODO
===================================================================
--- trunk/doc-rnd/TODO (revision 1268)
+++ trunk/doc-rnd/TODO (revision 1269)
@@ -7,6 +7,8 @@
- test onpoint
- PrintQuotedString(FILE * FP, char *S): remove dynamic string allocation
- get rid of gcode/lists.h, ds.[ch] and vector.[ch]
+ - test whether plugin compiled exporters work
+ - test whether gd based plugins can be compiled to so (png, nelma)
Index: trunk/doc-rnd/mods/after.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/doc-rnd/mods/index.html
===================================================================
--- trunk/doc-rnd/mods/index.html (revision 1268)
+++ trunk/doc-rnd/mods/index.html (revision 1269)
@@ -58,11 +58,11 @@
vendordrill | 567
| works
| buildin
| Vendor drill mapping.
Index: trunk/doc-rnd/mods/mods.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/scconfig/hooks.c
===================================================================
--- trunk/scconfig/hooks.c (revision 1268)
+++ trunk/scconfig/hooks.c (revision 1269)
@@ -21,8 +21,6 @@
"png", "libs/gui/gd/gdImagePng/presents",
"gif", "libs/gui/gd/gdImageGif/presents",
"jpg", "libs/gui/gd/gdImageJpeg/presents",
- "gcode", "libs/gui/gd/presents",
- "nelma", "libs/gui/gd/presents",
NULL, NULL
};
@@ -96,6 +94,14 @@
{"buildin-export_lpr", "/local/pcb/export_lpr/buildin", arg_true, "$static link the lpr printer into the executable"},
{"plugin-export_lpr", "/local/pcb/export_lpr/buildin", arg_false, "$the lpr printer is a dynamic loadable plugin"},
+ {"disable-export_gcode", "/local/pcb/export_gcode/enable", arg_false, "$do not compile the gcode exporter"},
+ {"buildin-export_gcode", "/local/pcb/export_gcode/buildin", arg_true, "$static link the gcode exporter into the executable"},
+ {"plugin-export_gcode", "/local/pcb/export_gcode/buildin", arg_false, "$the gcode exporter is a dynamic loadable plugin"},
+
+ {"disable-export_nelma", "/local/pcb/export_nelma/enable", arg_false, "$do not compile the nelma exporter"},
+ {"buildin-export_nelma", "/local/pcb/export_nelma/buildin", arg_true, "$static link the nelma exporter into the executable"},
+ {"plugin-export_nelma", "/local/pcb/export_nelma/buildin", arg_false, "$the nelma exporter is a dynamic loadable plugin"},
+
{NULL, NULL, NULL, NULL}
};
@@ -212,6 +218,14 @@
put("/local/pcb/export_lpr/enable", strue);
put("/local/pcb/export_lpr/buildin", strue);
+ db_mkdir("/local/pcb/export_gcode");
+ put("/local/pcb/export_gcode/enable", strue);
+ put("/local/pcb/export_gcode/buildin", strue);
+
+ db_mkdir("/local/pcb/export_nelma");
+ put("/local/pcb/export_nelma/enable", strue);
+ put("/local/pcb/export_nelma/buildin", strue);
+
return 0;
}
@@ -356,6 +370,13 @@
}
}
+ if (!istrue(get("libs/gui/gd/presents"))) {
+ if (istrue(get("/local/pcb/export_nelma/enable"))) {
+ report_repeat("WARNING: disabling the nelma exporter because libgd is not found or not configured...\n");
+ hook_custom_arg("disable-export_nelma", NULL);
+ }
+ }
+
return 0;
}
@@ -494,6 +515,8 @@
printf("\n");
plugin_stat("export_ps:", "/local/pcb/export_ps");
plugin_stat("export_lpr:", "/local/pcb/export_lpr");
+ plugin_stat("export_gcode:", "/local/pcb/export_gcode");
+ plugin_stat("export_nelma:", "/local/pcb/export_nelma");
if (repeat != NULL)
printf("\n%s\n", repeat);
Index: trunk/src/Makefile.in
===================================================================
--- trunk/src/Makefile.in (revision 1268)
+++ trunk/src/Makefile.in (revision 1269)
@@ -136,8 +136,6 @@
include {Makefile.in.mod/bom}
include {Makefile.in.mod/png}
include {Makefile.in.mod/gerber}
-include {Makefile.in.mod/gcode}
-include {Makefile.in.mod/nelma}
include {../src_plugins/autoplace/Plug.tmpasm}
include {../src_plugins/autoroute/Plug.tmpasm}
@@ -154,6 +152,8 @@
include {../src_plugins/import_sch/Plug.tmpasm}
include {../src_plugins/export_ps/Plug.tmpasm}
include {../src_plugins/export_lpr/Plug.tmpasm}
+include {../src_plugins/export_gcode/Plug.tmpasm}
+include {../src_plugins/export_nelma/Plug.tmpasm}
append /local/pcb/CFLAGS /target/libs/sul/glib/cflags
Index: trunk/src/Makefile.in.mod/gcode
===================================================================
--- trunk/src/Makefile.in.mod/gcode (revision 1268)
+++ trunk/src/Makefile.in.mod/gcode (nonexistent)
@@ -1,14 +0,0 @@
-if /target/libs/gui/gd/presents then
-
-append /local/pcb/HIDS {gcode}
-append /local/pcb/CFLAGS {-I./hid/gcode}
-append /local/pcb/OBJS [@
- hid/gcode/gcode.o
- hid/gcode/decompose.o
- hid/gcode/trace.o
- hid/gcode/curve.o
-@]
-
-append /local/pcb/ACTION_REG_SRC {hid/gcode/gcode.c hid/gcode/hid.conf}
-
-end
Index: trunk/src/Makefile.in.mod/nelma
===================================================================
--- trunk/src/Makefile.in.mod/nelma (revision 1268)
+++ trunk/src/Makefile.in.mod/nelma (nonexistent)
@@ -1,7 +0,0 @@
-if /target/libs/gui/gd/presents then
-append /local/pcb/HIDS {nelma}
-append /local/pcb/CFLAGS {-I./hid/nelma}
-append /local/pcb/OBJS {hid/nelma/nelma.o}
-append /local/pcb/ACTION_REG_SRC {hid/nelma/nelma.c hid/nelma/hid.conf}
-end
-
Index: trunk/src/hid/gcode/trace.c
===================================================================
--- trunk/src/hid/gcode/trace.c (revision 1268)
+++ trunk/src/hid/gcode/trace.c (nonexistent)
@@ -1,1292 +0,0 @@
-/* This file was slightly modified by Alberto Maccioni to be used with PCB G-CODE exporter*/
-
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* $Id: trace.c 147 2007-04-09 00:44:09Z selinger $ */
-/* transform jaggy paths into smooth curves */
-
-#include
-#include
-#include
-#include
-
-#include "global.h"
-#include "potracelib.h"
-#include "curve.h"
-#include "lists.h"
-#include "auxiliary.h"
-#include "trace.h"
-/*#include "progress.h"*/
-
-#define INFTY 10000000 /* it suffices that this is longer than any
- path; it need not be really infinite */
-#define COS179 -0.999847695156 /* the cosine of 179 degrees */
-
-/* ---------------------------------------------------------------------- */
-#define SAFE_MALLOC(var, n, typ) \
- if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error
-
-/* ---------------------------------------------------------------------- */
-/* auxiliary functions */
-
-/* return a direction that is 90 degrees counterclockwise from p2-p0,
- but then restricted to one of the major wind directions (n, nw, w, etc) */
-static inline point_t dorth_infty(dpoint_t p0, dpoint_t p2)
-{
- point_t r;
-
- r.y = sign(p2.x - p0.x);
- r.x = -sign(p2.y - p0.y);
-
- return r;
-}
-
-/* return (p1-p0)x(p2-p0), the area of the parallelogram */
-static inline double dpara(dpoint_t p0, dpoint_t p1, dpoint_t p2)
-{
- double x1, y1, x2, y2;
-
- x1 = p1.x - p0.x;
- y1 = p1.y - p0.y;
- x2 = p2.x - p0.x;
- y2 = p2.y - p0.y;
-
- return x1 * y2 - x2 * y1;
-}
-
-/* ddenom/dpara have the property that the square of radius 1 centered
- at p1 intersects the line p0p2 iff |dpara(p0,p1,p2)| <= ddenom(p0,p2) */
-static inline double ddenom(dpoint_t p0, dpoint_t p2)
-{
- point_t r = dorth_infty(p0, p2);
-
- return r.y * (p2.x - p0.x) - r.x * (p2.y - p0.y);
-}
-
-/* return 1 if a <= b < c < a, in a cyclic sense (mod n) */
-static inline int cyclic(int a, int b, int c)
-{
- if (a <= c) {
- return (a <= b && b < c);
- }
- else {
- return (a <= b || b < c);
- }
-}
-
-/* determine the center and slope of the line i..j. Assume ilen;
- sums_t *sums = pp->sums;
-
- double x, y, x2, xy, y2;
- double k;
- double a, b, c, lambda2, l;
- int r = 0; /* rotations from i to j */
-
- while (j >= n) {
- j -= n;
- r += 1;
- }
- while (i >= n) {
- i -= n;
- r -= 1;
- }
- while (j < 0) {
- j += n;
- r -= 1;
- }
- while (i < 0) {
- i += n;
- r += 1;
- }
-
- x = sums[j + 1].x - sums[i].x + r * sums[n].x;
- y = sums[j + 1].y - sums[i].y + r * sums[n].y;
- x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2;
- xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy;
- y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2;
- k = j + 1 - i + r * n;
-
- ctr->x = x / k;
- ctr->y = y / k;
-
- a = (x2 - (double) x * x / k) / k;
- b = (xy - (double) x * y / k) / k;
- c = (y2 - (double) y * y / k) / k;
-
- lambda2 = (a + c + sqrt((a - c) * (a - c) + 4 * b * b)) / 2; /* larger e.value */
-
- /* now find e.vector for lambda2 */
- a -= lambda2;
- c -= lambda2;
-
- if (fabs(a) >= fabs(c)) {
- l = sqrt(a * a + b * b);
- if (l != 0) {
- dir->x = -b / l;
- dir->y = a / l;
- }
- }
- else {
- l = sqrt(c * c + b * b);
- if (l != 0) {
- dir->x = -c / l;
- dir->y = b / l;
- }
- }
- if (l == 0) {
- dir->x = dir->y = 0; /* sometimes this can happen when k=4:
- the two eigenvalues coincide */
- }
-}
-
-/* the type of (affine) quadratic forms, represented as symmetric 3x3
- matrices. The value of the quadratic form at a vector (x,y) is v^t
- Q v, where v = (x,y,1)^t. */
-typedef double quadform_t[3][3];
-
-/* Apply quadratic form Q to vector w = (w.x,w.y) */
-static inline double quadform(quadform_t Q, dpoint_t w)
-{
- double v[3];
- int i, j;
- double sum;
-
- v[0] = w.x;
- v[1] = w.y;
- v[2] = 1;
- sum = 0.0;
-
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++) {
- sum += v[i] * Q[i][j] * v[j];
- }
- }
- return sum;
-}
-
-/* calculate p1 x p2 */
-static inline int xprod(point_t p1, point_t p2)
-{
- return p1.x * p2.y - p1.y * p2.x;
-}
-
-/* calculate (p1-p0)x(p3-p2) */
-static inline double cprod(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3)
-{
- double x1, y1, x2, y2;
-
- x1 = p1.x - p0.x;
- y1 = p1.y - p0.y;
- x2 = p3.x - p2.x;
- y2 = p3.y - p2.y;
-
- return x1 * y2 - x2 * y1;
-}
-
-/* calculate (p1-p0)*(p2-p0) */
-static inline double iprod(dpoint_t p0, dpoint_t p1, dpoint_t p2)
-{
- double x1, y1, x2, y2;
-
- x1 = p1.x - p0.x;
- y1 = p1.y - p0.y;
- x2 = p2.x - p0.x;
- y2 = p2.y - p0.y;
-
- return x1 * x2 + y1 * y2;
-}
-
-/* calculate (p1-p0)*(p3-p2) */
-static inline double iprod1(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3)
-{
- double x1, y1, x2, y2;
-
- x1 = p1.x - p0.x;
- y1 = p1.y - p0.y;
- x2 = p3.x - p2.x;
- y2 = p3.y - p2.y;
-
- return x1 * x2 + y1 * y2;
-}
-
-/* calculate distance between two points */
-static inline double ddist(dpoint_t p, dpoint_t q)
-{
- return sqrt(sq(p.x - q.x) + sq(p.y - q.y));
-}
-
-/* calculate point of a bezier curve */
-static inline dpoint_t bezier(double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3)
-{
- double s = 1 - t;
- dpoint_t res;
-
- /* Note: a good optimizing compiler (such as gcc-3) reduces the
- following to 16 multiplications, using common subexpression
- elimination. */
-
- res.x = s * s * s * p0.x + 3 * (s * s * t) * p1.x + 3 * (t * t * s) * p2.x + t * t * t * p3.x;
- res.y = s * s * s * p0.y + 3 * (s * s * t) * p1.y + 3 * (t * t * s) * p2.y + t * t * t * p3.y;
-
- return res;
-}
-
-/* calculate the point t in [0..1] on the (convex) bezier curve
- (p0,p1,p2,p3) which is tangent to q1-q0. Return -1.0 if there is no
- solution in [0..1]. */
-static double tangent(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3, dpoint_t q0, dpoint_t q1)
-{
- double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */
- double a, b, c; /* a t^2 + b t + c = 0 */
- double d, s, r1, r2;
-
- A = cprod(p0, p1, q0, q1);
- B = cprod(p1, p2, q0, q1);
- C = cprod(p2, p3, q0, q1);
-
- a = A - 2 * B + C;
- b = -2 * A + 2 * B;
- c = A;
-
- d = b * b - 4 * a * c;
-
- if (a == 0 || d < 0) {
- return -1.0;
- }
-
- s = sqrt(d);
-
- r1 = (-b + s) / (2 * a);
- r2 = (-b - s) / (2 * a);
-
- if (r1 >= 0 && r1 <= 1) {
- return r1;
- }
- else if (r2 >= 0 && r2 <= 1) {
- return r2;
- }
- else {
- return -1.0;
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/* Preparation: fill in the sum* fields of a path (used for later
- rapid summing). Return 0 on success, 1 with errno set on
- failure. */
-static int calc_sums(privpath_t * pp)
-{
- int i, x, y;
- int n = pp->len;
-
- SAFE_MALLOC(pp->sums, pp->len + 1, sums_t);
-
- /* origin */
- pp->x0 = pp->pt[0].x;
- pp->y0 = pp->pt[0].y;
-
- /* preparatory computation for later fast summing */
- pp->sums[0].x2 = pp->sums[0].xy = pp->sums[0].y2 = pp->sums[0].x = pp->sums[0].y = 0;
- for (i = 0; i < n; i++) {
- x = pp->pt[i].x - pp->x0;
- y = pp->pt[i].y - pp->y0;
- pp->sums[i + 1].x = pp->sums[i].x + x;
- pp->sums[i + 1].y = pp->sums[i].y + y;
- pp->sums[i + 1].x2 = pp->sums[i].x2 + x * x;
- pp->sums[i + 1].xy = pp->sums[i].xy + x * y;
- pp->sums[i + 1].y2 = pp->sums[i].y2 + y * y;
- }
- return 0;
-
-malloc_error:
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 1: determine the straight subpaths (Sec. 2.2.1). Fill in the
- "lon" component of a path object (based on pt/len). For each i,
- lon[i] is the furthest index such that a straight line can be drawn
- from i to lon[i]. Return 1 on error with errno set, else 0. */
-
-/* this algorithm depends on the fact that the existence of straight
- subpaths is a triplewise property. I.e., there exists a straight
- line through squares i0,...,in iff there exists a straight line
- through i,j,k, for all i0<=i= 0 and xprod(constraint[1],
- cur) <= 0. */
-
-/* Remark for Potrace 1.1: the current implementation of calc_lon is
- more complex than the implementation found in Potrace 1.0, but it
- is considerably faster. The introduction of the "nc" data structure
- means that we only have to test the constraints for "corner"
- points. On a typical input file, this speeds up the calc_lon
- function by a factor of 31.2, thereby decreasing its time share
- within the overall Potrace algorithm from 72.6% to 7.82%, and
- speeding up the overall algorithm by a factor of 3.36. On another
- input file, calc_lon was sped up by a factor of 6.7, decreasing its
- time share from 51.4% to 13.61%, and speeding up the overall
- algorithm by a factor of 1.78. In any case, the savings are
- substantial. */
-
-/* returns 0 on success, 1 on error with errno set */
-static int calc_lon(privpath_t * pp)
-{
- point_t *pt = pp->pt;
- int n = pp->len;
- int i, j, k, k1;
- int ct[4], dir;
- point_t constraint[2];
- point_t cur;
- point_t off;
- int *pivk = NULL; /* pivk[n] */
- int *nc = NULL; /* nc[n]: next corner */
- point_t dk; /* direction of k-k1 */
- int a, b, c, d;
-
- SAFE_MALLOC(pivk, n, int);
- SAFE_MALLOC(nc, n, int);
-
- /* initialize the nc data structure. Point from each point to the
- furthest future point to which it is connected by a vertical or
- horizontal segment. We take advantage of the fact that there is
- always a direction change at 0 (due to the path decomposition
- algorithm). But even if this were not so, there is no harm, as
- in practice, correctness does not depend on the word "furthest"
- above. */
- k = 0;
- for (i = n - 1; i >= 0; i--) {
- if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) {
- k = i + 1; /* necessarily ilon, n, int);
-
- /* determine pivot points: for each i, let pivk[i] be the furthest k
- such that all j with i= 0; i--) {
- ct[0] = ct[1] = ct[2] = ct[3] = 0;
-
- /* keep track of "directions" that have occurred */
- dir = (3 + 3 * (pt[mod(i + 1, n)].x - pt[i].x) + (pt[mod(i + 1, n)].y - pt[i].y)) / 2;
- ct[dir]++;
-
- constraint[0].x = 0;
- constraint[0].y = 0;
- constraint[1].x = 0;
- constraint[1].y = 0;
-
- /* find the next k such that no straight line from i to k */
- k = nc[i];
- k1 = i;
- while (1) {
-
- dir = (3 + 3 * sign(pt[k].x - pt[k1].x) + sign(pt[k].y - pt[k1].y)) / 2;
- ct[dir]++;
-
- /* if all four "directions" have occurred, cut this path */
- if (ct[0] && ct[1] && ct[2] && ct[3]) {
- pivk[i] = k1;
- goto foundk;
- }
-
- cur.x = pt[k].x - pt[i].x;
- cur.y = pt[k].y - pt[i].y;
-
- /* see if current constraint is violated */
- if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) {
- goto constraint_viol;
- }
-
- /* else, update constraint */
- if (abs(cur.x) <= 1 && abs(cur.y) <= 1) {
- /* no constraint */
- }
- else {
- off.x = cur.x + ((cur.y >= 0 && (cur.y > 0 || cur.x < 0)) ? 1 : -1);
- off.y = cur.y + ((cur.x <= 0 && (cur.x < 0 || cur.y < 0)) ? 1 : -1);
- if (xprod(constraint[0], off) >= 0) {
- constraint[0] = off;
- }
- off.x = cur.x + ((cur.y <= 0 && (cur.y < 0 || cur.x < 0)) ? 1 : -1);
- off.y = cur.y + ((cur.x >= 0 && (cur.x > 0 || cur.y < 0)) ? 1 : -1);
- if (xprod(constraint[1], off) <= 0) {
- constraint[1] = off;
- }
- }
- k1 = k;
- k = nc[k1];
- if (!cyclic(k, i, k1)) {
- break;
- }
- }
- constraint_viol:
- /* k1 was the last "corner" satisfying the current constraint, and
- k is the first one violating it. We now need to find the last
- point along k1..k which satisfied the constraint. */
- dk.x = sign(pt[k].x - pt[k1].x);
- dk.y = sign(pt[k].y - pt[k1].y);
- cur.x = pt[k1].x - pt[i].x;
- cur.y = pt[k1].y - pt[i].y;
- /* find largest integer j such that xprod(constraint[0], cur+j*dk)
- >= 0 and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity
- of xprod. */
- a = xprod(constraint[0], cur);
- b = xprod(constraint[0], dk);
- c = xprod(constraint[1], cur);
- d = xprod(constraint[1], dk);
- /* find largest integer j such that a+j*b>=0 and c+j*d<=0. This
- can be solved with integer arithmetic. */
- j = INFTY;
- if (b < 0) {
- j = floordiv(a, -b);
- }
- if (d > 0) {
- j = min(j, floordiv(-c, d));
- }
- pivk[i] = mod(k1 + j, n);
- foundk:
- ;
- } /* for i */
-
- /* clean up: for each i, let lon[i] be the largest k such that for
- all i' with i<=i'lon[n - 1] = j;
- for (i = n - 2; i >= 0; i--) {
- if (cyclic(i + 1, pivk[i], j)) {
- j = pivk[i];
- }
- pp->lon[i] = j;
- }
-
- for (i = n - 1; cyclic(mod(i + 1, n), j, pp->lon[i]); i--) {
- pp->lon[i] = j;
- }
-
- free(pivk);
- free(nc);
- return 0;
-
-malloc_error:
- free(pivk);
- free(nc);
- return 1;
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* Stage 2: calculate the optimal polygon (Sec. 2.2.2-2.2.4). */
-
-/* Auxiliary function: calculate the penalty of an edge from i to j in
- the given path. This needs the "lon" and "sum*" data. */
-
-static double penalty3(privpath_t * pp, int i, int j)
-{
- int n = pp->len;
- point_t *pt = pp->pt;
- sums_t *sums = pp->sums;
-
- /* assume 0<=i= n) {
- j -= n;
- r += 1;
- }
-
- x = sums[j + 1].x - sums[i].x + r * sums[n].x;
- y = sums[j + 1].y - sums[i].y + r * sums[n].y;
- x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2;
- xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy;
- y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2;
- k = j + 1 - i + r * n;
-
- px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x;
- py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y;
- ey = (pt[j].x - pt[i].x);
- ex = -(pt[j].y - pt[i].y);
-
- a = ((x2 - 2 * x * px) / k + px * px);
- b = ((xy - x * py - y * px) / k + px * py);
- c = ((y2 - 2 * y * py) / k + py * py);
-
- s = ex * ex * a + 2 * ex * ey * b + ey * ey * c;
-
- return sqrt(s);
-}
-
-/* find the optimal polygon. Fill in the m and po components. Return 1
- on failure with errno set, else 0. Non-cyclic version: assumes i=0
- is in the polygon. Fixme: ### implement cyclic version. */
-static int bestpolygon(privpath_t * pp)
-{
- int i, j, m, k;
- int n = pp->len;
- double *pen = NULL; /* pen[n+1]: penalty vector */
- int *prev = NULL; /* prev[n+1]: best path pointer vector */
- int *clip0 = NULL; /* clip0[n]: longest segment pointer, non-cyclic */
- int *clip1 = NULL; /* clip1[n+1]: backwards segment pointer, non-cyclic */
- int *seg0 = NULL; /* seg0[m+1]: forward segment bounds, m<=n */
- int *seg1 = NULL; /* seg1[m+1]: backward segment bounds, m<=n */
- double thispen;
- double best;
- int c;
-
- SAFE_MALLOC(pen, n + 1, double);
- SAFE_MALLOC(prev, n + 1, int);
- SAFE_MALLOC(clip0, n, int);
- SAFE_MALLOC(clip1, n + 1, int);
- SAFE_MALLOC(seg0, n + 1, int);
- SAFE_MALLOC(seg1, n + 1, int);
-
- /* calculate clipped paths */
- for (i = 0; i < n; i++) {
- c = mod(pp->lon[mod(i - 1, n)] - 1, n);
- if (c == i) {
- c = mod(i + 1, n);
- }
- if (c < i) {
- clip0[i] = n;
- }
- else {
- clip0[i] = c;
- }
- }
-
- /* calculate backwards path clipping, non-cyclic. j <= clip0[i] iff
- clip1[j] <= i, for i,j=0..n. */
- j = 1;
- for (i = 0; i < n; i++) {
- while (j <= clip0[i]) {
- clip1[j] = i;
- j++;
- }
- }
-
- /* calculate seg0[j] = longest path from 0 with j segments */
- i = 0;
- for (j = 0; i < n; j++) {
- seg0[j] = i;
- i = clip0[i];
- }
- seg0[j] = n;
- m = j;
-
- /* calculate seg1[j] = longest path to n with m-j segments */
- i = n;
- for (j = m; j > 0; j--) {
- seg1[j] = i;
- i = clip1[i];
- }
- seg1[0] = 0;
-
- /* now find the shortest path with m segments, based on penalty3 */
- /* note: the outer 2 loops jointly have at most n interations, thus
- the worst-case behavior here is quadratic. In practice, it is
- close to linear since the inner loop tends to be short. */
- pen[0] = 0;
- for (j = 1; j <= m; j++) {
- for (i = seg1[j]; i <= seg0[j]; i++) {
- best = -1;
- for (k = seg0[j - 1]; k >= clip1[i]; k--) {
- thispen = penalty3(pp, k, i) + pen[k];
- if (best < 0 || thispen < best) {
- prev[i] = k;
- best = thispen;
- }
- }
- pen[i] = best;
- }
- }
-
- pp->m = m;
- SAFE_MALLOC(pp->po, m, int);
-
- /* read off shortest path */
- for (i = n, j = m - 1; i > 0; j--) {
- i = prev[i];
- pp->po[j] = i;
- }
-
- free(pen);
- free(prev);
- free(clip0);
- free(clip1);
- free(seg0);
- free(seg1);
- return 0;
-
-malloc_error:
- free(pen);
- free(prev);
- free(clip0);
- free(clip1);
- free(seg0);
- free(seg1);
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 3: vertex adjustment (Sec. 2.3.1). */
-
-/* Adjust vertices of optimal polygon: calculate the intersection of
- the two "optimal" line segments, then move it into the unit square
- if it lies outside. Return 1 with errno set on error; 0 on
- success. */
-
-static int adjust_vertices(privpath_t * pp)
-{
- int m = pp->m;
- int *po = pp->po;
- int n = pp->len;
- point_t *pt = pp->pt;
- int x0 = pp->x0;
- int y0 = pp->y0;
-
- dpoint_t *ctr = NULL; /* ctr[m] */
- dpoint_t *dir = NULL; /* dir[m] */
- quadform_t *q = NULL; /* q[m] */
- double v[3];
- double d;
- int i, j, k, l;
- dpoint_t s;
- int r;
-
- SAFE_MALLOC(ctr, m, dpoint_t);
- SAFE_MALLOC(dir, m, dpoint_t);
- SAFE_MALLOC(q, m, quadform_t);
-
- r = privcurve_init(&pp->curve, m);
- if (r) {
- goto malloc_error;
- }
-
- /* calculate "optimal" point-slope representation for each line
- segment */
- for (i = 0; i < m; i++) {
- j = po[mod(i + 1, m)];
- j = mod(j - po[i], n) + po[i];
- pointslope(pp, po[i], j, &ctr[i], &dir[i]);
- }
-
- /* represent each line segment as a singular quadratic form; the
- distance of a point (x,y) from the line segment will be
- (x,y,1)Q(x,y,1)^t, where Q=q[i]. */
- for (i = 0; i < m; i++) {
- d = sq(dir[i].x) + sq(dir[i].y);
- if (d == 0.0) {
- for (j = 0; j < 3; j++) {
- for (k = 0; k < 3; k++) {
- q[i][j][k] = 0;
- }
- }
- }
- else {
- v[0] = dir[i].y;
- v[1] = -dir[i].x;
- v[2] = -v[1] * ctr[i].y - v[0] * ctr[i].x;
- for (l = 0; l < 3; l++) {
- for (k = 0; k < 3; k++) {
- q[i][l][k] = v[l] * v[k] / d;
- }
- }
- }
- }
-
- /* now calculate the "intersections" of consecutive segments.
- Instead of using the actual intersection, we find the point
- within a given unit square which minimizes the square distance to
- the two lines. */
- for (i = 0; i < m; i++) {
- quadform_t Q;
- dpoint_t w;
- double dx, dy;
- double det;
- double min, cand; /* minimum and candidate for minimum of quad. form */
- double xmin, ymin; /* coordinates of minimum */
- int z;
-
- /* let s be the vertex, in coordinates relative to x0/y0 */
- s.x = pt[po[i]].x - x0;
- s.y = pt[po[i]].y - y0;
-
- /* intersect segments i-1 and i */
-
- j = mod(i - 1, m);
-
- /* add quadratic forms */
- for (l = 0; l < 3; l++) {
- for (k = 0; k < 3; k++) {
- Q[l][k] = q[j][l][k] + q[i][l][k];
- }
- }
-
- while (1) {
- /* minimize the quadratic form Q on the unit square */
- /* find intersection */
-
-#ifdef HAVE_GCC_LOOP_BUG
- /* work around gcc bug #12243 */
- free(NULL);
-#endif
-
- det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0];
- if (det != 0.0) {
- w.x = (-Q[0][2] * Q[1][1] + Q[1][2] * Q[0][1]) / det;
- w.y = (Q[0][2] * Q[1][0] - Q[1][2] * Q[0][0]) / det;
- break;
- }
-
- /* matrix is singular - lines are parallel. Add another,
- orthogonal axis, through the center of the unit square */
- if (Q[0][0] > Q[1][1]) {
- v[0] = -Q[0][1];
- v[1] = Q[0][0];
- }
- else if (Q[1][1]) {
- v[0] = -Q[1][1];
- v[1] = Q[1][0];
- }
- else {
- v[0] = 1;
- v[1] = 0;
- }
- d = sq(v[0]) + sq(v[1]);
- v[2] = -v[1] * s.y - v[0] * s.x;
- for (l = 0; l < 3; l++) {
- for (k = 0; k < 3; k++) {
- Q[l][k] += v[l] * v[k] / d;
- }
- }
- }
- dx = fabs(w.x - s.x);
- dy = fabs(w.y - s.y);
- if (dx <= .5 && dy <= .5) {
- pp->curve.vertex[i].x = w.x + x0;
- pp->curve.vertex[i].y = w.y + y0;
- continue;
- }
-
- /* the minimum was not in the unit square; now minimize quadratic
- on boundary of square */
- min = quadform(Q, s);
- xmin = s.x;
- ymin = s.y;
-
- if (Q[0][0] == 0.0) {
- goto fixx;
- }
- for (z = 0; z < 2; z++) { /* value of the y-coordinate */
- w.y = s.y - 0.5 + z;
- w.x = -(Q[0][1] * w.y + Q[0][2]) / Q[0][0];
- dx = fabs(w.x - s.x);
- cand = quadform(Q, w);
- if (dx <= .5 && cand < min) {
- min = cand;
- xmin = w.x;
- ymin = w.y;
- }
- }
- fixx:
- if (Q[1][1] == 0.0) {
- goto corners;
- }
- for (z = 0; z < 2; z++) { /* value of the x-coordinate */
- w.x = s.x - 0.5 + z;
- w.y = -(Q[1][0] * w.x + Q[1][2]) / Q[1][1];
- dy = fabs(w.y - s.y);
- cand = quadform(Q, w);
- if (dy <= .5 && cand < min) {
- min = cand;
- xmin = w.x;
- ymin = w.y;
- }
- }
- corners:
- /* check four corners */
- for (l = 0; l < 2; l++) {
- for (k = 0; k < 2; k++) {
- w.x = s.x - 0.5 + l;
- w.y = s.y - 0.5 + k;
- cand = quadform(Q, w);
- if (cand < min) {
- min = cand;
- xmin = w.x;
- ymin = w.y;
- }
- }
- }
-
- pp->curve.vertex[i].x = xmin + x0;
- pp->curve.vertex[i].y = ymin + y0;
- continue;
- }
-
- free(ctr);
- free(dir);
- free(q);
- return 0;
-
-malloc_error:
- free(ctr);
- free(dir);
- free(q);
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 4: smoothing and corner analysis (Sec. 2.3.3) */
-
-/* Always succeeds and returns 0 */
-static int
-ATTRIBUTE_UNUSED smooth(privcurve_t * curve, int sign, double alphamax)
-{
- int m = curve->n;
-
- int i, j, k;
- double dd, denom, alpha;
- dpoint_t p2, p3, p4;
-
- if (sign == '-') {
- /* reverse orientation of negative paths */
- for (i = 0, j = m - 1; i < j; i++, j--) {
- dpoint_t tmp;
- tmp = curve->vertex[i];
- curve->vertex[i] = curve->vertex[j];
- curve->vertex[j] = tmp;
- }
- }
-
- /* examine each vertex and find its best fit */
- for (i = 0; i < m; i++) {
- j = mod(i + 1, m);
- k = mod(i + 2, m);
- p4 = interval(1 / 2.0, curve->vertex[k], curve->vertex[j]);
-
- denom = ddenom(curve->vertex[i], curve->vertex[k]);
- if (denom != 0.0) {
- dd = dpara(curve->vertex[i], curve->vertex[j], curve->vertex[k]) / denom;
- dd = fabs(dd);
- alpha = dd > 1 ? (1 - 1.0 / dd) : 0;
- alpha = alpha / 0.75;
- }
- else {
- alpha = 4 / 3.0;
- }
- curve->alpha0[j] = alpha; /* remember "original" value of alpha */
-
- if (alpha > alphamax) { /* pointed corner */
- curve->tag[j] = POTRACE_CORNER;
- curve->c[j][1] = curve->vertex[j];
- curve->c[j][2] = p4;
- }
- else {
- if (alpha < 0.55) {
- alpha = 0.55;
- }
- else if (alpha > 1) {
- alpha = 1;
- }
- p2 = interval(.5 + .5 * alpha, curve->vertex[i], curve->vertex[j]);
- p3 = interval(.5 + .5 * alpha, curve->vertex[k], curve->vertex[j]);
- curve->tag[j] = POTRACE_CURVETO;
- curve->c[j][0] = p2;
- curve->c[j][1] = p3;
- curve->c[j][2] = p4;
- }
- curve->alpha[j] = alpha; /* store the "cropped" value of alpha */
- curve->beta[j] = 0.5;
- }
- curve->alphacurve = 1;
-
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 5: Curve optimization (Sec. 2.4) */
-
-/* a private type for the result of opti_penalty */
-struct opti_s {
- double pen; /* penalty */
- dpoint_t c[2]; /* curve parameters */
- double t, s; /* curve parameters */
- double alpha; /* curve parameter */
-};
-typedef struct opti_s opti_t;
-
-/* calculate best fit from i+.5 to j+.5. Assume icurve.n;
- int k, k1, k2, conv, i1;
- double area, alpha, d, d1, d2;
- dpoint_t p0, p1, p2, p3, pt;
- double A, R, A1, A2, A3, A4;
- double s, t;
-
- /* check convexity, corner-freeness, and maximum bend < 179 degrees */
-
- if (i == j) { /* sanity - a full loop can never be an opticurve */
- return 1;
- }
-
- k = i;
- i1 = mod(i + 1, m);
- k1 = mod(k + 1, m);
- conv = convc[k1];
- if (conv == 0) {
- return 1;
- }
- d = ddist(pp->curve.vertex[i], pp->curve.vertex[i1]);
- for (k = k1; k != j; k = k1) {
- k1 = mod(k + 1, m);
- k2 = mod(k + 2, m);
- if (convc[k1] != conv) {
- return 1;
- }
- if (sign(cprod(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2])) != conv) {
- return 1;
- }
- if (iprod1
- (pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1],
- pp->curve.vertex[k2]) < d * ddist(pp->curve.vertex[k1], pp->curve.vertex[k2]) * COS179) {
- return 1;
- }
- }
-
- /* the curve we're working in: */
- p0 = pp->curve.c[mod(i, m)][2];
- p1 = pp->curve.vertex[mod(i + 1, m)];
- p2 = pp->curve.vertex[mod(j, m)];
- p3 = pp->curve.c[mod(j, m)][2];
-
- /* determine its area */
- area = areac[j] - areac[i];
- area -= dpara(pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2]) / 2;
- if (i >= j) {
- area += areac[m];
- }
-
- /* find intersection o of p0p1 and p2p3. Let t,s such that o =
- interval(t,p0,p1) = interval(s,p3,p2). Let A be the area of the
- triangle (p0,o,p3). */
-
- A1 = dpara(p0, p1, p2);
- A2 = dpara(p0, p1, p3);
- A3 = dpara(p0, p2, p3);
- /* A4 = dpara(p1, p2, p3); */
- A4 = A1 + A3 - A2;
-
- if (A2 == A1) { /* this should never happen */
- return 1;
- }
-
- t = A3 / (A3 - A4);
- s = A2 / (A2 - A1);
- A = A2 * t / 2.0;
-
- if (A == 0.0) { /* this should never happen */
- return 1;
- }
-
- R = area / A; /* relative area */
- alpha = 2 - sqrt(4 - R / 0.3); /* overall alpha for p0-o-p3 curve */
-
- res->c[0] = interval(t * alpha, p0, p1);
- res->c[1] = interval(s * alpha, p3, p2);
- res->alpha = alpha;
- res->t = t;
- res->s = s;
-
- p1 = res->c[0];
- p2 = res->c[1]; /* the proposed curve is now (p0,p1,p2,p3) */
-
- res->pen = 0;
-
- /* calculate penalty */
- /* check tangency with edges */
- for (k = mod(i + 1, m); k != j; k = k1) {
- k1 = mod(k + 1, m);
- t = tangent(p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1]);
- if (t < -.5) {
- return 1;
- }
- pt = bezier(t, p0, p1, p2, p3);
- d = ddist(pp->curve.vertex[k], pp->curve.vertex[k1]);
- if (d == 0.0) { /* this should never happen */
- return 1;
- }
- d1 = dpara(pp->curve.vertex[k], pp->curve.vertex[k1], pt) / d;
- if (fabs(d1) > opttolerance) {
- return 1;
- }
- if (iprod(pp->curve.vertex[k], pp->curve.vertex[k1], pt) < 0 || iprod(pp->curve.vertex[k1], pp->curve.vertex[k], pt) < 0) {
- return 1;
- }
- res->pen += sq(d1);
- }
-
- /* check corners */
- for (k = i; k != j; k = k1) {
- k1 = mod(k + 1, m);
- t = tangent(p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2]);
- if (t < -.5) {
- return 1;
- }
- pt = bezier(t, p0, p1, p2, p3);
- d = ddist(pp->curve.c[k][2], pp->curve.c[k1][2]);
- if (d == 0.0) { /* this should never happen */
- return 1;
- }
- d1 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pt) / d;
- d2 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pp->curve.vertex[k1]) / d;
- d2 *= 0.75 * pp->curve.alpha[k1];
- if (d2 < 0) {
- d1 = -d1;
- d2 = -d2;
- }
- if (d1 < d2 - opttolerance) {
- return 1;
- }
- if (d1 < d2) {
- res->pen += sq(d1 - d2);
- }
- }
-
- return 0;
-}
-
-/* optimize the path p, replacing sequences of Bezier segments by a
- single segment when possible. Return 0 on success, 1 with errno set
- on failure. */
-static int
-ATTRIBUTE_UNUSED opticurve(privpath_t * pp, double opttolerance)
-{
- int m = pp->curve.n;
- int *pt = NULL; /* pt[m+1] */
- double *pen = NULL; /* pen[m+1] */
- int *len = NULL; /* len[m+1] */
- opti_t *opt = NULL; /* opt[m+1] */
- int om;
- int i, j, r;
- opti_t o;
- dpoint_t p0;
- int i1;
- double area;
- double alpha;
- double *s = NULL;
- double *t = NULL;
-
- int *convc = NULL; /* conv[m]: pre-computed convexities */
- double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */
-
- SAFE_MALLOC(pt, m + 1, int);
- SAFE_MALLOC(pen, m + 1, double);
- SAFE_MALLOC(len, m + 1, int);
- SAFE_MALLOC(opt, m + 1, opti_t);
- SAFE_MALLOC(convc, m, int);
- SAFE_MALLOC(areac, m + 1, double);
-
- /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
- for (i = 0; i < m; i++) {
- if (pp->curve.tag[i] == POTRACE_CURVETO) {
- convc[i] = sign(dpara(pp->curve.vertex[mod(i - 1, m)], pp->curve.vertex[i], pp->curve.vertex[mod(i + 1, m)]));
- }
- else {
- convc[i] = 0;
- }
- }
-
- /* pre-calculate areas */
- area = 0.0;
- areac[0] = 0.0;
- p0 = pp->curve.vertex[0];
- for (i = 0; i < m; i++) {
- i1 = mod(i + 1, m);
- if (pp->curve.tag[i1] == POTRACE_CURVETO) {
- alpha = pp->curve.alpha[i1];
- area += 0.3 * alpha * (4 - alpha) * dpara(pp->curve.c[i][2], pp->curve.vertex[i1], pp->curve.c[i1][2]) / 2;
- area += dpara(p0, pp->curve.c[i][2], pp->curve.c[i1][2]) / 2;
- }
- areac[i + 1] = area;
- }
-
- pt[0] = -1;
- pen[0] = 0;
- len[0] = 0;
-
- /* Fixme: we always start from a fixed point -- should find the best
- curve cyclically ### */
-
- for (j = 1; j <= m; j++) {
- /* calculate best path from 0 to j */
- pt[j] = j - 1;
- pen[j] = pen[j - 1];
- len[j] = len[j - 1] + 1;
-
- for (i = j - 2; i >= 0; i--) {
- r = opti_penalty(pp, i, mod(j, m), &o, opttolerance, convc, areac);
- if (r) {
- break;
- }
- if (len[j] > len[i] + 1 || (len[j] == len[i] + 1 && pen[j] > pen[i] + o.pen)) {
- pt[j] = i;
- pen[j] = pen[i] + o.pen;
- len[j] = len[i] + 1;
- opt[j] = o;
- }
- }
- }
- om = len[m];
- r = privcurve_init(&pp->ocurve, om);
- if (r) {
- goto malloc_error;
- }
- SAFE_MALLOC(s, om, double);
- SAFE_MALLOC(t, om, double);
-
- j = m;
- for (i = om - 1; i >= 0; i--) {
- if (pt[j] == j - 1) {
- pp->ocurve.tag[i] = pp->curve.tag[mod(j, m)];
- pp->ocurve.c[i][0] = pp->curve.c[mod(j, m)][0];
- pp->ocurve.c[i][1] = pp->curve.c[mod(j, m)][1];
- pp->ocurve.c[i][2] = pp->curve.c[mod(j, m)][2];
- pp->ocurve.vertex[i] = pp->curve.vertex[mod(j, m)];
- pp->ocurve.alpha[i] = pp->curve.alpha[mod(j, m)];
- pp->ocurve.alpha0[i] = pp->curve.alpha0[mod(j, m)];
- pp->ocurve.beta[i] = pp->curve.beta[mod(j, m)];
- s[i] = t[i] = 1.0;
- }
- else {
- pp->ocurve.tag[i] = POTRACE_CURVETO;
- pp->ocurve.c[i][0] = opt[j].c[0];
- pp->ocurve.c[i][1] = opt[j].c[1];
- pp->ocurve.c[i][2] = pp->curve.c[mod(j, m)][2];
- pp->ocurve.vertex[i] = interval(opt[j].s, pp->curve.c[mod(j, m)][2], pp->curve.vertex[mod(j, m)]);
- pp->ocurve.alpha[i] = opt[j].alpha;
- pp->ocurve.alpha0[i] = opt[j].alpha;
- s[i] = opt[j].s;
- t[i] = opt[j].t;
- }
- j = pt[j];
- }
-
- /* calculate beta parameters */
- for (i = 0; i < om; i++) {
- i1 = mod(i + 1, om);
- pp->ocurve.beta[i] = s[i] / (s[i] + t[i1]);
- }
- pp->ocurve.alphacurve = 1;
-
- free(pt);
- free(pen);
- free(len);
- free(opt);
- free(s);
- free(t);
- free(convc);
- free(areac);
- return 0;
-
-malloc_error:
- free(pt);
- free(pen);
- free(len);
- free(opt);
- free(s);
- free(t);
- free(convc);
- free(areac);
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-double plotpolygon(privpath_t * pp, FILE * f, double scale)
-{
- int i;
- int m = pp->m;
- int *po = pp->po;
- point_t *pt = pp->pt;
- /* double scale=1.0/dpi; */
- double dm = 0;
-
- if (!m)
- return 0;
-
- po = pp->po;
- pt = pp->pt;
-
- fprintf(f, "G0 X%f Y%f (start point)\n", pt[po[0]].x * scale, pt[po[0]].y * scale);
- fprintf(f, "G1 Z#101\n");
- for (i = 1; i < m; i++) {
- fprintf(f, "G1 X%f Y%f\n", pt[po[i]].x * scale, pt[po[i]].y * scale);
- dm +=
- sqrt((pt[po[i]].x - pt[po[i - 1]].x) * scale * (pt[po[i]].x -
- pt[po[i - 1]].x) *
- scale + (pt[po[i]].y - pt[po[i - 1]].y) * scale * (pt[po[i]].y - pt[po[i - 1]].y) * scale);
- }
- fprintf(f, "G1 X%f Y%f\n", pt[po[0]].x * scale, pt[po[0]].y * scale);
- fprintf(f, "G0 Z#100\n");
- dm +=
- sqrt((pt[po[m - 1]].x - pt[po[0]].x) * scale * (pt[po[m - 1]].x -
- pt[po[0]].x) * scale +
- (pt[po[m - 1]].y - pt[po[0]].y) * scale * (pt[po[m - 1]].y - pt[po[0]].y) * scale);
- fprintf(f, "(polygon end, distance %.2f)\n", dm);
- return dm;
-}
-
-#define TRY(x) if (x) goto try_error
-
-/* return distance on success, -1 on error with errno set. */
-double process_path(path_t * plist, const potrace_param_t * param, const potrace_bitmap_t * bm, FILE * f, double scale)
-{
- path_t *p;
- double dm = 0;
- int n = 0;
- /* call downstream function with each path */
- list_forall(p, plist) {
- TRY(calc_sums(p->priv));
- TRY(calc_lon(p->priv));
- TRY(bestpolygon(p->priv));
- TRY(adjust_vertices(p->priv));
- fprintf(f, "(polygon %d)\n", ++n);
- dm += plotpolygon(p->priv, f, scale);
-/* No need to extract curves
- TRY(smooth(&p->priv->curve, p->sign, param->alphamax));
- if (param->opticurve) {
- TRY(opticurve(p->priv, param->opttolerance));
- p->priv->fcurve = &p->priv->ocurve;
- } else {
- p->priv->fcurve = &p->priv->curve;
- }
- privcurve_to_curve(p->priv->fcurve, &p->curve);*/
- }
-/* fprintf(f,"(end, total distance %.2fmm = %.2fin)\n",25.4*dm,dm); */
- return dm;
-
-try_error:
- return -1;
-}
Index: trunk/src/hid/gcode/decompose.c
===================================================================
--- trunk/src/hid/gcode/decompose.c (revision 1268)
+++ trunk/src/hid/gcode/decompose.c (nonexistent)
@@ -1,525 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* $Id: decompose.c 146 2007-04-09 00:43:46Z selinger $ */
-
-#include
-#include
-#include
-#include
-
-#include "potracelib.h"
-#include "curve.h"
-#include "lists.h"
-#include "auxiliary.h"
-#include "bitmap.h"
-#include "decompose.h"
-/*#include "progress.h"*/
-
-/* ---------------------------------------------------------------------- */
-/* auxiliary bitmap manipulations */
-
-/* set the excess padding to 0 */
-static void bm_clearexcess(potrace_bitmap_t * bm)
-{
- potrace_word mask;
- int y;
-
- if (bm->w % BM_WORDBITS != 0) {
- mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS));
- for (y = 0; y < bm->h; y++) {
- *bm_index(bm, bm->w, y) &= mask;
- }
- }
-}
-
-struct bbox_s {
- int x0, x1, y0, y1; /* bounding box */
-};
-typedef struct bbox_s bbox_t;
-
-/* clear the bm, assuming the bounding box is set correctly (faster
- than clearing the whole bitmap) */
-static void clear_bm_with_bbox(potrace_bitmap_t * bm, bbox_t * bbox)
-{
- int imin = (bbox->x0 / BM_WORDBITS);
- int imax = ((bbox->x1 + BM_WORDBITS - 1) / BM_WORDBITS);
- int i, y;
-
- for (y = bbox->y0; y < bbox->y1; y++) {
- for (i = imin; i < imax; i++) {
- bm_scanline(bm, y)[i] = 0;
- }
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/* auxiliary functions */
-
-/* deterministically and efficiently hash (x,y) into a pseudo-random bit */
-static inline int detrand(int x, int y)
-{
- unsigned int z;
- static const unsigned char t[256] = {
- /* non-linear sequence: constant term of inverse in GF(8),
- mod x^8+x^4+x^3+x+1 */
- 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
- 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
- 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
- 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
- 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
- 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
- 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
- 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
- };
-
- /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
- 5-bit sequence */
- z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
- z = t[z & 0xff] ^ t[(z >> 8) & 0xff] ^ t[(z >> 16) & 0xff] ^ t[(z >> 24) & 0xff];
- return z & 1;
-}
-
-/* return the "majority" value of bitmap bm at intersection (x,y). We
- assume that the bitmap is balanced at "radius" 1. */
-static int majority(potrace_bitmap_t * bm, int x, int y)
-{
- int i, a, ct;
-
- for (i = 2; i < 5; i++) { /* check at "radius" i */
- ct = 0;
- for (a = -i + 1; a <= i - 1; a++) {
- ct += BM_GET(bm, x + a, y + i - 1) ? 1 : -1;
- ct += BM_GET(bm, x + i - 1, y + a - 1) ? 1 : -1;
- ct += BM_GET(bm, x + a - 1, y - i) ? 1 : -1;
- ct += BM_GET(bm, x - i, y + a) ? 1 : -1;
- }
- if (ct > 0) {
- return 1;
- }
- else if (ct < 0) {
- return 0;
- }
- }
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-/* decompose image into paths */
-
-/* efficiently invert bits [x,infty) and [xa,infty) in line y. Here xa
- must be a multiple of BM_WORDBITS. */
-static void xor_to_ref(potrace_bitmap_t * bm, int x, int y, int xa)
-{
- int xhi = x & -BM_WORDBITS;
- int xlo = x & (BM_WORDBITS - 1); /* = x % BM_WORDBITS */
- int i;
-
- if (xhi < xa) {
- for (i = xhi; i < xa; i += BM_WORDBITS) {
- *bm_index(bm, i, y) ^= BM_ALLBITS;
- }
- }
- else {
- for (i = xa; i < xhi; i += BM_WORDBITS) {
- *bm_index(bm, i, y) ^= BM_ALLBITS;
- }
- }
- /* note: the following "if" is needed because x86 treats a<priv->len <= 0) { /* a path of length 0 is silly, but legal */
- return;
- }
-
- y1 = p->priv->pt[p->priv->len - 1].y;
-
- xa = p->priv->pt[0].x & -BM_WORDBITS;
- for (k = 0; k < p->priv->len; k++) {
- x = p->priv->pt[k].x;
- y = p->priv->pt[k].y;
-
- if (y != y1) {
- /* efficiently invert the rectangle [x,xa] x [y,y1] */
- xor_to_ref(bm, x, min(y, y1), xa);
- y1 = y;
- }
- }
-}
-
-/* Find the bounding box of a given path. Path is assumed to be of
- non-zero length. */
-static void setbbox_path(bbox_t * bbox, path_t * p)
-{
- int x, y;
- int k;
-
- bbox->y0 = INT_MAX;
- bbox->y1 = 0;
- bbox->x0 = INT_MAX;
- bbox->x1 = 0;
-
- for (k = 0; k < p->priv->len; k++) {
- x = p->priv->pt[k].x;
- y = p->priv->pt[k].y;
-
- if (x < bbox->x0) {
- bbox->x0 = x;
- }
- if (x > bbox->x1) {
- bbox->x1 = x;
- }
- if (y < bbox->y0) {
- bbox->y0 = y;
- }
- if (y > bbox->y1) {
- bbox->y1 = y;
- }
- }
-}
-
-/* compute a path in the given pixmap, separating black from white.
- Start path at the point (x0,x1), which must be an upper left corner
- of the path. Also compute the area enclosed by the path. Return a
- new path_t object, or NULL on error (note that a legitimate path
- cannot have length 0). Sign is required for correct interpretation
- of turnpolicies. */
-static path_t *findpath(potrace_bitmap_t * bm, int x0, int y0, int sign, int turnpolicy)
-{
- int x, y, dirx, diry, len, size, area;
- int c, d, tmp;
- point_t *pt, *pt1;
- path_t *p = NULL;
-
- x = x0;
- y = y0;
- dirx = 0;
- diry = -1;
-
- len = size = 0;
- pt = NULL;
- area = 0;
-
- while (1) {
- /* add point to path */
- if (len >= size) {
- size += 100;
- size = (int) (1.3 * size);
- pt1 = (point_t *) realloc(pt, size * sizeof(point_t));
- if (!pt1) {
- goto error;
- }
- pt = pt1;
- }
- pt[len].x = x;
- pt[len].y = y;
- len++;
-
- /* move to next point */
- x += dirx;
- y += diry;
- area += x * diry;
-
- /* path complete? */
- if (x == x0 && y == y0) {
- break;
- }
-
- /* determine next direction */
- c = BM_GET(bm, x + (dirx + diry - 1) / 2, y + (diry - dirx - 1) / 2);
- d = BM_GET(bm, x + (dirx - diry - 1) / 2, y + (diry + dirx - 1) / 2);
-
- if (c && !d) { /* ambiguous turn */
- if (turnpolicy == POTRACE_TURNPOLICY_RIGHT || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+')
- || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-')
- || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand(x, y))
- || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority(bm, x, y))
- || (turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority(bm, x, y))) {
- tmp = dirx; /* right turn */
- dirx = diry;
- diry = -tmp;
- }
- else {
- tmp = dirx; /* left turn */
- dirx = -diry;
- diry = tmp;
- }
- }
- else if (c) { /* right turn */
- tmp = dirx;
- dirx = diry;
- diry = -tmp;
- }
- else if (!d) { /* left turn */
- tmp = dirx;
- dirx = -diry;
- diry = tmp;
- }
- } /* while this path */
-
- /* allocate new path object */
- p = path_new();
- if (!p) {
- goto error;
- }
-
- p->priv->pt = pt;
- p->priv->len = len;
- p->area = area;
- p->sign = sign;
-
- return p;
-
-error:
- free(pt);
- return NULL;
-}
-
-/* Give a tree structure to the given path list, based on "insideness"
- testing. I.e., path A is considered "below" path B if it is inside
- path B. The input pathlist is assumed to be ordered so that "outer"
- paths occur before "inner" paths. The tree structure is stored in
- the "childlist" and "sibling" components of the path_t
- structure. The linked list structure is also changed so that
- negative path components are listed immediately after their
- positive parent. Note: some backends may ignore the tree
- structure, others may use it e.g. to group path components. We
- assume that in the input, point 0 of each path is an "upper left"
- corner of the path, as returned by bm_to_pathlist. This makes it
- easy to find an "interior" point. The bm argument should be a
- bitmap of the correct size (large enough to hold all the paths),
- and will be used as scratch space. Return 0 on success or -1 on
- error with errno set. */
-
-static void pathlist_to_tree(path_t * plist, potrace_bitmap_t * bm)
-{
- path_t *p, *p1;
- path_t *heap, *heap1;
- path_t *cur;
- path_t *head;
- path_t **hook, **hook_in, **hook_out; /* for fast appending to linked list */
- bbox_t bbox;
-
- bm_clear(bm, 0);
-
- /* save original "next" pointers */
- list_forall(p, plist) {
- p->sibling = p->next;
- p->childlist = NULL;
- }
-
- heap = plist;
-
- /* the heap holds a list of lists of paths. Use "childlist" field
- for outer list, "next" field for inner list. Each of the sublists
- is to be turned into a tree. This code is messy, but it is
- actually fast. Each path is rendered exactly once. We use the
- heap to get a tail recursive algorithm: the heap holds a list of
- pathlists which still need to be transformed. */
-
- while (heap) {
- /* unlink first sublist */
- cur = heap;
- heap = heap->childlist;
- cur->childlist = NULL;
-
- /* unlink first path */
- head = cur;
- cur = cur->next;
- head->next = NULL;
-
- /* render path */
- xor_path(bm, head);
- setbbox_path(&bbox, head);
-
- /* now do insideness test for each element of cur; append it to
- head->childlist if it's inside head, else append it to
- head->next. */
- hook_in = &head->childlist;
- hook_out = &head->next;
- list_forall_unlink(p, cur) {
- if (p->priv->pt[0].y <= bbox.y0) {
- list_insert_beforehook(p, hook_out);
- /* append the remainder of the list to hook_out */
- *hook_out = cur;
- break;
- }
- if (BM_GET(bm, p->priv->pt[0].x, p->priv->pt[0].y - 1)) {
- list_insert_beforehook(p, hook_in);
- }
- else {
- list_insert_beforehook(p, hook_out);
- }
- }
-
- /* clear bm */
- clear_bm_with_bbox(bm, &bbox);
-
- /* now schedule head->childlist and head->next for further
- processing */
- if (head->next) {
- head->next->childlist = heap;
- heap = head->next;
- }
- if (head->childlist) {
- head->childlist->childlist = heap;
- heap = head->childlist;
- }
- }
-
- /* copy sibling structure from "next" to "sibling" component */
- p = plist;
- while (p) {
- p1 = p->sibling;
- p->sibling = p->next;
- p = p1;
- }
-
- /* reconstruct a new linked list ("next") structure from tree
- ("childlist", "sibling") structure. This code is slightly messy,
- because we use a heap to make it tail recursive: the heap
- contains a list of childlists which still need to be
- processed. */
- heap = plist;
- if (heap) {
- heap->next = NULL; /* heap is a linked list of childlists */
- }
- plist = NULL;
- hook = &plist;
- while (heap) {
- heap1 = heap->next;
- for (p = heap; p; p = p->sibling) {
- /* p is a positive path */
- /* append to linked list */
- list_insert_beforehook(p, hook);
-
- /* go through its children */
- for (p1 = p->childlist; p1; p1 = p1->sibling) {
- /* append to linked list */
- list_insert_beforehook(p1, hook);
- /* append its childlist to heap, if non-empty */
- if (p1->childlist) {
- list_append(path_t, heap1, p1->childlist);
- }
- }
- }
- heap = heap1;
- }
-
- return;
-}
-
-/* find the next set pixel in a row <= y. Pixels are searched first
- left-to-right, then top-down. In other words, (x,y)<(x',y') if y>y'
- or y=y' and x= 0; y--) {
- for (x = 0; x < bm->w; x += BM_WORDBITS) {
- if (*bm_index(bm, x, y)) {
- while (!BM_GET(bm, x, y)) {
- x++;
- }
- /* found */
- *xp = x;
- *yp = y;
- return 0;
- }
- }
- }
- /* not found */
- return 1;
-}
-
-/* Decompose the given bitmap into paths. Returns a linked list of
- path_t objects with the fields len, pt, area, sign filled
- in. Returns 0 on success with plistp set, or -1 on error with errno
- set. */
-
-int bm_to_pathlist(const potrace_bitmap_t * bm, path_t ** plistp, const potrace_param_t * param)
-{
- int x;
- int y;
- path_t *p;
- path_t *plist = NULL; /* linked list of path objects */
- path_t **hook = &plist; /* used to speed up appending to linked list */
- potrace_bitmap_t *bm1 = NULL;
- int sign;
-
- bm1 = bm_dup(bm);
- if (!bm1) {
- goto error;
- }
-
- /* be sure the byte padding on the right is set to 0, as the fast
- pixel search below relies on it */
- bm_clearexcess(bm1);
-
- /* iterate through components */
- y = bm1->h - 1;
- while (findnext(bm1, &x, &y) == 0) {
- /* calculate the sign by looking at the original */
- sign = BM_GET(bm, x, y) ? '+' : '-';
-
- /* calculate the path */
- p = findpath(bm1, x, y + 1, sign, param->turnpolicy);
- if (p == NULL) {
- goto error;
- }
-
- /* update buffered image */
- xor_path(bm1, p);
-
- /* if it's a turd, eliminate it, else append it to the list */
- if (p->area <= param->turdsize) {
- path_free(p);
- }
- else {
- list_insert_beforehook(p, hook);
- }
-
- if (bm1->h > 0) { /* to be sure */
- /*progress_update(1-y/(double)bm1->h, progress); */
- }
- }
-
- pathlist_to_tree(plist, bm1);
- bm_free(bm1);
- *plistp = plist;
-
-/* progress_update(1.0, progress);*/
-
- return 0;
-
-error:
- bm_free(bm1);
- list_forall_unlink(p, plist) {
- path_free(p);
- }
- return -1;
-}
Index: trunk/src/hid/gcode/bitmap.h
===================================================================
--- trunk/src/hid/gcode/bitmap.h (revision 1268)
+++ trunk/src/hid/gcode/bitmap.h (nonexistent)
@@ -1,104 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-#ifndef BITMAP_H
-#define BITMAP_H
-
-#include "config.h"
-
-#include
-#include
-
-/* The bitmap type is defined in potracelib.h */
-#include "potracelib.h"
-
-/* The present file defines some convenient macros and static inline
- functions for accessing bitmaps. Since they only produce inline
- code, they can be conveniently shared by the library and frontends,
- if desired */
-
-/* ---------------------------------------------------------------------- */
-/* some measurements */
-
-#define BM_WORDSIZE ((int)sizeof(potrace_word))
-#define BM_WORDBITS (8*BM_WORDSIZE)
-#define BM_HIBIT (((potrace_word)1)<<(BM_WORDBITS-1))
-#define BM_ALLBITS (~(potrace_word)0)
-
-/* macros for accessing pixel at index (x,y). U* macros omit the
- bounds check. */
-
-#define bm_scanline(bm, y) ((bm)->map + (y)*(bm)->dy)
-#define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS])
-#define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1)))
-#define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a))
-#define bm_safe(bm, x, y) (bm_range(x, (bm)->w) && bm_range(y, (bm)->h))
-#define BM_UGET(bm, x, y) ((*bm_index(bm, x, y) & bm_mask(x)) != 0)
-#define BM_USET(bm, x, y) (*bm_index(bm, x, y) |= bm_mask(x))
-#define BM_UCLR(bm, x, y) (*bm_index(bm, x, y) &= ~bm_mask(x))
-#define BM_UINV(bm, x, y) (*bm_index(bm, x, y) ^= bm_mask(x))
-#define BM_UPUT(bm, x, y, b) ((b) ? BM_USET(bm, x, y) : BM_UCLR(bm, x, y))
-#define BM_GET(bm, x, y) (bm_safe(bm, x, y) ? BM_UGET(bm, x, y) : 0)
-#define BM_SET(bm, x, y) (bm_safe(bm, x, y) ? BM_USET(bm, x, y) : 0)
-#define BM_CLR(bm, x, y) (bm_safe(bm, x, y) ? BM_UCLR(bm, x, y) : 0)
-#define BM_INV(bm, x, y) (bm_safe(bm, x, y) ? BM_UINV(bm, x, y) : 0)
-#define BM_PUT(bm, x, y, b) (bm_safe(bm, x, y) ? BM_UPUT(bm, x, y, b) : 0)
-
-/* free the given bitmap. Leaves errno untouched. */
-static inline void bm_free(potrace_bitmap_t * bm)
-{
- if (bm) {
- free(bm->map);
- }
- free(bm);
-}
-
-/* return new un-initialized bitmap. NULL with errno on error */
-static inline potrace_bitmap_t *bm_new(int w, int h)
-{
- potrace_bitmap_t *bm;
- int dy = (w + BM_WORDBITS - 1) / BM_WORDBITS;
-
- bm = (potrace_bitmap_t *) malloc(sizeof(potrace_bitmap_t));
- if (!bm) {
- return NULL;
- }
- bm->w = w;
- bm->h = h;
- bm->dy = dy;
- bm->map = (potrace_word *) malloc(dy * h * BM_WORDSIZE);
- if (!bm->map) {
- free(bm);
- return NULL;
- }
- return bm;
-}
-
-/* clear the given bitmap. Set all bits to c. */
-static inline void bm_clear(potrace_bitmap_t * bm, int c)
-{
- memset(bm->map, c ? -1 : 0, bm->dy * bm->h * BM_WORDSIZE);
-}
-
-/* duplicate the given bitmap. Return NULL on error with errno set. */
-static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t * bm)
-{
- potrace_bitmap_t *bm1 = bm_new(bm->w, bm->h);
- if (!bm1) {
- return NULL;
- }
- memcpy(bm1->map, bm->map, bm->dy * bm->h * BM_WORDSIZE);
- return bm1;
-}
-
-/* invert the given bitmap. */
-static inline void bm_invert(potrace_bitmap_t * bm)
-{
- int i;
- for (i = 0; i < bm->dy * bm->h; i++) {
- bm->map[i] ^= BM_ALLBITS;
- }
-}
-
-#endif /* BITMAP_H */
Index: trunk/src/hid/gcode/gcode.c
===================================================================
--- trunk/src/hid/gcode/gcode.c (revision 1268)
+++ trunk/src/hid/gcode/gcode.c (nonexistent)
@@ -1,898 +0,0 @@
-/*
- * COPYRIGHT
- *
- * PCB, interactive printed circuit board design
- *
- * GCODE export HID
- * Copyright (C) 2010 Alberto Maccioni
- * this code is based on the NELMA export HID, the PNG export HID,
- * and potrace, a tracing program by Peter Selinger
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
- * This HID exports a PCB layout into:
- * one layer mask file (PNG format) per copper layer,
- * one G-CODE CNC drill file.
- * one G-CODE CNC file per copper layer.
- * The latter is used by a CNC milling machine to mill the pcb.
- */
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include "global.h"
-#include "error.h" /* Message() */
-#include "data.h"
-#include "misc.h"
-#include "rats.h"
-
-#include "hid.h"
-#include "../hidint.h"
-#include
-#include "hid/common/hidnogui.h"
-#include "hid/common/draw_helpers.h"
-#include "gcode.h"
-#include "bitmap.h"
-#include "curve.h"
-#include "potracelib.h"
-#include "trace.h"
-#include "decompose.h"
-#include "pcb-printf.h"
-
-#include "hid/common/hidinit.h"
-
-const char *gcode_cookie = "gcode HID";
-
-#define CRASH fprintf(stderr, "HID error: pcb called unimplemented GCODE function %s.\n", __FUNCTION__); abort()
-struct color_struct {
- /* the descriptor used by the gd library */
- int c;
-
- /* so I can figure out what rgb value c refers to */
- unsigned int r, g, b;
-};
-
-struct hid_gc_struct {
- HID *me_pointer;
- EndCapStyle cap;
- int width;
- unsigned char r, g, b;
- int erase;
- int faded;
- struct color_struct *color;
- gdImagePtr brush;
-};
-
-static struct color_struct *black = NULL, *white = NULL;
-static int linewidth = -1;
-static gdImagePtr lastbrush = (gdImagePtr) ((void *) -1);
-static int lastcolor = -1;
-
-/* gd image and file for PNG export */
-static gdImagePtr gcode_im = NULL;
-static FILE *gcode_f = NULL, *gcode_f2 = NULL;
-
-static int is_mask;
-static int is_drill;
-static int is_solder;
-
-/*
- * Which groups of layers to export into PNG layer masks. 1 means export, 0
- * means do not export.
- */
-static int gcode_export_group[MAX_LAYER];
-
-/* Group that is currently exported. */
-static int gcode_cur_group;
-
-/* Filename prefix that will be used when saving files. */
-static const char *gcode_basename = NULL;
-
-/* Horizontal DPI (grid points per inch) */
-static int gcode_dpi = -1;
-
-static double gcode_cutdepth = 0; /* milling depth (inch) */
-static double gcode_drilldepth = 0; /* drilling depth (inch) */
-static double gcode_safeZ = 100; /* safe Z (inch) */
-static double gcode_toolradius = 0; /* tool radius(inch) */
-static int save_drill = 0;
-static int n_drill = 0;
-static int nmax_drill = 0;
-struct drill_struct {
- double x;
- double y;
-};
-
-static struct drill_struct *drill = 0;
-
-static const char *units[] = {
- "mm",
- "mil",
- "um",
- "inch",
- NULL
-};
-
-HID_Attribute gcode_attribute_list[] = {
- /* other HIDs expect this to be first. */
- {"basename", "File name prefix",
- HID_String, 0, 0, {0, 0, 0}, 0, 0},
-#define HA_basename 0
-
- {"dpi", "Resolution of intermediate image (pixels/inch)",
- HID_Integer, 0, 2000, {600, 0, 0}, 0, 0},
-#define HA_dpi 1
-
- {"mill-depth", "Milling depth",
- HID_Real, -1000, 1000, {0, 0, -0.05}, 0, 0},
-#define HA_cutdepth 2
-
- {"safe-Z", "Safe Z for traverse move",
- HID_Real, -1000, 10000, {0, 0, 2}, 0, 0},
-#define HA_safeZ 3
-
- {"tool-radius", "Milling tool radius compensation",
- HID_Real, 0, 10000, {0, 0, 0.1}, 0, 0},
-#define HA_toolradius 4
-
- {"drill-depth", "Drilling depth",
- HID_Real, -10000, 10000, {0, 0, -2}, 0, 0},
-#define HA_drilldepth 5
-
- {"measurement-unit", "Measurement unit",
- HID_Unit, 0, 0, {-1, 0, 0}, units, 0},
-#define HA_unit 6
-
-};
-
-#define NUM_OPTIONS (sizeof(gcode_attribute_list)/sizeof(gcode_attribute_list[0]))
-
-REGISTER_ATTRIBUTES(gcode_attribute_list, gcode_cookie)
- static HID_Attr_Val gcode_values[NUM_OPTIONS];
-
-/* *** Utility funcions **************************************************** */
-
-/* convert from default PCB units to gcode units */
- static int pcb_to_gcode(int pcb)
-{
- return round(COORD_TO_INCH(pcb) * gcode_dpi);
-}
-
-static char *gcode_get_png_name(const char *basename, const char *suffix)
-{
- return pcb_strdup_printf("%s.%s.png", basename, suffix);
-}
-
-/* Sorts drills in order of distance from the origin */
-struct drill_struct *sort_drill(struct drill_struct *drill, int n_drill)
-{
- int i, j, imin;
- double dmin, d;
- struct drill_struct p = { 0, 0 };
- struct drill_struct *temp = (struct drill_struct *) malloc(n_drill * sizeof(struct drill_struct));
- for (j = 0; j < n_drill; j++) {
- dmin = 1e20;
- imin = 0;
- for (i = 0; i < n_drill - j; i++) {
- d = (drill[i].x - p.x) * (drill[i].x - p.x) + (drill[i].y - p.y) * (drill[i].y - p.y);
- if (d < dmin) {
- imin = i;
- dmin = d;
- }
- }
- /* printf("j=%d imin=%d dmin=%f p=(%f,%f)\n",j,imin,dmin,p.x,p.y); */
- temp[j] = drill[imin];
- drill[imin] = drill[n_drill - j - 1];
- p = temp[j];
- }
- free(drill);
- return temp;
-}
-
-/* *** Main export callback ************************************************ */
-
-static void gcode_parse_arguments(int *argc, char ***argv)
-{
- hid_register_attributes(gcode_attribute_list, sizeof(gcode_attribute_list) / sizeof(gcode_attribute_list[0]), gcode_cookie);
- hid_parse_command_line(argc, argv);
-}
-
-static HID_Attribute *gcode_get_export_options(int *n)
-{
- static char *last_made_filename = 0;
- static int last_unit_value = -1;
-
- if (gcode_attribute_list[HA_unit].default_val.int_value == last_unit_value) {
- if (Settings.grid_unit)
- gcode_attribute_list[HA_unit].default_val.int_value = Settings.grid_unit->index;
- else
- gcode_attribute_list[HA_unit].default_val.int_value = get_unit_struct("mil")->index;
- last_unit_value = gcode_attribute_list[HA_unit].default_val.int_value;
- }
-
- if (PCB) {
- derive_default_filename(PCB->Filename, &gcode_attribute_list[HA_basename], ".gcode", &last_made_filename);
- }
- if (n) {
- *n = NUM_OPTIONS;
- }
- return gcode_attribute_list;
-}
-
-/* Populates gcode_export_group array */
-void gcode_choose_groups()
-{
- int n, m;
- LayerType *layer;
-
- /* Set entire array to 0 (don't export any layer groups by default */
- memset(gcode_export_group, 0, sizeof(gcode_export_group));
-
- for (n = 0; n < max_copper_layer; n++) {
- layer = &PCB->Data->Layer[n];
-
- if (!LAYER_IS_EMPTY(layer)) {
- /* layer isn't empty */
-
- /*
- * is this check necessary? It seems that special
- * layers have negative indexes?
- */
-
- if (SL_TYPE(n) == 0) {
- /* layer is a copper layer */
- m = GetLayerGroupNumberByNumber(n);
-
- /* the export layer */
- gcode_export_group[m] = 1;
- }
- }
- }
-}
-
-static void gcode_alloc_colors()
-{
- /*
- * Allocate white and black -- the first color allocated becomes the
- * background color
- */
-
- white = (struct color_struct *) malloc(sizeof(*white));
- white->r = white->g = white->b = 255;
- white->c = gdImageColorAllocate(gcode_im, white->r, white->g, white->b);
-
- black = (struct color_struct *) malloc(sizeof(*black));
- black->r = black->g = black->b = 0;
- black->c = gdImageColorAllocate(gcode_im, black->r, black->g, black->b);
-}
-
-static void gcode_start_png(const char *basename, const char *suffix)
-{
- int h, w;
- char *buf;
-
- buf = gcode_get_png_name(basename, suffix);
-
- h = pcb_to_gcode(PCB->MaxHeight);
- w = pcb_to_gcode(PCB->MaxWidth);
-
- /* Nelma only works with true color images */
- gcode_im = gdImageCreate(w, h);
- gcode_f = fopen(buf, "wb");
-
- gcode_alloc_colors();
-
- free(buf);
-}
-
-static void gcode_finish_png()
-{
-#ifdef HAVE_GDIMAGEPNG
- gdImagePng(gcode_im, gcode_f);
-#else
- Message("GCODE: PNG not supported by gd. Can't write layer mask.\n");
-#endif
- gdImageDestroy(gcode_im);
- fclose(gcode_f);
-
- free(white);
- free(black);
-
- gcode_im = NULL;
- gcode_f = NULL;
-}
-
-void gcode_start_png_export()
-{
- BoxType region;
-
- region.X1 = 0;
- region.Y1 = 0;
- region.X2 = PCB->MaxWidth;
- region.Y2 = PCB->MaxHeight;
-
- linewidth = -1;
- lastbrush = (gdImagePtr) ((void *) -1);
- lastcolor = -1;
-
- hid_expose_callback(&gcode_hid, ®ion, 0);
-}
-
-static void gcode_do_export(HID_Attr_Val * options)
-{
- int save_ons[MAX_LAYER + 2];
- int i, idx;
- time_t t;
- const Unit *unit;
- double scale = 0, d = 0;
- int r, c, v, p, metric;
- char *filename;
- path_t *plist = NULL;
- potrace_bitmap_t *bm = NULL;
- potrace_param_t param_default = {
- 2, /* turnsize */
- POTRACE_TURNPOLICY_MINORITY, /* turnpolicy */
- 1.0, /* alphamax */
- 1, /* opticurve */
- 0.2, /* opttolerance */
- {
- NULL, /* callback function */
- NULL, /* callback data */
- 0.0, 1.0, /* progress range */
- 0.0, /* granularity */
- },
- };
-
- if (!options) {
- gcode_get_export_options(0);
- for (i = 0; i < NUM_OPTIONS; i++) {
- gcode_values[i] = gcode_attribute_list[i].default_val;
- }
- options = gcode_values;
- }
- gcode_basename = options[HA_basename].str_value;
- if (!gcode_basename) {
- gcode_basename = "pcb-out";
- }
- gcode_dpi = options[HA_dpi].int_value;
- if (gcode_dpi < 0) {
- fprintf(stderr, "ERROR: dpi may not be < 0\n");
- return;
- }
- unit = &(get_unit_list()[options[HA_unit].int_value]);
- metric = (unit->family == METRIC);
- scale = metric ? 1.0 / coord_to_unit(unit, MM_TO_COORD(1.0))
- : 1.0 / coord_to_unit(unit, INCH_TO_COORD(1.0));
-
- gcode_cutdepth = options[HA_cutdepth].real_value * scale;
- gcode_drilldepth = options[HA_drilldepth].real_value * scale;
- gcode_safeZ = options[HA_safeZ].real_value * scale;
- gcode_toolradius = metric ? MM_TO_COORD(options[HA_toolradius].real_value * scale)
- : INCH_TO_COORD(options[HA_toolradius].real_value * scale);
- gcode_choose_groups();
-
- for (i = 0; i < MAX_LAYER; i++) {
- if (gcode_export_group[i]) {
-
- gcode_cur_group = i;
-
- /* magic */
- idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
- printf("idx=%d %s\n", idx, layer_type_to_file_name(idx, FNS_fixed));
- is_solder = (GetLayerGroupNumberByNumber(idx) == GetLayerGroupNumberByNumber(solder_silk_layer)) ? 1 : 0;
- save_drill = is_solder; /* save drills for one layer only */
- gcode_start_png(gcode_basename, layer_type_to_file_name(idx, FNS_fixed));
- hid_save_and_show_layer_ons(save_ons);
- gcode_start_png_export();
- hid_restore_layer_ons(save_ons);
-
-/* ***************** gcode conversion *************************** */
-/* potrace uses a different kind of bitmap; for simplicity gcode_im is copied to this format */
- bm = bm_new(gdImageSX(gcode_im), gdImageSY(gcode_im));
- filename = (char *) malloc(MAXPATHLEN);
- plist = NULL;
- if (is_solder) { /* only for back layer */
- gdImagePtr temp_im = gdImageCreate(gdImageSX(gcode_im), gdImageSY(gcode_im));
- gdImageCopy(temp_im, gcode_im, 0, 0, 0, 0, gdImageSX(gcode_im), gdImageSY(gcode_im));
- for (r = 0; r < gdImageSX(gcode_im); r++) {
- for (c = 0; c < gdImageSY(gcode_im); c++) {
- gdImageSetPixel(gcode_im, r, c, gdImageGetPixel(temp_im, gdImageSX(gcode_im) - 1 - r, c));
- }
- }
- gdImageDestroy(temp_im);
- }
- sprintf(filename, "%s.%s.cnc", gcode_basename, layer_type_to_file_name(idx, FNS_fixed));
- for (r = 0; r < gdImageSX(gcode_im); r++) {
- for (c = 0; c < gdImageSY(gcode_im); c++) {
- v = gdImageGetPixel(gcode_im, r, gdImageSY(gcode_im) - 1 - c);
- p = (gcode_im->red[v] || gcode_im->green[v]
- || gcode_im->blue[v]) ? 0 : 0xFFFFFF;
- BM_PUT(bm, r, c, p);
- }
- }
- gcode_f2 = fopen(filename, "wb");
- if (!gcode_f2) {
- perror(filename);
- return;
- }
- fprintf(gcode_f2, "(Created by G-code exporter)\n");
- t = time(NULL);
- sprintf(filename, "%s", ctime(&t));
- filename[strlen(filename) - 1] = 0;
- fprintf(gcode_f2, "( %s )\n", filename);
- fprintf(gcode_f2, "(%d dpi)\n", gcode_dpi);
- fprintf(gcode_f2, "(Unit: %s)\n", metric ? "mm" : "inch");
- if (metric)
- pcb_fprintf(gcode_f2, "(Board size: %.2mmx%.2mm mm)", PCB->MaxWidth, PCB->MaxHeight);
- else
- pcb_fprintf(gcode_f2, "(Board size: %.2mix%.2mi inches)", PCB->MaxWidth, PCB->MaxHeight);
- fprintf(gcode_f2, "#100=%f (safe Z)\n", gcode_safeZ);
- fprintf(gcode_f2, "#101=%f (cutting depth)\n", gcode_cutdepth);
- fprintf(gcode_f2, "(---------------------------------)\n");
- fprintf(gcode_f2, "G17 G%d G90 G64 P0.003 M3 S3000 M7 F%d\n", metric ? 21 : 20, metric ? 25 : 1);
- fprintf(gcode_f2, "G0 Z#100\n");
- /* extract contour points from image */
- r = bm_to_pathlist(bm, &plist, ¶m_default);
- if (r) {
- fprintf(stderr, "ERROR: pathlist function failed\n");
- return;
- }
- /* generate best polygon and write vertices in g-code format */
- d = process_path(plist, ¶m_default, bm, gcode_f2, metric ? 25.4 / gcode_dpi : 1.0 / gcode_dpi);
- if (d < 0) {
- fprintf(stderr, "ERROR: path process function failed\n");
- return;
- }
- if (metric)
- fprintf(gcode_f2, "(end, total distance %.2fmm = %.2fin)\n", d, d * 1 / 25.4);
- else
- fprintf(gcode_f2, "(end, total distance %.2fmm = %.2fin)\n", 25.4 * d, d);
- fprintf(gcode_f2, "M5 M9 M2\n");
- pathlist_free(plist);
- bm_free(bm);
- fclose(gcode_f2);
- if (save_drill) {
- d = 0;
- drill = sort_drill(drill, n_drill);
- sprintf(filename, "%s.drill.cnc", gcode_basename);
- gcode_f2 = fopen(filename, "wb");
- if (!gcode_f2) {
- perror(filename);
- return;
- }
- fprintf(gcode_f2, "(Created by G-code exporter)\n");
- fprintf(gcode_f2, "(drill file: %d drills)\n", n_drill);
- sprintf(filename, "%s", ctime(&t));
- filename[strlen(filename) - 1] = 0;
- fprintf(gcode_f2, "( %s )\n", filename);
- fprintf(gcode_f2, "(Unit: %s)\n", metric ? "mm" : "inch");
- if (metric)
- pcb_fprintf(gcode_f2, "(Board size: %.2mmx%.2mm mm)", PCB->MaxWidth, PCB->MaxHeight);
- else
- pcb_fprintf(gcode_f2, "(Board size: %.2mix%.2mi inches)", PCB->MaxWidth, PCB->MaxHeight);
- fprintf(gcode_f2, "#100=%f (safe Z)\n", gcode_safeZ);
- fprintf(gcode_f2, "#101=%f (drill depth)\n", gcode_drilldepth);
- fprintf(gcode_f2, "(---------------------------------)\n");
- fprintf(gcode_f2, "G17 G%d G90 G64 P0.003 M3 S3000 M7 F%d\n", metric ? 21 : 20, metric ? 25 : 1);
-/* fprintf(gcode_f2,"G0 Z#100\n"); */
- for (r = 0; r < n_drill; r++) {
-/* if(metric) fprintf(gcode_f2,"G0 X%f Y%f\n",drill[r].x*25.4,drill[r].y*25.4); */
-/* else fprintf(gcode_f2,"G0 X%f Y%f\n",drill[r].x,drill[r].y); */
- if (metric)
- fprintf(gcode_f2, "G81 X%f Y%f Z#101 R#100\n", drill[r].x * 25.4, drill[r].y * 25.4);
- else
- fprintf(gcode_f2, "G81 X%f Y%f Z#101 R#100\n", drill[r].x, drill[r].y);
-/* fprintf(gcode_f2,"G1 Z#101\n"); */
-/* fprintf(gcode_f2,"G0 Z#100\n"); */
- if (r > 0)
- d +=
- sqrt((drill[r].x - drill[r - 1].x) * (drill[r].x -
- drill[r - 1].x) +
- (drill[r].y - drill[r - 1].y) * (drill[r].y - drill[r - 1].y));
- }
- fprintf(gcode_f2, "M5 M9 M2\n");
- fprintf(gcode_f2, "(end, total distance %.2fmm = %.2fin)\n", 25.4 * d, d);
- fclose(gcode_f2);
- free(drill);
- drill = NULL;
- n_drill = nmax_drill = 0;
- }
- free(filename);
-
-/* ******************* end gcode conversion **************************** */
- gcode_finish_png();
- }
- }
-}
-
-/* *** PNG export (slightly modified code from PNG export HID) ************* */
-
-static int gcode_set_layer(const char *name, int group, int empty)
-{
- int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group;
-
- if (name == 0) {
- name = PCB->Data->Layer[idx].Name;
- }
- if (strcmp(name, "invisible") == 0) {
- return 0;
- }
- is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL);
- is_mask = (SL_TYPE(idx) == SL_MASK);
-
- if (is_mask) {
- /* Don't print masks */
- return 0;
- }
- if (is_drill) {
- /*
- * Print 'holes', so that we can fill gaps in the copper
- * layer
- */
- return 1;
- }
- if (group == gcode_cur_group) {
- return 1;
- }
- return 0;
-}
-
-static hidGC gcode_make_gc(void)
-{
- hidGC rv = (hidGC) malloc(sizeof(struct hid_gc_struct));
- rv->me_pointer = &gcode_hid;
- rv->cap = Trace_Cap;
- rv->width = 1;
- rv->color = (struct color_struct *) malloc(sizeof(*rv->color));
- rv->color->r = rv->color->g = rv->color->b = 0;
- rv->color->c = 0;
- return rv;
-}
-
-static void gcode_destroy_gc(hidGC gc)
-{
- free(gc);
-}
-
-static void gcode_use_mask(int use_it)
-{
- /* does nothing */
-}
-
-static void gcode_set_color(hidGC gc, const char *name)
-{
- if (gcode_im == NULL) {
- return;
- }
- if (name == NULL) {
- name = "#ff0000";
- }
- if (!strcmp(name, "drill")) {
- gc->color = black;
- gc->erase = 0;
- return;
- }
- if (!strcmp(name, "erase")) {
- /* FIXME -- should be background, not white */
- gc->color = white;
- gc->erase = 1;
- return;
- }
- gc->color = black;
- gc->erase = 0;
- return;
-}
-
-static void gcode_set_line_cap(hidGC gc, EndCapStyle style)
-{
- gc->cap = style;
-}
-
-static void gcode_set_line_width(hidGC gc, Coord width)
-{
- gc->width = width;
-}
-
-static void gcode_set_draw_xor(hidGC gc, int xor_)
-{
- ;
-}
-
-static void gcode_set_draw_faded(hidGC gc, int faded)
-{
- gc->faded = faded;
-}
-
-static void use_gc(hidGC gc)
-{
- int need_brush = 0;
-
- if (gc->me_pointer != &gcode_hid) {
- fprintf(stderr, "Fatal: GC from another HID passed to gcode HID\n");
- abort();
- }
- if (linewidth != gc->width) {
- /* Make sure the scaling doesn't erase lines completely */
- /*
- if (SCALE (gc->width) == 0 && gc->width > 0)
- gdImageSetThickness (im, 1);
- else
- */
- gdImageSetThickness(gcode_im, pcb_to_gcode(gc->width + 2 * gcode_toolradius));
- linewidth = gc->width;
- need_brush = 1;
- }
- if (lastbrush != gc->brush || need_brush) {
- static void *bcache = 0;
- hidval bval;
- char name[256];
- char type;
- int r;
-
- switch (gc->cap) {
- case Round_Cap:
- case Trace_Cap:
- type = 'C';
- r = pcb_to_gcode(gc->width / 2 + gcode_toolradius);
- break;
- default:
- case Square_Cap:
- r = pcb_to_gcode(gc->width + gcode_toolradius * 2);
- type = 'S';
- break;
- }
- sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r);
-
- if (hid_cache_color(0, name, &bval, &bcache)) {
- gc->brush = (gdImagePtr) bval.ptr;
- }
- else {
- int bg, fg;
- if (type == 'C')
- gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1);
- else
- gc->brush = gdImageCreate(r + 1, r + 1);
- bg = gdImageColorAllocate(gc->brush, 255, 255, 255);
- fg = gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g, gc->color->b);
- gdImageColorTransparent(gc->brush, bg);
-
- /*
- * if we shrunk to a radius/box width of zero, then just use
- * a single pixel to draw with.
- */
- if (r == 0)
- gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg);
- else {
- if (type == 'C')
- gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg);
- else
- gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg);
- }
- bval.ptr = gc->brush;
- hid_cache_color(1, name, &bval, &bcache);
- }
-
- gdImageSetBrush(gcode_im, gc->brush);
- lastbrush = gc->brush;
-
- }
-#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
- if (lastcolor != CBLEND(gc)) {
- if (is_drill || is_mask) {
-#ifdef FIXME
- fprintf(f, "%d gray\n", gc->erase ? 0 : 1);
-#endif
- lastcolor = 0;
- }
- else {
- double r, g, b;
- r = gc->r;
- g = gc->g;
- b = gc->b;
- if (gc->faded) {
- r = 0.8 * 255 + 0.2 * r;
- g = 0.8 * 255 + 0.2 * g;
- b = 0.8 * 255 + 0.2 * b;
- }
-#ifdef FIXME
- if (gc->r == gc->g && gc->g == gc->b)
- fprintf(f, "%g gray\n", r / 255.0);
- else
- fprintf(f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0);
-#endif
- lastcolor = CBLEND(gc);
- }
- }
-}
-
-static void gcode_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
-{
- use_gc(gc);
- gdImageRectangle(gcode_im,
- pcb_to_gcode(x1 - gcode_toolradius),
- pcb_to_gcode(y1 - gcode_toolradius),
- pcb_to_gcode(x2 + gcode_toolradius), pcb_to_gcode(y2 + gcode_toolradius), gc->color->c);
-/* printf("Rect %d %d %d %d\n",x1,y1,x2,y2); */
-}
-
-static void gcode_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
-{
- use_gc(gc);
- gdImageSetThickness(gcode_im, 0);
- linewidth = 0;
- gdImageFilledRectangle(gcode_im,
- pcb_to_gcode(x1 - gcode_toolradius),
- pcb_to_gcode(y1 - gcode_toolradius),
- pcb_to_gcode(x2 + gcode_toolradius), pcb_to_gcode(y2 + gcode_toolradius), gc->color->c);
-/* printf("FillRect %d %d %d %d\n",x1,y1,x2,y2); */
-}
-
-static void gcode_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
-{
- if (x1 == x2 && y1 == y2) {
- Coord w = gc->width / 2;
- gcode_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w);
- return;
- }
- use_gc(gc);
-
- gdImageSetThickness(gcode_im, 0);
- linewidth = 0;
- gdImageLine(gcode_im, pcb_to_gcode(x1), pcb_to_gcode(y1), pcb_to_gcode(x2), pcb_to_gcode(y2), gdBrushed);
-}
-
-static void gcode_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle)
-{
- Angle sa, ea;
-
- /*
- * in gdImageArc, 0 degrees is to the right and +90 degrees is down
- * in pcb, 0 degrees is to the left and +90 degrees is down
- */
- start_angle = 180 - start_angle;
- delta_angle = -delta_angle;
- if (delta_angle > 0) {
- sa = start_angle;
- ea = start_angle + delta_angle;
- }
- else {
- sa = start_angle + delta_angle;
- ea = start_angle;
- }
-
- /*
- * make sure we start between 0 and 360 otherwise gd does strange
- * things
- */
- sa = NormalizeAngle(sa);
- ea = NormalizeAngle(ea);
-
-#if 0
- printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea);
- printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
- im, SCALE_X(cx), SCALE_Y(cy), SCALE(width), SCALE(height), sa, ea, gc->color->c);
-#endif
- use_gc(gc);
- gdImageSetThickness(gcode_im, 0);
- linewidth = 0;
- gdImageArc(gcode_im, pcb_to_gcode(cx), pcb_to_gcode(cy),
- pcb_to_gcode(2 * width + gcode_toolradius * 2),
- pcb_to_gcode(2 * height + gcode_toolradius * 2), sa, ea, gdBrushed);
-}
-
-static void gcode_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius)
-{
- use_gc(gc);
-
- gdImageSetThickness(gcode_im, 0);
- linewidth = 0;
- gdImageFilledEllipse(gcode_im, pcb_to_gcode(cx), pcb_to_gcode(cy),
- pcb_to_gcode(2 * radius + gcode_toolradius * 2),
- pcb_to_gcode(2 * radius + gcode_toolradius * 2), gc->color->c);
- if (save_drill && is_drill) {
- if (n_drill == nmax_drill) {
- drill = (struct drill_struct *) realloc(drill, (nmax_drill + 100) * sizeof(struct drill_struct));
- nmax_drill += 100;
- }
- drill[n_drill].x = COORD_TO_INCH(PCB->MaxWidth - cx); /* convert to inch, flip: will drill from bottom side */
- drill[n_drill].y = COORD_TO_INCH(PCB->MaxHeight - cy); /* PCB reverses y axis */
- n_drill++;
-/* printf("Circle %d %d\n",cx,cy); */
- }
-}
-
-static void gcode_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y)
-{
- int i;
- gdPoint *points;
-
- points = (gdPoint *) malloc(n_coords * sizeof(gdPoint));
- if (points == NULL) {
- fprintf(stderr, "ERROR: gcode_fill_polygon(): malloc failed\n");
- exit(1);
- }
- use_gc(gc);
- for (i = 0; i < n_coords; i++) {
- points[i].x = pcb_to_gcode(x[i]);
- points[i].y = pcb_to_gcode(y[i]);
- }
- gdImageSetThickness(gcode_im, 0);
- linewidth = 0;
- gdImageFilledPolygon(gcode_im, points, n_coords, gc->color->c);
- free(points);
-/* printf("FillPoly\n"); */
-}
-
-static void gcode_calibrate(double xval, double yval)
-{
- CRASH;
-}
-
-static void gcode_set_crosshair(int x, int y, int a)
-{
-}
-
-/* *** Miscellaneous ******************************************************* */
-
-#include "dolists.h"
-
-HID gcode_hid;
-
-void hid_gcode_init()
-{
- memset(&gcode_hid, 0, sizeof(HID));
-
- common_nogui_init(&gcode_hid);
- common_draw_helpers_init(&gcode_hid);
-
- gcode_hid.struct_size = sizeof(HID);
- gcode_hid.name = "gcode";
- gcode_hid.description = "G-CODE export";
- gcode_hid.exporter = 1;
- gcode_hid.poly_before = 1;
-
- gcode_hid.get_export_options = gcode_get_export_options;
- gcode_hid.do_export = gcode_do_export;
- gcode_hid.parse_arguments = gcode_parse_arguments;
- gcode_hid.set_layer = gcode_set_layer;
- gcode_hid.make_gc = gcode_make_gc;
- gcode_hid.destroy_gc = gcode_destroy_gc;
- gcode_hid.use_mask = gcode_use_mask;
- gcode_hid.set_color = gcode_set_color;
- gcode_hid.set_line_cap = gcode_set_line_cap;
- gcode_hid.set_line_width = gcode_set_line_width;
- gcode_hid.set_draw_xor = gcode_set_draw_xor;
- gcode_hid.set_draw_faded = gcode_set_draw_faded;
- gcode_hid.draw_line = gcode_draw_line;
- gcode_hid.draw_arc = gcode_draw_arc;
- gcode_hid.draw_rect = gcode_draw_rect;
- gcode_hid.fill_circle = gcode_fill_circle;
- gcode_hid.fill_polygon = gcode_fill_polygon;
- gcode_hid.fill_rect = gcode_fill_rect;
- gcode_hid.calibrate = gcode_calibrate;
- gcode_hid.set_crosshair = gcode_set_crosshair;
-
- hid_register_hid(&gcode_hid);
-}
Index: trunk/src/hid/gcode/decompose.h
===================================================================
--- trunk/src/hid/gcode/decompose.h (revision 1268)
+++ trunk/src/hid/gcode/decompose.h (nonexistent)
@@ -1,15 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* $Id: decompose.h 147 2007-04-09 00:44:09Z selinger $ */
-
-#ifndef DECOMPOSE_H
-#define DECOMPOSE_H
-
-#include "potracelib.h"
-/*#include "progress.h"*/
-
-int bm_to_pathlist(const potrace_bitmap_t * bm, path_t ** plistp, const potrace_param_t * param);
-
-#endif /* DECOMPOSE_H */
Index: trunk/src/hid/gcode/lists.h
===================================================================
--- trunk/src/hid/gcode/lists.h (revision 1268)
+++ trunk/src/hid/gcode/lists.h (nonexistent)
@@ -1,285 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* $Id: lists.h 147 2007-04-09 00:44:09Z selinger $ */
-
-#ifndef PCB_HID_GCODE_LISTS_H
-#define PCB_HID_GCODE_LISTS_H
-
-/* here we define some general list macros. Because they are macros,
- they should work on any datatype with a "->next" component. Some of
- them use a "hook". If elt and list are of type t* then hook is of
- type t**. A hook stands for an insertion point in the list, i.e.,
- either before the first element, or between two elements, or after
- the last element. If an operation "sets the hook" for an element,
- then the hook is set to just before the element. One can insert
- something at a hook. One can also unlink at a hook: this means,
- unlink the element just after the hook. By "to unlink", we mean the
- element is removed from the list, but not deleted. Thus, it and its
- components still need to be freed. */
-
-/* Note: these macros are somewhat experimental. Only the ones that
- are actually *used* have been tested. So be careful to test any
- that you use. Looking at the output of the preprocessor, "gcc -E"
- (possibly piped though "indent"), might help too. Also: these
- macros define some internal (local) variables that start with
- "_". */
-
-/* we enclose macro definitions whose body consists of more than one
- statement in MACRO_BEGIN and MACRO_END, rather than '{' and '}'. The
- reason is that we want to be able to use the macro in a context
- such as "if (...) macro(...); else ...". If we didn't use this obscure
- trick, we'd have to omit the ";" in such cases. */
-
-#define MACRO_BEGIN do {
-#define MACRO_END } while (0)
-
-/* ---------------------------------------------------------------------- */
-/* macros for singly-linked lists */
-
-/* traverse list. At the end, elt is set to NULL. */
-#define list_forall(elt, list) for (elt=list; elt!=NULL; elt=elt->next)
-
-/* set elt to the first element of list satisfying boolean condition
- c, or NULL if not found */
-#define list_find(elt, list, c) \
- MACRO_BEGIN list_forall(elt, list) if (c) break; MACRO_END
-
-/* like forall, except also set hook for elt. */
-#define list_forall2(elt, list, hook) \
- for (elt=list, hook=&list; elt!=NULL; hook=&elt->next, elt=elt->next)
-
-/* same as list_find, except also set hook for elt. */
-#define list_find2(elt, list, c, hook) \
- MACRO_BEGIN list_forall2(elt, list, hook) if (c) break; MACRO_END
-
-/* same, except only use hook. */
-#define _list_forall_hook(list, hook) \
- for (hook=&list; *hook!=NULL; hook=&(*hook)->next)
-
-/* same, except only use hook. Note: c may only refer to *hook, not elt. */
-#define _list_find_hook(list, c, hook) \
- MACRO_BEGIN _list_forall_hook(list, hook) if (c) break; MACRO_END
-
-/* insert element after hook */
-#define list_insert_athook(elt, hook) \
- MACRO_BEGIN elt->next = *hook; *hook = elt; MACRO_END
-
-/* insert element before hook */
-#define list_insert_beforehook(elt, hook) \
- MACRO_BEGIN elt->next = *hook; *hook = elt; hook=&elt->next; MACRO_END
-
-/* unlink element after hook, let elt be unlinked element, or NULL.
- hook remains. */
-#define list_unlink_athook(list, elt, hook) \
- MACRO_BEGIN \
- elt = hook ? *hook : NULL; if (elt) { *hook = elt->next; elt->next = NULL; }\
- MACRO_END
-
-/* unlink the specific element, if it is in the list. Otherwise, set
- elt to NULL */
-#define list_unlink(listtype, list, elt) \
- MACRO_BEGIN \
- listtype **_hook; \
- _list_find_hook(list, *_hook==elt, _hook); \
- list_unlink_athook(list, elt, _hook); \
- MACRO_END
-
-/* prepend elt to list */
-#define list_prepend(list, elt) \
- MACRO_BEGIN elt->next = list; list = elt; MACRO_END
-
-/* append elt to list. */
-#define list_append(listtype, list, elt) \
- MACRO_BEGIN \
- listtype **_hook; \
- _list_forall_hook(list, _hook) {} \
- list_insert_athook(elt, _hook); \
- MACRO_END
-
-/* unlink the first element that satisfies the condition. */
-#define list_unlink_cond(listtype, list, elt, c) \
- MACRO_BEGIN \
- listtype **_hook; \
- list_find2(elt, list, c, _hook); \
- list_unlink_athook(list, elt, _hook); \
- MACRO_END
-
-/* let elt be the nth element of the list, starting to count from 0.
- Return NULL if out of bounds. */
-#define list_nth(elt, list, n) \
- MACRO_BEGIN \
- int _x; /* only evaluate n once */ \
- for (_x=(n), elt=list; _x && elt; _x--, elt=elt->next) {} \
- MACRO_END
-
-/* let elt be the nth element of the list, starting to count from 0.
- Return NULL if out of bounds. */
-#define list_nth_hook(elt, list, n, hook) \
- MACRO_BEGIN \
- int _x; /* only evaluate n once */ \
- for (_x=(n), elt=list, hook=&list; _x && elt; _x--, hook=&elt->next, elt=elt->next) {} \
- MACRO_END
-
-/* set n to the length of the list */
-#define list_length(listtype, list, n) \
- MACRO_BEGIN \
- listtype *_elt; \
- n=0; \
- list_forall(_elt, list) \
- n++; \
- MACRO_END
-
-/* set n to the index of the first element satisfying cond, or -1 if
- none found. Also set elt to the element, or NULL if none found. */
-#define list_index(list, n, elt, c) \
- MACRO_BEGIN \
- n=0; \
- list_forall(elt, list) { \
- if (c) break; \
- n++; \
- } \
- if (!elt) \
- n=-1; \
- MACRO_END
-
-/* set n to the number of elements in the list that satisfy condition c */
-#define list_count(list, n, elt, c) \
- MACRO_BEGIN \
- n=0; \
- list_forall(elt, list) { \
- if (c) n++; \
- } \
- MACRO_END
-
-/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
-#define list_forall_unlink(elt, list) \
- for (elt=list; elt ? (list=elt->next, elt->next=NULL), 1 : 0; elt=list)
-
-/* reverse a list (efficient) */
-#define list_reverse(listtype, list) \
- MACRO_BEGIN \
- listtype *_list1=NULL, *elt; \
- list_forall_unlink(elt, list) \
- list_prepend(_list1, elt); \
- list = _list1; \
- MACRO_END
-
-/* insert the element ELT just before the first element TMP of the
- list for which COND holds. Here COND must be a condition of ELT and
- TMP. Typical usage is to insert an element into an ordered list:
- for instance, list_insert_ordered(listtype, list, elt, tmp,
- elt->size <= tmp->size). Note: if we give a "less than or equal"
- condition, the new element will be inserted just before a sequence
- of equal elements. If we give a "less than" condition, the new
- element will be inserted just after a list of equal elements.
- Note: it is much more efficient to construct a list with
- list_prepend and then order it with list_merge_sort, than to
- construct it with list_insert_ordered. */
-#define list_insert_ordered(listtype, list, elt, tmp, cond) \
- MACRO_BEGIN \
- listtype **_hook; \
- _list_find_hook(list, (tmp=*_hook, (cond)), _hook); \
- list_insert_athook(elt, _hook); \
- MACRO_END
-
-/* sort the given list, according to the comparison condition.
- Typical usage is list_sort(listtype, list, a, b, a->size <
- b->size). Note: if we give "less than or equal" condition, each
- segment of equal elements will be reversed in order. If we give a
- "less than" condition, each segment of equal elements will retain
- the original order. The latter is slower but sometimes
- prettier. Average running time: n*n/2. */
-#define list_sort(listtype, list, a, b, cond) \
- MACRO_BEGIN \
- listtype *_newlist=NULL; \
- list_forall_unlink(a, list) \
- list_insert_ordered(listtype, _newlist, a, b, cond); \
- list = _newlist; \
- MACRO_END
-
-/* a much faster sort algorithm (merge sort, n log n worst case). It
- is required that the list type has an additional, unused next1
- component. Note there is no curious reversal of order of equal
- elements as for list_sort. */
-
-#define list_mergesort(listtype, list, a, b, cond) \
- MACRO_BEGIN \
- listtype *_elt, **_hook1; \
- \
- for (_elt=list; _elt; _elt=_elt->next1) { \
- _elt->next1 = _elt->next; \
- _elt->next = NULL; \
- } \
- do { \
- _hook1 = &(list); \
- while ((a = *_hook1) != NULL && (b = a->next1) != NULL ) { \
- _elt = b->next1; \
- _list_merge_cond(listtype, a, b, cond, *_hook1); \
- _hook1 = &((*_hook1)->next1); \
- *_hook1 = _elt; \
- } \
- } while (_hook1 != &(list)); \
- MACRO_END
-
-/* merge two sorted lists. Store result at &result */
-#define _list_merge_cond(listtype, a, b, cond, result) \
- MACRO_BEGIN \
- listtype **_hook; \
- _hook = &(result); \
- while (1) { \
- if (a==NULL) { \
- *_hook = b; \
- break; \
- } else if (b==NULL) { \
- *_hook = a; \
- break; \
- } else if (cond) { \
- *_hook = a; \
- _hook = &(a->next); \
- a = a->next; \
- } else { \
- *_hook = b; \
- _hook = &(b->next); \
- b = b->next; \
- } \
- } \
- MACRO_END
-
-/* ---------------------------------------------------------------------- */
-/* macros for doubly-linked lists */
-
-#define dlist_append(head, end, elt) \
- MACRO_BEGIN \
- elt->prev = end; \
- elt->next = NULL; \
- if (end) { \
- end->next = elt; \
- } else { \
- head = elt; \
- } \
- end = elt; \
- MACRO_END
-
-/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
-#define dlist_forall_unlink(elt, head, end) \
- for (elt=head; elt ? (head=elt->next, elt->next=NULL, elt->prev=NULL), 1 : (end=NULL, 0); elt=head)
-
-/* unlink the first element of the list */
-#define dlist_unlink_first(head, end, elt) \
- MACRO_BEGIN \
- elt = head; \
- if (head) { \
- head = head->next; \
- if (head) { \
- head->prev = NULL; \
- } else { \
- end = NULL; \
- } \
- elt->prev = NULL; \
- elt->next = NULL; \
- } \
- MACRO_END
-
-#endif /* PCB_HID_GCODE_LISTS_H */
Index: trunk/src/hid/gcode/trace.h
===================================================================
--- trunk/src/hid/gcode/trace.h (revision 1268)
+++ trunk/src/hid/gcode/trace.h (nonexistent)
@@ -1,14 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* $Id: trace.h 147 2007-04-09 00:44:09Z selinger $ */
-
-#ifndef TRACE_H
-#define TRACE_H
-
-#include "potracelib.h"
-
-double process_path(path_t * plist, const potrace_param_t * param, const potrace_bitmap_t * bm, FILE * f, double scale);
-
-#endif /* TRACE_H */
Index: trunk/src/hid/gcode/curve.c
===================================================================
--- trunk/src/hid/gcode/curve.c (revision 1268)
+++ trunk/src/hid/gcode/curve.c (nonexistent)
@@ -1,114 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* $Id: curve.c 147 2007-04-09 00:44:09Z selinger $ */
-/* private part of the path and curve data structures */
-
-#include
-#include
-#include
-
-#include "potracelib.h"
-#include "lists.h"
-#include "curve.h"
-
-#define SAFE_MALLOC(var, n, typ) \
- if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error
-
-/* ---------------------------------------------------------------------- */
-/* allocate and free path objects */
-
-path_t *path_new(void)
-{
- path_t *p = NULL;
- privpath_t *priv = NULL;
-
- SAFE_MALLOC(p, 1, path_t);
- memset(p, 0, sizeof(path_t));
- SAFE_MALLOC(priv, 1, privpath_t);
- memset(priv, 0, sizeof(privpath_t));
- p->priv = priv;
- return p;
-
-malloc_error:
- free(p);
- free(priv);
- return NULL;
-}
-
-/* free the members of the given curve structure. Leave errno unchanged. */
-static void privcurve_free_members(privcurve_t * curve)
-{
- free(curve->tag);
- free(curve->c);
- free(curve->vertex);
- free(curve->alpha);
- free(curve->alpha0);
- free(curve->beta);
-}
-
-/* free a path. Leave errno untouched. */
-void path_free(path_t * p)
-{
- if (p) {
- if (p->priv) {
- free(p->priv->pt);
- free(p->priv->lon);
- free(p->priv->sums);
- free(p->priv->po);
- privcurve_free_members(&p->priv->curve);
- privcurve_free_members(&p->priv->ocurve);
- }
- free(p->priv);
- /* do not free p->fcurve ! */
- }
- free(p);
-}
-
-/* free a pathlist, leaving errno untouched. */
-void pathlist_free(path_t * plist)
-{
- path_t *p;
-
- list_forall_unlink(p, plist) {
- path_free(p);
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/* initialize and finalize curve structures */
-
-typedef dpoint_t dpoint3_t[3];
-
-/* initialize the members of the given curve structure to size m.
- Return 0 on success, 1 on error with errno set. */
-int privcurve_init(privcurve_t * curve, int n)
-{
- memset(curve, 0, sizeof(privcurve_t));
- curve->n = n;
- SAFE_MALLOC(curve->tag, n, int);
- SAFE_MALLOC(curve->c, n, dpoint3_t);
- SAFE_MALLOC(curve->vertex, n, dpoint_t);
- SAFE_MALLOC(curve->alpha, n, double);
- SAFE_MALLOC(curve->alpha0, n, double);
- SAFE_MALLOC(curve->beta, n, double);
- return 0;
-
-malloc_error:
- free(curve->tag);
- free(curve->c);
- free(curve->vertex);
- free(curve->alpha);
- free(curve->alpha0);
- free(curve->beta);
- return 1;
-}
-
-/* copy private to public curve structure */
-void privcurve_to_curve(privcurve_t * pc, potrace_curve_t * c)
-{
- c->n = pc->n;
- c->tag = pc->tag;
- c->c = pc->c;
-}
Index: trunk/src/hid/gcode/gcode.h
===================================================================
--- trunk/src/hid/gcode/gcode.h (revision 1268)
+++ trunk/src/hid/gcode/gcode.h (nonexistent)
@@ -1,3 +0,0 @@
-/* $Id: nelma.h,v 1.2 2007/04/20 11:31:15 danmc Exp $ */
-extern const char *gcode_cookie;
-extern HID gcode_hid;
Index: trunk/src/hid/gcode/hid.conf
===================================================================
--- trunk/src/hid/gcode/hid.conf (revision 1268)
+++ trunk/src/hid/gcode/hid.conf (nonexistent)
@@ -1 +0,0 @@
-type=export
Index: trunk/src/hid/gcode/curve.h
===================================================================
--- trunk/src/hid/gcode/curve.h (revision 1268)
+++ trunk/src/hid/gcode/curve.h (nonexistent)
@@ -1,76 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-#ifndef CURVE_H
-#define CURVE_H
-
-#include "auxiliary.h"
-
-/* vertex is c[1] for tag=POTRACE_CORNER, and the intersection of
- .c[-1][2]..c[0] and c[1]..c[2] for tag=POTRACE_CURVETO. alpha is only
- defined for tag=POTRACE_CURVETO and is the alpha parameter of the curve:
- .c[-1][2]..c[0] = alpha*(.c[-1][2]..vertex), and
- c[2]..c[1] = alpha*(c[2]..vertex).
- Beta is so that (.beta[i])[.vertex[i],.vertex[i+1]] = .c[i][2].
-*/
-
-struct privcurve_s {
- int n; /* number of segments */
- int *tag; /* tag[n]: POTRACE_CORNER or POTRACE_CURVETO */
- dpoint_t(*c)[3]; /* c[n][i]: control points.
- c[n][0] is unused for tag[n]=POTRACE_CORNER */
- /* the remainder of this structure is special to privcurve, and is
- used in EPS debug output and special EPS "short coding". These
- fields are valid only if "alphacurve" is set. */
- int alphacurve; /* have the following fields been initialized? */
- dpoint_t *vertex; /* for POTRACE_CORNER, this equals c[1] */
- double *alpha; /* only for POTRACE_CURVETO */
- double *alpha0; /* "uncropped" alpha parameter - for debug output only */
- double *beta;
-};
-typedef struct privcurve_s privcurve_t;
-
-struct sums_s {
- double x;
- double y;
- double x2;
- double xy;
- double y2;
-};
-typedef struct sums_s sums_t;
-
-/* the path structure is filled in with information about a given path
- as it is accumulated and passed through the different stages of the
- Potrace algorithm. Backends only need to read the fcurve and fm
- fields of this data structure, but debugging backends may read
- other fields. */
-struct potrace_privpath_s {
- int len;
- point_t *pt; /* pt[len]: path as extracted from bitmap */
- int *lon; /* lon[len]: (i,lon[i]) = longest straight line from i */
-
- int x0, y0; /* origin for sums */
- sums_t *sums; /* sums[len+1]: cache for fast summing */
-
- int m; /* length of optimal polygon */
- int *po; /* po[m]: optimal polygon */
-
- privcurve_t curve; /* curve[m]: array of curve elements */
- privcurve_t ocurve; /* ocurve[om]: array of curve elements */
- privcurve_t *fcurve; /* final curve: this points to either curve or
- ocurve. Do not free this separately. */
-};
-typedef struct potrace_privpath_s potrace_privpath_t;
-
-/* shorter names */
-typedef potrace_privpath_t privpath_t;
-typedef potrace_path_t path_t;
-
-path_t *path_new(void);
-void path_free(path_t * p);
-void pathlist_free(path_t * plist);
-int privcurve_init(privcurve_t * curve, int n);
-void privcurve_to_curve(privcurve_t * pc, potrace_curve_t * c);
-
-#endif /* CURVE_H */
Index: trunk/src/hid/gcode/potracelib.h
===================================================================
--- trunk/src/hid/gcode/potracelib.h (revision 1268)
+++ trunk/src/hid/gcode/potracelib.h (nonexistent)
@@ -1,130 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-#ifndef POTRACELIB_H
-#define POTRACELIB_H
-
-/* this file defines the API for the core Potrace library. For a more
- detailed description of the API, see doc/potracelib.txt */
-
-/* ---------------------------------------------------------------------- */
-/* tracing parameters */
-
-/* turn policies */
-#define POTRACE_TURNPOLICY_BLACK 0
-#define POTRACE_TURNPOLICY_WHITE 1
-#define POTRACE_TURNPOLICY_LEFT 2
-#define POTRACE_TURNPOLICY_RIGHT 3
-#define POTRACE_TURNPOLICY_MINORITY 4
-#define POTRACE_TURNPOLICY_MAJORITY 5
-#define POTRACE_TURNPOLICY_RANDOM 6
-
-/* structure to hold progress bar callback data */
-struct potrace_progress_s {
- void (*callback) (double progress, void *privdata); /* callback fn */
- void *data; /* callback function's private data */
- double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */
- double epsilon; /* granularity: can skip smaller increments */
-};
-typedef struct potrace_progress_s potrace_progress_t;
-
-/* structure to hold tracing parameters */
-struct potrace_param_s {
- int turdsize; /* area of largest path to be ignored */
- int turnpolicy; /* resolves ambiguous turns in path decomposition */
- double alphamax; /* corner threshold */
- int opticurve; /* use curve optimization? */
- double opttolerance; /* curve optimization tolerance */
- potrace_progress_t progress; /* progress callback function */
-};
-typedef struct potrace_param_s potrace_param_t;
-
-/* ---------------------------------------------------------------------- */
-/* bitmaps */
-
-/* native word size */
-typedef unsigned long potrace_word;
-
-/* Internal bitmap format. The n-th scanline starts at scanline(n) =
- (map + n*dy). Raster data is stored as a sequence of potrace_words
- (NOT bytes). The leftmost bit of scanline n is the most significant
- bit of scanline(n)[0]. */
-struct potrace_bitmap_s {
- int w, h; /* width and height, in pixels */
- int dy; /* words per scanline (not bytes) */
- potrace_word *map; /* raw data, dy*h words */
-};
-typedef struct potrace_bitmap_s potrace_bitmap_t;
-
-/* ---------------------------------------------------------------------- */
-/* curves */
-
-/* point */
-struct potrace_dpoint_s {
- double x, y;
-};
-typedef struct potrace_dpoint_s potrace_dpoint_t;
-
-/* segment tags */
-#define POTRACE_CURVETO 1
-#define POTRACE_CORNER 2
-
-/* closed curve segment */
-struct potrace_curve_s {
- int n; /* number of segments */
- int *tag; /* tag[n]: POTRACE_CURVETO or POTRACE_CORNER */
- potrace_dpoint_t(*c)[3]; /* c[n][3]: control points.
- c[n][0] is unused for tag[n]=POTRACE_CORNER */
-};
-typedef struct potrace_curve_s potrace_curve_t;
-
-/* Linked list of signed curve segments. Also carries a tree structure. */
-struct potrace_path_s {
- int area; /* area of the bitmap path */
- int sign; /* '+' or '-', depending on orientation */
- potrace_curve_t curve; /* this path's vector data */
-
- struct potrace_path_s *next; /* linked list structure */
-
- struct potrace_path_s *childlist; /* tree structure */
- struct potrace_path_s *sibling; /* tree structure */
-
- struct potrace_privpath_s *priv; /* private state */
-};
-typedef struct potrace_path_s potrace_path_t;
-
-/* ---------------------------------------------------------------------- */
-/* Potrace state */
-
-#define POTRACE_STATUS_OK 0
-#define POTRACE_STATUS_INCOMPLETE 1
-
-struct potrace_state_s {
- int status;
- potrace_path_t *plist; /* vector data */
-
- struct potrace_privstate_s *priv; /* private state */
-};
-typedef struct potrace_state_s potrace_state_t;
-
-/* ---------------------------------------------------------------------- */
-/* API functions */
-
-/* get default parameters */
-potrace_param_t *potrace_param_default(void);
-
-/* free parameter set */
-void potrace_param_free(potrace_param_t * p);
-
-/* trace a bitmap*/
-potrace_state_t *potrace_trace(const potrace_param_t * param, const potrace_bitmap_t * bm);
-
-/* free a Potrace state */
-void potrace_state_free(potrace_state_t * st);
-
-/* return a static plain text version string identifying this version
- of potracelib */
-char *potrace_version(void);
-
-#endif /* POTRACELIB_H */
Index: trunk/src/hid/gcode/auxiliary.h
===================================================================
--- trunk/src/hid/gcode/auxiliary.h (revision 1268)
+++ trunk/src/hid/gcode/auxiliary.h (nonexistent)
@@ -1,80 +0,0 @@
-/* Copyright (C) 2001-2007 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* This header file collects some general-purpose macros (and static
- inline functions) that are used in various places. */
-
-#ifndef AUXILIARY_H
-#define AUXILIARY_H
-
-#include "config.h"
-
-/* ---------------------------------------------------------------------- */
-/* point arithmetic */
-
-#include "potracelib.h"
-
-struct point_s {
- long x;
- long y;
-};
-typedef struct point_s point_t;
-
-typedef potrace_dpoint_t dpoint_t;
-
-/* convert point_t to dpoint_t */
-static inline dpoint_t dpoint(point_t p)
-{
- dpoint_t res;
- res.x = p.x;
- res.y = p.y;
- return res;
-}
-
-/* range over the straight line segment [a,b] when lambda ranges over [0,1] */
-static inline dpoint_t interval(double lambda, dpoint_t a, dpoint_t b)
-{
- dpoint_t res;
-
- res.x = a.x + lambda * (b.x - a.x);
- res.y = a.y + lambda * (b.y - a.y);
- return res;
-}
-
-/* ---------------------------------------------------------------------- */
-/* some useful macros. Note: the "mod" macro works correctly for
- negative a. Also note that the test for a>=n, while redundant,
- speeds up the mod function by 70% in the average case (significant
- since the program spends about 16% of its time here - or 40%
- without the test). The "floordiv" macro returns the largest integer
- <= a/n, and again this works correctly for negative a, as long as
- a,n are integers and n>0. */
-
-/* integer arithmetic */
-
-static inline int mod(int a, int n)
-{
- return a >= n ? a % n : a >= 0 ? a : n - 1 - (-1 - a) % n;
-}
-
-static inline int floordiv(int a, int n)
-{
- return a >= 0 ? a / n : -1 - (-1 - a) / n;
-}
-
-/* Note: the following work for integers and other numeric types. */
-#undef sign
-#undef abs
-#undef min
-#undef max
-#undef sq
-#undef cu
-#define sign(x) ((x)>0 ? 1 : (x)<0 ? -1 : 0)
-#define abs(a) ((a)>0 ? (a) : -(a))
-#define min(a,b) ((a)<(b) ? (a) : (b))
-#define max(a,b) ((a)>(b) ? (a) : (b))
-#define sq(a) ((a)*(a))
-#define cu(a) ((a)*(a)*(a))
-
-#endif /* AUXILIARY_H */
Index: trunk/src/hid/nelma/hid.conf
===================================================================
--- trunk/src/hid/nelma/hid.conf (revision 1268)
+++ trunk/src/hid/nelma/hid.conf (nonexistent)
@@ -1 +0,0 @@
-type=export
Index: trunk/src/hid/nelma/nelma.c
===================================================================
--- trunk/src/hid/nelma/nelma.c (revision 1268)
+++ trunk/src/hid/nelma/nelma.c (nonexistent)
@@ -1,1033 +0,0 @@
-/*
- * COPYRIGHT
- *
- * PCB, interactive printed circuit board design
- *
- * NELMA (Numerical capacitance calculator) export HID
- * Copyright (C) 2006 Tomaz Solc (tomaz.solc@tablix.org)
- *
- * PNG export code is based on the PNG export HID
- * Copyright (C) 2006 Dan McMahill
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
- * This HID exports a PCB layout into: o One layer mask file (PNG format) per
- * copper layer. o Nelma configuration file that contains netlist and pin
- * information.
- */
-
-/*
- * FIXME:
- *
- * If you have a section of a net that does not contain any pins then that
- * section will be missing from the Nelma's copper geometry.
- *
- * For example:
- *
- * this section will be ignored by Nelma | |
- *
- * || ||=======|| || component layer ||
- * || || || ||=============|| ||============||
- * solder layer
- *
- * pin1 via via pin2
- *
- * Single layer layouts are always exported correctly.
- *
- */
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include "global.h"
-#include "error.h" /* Message() */
-#include "data.h"
-#include "misc.h"
-#include "rats.h"
-
-#include "hid.h"
-#include "../hidint.h"
-#include "hid/common/hidnogui.h"
-#include "hid/common/draw_helpers.h"
-
-#include
-
-#include "hid/common/hidinit.h"
-
-
-RCSID("$Id$");
-
-const char *nelma_cookie = "nelma HID";
-
-#define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
-
-/* Needed for PNG export */
-
-struct color_struct {
- /* the descriptor used by the gd library */
- int c;
-
- /* so I can figure out what rgb value c refers to */
- unsigned int r, g, b;
-};
-
-struct hid_gc_struct {
- HID *me_pointer;
- EndCapStyle cap;
- Coord width;
- unsigned char r, g, b;
- int erase;
- int faded;
- struct color_struct *color;
- gdImagePtr brush;
-};
-
-static HID nelma_hid;
-
-static struct color_struct *black = NULL, *white = NULL;
-static Coord linewidth = -1;
-static gdImagePtr lastbrush = (gdImagePtr) ((void *) -1);
-static int lastcolor = -1;
-
-/* gd image and file for PNG export */
-static gdImagePtr nelma_im = NULL;
-static FILE *nelma_f = NULL;
-
-static int is_mask;
-static int is_drill;
-
-/*
- * Which groups of layers to export into PNG layer masks. 1 means export, 0
- * means do not export.
- */
-static int nelma_export_group[MAX_LAYER];
-
-/* Group that is currently exported. */
-static int nelma_cur_group;
-
-/* Filename prefix that will be used when saving files. */
-static const char *nelma_basename = NULL;
-
-/* Horizontal DPI (grid points per inch) */
-static int nelma_dpi = -1;
-
-/* Height of the copper layers in micrometers. */
-
-/*
- * The height of the copper layer is currently taken as the vertical grid
- * step, since this is the smallest vertical feature in the layout.
- */
-static int nelma_copperh = -1;
-/* Height of the substrate layers in micrometers. */
-static int nelma_substrateh = -1;
-/* Relative permittivity of the substrate. */
-static double nelma_substratee = -1;
-
-/* Permittivity of empty space (As/Vm) */
-static const double nelma_air_epsilon = 8.85e-12;
-
-HID_Attribute nelma_attribute_list[] = {
- /* other HIDs expect this to be first. */
-
-/* %start-doc options "nelma Options"
-@ftable @code
-@item -- basename
-File name prefix.
-@end ftable
-%end-doc
-*/
- {"basename", "File name prefix",
- HID_String, 0, 0, {0, 0, 0}, 0, 0},
-#define HA_basename 0
-
-/* %start-doc options "nelma Options"
-@ftable @code
-@item --dpi
-Horizontal scale factor (grid points/inch).
-@end ftable
-%end-doc
-*/
- {"dpi", "Horizontal scale factor (grid points/inch)",
- HID_Integer, 0, 1000, {100, 0, 0}, 0, 0},
-#define HA_dpi 1
-
-/* %start-doc options "nelma Options"
-@ftable @code
-@item --copper-height
-Copper layer height (um).
-@end ftable
-%end-doc
-*/
- {"copper-height", "Copper layer height (um)",
- HID_Integer, 0, 200, {100, 0, 0}, 0, 0},
-#define HA_copperh 2
-
-/* %start-doc options "nelma Options"
-@ftable @code
-@item --substrate-height
-Substrate layer height (um).
-@end ftable
-%end-doc
-*/
- {"substrate-height", "Substrate layer height (um)",
- HID_Integer, 0, 10000, {2000, 0, 0}, 0, 0},
-#define HA_substrateh 3
-
-/* %start-doc options "nelma Options"
-@ftable @code
-@item --substrate-epsilon
-Substrate relative epsilon.
-@end ftable
-%end-doc
-*/
- {"substrate-epsilon", "Substrate relative epsilon",
- HID_Real, 0, 100, {0, 0, 4.0}, 0, 0},
-#define HA_substratee 4
-};
-
-#define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0]))
-
-REGISTER_ATTRIBUTES(nelma_attribute_list, nelma_cookie)
- static HID_Attr_Val nelma_values[NUM_OPTIONS];
-
-/* *** Utility funcions **************************************************** */
-
-/* convert from default PCB units to nelma units */
- static int pcb_to_nelma(Coord pcb)
-{
- return COORD_TO_INCH(pcb) * nelma_dpi;
-}
-
-static char *nelma_get_png_name(const char *basename, const char *suffix)
-{
- char *buf;
- int len;
-
- len = strlen(basename) + strlen(suffix) + 6;
- buf = (char *) malloc(sizeof(*buf) * len);
-
- sprintf(buf, "%s.%s.png", basename, suffix);
-
- return buf;
-}
-
-/* Retrieves coordinates (in default PCB units) of a pin or pad. */
-/* Copied from netlist.c */
-static int pin_name_to_xy(LibraryEntryType * pin, Coord * x, Coord * y)
-{
- ConnectionType conn;
- if (!SeekPad(pin, &conn, false))
- return 1;
- switch (conn.type) {
- case PIN_TYPE:
- *x = ((PinType *) (conn.ptr2))->X;
- *y = ((PinType *) (conn.ptr2))->Y;
- return 0;
- case PAD_TYPE:
- *x = ((PadType *) (conn.ptr2))->Point1.X;
- *y = ((PadType *) (conn.ptr2))->Point1.Y;
- return 0;
- }
- return 1;
-}
-
-/* *** Exporting netlist data and geometry to the nelma config file ******** */
-
-static void nelma_write_space(FILE * out)
-{
- double xh, zh;
-
- int z;
- int i, idx;
- const char *ext;
-
- xh = 2.54e-2 / ((double) nelma_dpi);
- zh = nelma_copperh * 1e-6;
-
- fprintf(out, "\n/* **** Space **** */\n\n");
-
- fprintf(out, "space pcb {\n");
- fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh);
- fprintf(out, "\tlayers = {\n");
-
- fprintf(out, "\t\t\"air-top\",\n");
- fprintf(out, "\t\t\"air-bottom\"");
-
- z = 10;
- for (i = 0; i < MAX_LAYER; i++)
- if (nelma_export_group[i]) {
- idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
- ext = layer_type_to_file_name(idx, FNS_fixed);
-
- if (z != 10) {
- fprintf(out, ",\n");
- fprintf(out, "\t\t\"substrate-%d\"", z);
- z++;
- }
- fprintf(out, ",\n");
- fprintf(out, "\t\t\"%s\"", ext);
- z++;
- }
- fprintf(out, "\n\t}\n");
- fprintf(out, "}\n");
-}
-
-
-static void nelma_write_material(FILE * out, char *name, char *type, double e)
-{
- fprintf(out, "material %s {\n", name);
- fprintf(out, "\ttype = \"%s\"\n", type);
- fprintf(out, "\tpermittivity = %e\n", e);
- fprintf(out, "\tconductivity = 0.0\n");
- fprintf(out, "\tpermeability = 0.0\n");
- fprintf(out, "}\n");
-}
-
-static void nelma_write_materials(FILE * out)
-{
- fprintf(out, "\n/* **** Materials **** */\n\n");
-
- nelma_write_material(out, "copper", "metal", nelma_air_epsilon);
- nelma_write_material(out, "air", "dielectric", nelma_air_epsilon);
- nelma_write_material(out, "composite", "dielectric", nelma_air_epsilon * nelma_substratee);
-}
-
-static void nelma_write_nets(FILE * out)
-{
- LibraryType netlist;
- LibraryMenuTypePtr net;
- LibraryEntryTypePtr pin;
-
- int n, m, i, idx;
-
- const char *ext;
-
- netlist = PCB->NetlistLib[NETLIST_EDITED];
-
- fprintf(out, "\n/* **** Nets **** */\n\n");
-
- for (n = 0; n < netlist.MenuN; n++) {
- net = &netlist.Menu[n];
-
- /* Weird, but correct */
- fprintf(out, "net %s {\n", &net->Name[2]);
-
- fprintf(out, "\tobjects = {\n");
-
- for (m = 0; m < net->EntryN; m++) {
- pin = &net->Entry[m];
-
- /* pin_name_to_xy(pin, &x, &y); */
-
- for (i = 0; i < MAX_LAYER; i++)
- if (nelma_export_group[i]) {
- idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
- ext = layer_type_to_file_name(idx, FNS_fixed);
-
- if (m != 0 || i != 0)
- fprintf(out, ",\n");
- fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, ext);
- }
- }
-
- fprintf(out, "\n");
- fprintf(out, "\t}\n");
- fprintf(out, "}\n");
- }
-}
-
-static void nelma_write_layer(FILE * out, int z, int h, const char *name, int full, char *mat)
-{
- LibraryType netlist;
- LibraryMenuTypePtr net;
- LibraryEntryTypePtr pin;
-
- int n, m;
-
- fprintf(out, "layer %s {\n", name);
- fprintf(out, "\theight = %d\n", h);
- fprintf(out, "\tz-order = %d\n", z);
- fprintf(out, "\tmaterial = \"%s\"\n", mat);
-
- if (full) {
- fprintf(out, "\tobjects = {\n");
- netlist = PCB->NetlistLib[NETLIST_EDITED];
-
- for (n = 0; n < netlist.MenuN; n++) {
- net = &netlist.Menu[n];
-
- for (m = 0; m < net->EntryN; m++) {
- pin = &net->Entry[m];
-
- if (m != 0 || n != 0)
- fprintf(out, ",\n");
- fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, name);
- }
-
- }
- fprintf(out, "\n\t}\n");
- }
- fprintf(out, "}\n");
-}
-
-static void nelma_write_layers(FILE * out)
-{
- int i, idx;
- int z;
-
- const char *ext;
- char buf[100];
-
- int subh;
-
- subh = nelma_substrateh / nelma_copperh;
-
- fprintf(out, "\n/* **** Layers **** */\n\n");
-
- /* Air layers on top and bottom of the stack */
- /* Their height is double substrate height. */
- nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air");
- nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air");
-
- z = 10;
- for (i = 0; i < MAX_LAYER; i++)
- if (nelma_export_group[i]) {
- idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
- ext = layer_type_to_file_name(idx, FNS_fixed);
-
- if (z != 10) {
- sprintf(buf, "substrate-%d", z);
- nelma_write_layer(out, z, subh, buf, 0, "composite");
- z++;
- }
- /*
- * FIXME: for layers that are not on top or bottom,
- * the material should be "composite"
- */
- nelma_write_layer(out, z, 1, ext, 1, "air");
-
- z++;
- }
-}
-
-static void nelma_write_object(FILE * out, LibraryEntryTypePtr pin)
-{
- int i, idx;
- Coord px = 0, py = 0;
- int x, y;
-
- char *f;
- const char *ext;
-
- pin_name_to_xy(pin, &px, &py);
-
- x = pcb_to_nelma(px);
- y = pcb_to_nelma(py);
-
- for (i = 0; i < MAX_LAYER; i++)
- if (nelma_export_group[i]) {
- idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
- ext = layer_type_to_file_name(idx, FNS_fixed);
-
- fprintf(out, "object %s-%s {\n", pin->ListEntry, ext);
- fprintf(out, "\tposition = { 0, 0 }\n");
- fprintf(out, "\tmaterial = \"copper\"\n");
- fprintf(out, "\ttype = \"image\"\n");
- fprintf(out, "\trole = \"net\"\n");
-
- f = nelma_get_png_name(nelma_basename, ext);
-
- fprintf(out, "\tfile = \"%s\"\n", f);
-
- free(f);
-
- fprintf(out, "\tfile-pos = { %d, %d }\n", x, y);
- fprintf(out, "}\n");
- }
-}
-
-static void nelma_write_objects(FILE * out)
-{
- LibraryType netlist;
- LibraryMenuTypePtr net;
- LibraryEntryTypePtr pin;
-
- int n, m;
-
- netlist = PCB->NetlistLib[NETLIST_EDITED];
-
- fprintf(out, "\n/* **** Objects **** */\n\n");
-
- for (n = 0; n < netlist.MenuN; n++) {
- net = &netlist.Menu[n];
-
- for (m = 0; m < net->EntryN; m++) {
- pin = &net->Entry[m];
-
- nelma_write_object(out, pin);
- }
- }
-}
-
-/* *** Main export callback ************************************************ */
-
-static void nelma_parse_arguments(int *argc, char ***argv)
-{
- hid_register_attributes(nelma_attribute_list, sizeof(nelma_attribute_list) / sizeof(nelma_attribute_list[0]), nelma_cookie);
- hid_parse_command_line(argc, argv);
-}
-
-static HID_Attribute *nelma_get_export_options(int *n)
-{
- static char *last_made_filename = 0;
-
- if (PCB) {
- derive_default_filename(PCB->Filename, &nelma_attribute_list[HA_basename], ".nelma", &last_made_filename);
- }
- if (n) {
- *n = NUM_OPTIONS;
- }
- return nelma_attribute_list;
-}
-
-/* Populates nelma_export_group array */
-void nelma_choose_groups()
-{
- int n, m;
- LayerType *layer;
-
- /* Set entire array to 0 (don't export any layer groups by default */
- memset(nelma_export_group, 0, sizeof(nelma_export_group));
-
- for (n = 0; n < max_copper_layer; n++) {
- layer = &PCB->Data->Layer[n];
-
- if (!LAYER_IS_EMPTY(layer)) {
- /* layer isn't empty */
-
- /*
- * is this check necessary? It seems that special
- * layers have negative indexes?
- */
-
- if (SL_TYPE(n) == 0) {
- /* layer is a copper layer */
- m = GetLayerGroupNumberByNumber(n);
-
- /* the export layer */
- nelma_export_group[m] = 1;
- }
- }
- }
-}
-
-static void nelma_alloc_colors()
-{
- /*
- * Allocate white and black -- the first color allocated becomes the
- * background color
- */
-
- white = (struct color_struct *) malloc(sizeof(*white));
- white->r = white->g = white->b = 255;
- white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b);
-
- black = (struct color_struct *) malloc(sizeof(*black));
- black->r = black->g = black->b = 0;
- black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b);
-}
-
-static void nelma_start_png(const char *basename, const char *suffix)
-{
- int h, w;
- char *buf;
-
- buf = nelma_get_png_name(basename, suffix);
-
- h = pcb_to_nelma(PCB->MaxHeight);
- w = pcb_to_nelma(PCB->MaxWidth);
-
- /* nelma_im = gdImageCreate (w, h); */
-
- /* Nelma only works with true color images */
- nelma_im = gdImageCreate(w, h);
- nelma_f = fopen(buf, "wb");
-
- nelma_alloc_colors();
-
- free(buf);
-}
-
-static void nelma_finish_png()
-{
-#ifdef HAVE_GDIMAGEPNG
- gdImagePng(nelma_im, nelma_f);
-#else
- Message("NELMA: PNG not supported by gd. Can't write layer mask.\n");
-#endif
- gdImageDestroy(nelma_im);
- fclose(nelma_f);
-
- free(white);
- free(black);
-
- nelma_im = NULL;
- nelma_f = NULL;
-}
-
-void nelma_start_png_export()
-{
- BoxType region;
-
- region.X1 = 0;
- region.Y1 = 0;
- region.X2 = PCB->MaxWidth;
- region.Y2 = PCB->MaxHeight;
-
- linewidth = -1;
- lastbrush = (gdImagePtr) ((void *) -1);
- lastcolor = -1;
-
- hid_expose_callback(&nelma_hid, ®ion, 0);
-}
-
-static void nelma_do_export(HID_Attr_Val * options)
-{
- int save_ons[MAX_LAYER + 2];
- int i, idx;
- FILE *nelma_config;
- char *buf;
- int len;
-
- time_t t;
-
- if (!options) {
- nelma_get_export_options(0);
- for (i = 0; i < NUM_OPTIONS; i++) {
- nelma_values[i] = nelma_attribute_list[i].default_val;
- }
- options = nelma_values;
- }
- nelma_basename = options[HA_basename].str_value;
- if (!nelma_basename) {
- nelma_basename = "pcb-out";
- }
- nelma_dpi = options[HA_dpi].int_value;
- if (nelma_dpi < 0) {
- fprintf(stderr, "ERROR: dpi may not be < 0\n");
- return;
- }
- nelma_copperh = options[HA_copperh].int_value;
- nelma_substrateh = options[HA_substrateh].int_value;
- nelma_substratee = options[HA_substratee].real_value;
-
- nelma_choose_groups();
-
- for (i = 0; i < MAX_LAYER; i++) {
- if (nelma_export_group[i]) {
-
- nelma_cur_group = i;
-
- /* magic */
- idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
-
- nelma_start_png(nelma_basename, layer_type_to_file_name(idx, FNS_fixed));
-
- hid_save_and_show_layer_ons(save_ons);
- nelma_start_png_export();
- hid_restore_layer_ons(save_ons);
-
- nelma_finish_png();
- }
- }
-
- len = strlen(nelma_basename) + 4;
- buf = (char *) malloc(sizeof(*buf) * len);
-
- sprintf(buf, "%s.em", nelma_basename);
- nelma_config = fopen(buf, "w");
-
- free(buf);
-
- fprintf(nelma_config, "/* Made with PCB Nelma export HID */");
- t = time(NULL);
- fprintf(nelma_config, "/* %s */", ctime(&t));
-
- nelma_write_nets(nelma_config);
- nelma_write_objects(nelma_config);
- nelma_write_layers(nelma_config);
- nelma_write_materials(nelma_config);
- nelma_write_space(nelma_config);
-
- fclose(nelma_config);
-}
-
-/* *** PNG export (slightly modified code from PNG export HID) ************* */
-
-static int nelma_set_layer(const char *name, int group, int empty)
-{
- int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group;
-
- if (name == 0) {
- name = PCB->Data->Layer[idx].Name;
- }
- if (strcmp(name, "invisible") == 0) {
- return 0;
- }
- is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL);
- is_mask = (SL_TYPE(idx) == SL_MASK);
-
- if (is_mask) {
- /* Don't print masks */
- return 0;
- }
- if (is_drill) {
- /*
- * Print 'holes', so that we can fill gaps in the copper
- * layer
- */
- return 1;
- }
- if (group == nelma_cur_group) {
- return 1;
- }
- return 0;
-}
-
-static hidGC nelma_make_gc(void)
-{
- hidGC rv = (hidGC) malloc(sizeof(struct hid_gc_struct));
- rv->me_pointer = &nelma_hid;
- rv->cap = Trace_Cap;
- rv->width = 1;
- rv->color = (struct color_struct *) malloc(sizeof(*rv->color));
- rv->color->r = rv->color->g = rv->color->b = 0;
- rv->color->c = 0;
- return rv;
-}
-
-static void nelma_destroy_gc(hidGC gc)
-{
- free(gc);
-}
-
-static void nelma_use_mask(int use_it)
-{
- /* does nothing */
-}
-
-static void nelma_set_color(hidGC gc, const char *name)
-{
- if (nelma_im == NULL) {
- return;
- }
- if (name == NULL) {
- name = "#ff0000";
- }
- if (!strcmp(name, "drill")) {
- gc->color = black;
- gc->erase = 0;
- return;
- }
- if (!strcmp(name, "erase")) {
- /* FIXME -- should be background, not white */
- gc->color = white;
- gc->erase = 1;
- return;
- }
- gc->color = black;
- gc->erase = 0;
- return;
-}
-
-static void nelma_set_line_cap(hidGC gc, EndCapStyle style)
-{
- gc->cap = style;
-}
-
-static void nelma_set_line_width(hidGC gc, Coord width)
-{
- gc->width = width;
-}
-
-static void nelma_set_draw_xor(hidGC gc, int xor_)
-{
- ;
-}
-
-static void nelma_set_draw_faded(hidGC gc, int faded)
-{
- gc->faded = faded;
-}
-
-static void use_gc(hidGC gc)
-{
- int need_brush = 0;
-
- if (gc->me_pointer != &nelma_hid) {
- fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n");
- abort();
- }
- if (linewidth != gc->width) {
- /* Make sure the scaling doesn't erase lines completely */
- /*
- if (SCALE (gc->width) == 0 && gc->width > 0)
- gdImageSetThickness (im, 1);
- else
- */
- gdImageSetThickness(nelma_im, pcb_to_nelma(gc->width));
- linewidth = gc->width;
- need_brush = 1;
- }
- if (lastbrush != gc->brush || need_brush) {
- static void *bcache = 0;
- hidval bval;
- char name[256];
- char type;
- int r;
-
- switch (gc->cap) {
- case Round_Cap:
- case Trace_Cap:
- type = 'C';
- r = pcb_to_nelma(gc->width / 2);
- break;
- default:
- case Square_Cap:
- r = pcb_to_nelma(gc->width);
- type = 'S';
- break;
- }
- sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r);
-
- if (hid_cache_color(0, name, &bval, &bcache)) {
- gc->brush = (gdImagePtr) bval.ptr;
- }
- else {
- int bg, fg;
- if (type == 'C')
- gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1);
- else
- gc->brush = gdImageCreate(r + 1, r + 1);
- bg = gdImageColorAllocate(gc->brush, 255, 255, 255);
- fg = gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g, gc->color->b);
- gdImageColorTransparent(gc->brush, bg);
-
- /*
- * if we shrunk to a radius/box width of zero, then just use
- * a single pixel to draw with.
- */
- if (r == 0)
- gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg);
- else {
- if (type == 'C')
- gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg);
- else
- gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg);
- }
- bval.ptr = gc->brush;
- hid_cache_color(1, name, &bval, &bcache);
- }
-
- gdImageSetBrush(nelma_im, gc->brush);
- lastbrush = gc->brush;
-
- }
-#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
- if (lastcolor != CBLEND(gc)) {
- if (is_drill || is_mask) {
-#ifdef FIXME
- fprintf(f, "%d gray\n", gc->erase ? 0 : 1);
-#endif
- lastcolor = 0;
- }
- else {
- double r, g, b;
- r = gc->r;
- g = gc->g;
- b = gc->b;
- if (gc->faded) {
- r = 0.8 * 255 + 0.2 * r;
- g = 0.8 * 255 + 0.2 * g;
- b = 0.8 * 255 + 0.2 * b;
- }
-#ifdef FIXME
- if (gc->r == gc->g && gc->g == gc->b)
- fprintf(f, "%g gray\n", r / 255.0);
- else
- fprintf(f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0);
-#endif
- lastcolor = CBLEND(gc);
- }
- }
-}
-
-static void nelma_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
-{
- use_gc(gc);
- gdImageRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
-}
-
-static void nelma_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
-{
- use_gc(gc);
- gdImageSetThickness(nelma_im, 0);
- linewidth = 0;
- gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
-}
-
-static void nelma_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
-{
- if (x1 == x2 && y1 == y2) {
- Coord w = gc->width / 2;
- nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w);
- return;
- }
- use_gc(gc);
-
- gdImageSetThickness(nelma_im, 0);
- linewidth = 0;
- gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed);
-}
-
-static void nelma_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle)
-{
- Angle sa, ea;
-
- /*
- * in gdImageArc, 0 degrees is to the right and +90 degrees is down
- * in pcb, 0 degrees is to the left and +90 degrees is down
- */
- start_angle = 180 - start_angle;
- delta_angle = -delta_angle;
- if (delta_angle > 0) {
- sa = start_angle;
- ea = start_angle + delta_angle;
- }
- else {
- sa = start_angle + delta_angle;
- ea = start_angle;
- }
-
- /*
- * make sure we start between 0 and 360 otherwise gd does strange
- * things
- */
- sa = NormalizeAngle(sa);
- ea = NormalizeAngle(ea);
-
-#if 0
- printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea);
- printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
- im, SCALE_X(cx), SCALE_Y(cy), SCALE(width), SCALE(height), sa, ea, gc->color->c);
-#endif
- use_gc(gc);
- gdImageSetThickness(nelma_im, 0);
- linewidth = 0;
- gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
- pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed);
-}
-
-static void nelma_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius)
-{
- use_gc(gc);
-
- gdImageSetThickness(nelma_im, 0);
- linewidth = 0;
- gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
- pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), gc->color->c);
-
-}
-
-static void nelma_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y)
-{
- int i;
- gdPoint *points;
-
- points = (gdPoint *) malloc(n_coords * sizeof(gdPoint));
- if (points == NULL) {
- fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n");
- exit(1);
- }
- use_gc(gc);
- for (i = 0; i < n_coords; i++) {
- points[i].x = pcb_to_nelma(x[i]);
- points[i].y = pcb_to_nelma(y[i]);
- }
- gdImageSetThickness(nelma_im, 0);
- linewidth = 0;
- gdImageFilledPolygon(nelma_im, points, n_coords, gc->color->c);
- free(points);
-}
-
-static void nelma_calibrate(double xval, double yval)
-{
- CRASH;
-}
-
-static void nelma_set_crosshair(int x, int y, int a)
-{
-}
-
-/* *** Miscellaneous ******************************************************* */
-
-#include "dolists.h"
-
-void hid_nelma_init()
-{
- memset(&nelma_hid, 0, sizeof(HID));
-
- common_nogui_init(&nelma_hid);
- common_draw_helpers_init(&nelma_hid);
-
- nelma_hid.struct_size = sizeof(HID);
- nelma_hid.name = "nelma";
- nelma_hid.description = "Numerical analysis package export";
- nelma_hid.exporter = 1;
- nelma_hid.poly_before = 1;
-
- nelma_hid.get_export_options = nelma_get_export_options;
- nelma_hid.do_export = nelma_do_export;
- nelma_hid.parse_arguments = nelma_parse_arguments;
- nelma_hid.set_layer = nelma_set_layer;
- nelma_hid.make_gc = nelma_make_gc;
- nelma_hid.destroy_gc = nelma_destroy_gc;
- nelma_hid.use_mask = nelma_use_mask;
- nelma_hid.set_color = nelma_set_color;
- nelma_hid.set_line_cap = nelma_set_line_cap;
- nelma_hid.set_line_width = nelma_set_line_width;
- nelma_hid.set_draw_xor = nelma_set_draw_xor;
- nelma_hid.set_draw_faded = nelma_set_draw_faded;
- nelma_hid.draw_line = nelma_draw_line;
- nelma_hid.draw_arc = nelma_draw_arc;
- nelma_hid.draw_rect = nelma_draw_rect;
- nelma_hid.fill_circle = nelma_fill_circle;
- nelma_hid.fill_polygon = nelma_fill_polygon;
- nelma_hid.fill_rect = nelma_fill_rect;
- nelma_hid.calibrate = nelma_calibrate;
- nelma_hid.set_crosshair = nelma_set_crosshair;
-
- hid_register_hid(&nelma_hid);
-}
Index: trunk/src/hid/common/actions.c
===================================================================
--- trunk/src/hid/common/actions.c (revision 1268)
+++ trunk/src/hid/common/actions.c (revision 1269)
@@ -72,7 +72,7 @@
}
}
-void hid_register_action(const HID_Action * a, void *cookie)
+void hid_register_action(const HID_Action * a, const char *cookie)
{
hid_register_actions(a, 1, cookie);
}
Index: trunk/src_plugins/export_gcode/Makefile
===================================================================
--- trunk/src_plugins/export_gcode/Makefile (nonexistent)
+++ trunk/src_plugins/export_gcode/Makefile (revision 1269)
@@ -0,0 +1,5 @@
+all:
+ cd ../../src && make mod_export_gcode
+
+clean:
+ rm *.o *.so 2>/dev/null ; true
Index: trunk/src_plugins/export_gcode/Plug.tmpasm
===================================================================
--- trunk/src_plugins/export_gcode/Plug.tmpasm (nonexistent)
+++ trunk/src_plugins/export_gcode/Plug.tmpasm (revision 1269)
@@ -0,0 +1,15 @@
+append /local/pcb/export_gcode/enable {}
+append /local/pcb/export_gcode/buildin {}
+
+put /local/pcb/mod {export_gcode}
+put /local/pcb/mod/OBJS [@ $(PLUGDIR)/export_gcode/gcode.o $(PLUGDIR)/export_gcode/decompose.o $(PLUGDIR)/export_gcode/trace.o $(PLUGDIR)/export_gcode/curve.o @]
+
+if /local/pcb/export_gcode/enable then
+ if /local/pcb/export_gcode/buildin then
+ include {Makefile.in.mod/Buildin}
+ else
+ include {Makefile.in.mod/Plugin}
+ end
+else
+ include {Makefile.in.mod/Disable}
+end
Index: trunk/src_plugins/export_gcode/README
===================================================================
--- trunk/src_plugins/export_gcode/README (nonexistent)
+++ trunk/src_plugins/export_gcode/README (revision 1269)
@@ -0,0 +1,4 @@
+Export to gcode
+
+#state: works
+#default: buildin
Index: trunk/src_plugins/export_gcode/auxiliary.h
===================================================================
--- trunk/src_plugins/export_gcode/auxiliary.h (nonexistent)
+++ trunk/src_plugins/export_gcode/auxiliary.h (revision 1269)
@@ -0,0 +1,80 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+/* This header file collects some general-purpose macros (and static
+ inline functions) that are used in various places. */
+
+#ifndef AUXILIARY_H
+#define AUXILIARY_H
+
+#include "config.h"
+
+/* ---------------------------------------------------------------------- */
+/* point arithmetic */
+
+#include "potracelib.h"
+
+struct point_s {
+ long x;
+ long y;
+};
+typedef struct point_s point_t;
+
+typedef potrace_dpoint_t dpoint_t;
+
+/* convert point_t to dpoint_t */
+static inline dpoint_t dpoint(point_t p)
+{
+ dpoint_t res;
+ res.x = p.x;
+ res.y = p.y;
+ return res;
+}
+
+/* range over the straight line segment [a,b] when lambda ranges over [0,1] */
+static inline dpoint_t interval(double lambda, dpoint_t a, dpoint_t b)
+{
+ dpoint_t res;
+
+ res.x = a.x + lambda * (b.x - a.x);
+ res.y = a.y + lambda * (b.y - a.y);
+ return res;
+}
+
+/* ---------------------------------------------------------------------- */
+/* some useful macros. Note: the "mod" macro works correctly for
+ negative a. Also note that the test for a>=n, while redundant,
+ speeds up the mod function by 70% in the average case (significant
+ since the program spends about 16% of its time here - or 40%
+ without the test). The "floordiv" macro returns the largest integer
+ <= a/n, and again this works correctly for negative a, as long as
+ a,n are integers and n>0. */
+
+/* integer arithmetic */
+
+static inline int mod(int a, int n)
+{
+ return a >= n ? a % n : a >= 0 ? a : n - 1 - (-1 - a) % n;
+}
+
+static inline int floordiv(int a, int n)
+{
+ return a >= 0 ? a / n : -1 - (-1 - a) / n;
+}
+
+/* Note: the following work for integers and other numeric types. */
+#undef sign
+#undef abs
+#undef min
+#undef max
+#undef sq
+#undef cu
+#define sign(x) ((x)>0 ? 1 : (x)<0 ? -1 : 0)
+#define abs(a) ((a)>0 ? (a) : -(a))
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#define max(a,b) ((a)>(b) ? (a) : (b))
+#define sq(a) ((a)*(a))
+#define cu(a) ((a)*(a)*(a))
+
+#endif /* AUXILIARY_H */
Index: trunk/src_plugins/export_gcode/bitmap.h
===================================================================
--- trunk/src_plugins/export_gcode/bitmap.h (nonexistent)
+++ trunk/src_plugins/export_gcode/bitmap.h (revision 1269)
@@ -0,0 +1,104 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+#ifndef BITMAP_H
+#define BITMAP_H
+
+#include "config.h"
+
+#include
+#include
+
+/* The bitmap type is defined in potracelib.h */
+#include "potracelib.h"
+
+/* The present file defines some convenient macros and static inline
+ functions for accessing bitmaps. Since they only produce inline
+ code, they can be conveniently shared by the library and frontends,
+ if desired */
+
+/* ---------------------------------------------------------------------- */
+/* some measurements */
+
+#define BM_WORDSIZE ((int)sizeof(potrace_word))
+#define BM_WORDBITS (8*BM_WORDSIZE)
+#define BM_HIBIT (((potrace_word)1)<<(BM_WORDBITS-1))
+#define BM_ALLBITS (~(potrace_word)0)
+
+/* macros for accessing pixel at index (x,y). U* macros omit the
+ bounds check. */
+
+#define bm_scanline(bm, y) ((bm)->map + (y)*(bm)->dy)
+#define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS])
+#define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1)))
+#define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a))
+#define bm_safe(bm, x, y) (bm_range(x, (bm)->w) && bm_range(y, (bm)->h))
+#define BM_UGET(bm, x, y) ((*bm_index(bm, x, y) & bm_mask(x)) != 0)
+#define BM_USET(bm, x, y) (*bm_index(bm, x, y) |= bm_mask(x))
+#define BM_UCLR(bm, x, y) (*bm_index(bm, x, y) &= ~bm_mask(x))
+#define BM_UINV(bm, x, y) (*bm_index(bm, x, y) ^= bm_mask(x))
+#define BM_UPUT(bm, x, y, b) ((b) ? BM_USET(bm, x, y) : BM_UCLR(bm, x, y))
+#define BM_GET(bm, x, y) (bm_safe(bm, x, y) ? BM_UGET(bm, x, y) : 0)
+#define BM_SET(bm, x, y) (bm_safe(bm, x, y) ? BM_USET(bm, x, y) : 0)
+#define BM_CLR(bm, x, y) (bm_safe(bm, x, y) ? BM_UCLR(bm, x, y) : 0)
+#define BM_INV(bm, x, y) (bm_safe(bm, x, y) ? BM_UINV(bm, x, y) : 0)
+#define BM_PUT(bm, x, y, b) (bm_safe(bm, x, y) ? BM_UPUT(bm, x, y, b) : 0)
+
+/* free the given bitmap. Leaves errno untouched. */
+static inline void bm_free(potrace_bitmap_t * bm)
+{
+ if (bm) {
+ free(bm->map);
+ }
+ free(bm);
+}
+
+/* return new un-initialized bitmap. NULL with errno on error */
+static inline potrace_bitmap_t *bm_new(int w, int h)
+{
+ potrace_bitmap_t *bm;
+ int dy = (w + BM_WORDBITS - 1) / BM_WORDBITS;
+
+ bm = (potrace_bitmap_t *) malloc(sizeof(potrace_bitmap_t));
+ if (!bm) {
+ return NULL;
+ }
+ bm->w = w;
+ bm->h = h;
+ bm->dy = dy;
+ bm->map = (potrace_word *) malloc(dy * h * BM_WORDSIZE);
+ if (!bm->map) {
+ free(bm);
+ return NULL;
+ }
+ return bm;
+}
+
+/* clear the given bitmap. Set all bits to c. */
+static inline void bm_clear(potrace_bitmap_t * bm, int c)
+{
+ memset(bm->map, c ? -1 : 0, bm->dy * bm->h * BM_WORDSIZE);
+}
+
+/* duplicate the given bitmap. Return NULL on error with errno set. */
+static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t * bm)
+{
+ potrace_bitmap_t *bm1 = bm_new(bm->w, bm->h);
+ if (!bm1) {
+ return NULL;
+ }
+ memcpy(bm1->map, bm->map, bm->dy * bm->h * BM_WORDSIZE);
+ return bm1;
+}
+
+/* invert the given bitmap. */
+static inline void bm_invert(potrace_bitmap_t * bm)
+{
+ int i;
+ for (i = 0; i < bm->dy * bm->h; i++) {
+ bm->map[i] ^= BM_ALLBITS;
+ }
+}
+
+#endif /* BITMAP_H */
Index: trunk/src_plugins/export_gcode/curve.c
===================================================================
--- trunk/src_plugins/export_gcode/curve.c (nonexistent)
+++ trunk/src_plugins/export_gcode/curve.c (revision 1269)
@@ -0,0 +1,114 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+/* $Id: curve.c 147 2007-04-09 00:44:09Z selinger $ */
+/* private part of the path and curve data structures */
+
+#include
+#include
+#include
+
+#include "potracelib.h"
+#include "lists.h"
+#include "curve.h"
+
+#define SAFE_MALLOC(var, n, typ) \
+ if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error
+
+/* ---------------------------------------------------------------------- */
+/* allocate and free path objects */
+
+path_t *path_new(void)
+{
+ path_t *p = NULL;
+ privpath_t *priv = NULL;
+
+ SAFE_MALLOC(p, 1, path_t);
+ memset(p, 0, sizeof(path_t));
+ SAFE_MALLOC(priv, 1, privpath_t);
+ memset(priv, 0, sizeof(privpath_t));
+ p->priv = priv;
+ return p;
+
+malloc_error:
+ free(p);
+ free(priv);
+ return NULL;
+}
+
+/* free the members of the given curve structure. Leave errno unchanged. */
+static void privcurve_free_members(privcurve_t * curve)
+{
+ free(curve->tag);
+ free(curve->c);
+ free(curve->vertex);
+ free(curve->alpha);
+ free(curve->alpha0);
+ free(curve->beta);
+}
+
+/* free a path. Leave errno untouched. */
+void path_free(path_t * p)
+{
+ if (p) {
+ if (p->priv) {
+ free(p->priv->pt);
+ free(p->priv->lon);
+ free(p->priv->sums);
+ free(p->priv->po);
+ privcurve_free_members(&p->priv->curve);
+ privcurve_free_members(&p->priv->ocurve);
+ }
+ free(p->priv);
+ /* do not free p->fcurve ! */
+ }
+ free(p);
+}
+
+/* free a pathlist, leaving errno untouched. */
+void pathlist_free(path_t * plist)
+{
+ path_t *p;
+
+ list_forall_unlink(p, plist) {
+ path_free(p);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* initialize and finalize curve structures */
+
+typedef dpoint_t dpoint3_t[3];
+
+/* initialize the members of the given curve structure to size m.
+ Return 0 on success, 1 on error with errno set. */
+int privcurve_init(privcurve_t * curve, int n)
+{
+ memset(curve, 0, sizeof(privcurve_t));
+ curve->n = n;
+ SAFE_MALLOC(curve->tag, n, int);
+ SAFE_MALLOC(curve->c, n, dpoint3_t);
+ SAFE_MALLOC(curve->vertex, n, dpoint_t);
+ SAFE_MALLOC(curve->alpha, n, double);
+ SAFE_MALLOC(curve->alpha0, n, double);
+ SAFE_MALLOC(curve->beta, n, double);
+ return 0;
+
+malloc_error:
+ free(curve->tag);
+ free(curve->c);
+ free(curve->vertex);
+ free(curve->alpha);
+ free(curve->alpha0);
+ free(curve->beta);
+ return 1;
+}
+
+/* copy private to public curve structure */
+void privcurve_to_curve(privcurve_t * pc, potrace_curve_t * c)
+{
+ c->n = pc->n;
+ c->tag = pc->tag;
+ c->c = pc->c;
+}
Index: trunk/src_plugins/export_gcode/curve.h
===================================================================
--- trunk/src_plugins/export_gcode/curve.h (nonexistent)
+++ trunk/src_plugins/export_gcode/curve.h (revision 1269)
@@ -0,0 +1,76 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+#ifndef CURVE_H
+#define CURVE_H
+
+#include "auxiliary.h"
+
+/* vertex is c[1] for tag=POTRACE_CORNER, and the intersection of
+ .c[-1][2]..c[0] and c[1]..c[2] for tag=POTRACE_CURVETO. alpha is only
+ defined for tag=POTRACE_CURVETO and is the alpha parameter of the curve:
+ .c[-1][2]..c[0] = alpha*(.c[-1][2]..vertex), and
+ c[2]..c[1] = alpha*(c[2]..vertex).
+ Beta is so that (.beta[i])[.vertex[i],.vertex[i+1]] = .c[i][2].
+*/
+
+struct privcurve_s {
+ int n; /* number of segments */
+ int *tag; /* tag[n]: POTRACE_CORNER or POTRACE_CURVETO */
+ dpoint_t(*c)[3]; /* c[n][i]: control points.
+ c[n][0] is unused for tag[n]=POTRACE_CORNER */
+ /* the remainder of this structure is special to privcurve, and is
+ used in EPS debug output and special EPS "short coding". These
+ fields are valid only if "alphacurve" is set. */
+ int alphacurve; /* have the following fields been initialized? */
+ dpoint_t *vertex; /* for POTRACE_CORNER, this equals c[1] */
+ double *alpha; /* only for POTRACE_CURVETO */
+ double *alpha0; /* "uncropped" alpha parameter - for debug output only */
+ double *beta;
+};
+typedef struct privcurve_s privcurve_t;
+
+struct sums_s {
+ double x;
+ double y;
+ double x2;
+ double xy;
+ double y2;
+};
+typedef struct sums_s sums_t;
+
+/* the path structure is filled in with information about a given path
+ as it is accumulated and passed through the different stages of the
+ Potrace algorithm. Backends only need to read the fcurve and fm
+ fields of this data structure, but debugging backends may read
+ other fields. */
+struct potrace_privpath_s {
+ int len;
+ point_t *pt; /* pt[len]: path as extracted from bitmap */
+ int *lon; /* lon[len]: (i,lon[i]) = longest straight line from i */
+
+ int x0, y0; /* origin for sums */
+ sums_t *sums; /* sums[len+1]: cache for fast summing */
+
+ int m; /* length of optimal polygon */
+ int *po; /* po[m]: optimal polygon */
+
+ privcurve_t curve; /* curve[m]: array of curve elements */
+ privcurve_t ocurve; /* ocurve[om]: array of curve elements */
+ privcurve_t *fcurve; /* final curve: this points to either curve or
+ ocurve. Do not free this separately. */
+};
+typedef struct potrace_privpath_s potrace_privpath_t;
+
+/* shorter names */
+typedef potrace_privpath_t privpath_t;
+typedef potrace_path_t path_t;
+
+path_t *path_new(void);
+void path_free(path_t * p);
+void pathlist_free(path_t * plist);
+int privcurve_init(privcurve_t * curve, int n);
+void privcurve_to_curve(privcurve_t * pc, potrace_curve_t * c);
+
+#endif /* CURVE_H */
Index: trunk/src_plugins/export_gcode/decompose.c
===================================================================
--- trunk/src_plugins/export_gcode/decompose.c (nonexistent)
+++ trunk/src_plugins/export_gcode/decompose.c (revision 1269)
@@ -0,0 +1,525 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+/* $Id: decompose.c 146 2007-04-09 00:43:46Z selinger $ */
+
+#include
+#include
+#include
+#include
+
+#include "potracelib.h"
+#include "curve.h"
+#include "lists.h"
+#include "auxiliary.h"
+#include "bitmap.h"
+#include "decompose.h"
+/*#include "progress.h"*/
+
+/* ---------------------------------------------------------------------- */
+/* auxiliary bitmap manipulations */
+
+/* set the excess padding to 0 */
+static void bm_clearexcess(potrace_bitmap_t * bm)
+{
+ potrace_word mask;
+ int y;
+
+ if (bm->w % BM_WORDBITS != 0) {
+ mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS));
+ for (y = 0; y < bm->h; y++) {
+ *bm_index(bm, bm->w, y) &= mask;
+ }
+ }
+}
+
+struct bbox_s {
+ int x0, x1, y0, y1; /* bounding box */
+};
+typedef struct bbox_s bbox_t;
+
+/* clear the bm, assuming the bounding box is set correctly (faster
+ than clearing the whole bitmap) */
+static void clear_bm_with_bbox(potrace_bitmap_t * bm, bbox_t * bbox)
+{
+ int imin = (bbox->x0 / BM_WORDBITS);
+ int imax = ((bbox->x1 + BM_WORDBITS - 1) / BM_WORDBITS);
+ int i, y;
+
+ for (y = bbox->y0; y < bbox->y1; y++) {
+ for (i = imin; i < imax; i++) {
+ bm_scanline(bm, y)[i] = 0;
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* auxiliary functions */
+
+/* deterministically and efficiently hash (x,y) into a pseudo-random bit */
+static inline int detrand(int x, int y)
+{
+ unsigned int z;
+ static const unsigned char t[256] = {
+ /* non-linear sequence: constant term of inverse in GF(8),
+ mod x^8+x^4+x^3+x+1 */
+ 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+ 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
+ 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ };
+
+ /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
+ 5-bit sequence */
+ z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
+ z = t[z & 0xff] ^ t[(z >> 8) & 0xff] ^ t[(z >> 16) & 0xff] ^ t[(z >> 24) & 0xff];
+ return z & 1;
+}
+
+/* return the "majority" value of bitmap bm at intersection (x,y). We
+ assume that the bitmap is balanced at "radius" 1. */
+static int majority(potrace_bitmap_t * bm, int x, int y)
+{
+ int i, a, ct;
+
+ for (i = 2; i < 5; i++) { /* check at "radius" i */
+ ct = 0;
+ for (a = -i + 1; a <= i - 1; a++) {
+ ct += BM_GET(bm, x + a, y + i - 1) ? 1 : -1;
+ ct += BM_GET(bm, x + i - 1, y + a - 1) ? 1 : -1;
+ ct += BM_GET(bm, x + a - 1, y - i) ? 1 : -1;
+ ct += BM_GET(bm, x - i, y + a) ? 1 : -1;
+ }
+ if (ct > 0) {
+ return 1;
+ }
+ else if (ct < 0) {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* decompose image into paths */
+
+/* efficiently invert bits [x,infty) and [xa,infty) in line y. Here xa
+ must be a multiple of BM_WORDBITS. */
+static void xor_to_ref(potrace_bitmap_t * bm, int x, int y, int xa)
+{
+ int xhi = x & -BM_WORDBITS;
+ int xlo = x & (BM_WORDBITS - 1); /* = x % BM_WORDBITS */
+ int i;
+
+ if (xhi < xa) {
+ for (i = xhi; i < xa; i += BM_WORDBITS) {
+ *bm_index(bm, i, y) ^= BM_ALLBITS;
+ }
+ }
+ else {
+ for (i = xa; i < xhi; i += BM_WORDBITS) {
+ *bm_index(bm, i, y) ^= BM_ALLBITS;
+ }
+ }
+ /* note: the following "if" is needed because x86 treats a<priv->len <= 0) { /* a path of length 0 is silly, but legal */
+ return;
+ }
+
+ y1 = p->priv->pt[p->priv->len - 1].y;
+
+ xa = p->priv->pt[0].x & -BM_WORDBITS;
+ for (k = 0; k < p->priv->len; k++) {
+ x = p->priv->pt[k].x;
+ y = p->priv->pt[k].y;
+
+ if (y != y1) {
+ /* efficiently invert the rectangle [x,xa] x [y,y1] */
+ xor_to_ref(bm, x, min(y, y1), xa);
+ y1 = y;
+ }
+ }
+}
+
+/* Find the bounding box of a given path. Path is assumed to be of
+ non-zero length. */
+static void setbbox_path(bbox_t * bbox, path_t * p)
+{
+ int x, y;
+ int k;
+
+ bbox->y0 = INT_MAX;
+ bbox->y1 = 0;
+ bbox->x0 = INT_MAX;
+ bbox->x1 = 0;
+
+ for (k = 0; k < p->priv->len; k++) {
+ x = p->priv->pt[k].x;
+ y = p->priv->pt[k].y;
+
+ if (x < bbox->x0) {
+ bbox->x0 = x;
+ }
+ if (x > bbox->x1) {
+ bbox->x1 = x;
+ }
+ if (y < bbox->y0) {
+ bbox->y0 = y;
+ }
+ if (y > bbox->y1) {
+ bbox->y1 = y;
+ }
+ }
+}
+
+/* compute a path in the given pixmap, separating black from white.
+ Start path at the point (x0,x1), which must be an upper left corner
+ of the path. Also compute the area enclosed by the path. Return a
+ new path_t object, or NULL on error (note that a legitimate path
+ cannot have length 0). Sign is required for correct interpretation
+ of turnpolicies. */
+static path_t *findpath(potrace_bitmap_t * bm, int x0, int y0, int sign, int turnpolicy)
+{
+ int x, y, dirx, diry, len, size, area;
+ int c, d, tmp;
+ point_t *pt, *pt1;
+ path_t *p = NULL;
+
+ x = x0;
+ y = y0;
+ dirx = 0;
+ diry = -1;
+
+ len = size = 0;
+ pt = NULL;
+ area = 0;
+
+ while (1) {
+ /* add point to path */
+ if (len >= size) {
+ size += 100;
+ size = (int) (1.3 * size);
+ pt1 = (point_t *) realloc(pt, size * sizeof(point_t));
+ if (!pt1) {
+ goto error;
+ }
+ pt = pt1;
+ }
+ pt[len].x = x;
+ pt[len].y = y;
+ len++;
+
+ /* move to next point */
+ x += dirx;
+ y += diry;
+ area += x * diry;
+
+ /* path complete? */
+ if (x == x0 && y == y0) {
+ break;
+ }
+
+ /* determine next direction */
+ c = BM_GET(bm, x + (dirx + diry - 1) / 2, y + (diry - dirx - 1) / 2);
+ d = BM_GET(bm, x + (dirx - diry - 1) / 2, y + (diry + dirx - 1) / 2);
+
+ if (c && !d) { /* ambiguous turn */
+ if (turnpolicy == POTRACE_TURNPOLICY_RIGHT || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+')
+ || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-')
+ || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand(x, y))
+ || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority(bm, x, y))
+ || (turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority(bm, x, y))) {
+ tmp = dirx; /* right turn */
+ dirx = diry;
+ diry = -tmp;
+ }
+ else {
+ tmp = dirx; /* left turn */
+ dirx = -diry;
+ diry = tmp;
+ }
+ }
+ else if (c) { /* right turn */
+ tmp = dirx;
+ dirx = diry;
+ diry = -tmp;
+ }
+ else if (!d) { /* left turn */
+ tmp = dirx;
+ dirx = -diry;
+ diry = tmp;
+ }
+ } /* while this path */
+
+ /* allocate new path object */
+ p = path_new();
+ if (!p) {
+ goto error;
+ }
+
+ p->priv->pt = pt;
+ p->priv->len = len;
+ p->area = area;
+ p->sign = sign;
+
+ return p;
+
+error:
+ free(pt);
+ return NULL;
+}
+
+/* Give a tree structure to the given path list, based on "insideness"
+ testing. I.e., path A is considered "below" path B if it is inside
+ path B. The input pathlist is assumed to be ordered so that "outer"
+ paths occur before "inner" paths. The tree structure is stored in
+ the "childlist" and "sibling" components of the path_t
+ structure. The linked list structure is also changed so that
+ negative path components are listed immediately after their
+ positive parent. Note: some backends may ignore the tree
+ structure, others may use it e.g. to group path components. We
+ assume that in the input, point 0 of each path is an "upper left"
+ corner of the path, as returned by bm_to_pathlist. This makes it
+ easy to find an "interior" point. The bm argument should be a
+ bitmap of the correct size (large enough to hold all the paths),
+ and will be used as scratch space. Return 0 on success or -1 on
+ error with errno set. */
+
+static void pathlist_to_tree(path_t * plist, potrace_bitmap_t * bm)
+{
+ path_t *p, *p1;
+ path_t *heap, *heap1;
+ path_t *cur;
+ path_t *head;
+ path_t **hook, **hook_in, **hook_out; /* for fast appending to linked list */
+ bbox_t bbox;
+
+ bm_clear(bm, 0);
+
+ /* save original "next" pointers */
+ list_forall(p, plist) {
+ p->sibling = p->next;
+ p->childlist = NULL;
+ }
+
+ heap = plist;
+
+ /* the heap holds a list of lists of paths. Use "childlist" field
+ for outer list, "next" field for inner list. Each of the sublists
+ is to be turned into a tree. This code is messy, but it is
+ actually fast. Each path is rendered exactly once. We use the
+ heap to get a tail recursive algorithm: the heap holds a list of
+ pathlists which still need to be transformed. */
+
+ while (heap) {
+ /* unlink first sublist */
+ cur = heap;
+ heap = heap->childlist;
+ cur->childlist = NULL;
+
+ /* unlink first path */
+ head = cur;
+ cur = cur->next;
+ head->next = NULL;
+
+ /* render path */
+ xor_path(bm, head);
+ setbbox_path(&bbox, head);
+
+ /* now do insideness test for each element of cur; append it to
+ head->childlist if it's inside head, else append it to
+ head->next. */
+ hook_in = &head->childlist;
+ hook_out = &head->next;
+ list_forall_unlink(p, cur) {
+ if (p->priv->pt[0].y <= bbox.y0) {
+ list_insert_beforehook(p, hook_out);
+ /* append the remainder of the list to hook_out */
+ *hook_out = cur;
+ break;
+ }
+ if (BM_GET(bm, p->priv->pt[0].x, p->priv->pt[0].y - 1)) {
+ list_insert_beforehook(p, hook_in);
+ }
+ else {
+ list_insert_beforehook(p, hook_out);
+ }
+ }
+
+ /* clear bm */
+ clear_bm_with_bbox(bm, &bbox);
+
+ /* now schedule head->childlist and head->next for further
+ processing */
+ if (head->next) {
+ head->next->childlist = heap;
+ heap = head->next;
+ }
+ if (head->childlist) {
+ head->childlist->childlist = heap;
+ heap = head->childlist;
+ }
+ }
+
+ /* copy sibling structure from "next" to "sibling" component */
+ p = plist;
+ while (p) {
+ p1 = p->sibling;
+ p->sibling = p->next;
+ p = p1;
+ }
+
+ /* reconstruct a new linked list ("next") structure from tree
+ ("childlist", "sibling") structure. This code is slightly messy,
+ because we use a heap to make it tail recursive: the heap
+ contains a list of childlists which still need to be
+ processed. */
+ heap = plist;
+ if (heap) {
+ heap->next = NULL; /* heap is a linked list of childlists */
+ }
+ plist = NULL;
+ hook = &plist;
+ while (heap) {
+ heap1 = heap->next;
+ for (p = heap; p; p = p->sibling) {
+ /* p is a positive path */
+ /* append to linked list */
+ list_insert_beforehook(p, hook);
+
+ /* go through its children */
+ for (p1 = p->childlist; p1; p1 = p1->sibling) {
+ /* append to linked list */
+ list_insert_beforehook(p1, hook);
+ /* append its childlist to heap, if non-empty */
+ if (p1->childlist) {
+ list_append(path_t, heap1, p1->childlist);
+ }
+ }
+ }
+ heap = heap1;
+ }
+
+ return;
+}
+
+/* find the next set pixel in a row <= y. Pixels are searched first
+ left-to-right, then top-down. In other words, (x,y)<(x',y') if y>y'
+ or y=y' and x= 0; y--) {
+ for (x = 0; x < bm->w; x += BM_WORDBITS) {
+ if (*bm_index(bm, x, y)) {
+ while (!BM_GET(bm, x, y)) {
+ x++;
+ }
+ /* found */
+ *xp = x;
+ *yp = y;
+ return 0;
+ }
+ }
+ }
+ /* not found */
+ return 1;
+}
+
+/* Decompose the given bitmap into paths. Returns a linked list of
+ path_t objects with the fields len, pt, area, sign filled
+ in. Returns 0 on success with plistp set, or -1 on error with errno
+ set. */
+
+int bm_to_pathlist(const potrace_bitmap_t * bm, path_t ** plistp, const potrace_param_t * param)
+{
+ int x;
+ int y;
+ path_t *p;
+ path_t *plist = NULL; /* linked list of path objects */
+ path_t **hook = &plist; /* used to speed up appending to linked list */
+ potrace_bitmap_t *bm1 = NULL;
+ int sign;
+
+ bm1 = bm_dup(bm);
+ if (!bm1) {
+ goto error;
+ }
+
+ /* be sure the byte padding on the right is set to 0, as the fast
+ pixel search below relies on it */
+ bm_clearexcess(bm1);
+
+ /* iterate through components */
+ y = bm1->h - 1;
+ while (findnext(bm1, &x, &y) == 0) {
+ /* calculate the sign by looking at the original */
+ sign = BM_GET(bm, x, y) ? '+' : '-';
+
+ /* calculate the path */
+ p = findpath(bm1, x, y + 1, sign, param->turnpolicy);
+ if (p == NULL) {
+ goto error;
+ }
+
+ /* update buffered image */
+ xor_path(bm1, p);
+
+ /* if it's a turd, eliminate it, else append it to the list */
+ if (p->area <= param->turdsize) {
+ path_free(p);
+ }
+ else {
+ list_insert_beforehook(p, hook);
+ }
+
+ if (bm1->h > 0) { /* to be sure */
+ /*progress_update(1-y/(double)bm1->h, progress); */
+ }
+ }
+
+ pathlist_to_tree(plist, bm1);
+ bm_free(bm1);
+ *plistp = plist;
+
+/* progress_update(1.0, progress);*/
+
+ return 0;
+
+error:
+ bm_free(bm1);
+ list_forall_unlink(p, plist) {
+ path_free(p);
+ }
+ return -1;
+}
Index: trunk/src_plugins/export_gcode/decompose.h
===================================================================
--- trunk/src_plugins/export_gcode/decompose.h (nonexistent)
+++ trunk/src_plugins/export_gcode/decompose.h (revision 1269)
@@ -0,0 +1,15 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+/* $Id: decompose.h 147 2007-04-09 00:44:09Z selinger $ */
+
+#ifndef DECOMPOSE_H
+#define DECOMPOSE_H
+
+#include "potracelib.h"
+/*#include "progress.h"*/
+
+int bm_to_pathlist(const potrace_bitmap_t * bm, path_t ** plistp, const potrace_param_t * param);
+
+#endif /* DECOMPOSE_H */
Index: trunk/src_plugins/export_gcode/gcode.c
===================================================================
--- trunk/src_plugins/export_gcode/gcode.c (nonexistent)
+++ trunk/src_plugins/export_gcode/gcode.c (revision 1269)
@@ -0,0 +1,901 @@
+/*
+ * COPYRIGHT
+ *
+ * PCB, interactive printed circuit board design
+ *
+ * GCODE export HID
+ * Copyright (C) 2010 Alberto Maccioni
+ * this code is based on the NELMA export HID, the PNG export HID,
+ * and potrace, a tracing program by Peter Selinger
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * This HID exports a PCB layout into:
+ * one layer mask file (PNG format) per copper layer,
+ * one G-CODE CNC drill file.
+ * one G-CODE CNC file per copper layer.
+ * The latter is used by a CNC milling machine to mill the pcb.
+ */
+
+#include "config.h"
+#include "plugins.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "global.h"
+#include "error.h" /* Message() */
+#include "data.h"
+#include "misc.h"
+#include "rats.h"
+
+#include "hid.h"
+#include "../hidint.h"
+#include
+#include "hid/common/hidnogui.h"
+#include "hid/common/draw_helpers.h"
+#include "gcode.h"
+#include "bitmap.h"
+#include "curve.h"
+#include "potracelib.h"
+#include "trace.h"
+#include "decompose.h"
+#include "pcb-printf.h"
+
+#include "hid/common/hidinit.h"
+
+const char *gcode_cookie = "gcode HID";
+
+#define CRASH fprintf(stderr, "HID error: pcb called unimplemented GCODE function %s.\n", __FUNCTION__); abort()
+struct color_struct {
+ /* the descriptor used by the gd library */
+ int c;
+
+ /* so I can figure out what rgb value c refers to */
+ unsigned int r, g, b;
+};
+
+struct hid_gc_struct {
+ HID *me_pointer;
+ EndCapStyle cap;
+ int width;
+ unsigned char r, g, b;
+ int erase;
+ int faded;
+ struct color_struct *color;
+ gdImagePtr brush;
+};
+
+static struct color_struct *black = NULL, *white = NULL;
+static int linewidth = -1;
+static gdImagePtr lastbrush = (gdImagePtr) ((void *) -1);
+static int lastcolor = -1;
+
+/* gd image and file for PNG export */
+static gdImagePtr gcode_im = NULL;
+static FILE *gcode_f = NULL, *gcode_f2 = NULL;
+
+static int is_mask;
+static int is_drill;
+static int is_solder;
+
+/*
+ * Which groups of layers to export into PNG layer masks. 1 means export, 0
+ * means do not export.
+ */
+static int gcode_export_group[MAX_LAYER];
+
+/* Group that is currently exported. */
+static int gcode_cur_group;
+
+/* Filename prefix that will be used when saving files. */
+static const char *gcode_basename = NULL;
+
+/* Horizontal DPI (grid points per inch) */
+static int gcode_dpi = -1;
+
+static double gcode_cutdepth = 0; /* milling depth (inch) */
+static double gcode_drilldepth = 0; /* drilling depth (inch) */
+static double gcode_safeZ = 100; /* safe Z (inch) */
+static double gcode_toolradius = 0; /* tool radius(inch) */
+static int save_drill = 0;
+static int n_drill = 0;
+static int nmax_drill = 0;
+struct drill_struct {
+ double x;
+ double y;
+};
+
+static struct drill_struct *drill = 0;
+
+static const char *units[] = {
+ "mm",
+ "mil",
+ "um",
+ "inch",
+ NULL
+};
+
+HID_Attribute gcode_attribute_list[] = {
+ /* other HIDs expect this to be first. */
+ {"basename", "File name prefix",
+ HID_String, 0, 0, {0, 0, 0}, 0, 0},
+#define HA_basename 0
+
+ {"dpi", "Resolution of intermediate image (pixels/inch)",
+ HID_Integer, 0, 2000, {600, 0, 0}, 0, 0},
+#define HA_dpi 1
+
+ {"mill-depth", "Milling depth",
+ HID_Real, -1000, 1000, {0, 0, -0.05}, 0, 0},
+#define HA_cutdepth 2
+
+ {"safe-Z", "Safe Z for traverse move",
+ HID_Real, -1000, 10000, {0, 0, 2}, 0, 0},
+#define HA_safeZ 3
+
+ {"tool-radius", "Milling tool radius compensation",
+ HID_Real, 0, 10000, {0, 0, 0.1}, 0, 0},
+#define HA_toolradius 4
+
+ {"drill-depth", "Drilling depth",
+ HID_Real, -10000, 10000, {0, 0, -2}, 0, 0},
+#define HA_drilldepth 5
+
+ {"measurement-unit", "Measurement unit",
+ HID_Unit, 0, 0, {-1, 0, 0}, units, 0},
+#define HA_unit 6
+
+};
+
+#define NUM_OPTIONS (sizeof(gcode_attribute_list)/sizeof(gcode_attribute_list[0]))
+
+REGISTER_ATTRIBUTES(gcode_attribute_list, gcode_cookie)
+ static HID_Attr_Val gcode_values[NUM_OPTIONS];
+
+/* *** Utility funcions **************************************************** */
+
+/* convert from default PCB units to gcode units */
+ static int pcb_to_gcode(int pcb)
+{
+ return round(COORD_TO_INCH(pcb) * gcode_dpi);
+}
+
+static char *gcode_get_png_name(const char *basename, const char *suffix)
+{
+ return pcb_strdup_printf("%s.%s.png", basename, suffix);
+}
+
+/* Sorts drills in order of distance from the origin */
+struct drill_struct *sort_drill(struct drill_struct *drill, int n_drill)
+{
+ int i, j, imin;
+ double dmin, d;
+ struct drill_struct p = { 0, 0 };
+ struct drill_struct *temp = (struct drill_struct *) malloc(n_drill * sizeof(struct drill_struct));
+ for (j = 0; j < n_drill; j++) {
+ dmin = 1e20;
+ imin = 0;
+ for (i = 0; i < n_drill - j; i++) {
+ d = (drill[i].x - p.x) * (drill[i].x - p.x) + (drill[i].y - p.y) * (drill[i].y - p.y);
+ if (d < dmin) {
+ imin = i;
+ dmin = d;
+ }
+ }
+ /* printf("j=%d imin=%d dmin=%f p=(%f,%f)\n",j,imin,dmin,p.x,p.y); */
+ temp[j] = drill[imin];
+ drill[imin] = drill[n_drill - j - 1];
+ p = temp[j];
+ }
+ free(drill);
+ return temp;
+}
+
+/* *** Main export callback ************************************************ */
+
+static void gcode_parse_arguments(int *argc, char ***argv)
+{
+ hid_register_attributes(gcode_attribute_list, sizeof(gcode_attribute_list) / sizeof(gcode_attribute_list[0]), gcode_cookie);
+ hid_parse_command_line(argc, argv);
+}
+
+static HID_Attribute *gcode_get_export_options(int *n)
+{
+ static char *last_made_filename = 0;
+ static int last_unit_value = -1;
+
+ if (gcode_attribute_list[HA_unit].default_val.int_value == last_unit_value) {
+ if (Settings.grid_unit)
+ gcode_attribute_list[HA_unit].default_val.int_value = Settings.grid_unit->index;
+ else
+ gcode_attribute_list[HA_unit].default_val.int_value = get_unit_struct("mil")->index;
+ last_unit_value = gcode_attribute_list[HA_unit].default_val.int_value;
+ }
+
+ if (PCB) {
+ derive_default_filename(PCB->Filename, &gcode_attribute_list[HA_basename], ".gcode", &last_made_filename);
+ }
+ if (n) {
+ *n = NUM_OPTIONS;
+ }
+ return gcode_attribute_list;
+}
+
+/* Populates gcode_export_group array */
+void gcode_choose_groups()
+{
+ int n, m;
+ LayerType *layer;
+
+ /* Set entire array to 0 (don't export any layer groups by default */
+ memset(gcode_export_group, 0, sizeof(gcode_export_group));
+
+ for (n = 0; n < max_copper_layer; n++) {
+ layer = &PCB->Data->Layer[n];
+
+ if (!LAYER_IS_EMPTY(layer)) {
+ /* layer isn't empty */
+
+ /*
+ * is this check necessary? It seems that special
+ * layers have negative indexes?
+ */
+
+ if (SL_TYPE(n) == 0) {
+ /* layer is a copper layer */
+ m = GetLayerGroupNumberByNumber(n);
+
+ /* the export layer */
+ gcode_export_group[m] = 1;
+ }
+ }
+ }
+}
+
+static void gcode_alloc_colors()
+{
+ /*
+ * Allocate white and black -- the first color allocated becomes the
+ * background color
+ */
+
+ white = (struct color_struct *) malloc(sizeof(*white));
+ white->r = white->g = white->b = 255;
+ white->c = gdImageColorAllocate(gcode_im, white->r, white->g, white->b);
+
+ black = (struct color_struct *) malloc(sizeof(*black));
+ black->r = black->g = black->b = 0;
+ black->c = gdImageColorAllocate(gcode_im, black->r, black->g, black->b);
+}
+
+static void gcode_start_png(const char *basename, const char *suffix)
+{
+ int h, w;
+ char *buf;
+
+ buf = gcode_get_png_name(basename, suffix);
+
+ h = pcb_to_gcode(PCB->MaxHeight);
+ w = pcb_to_gcode(PCB->MaxWidth);
+
+ /* Nelma only works with true color images */
+ gcode_im = gdImageCreate(w, h);
+ gcode_f = fopen(buf, "wb");
+
+ gcode_alloc_colors();
+
+ free(buf);
+}
+
+static void gcode_finish_png()
+{
+#ifdef HAVE_GDIMAGEPNG
+ gdImagePng(gcode_im, gcode_f);
+#else
+ Message("GCODE: PNG not supported by gd. Can't write layer mask.\n");
+#endif
+ gdImageDestroy(gcode_im);
+ fclose(gcode_f);
+
+ free(white);
+ free(black);
+
+ gcode_im = NULL;
+ gcode_f = NULL;
+}
+
+void gcode_start_png_export()
+{
+ BoxType region;
+
+ region.X1 = 0;
+ region.Y1 = 0;
+ region.X2 = PCB->MaxWidth;
+ region.Y2 = PCB->MaxHeight;
+
+ linewidth = -1;
+ lastbrush = (gdImagePtr) ((void *) -1);
+ lastcolor = -1;
+
+ hid_expose_callback(&gcode_hid, ®ion, 0);
+}
+
+static void gcode_do_export(HID_Attr_Val * options)
+{
+ int save_ons[MAX_LAYER + 2];
+ int i, idx;
+ time_t t;
+ const Unit *unit;
+ double scale = 0, d = 0;
+ int r, c, v, p, metric;
+ char *filename;
+ path_t *plist = NULL;
+ potrace_bitmap_t *bm = NULL;
+ potrace_param_t param_default = {
+ 2, /* turnsize */
+ POTRACE_TURNPOLICY_MINORITY, /* turnpolicy */
+ 1.0, /* alphamax */
+ 1, /* opticurve */
+ 0.2, /* opttolerance */
+ {
+ NULL, /* callback function */
+ NULL, /* callback data */
+ 0.0, 1.0, /* progress range */
+ 0.0, /* granularity */
+ },
+ };
+
+ if (!options) {
+ gcode_get_export_options(0);
+ for (i = 0; i < NUM_OPTIONS; i++) {
+ gcode_values[i] = gcode_attribute_list[i].default_val;
+ }
+ options = gcode_values;
+ }
+ gcode_basename = options[HA_basename].str_value;
+ if (!gcode_basename) {
+ gcode_basename = "pcb-out";
+ }
+ gcode_dpi = options[HA_dpi].int_value;
+ if (gcode_dpi < 0) {
+ fprintf(stderr, "ERROR: dpi may not be < 0\n");
+ return;
+ }
+ unit = &(get_unit_list()[options[HA_unit].int_value]);
+ metric = (unit->family == METRIC);
+ scale = metric ? 1.0 / coord_to_unit(unit, MM_TO_COORD(1.0))
+ : 1.0 / coord_to_unit(unit, INCH_TO_COORD(1.0));
+
+ gcode_cutdepth = options[HA_cutdepth].real_value * scale;
+ gcode_drilldepth = options[HA_drilldepth].real_value * scale;
+ gcode_safeZ = options[HA_safeZ].real_value * scale;
+ gcode_toolradius = metric ? MM_TO_COORD(options[HA_toolradius].real_value * scale)
+ : INCH_TO_COORD(options[HA_toolradius].real_value * scale);
+ gcode_choose_groups();
+
+ for (i = 0; i < MAX_LAYER; i++) {
+ if (gcode_export_group[i]) {
+
+ gcode_cur_group = i;
+
+ /* magic */
+ idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
+ printf("idx=%d %s\n", idx, layer_type_to_file_name(idx, FNS_fixed));
+ is_solder = (GetLayerGroupNumberByNumber(idx) == GetLayerGroupNumberByNumber(solder_silk_layer)) ? 1 : 0;
+ save_drill = is_solder; /* save drills for one layer only */
+ gcode_start_png(gcode_basename, layer_type_to_file_name(idx, FNS_fixed));
+ hid_save_and_show_layer_ons(save_ons);
+ gcode_start_png_export();
+ hid_restore_layer_ons(save_ons);
+
+/* ***************** gcode conversion *************************** */
+/* potrace uses a different kind of bitmap; for simplicity gcode_im is copied to this format */
+ bm = bm_new(gdImageSX(gcode_im), gdImageSY(gcode_im));
+ filename = (char *) malloc(MAXPATHLEN);
+ plist = NULL;
+ if (is_solder) { /* only for back layer */
+ gdImagePtr temp_im = gdImageCreate(gdImageSX(gcode_im), gdImageSY(gcode_im));
+ gdImageCopy(temp_im, gcode_im, 0, 0, 0, 0, gdImageSX(gcode_im), gdImageSY(gcode_im));
+ for (r = 0; r < gdImageSX(gcode_im); r++) {
+ for (c = 0; c < gdImageSY(gcode_im); c++) {
+ gdImageSetPixel(gcode_im, r, c, gdImageGetPixel(temp_im, gdImageSX(gcode_im) - 1 - r, c));
+ }
+ }
+ gdImageDestroy(temp_im);
+ }
+ sprintf(filename, "%s.%s.cnc", gcode_basename, layer_type_to_file_name(idx, FNS_fixed));
+ for (r = 0; r < gdImageSX(gcode_im); r++) {
+ for (c = 0; c < gdImageSY(gcode_im); c++) {
+ v = gdImageGetPixel(gcode_im, r, gdImageSY(gcode_im) - 1 - c);
+ p = (gcode_im->red[v] || gcode_im->green[v]
+ || gcode_im->blue[v]) ? 0 : 0xFFFFFF;
+ BM_PUT(bm, r, c, p);
+ }
+ }
+ gcode_f2 = fopen(filename, "wb");
+ if (!gcode_f2) {
+ perror(filename);
+ return;
+ }
+ fprintf(gcode_f2, "(Created by G-code exporter)\n");
+ t = time(NULL);
+ sprintf(filename, "%s", ctime(&t));
+ filename[strlen(filename) - 1] = 0;
+ fprintf(gcode_f2, "( %s )\n", filename);
+ fprintf(gcode_f2, "(%d dpi)\n", gcode_dpi);
+ fprintf(gcode_f2, "(Unit: %s)\n", metric ? "mm" : "inch");
+ if (metric)
+ pcb_fprintf(gcode_f2, "(Board size: %.2mmx%.2mm mm)", PCB->MaxWidth, PCB->MaxHeight);
+ else
+ pcb_fprintf(gcode_f2, "(Board size: %.2mix%.2mi inches)", PCB->MaxWidth, PCB->MaxHeight);
+ fprintf(gcode_f2, "#100=%f (safe Z)\n", gcode_safeZ);
+ fprintf(gcode_f2, "#101=%f (cutting depth)\n", gcode_cutdepth);
+ fprintf(gcode_f2, "(---------------------------------)\n");
+ fprintf(gcode_f2, "G17 G%d G90 G64 P0.003 M3 S3000 M7 F%d\n", metric ? 21 : 20, metric ? 25 : 1);
+ fprintf(gcode_f2, "G0 Z#100\n");
+ /* extract contour points from image */
+ r = bm_to_pathlist(bm, &plist, ¶m_default);
+ if (r) {
+ fprintf(stderr, "ERROR: pathlist function failed\n");
+ return;
+ }
+ /* generate best polygon and write vertices in g-code format */
+ d = process_path(plist, ¶m_default, bm, gcode_f2, metric ? 25.4 / gcode_dpi : 1.0 / gcode_dpi);
+ if (d < 0) {
+ fprintf(stderr, "ERROR: path process function failed\n");
+ return;
+ }
+ if (metric)
+ fprintf(gcode_f2, "(end, total distance %.2fmm = %.2fin)\n", d, d * 1 / 25.4);
+ else
+ fprintf(gcode_f2, "(end, total distance %.2fmm = %.2fin)\n", 25.4 * d, d);
+ fprintf(gcode_f2, "M5 M9 M2\n");
+ pathlist_free(plist);
+ bm_free(bm);
+ fclose(gcode_f2);
+ if (save_drill) {
+ d = 0;
+ drill = sort_drill(drill, n_drill);
+ sprintf(filename, "%s.drill.cnc", gcode_basename);
+ gcode_f2 = fopen(filename, "wb");
+ if (!gcode_f2) {
+ perror(filename);
+ return;
+ }
+ fprintf(gcode_f2, "(Created by G-code exporter)\n");
+ fprintf(gcode_f2, "(drill file: %d drills)\n", n_drill);
+ sprintf(filename, "%s", ctime(&t));
+ filename[strlen(filename) - 1] = 0;
+ fprintf(gcode_f2, "( %s )\n", filename);
+ fprintf(gcode_f2, "(Unit: %s)\n", metric ? "mm" : "inch");
+ if (metric)
+ pcb_fprintf(gcode_f2, "(Board size: %.2mmx%.2mm mm)", PCB->MaxWidth, PCB->MaxHeight);
+ else
+ pcb_fprintf(gcode_f2, "(Board size: %.2mix%.2mi inches)", PCB->MaxWidth, PCB->MaxHeight);
+ fprintf(gcode_f2, "#100=%f (safe Z)\n", gcode_safeZ);
+ fprintf(gcode_f2, "#101=%f (drill depth)\n", gcode_drilldepth);
+ fprintf(gcode_f2, "(---------------------------------)\n");
+ fprintf(gcode_f2, "G17 G%d G90 G64 P0.003 M3 S3000 M7 F%d\n", metric ? 21 : 20, metric ? 25 : 1);
+/* fprintf(gcode_f2,"G0 Z#100\n"); */
+ for (r = 0; r < n_drill; r++) {
+/* if(metric) fprintf(gcode_f2,"G0 X%f Y%f\n",drill[r].x*25.4,drill[r].y*25.4); */
+/* else fprintf(gcode_f2,"G0 X%f Y%f\n",drill[r].x,drill[r].y); */
+ if (metric)
+ fprintf(gcode_f2, "G81 X%f Y%f Z#101 R#100\n", drill[r].x * 25.4, drill[r].y * 25.4);
+ else
+ fprintf(gcode_f2, "G81 X%f Y%f Z#101 R#100\n", drill[r].x, drill[r].y);
+/* fprintf(gcode_f2,"G1 Z#101\n"); */
+/* fprintf(gcode_f2,"G0 Z#100\n"); */
+ if (r > 0)
+ d +=
+ sqrt((drill[r].x - drill[r - 1].x) * (drill[r].x -
+ drill[r - 1].x) +
+ (drill[r].y - drill[r - 1].y) * (drill[r].y - drill[r - 1].y));
+ }
+ fprintf(gcode_f2, "M5 M9 M2\n");
+ fprintf(gcode_f2, "(end, total distance %.2fmm = %.2fin)\n", 25.4 * d, d);
+ fclose(gcode_f2);
+ free(drill);
+ drill = NULL;
+ n_drill = nmax_drill = 0;
+ }
+ free(filename);
+
+/* ******************* end gcode conversion **************************** */
+ gcode_finish_png();
+ }
+ }
+}
+
+/* *** PNG export (slightly modified code from PNG export HID) ************* */
+
+static int gcode_set_layer(const char *name, int group, int empty)
+{
+ int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group;
+
+ if (name == 0) {
+ name = PCB->Data->Layer[idx].Name;
+ }
+ if (strcmp(name, "invisible") == 0) {
+ return 0;
+ }
+ is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL);
+ is_mask = (SL_TYPE(idx) == SL_MASK);
+
+ if (is_mask) {
+ /* Don't print masks */
+ return 0;
+ }
+ if (is_drill) {
+ /*
+ * Print 'holes', so that we can fill gaps in the copper
+ * layer
+ */
+ return 1;
+ }
+ if (group == gcode_cur_group) {
+ return 1;
+ }
+ return 0;
+}
+
+static hidGC gcode_make_gc(void)
+{
+ hidGC rv = (hidGC) malloc(sizeof(struct hid_gc_struct));
+ rv->me_pointer = &gcode_hid;
+ rv->cap = Trace_Cap;
+ rv->width = 1;
+ rv->color = (struct color_struct *) malloc(sizeof(*rv->color));
+ rv->color->r = rv->color->g = rv->color->b = 0;
+ rv->color->c = 0;
+ return rv;
+}
+
+static void gcode_destroy_gc(hidGC gc)
+{
+ free(gc);
+}
+
+static void gcode_use_mask(int use_it)
+{
+ /* does nothing */
+}
+
+static void gcode_set_color(hidGC gc, const char *name)
+{
+ if (gcode_im == NULL) {
+ return;
+ }
+ if (name == NULL) {
+ name = "#ff0000";
+ }
+ if (!strcmp(name, "drill")) {
+ gc->color = black;
+ gc->erase = 0;
+ return;
+ }
+ if (!strcmp(name, "erase")) {
+ /* FIXME -- should be background, not white */
+ gc->color = white;
+ gc->erase = 1;
+ return;
+ }
+ gc->color = black;
+ gc->erase = 0;
+ return;
+}
+
+static void gcode_set_line_cap(hidGC gc, EndCapStyle style)
+{
+ gc->cap = style;
+}
+
+static void gcode_set_line_width(hidGC gc, Coord width)
+{
+ gc->width = width;
+}
+
+static void gcode_set_draw_xor(hidGC gc, int xor_)
+{
+ ;
+}
+
+static void gcode_set_draw_faded(hidGC gc, int faded)
+{
+ gc->faded = faded;
+}
+
+static void use_gc(hidGC gc)
+{
+ int need_brush = 0;
+
+ if (gc->me_pointer != &gcode_hid) {
+ fprintf(stderr, "Fatal: GC from another HID passed to gcode HID\n");
+ abort();
+ }
+ if (linewidth != gc->width) {
+ /* Make sure the scaling doesn't erase lines completely */
+ /*
+ if (SCALE (gc->width) == 0 && gc->width > 0)
+ gdImageSetThickness (im, 1);
+ else
+ */
+ gdImageSetThickness(gcode_im, pcb_to_gcode(gc->width + 2 * gcode_toolradius));
+ linewidth = gc->width;
+ need_brush = 1;
+ }
+ if (lastbrush != gc->brush || need_brush) {
+ static void *bcache = 0;
+ hidval bval;
+ char name[256];
+ char type;
+ int r;
+
+ switch (gc->cap) {
+ case Round_Cap:
+ case Trace_Cap:
+ type = 'C';
+ r = pcb_to_gcode(gc->width / 2 + gcode_toolradius);
+ break;
+ default:
+ case Square_Cap:
+ r = pcb_to_gcode(gc->width + gcode_toolradius * 2);
+ type = 'S';
+ break;
+ }
+ sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r);
+
+ if (hid_cache_color(0, name, &bval, &bcache)) {
+ gc->brush = (gdImagePtr) bval.ptr;
+ }
+ else {
+ int bg, fg;
+ if (type == 'C')
+ gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1);
+ else
+ gc->brush = gdImageCreate(r + 1, r + 1);
+ bg = gdImageColorAllocate(gc->brush, 255, 255, 255);
+ fg = gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g, gc->color->b);
+ gdImageColorTransparent(gc->brush, bg);
+
+ /*
+ * if we shrunk to a radius/box width of zero, then just use
+ * a single pixel to draw with.
+ */
+ if (r == 0)
+ gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg);
+ else {
+ if (type == 'C')
+ gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg);
+ else
+ gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg);
+ }
+ bval.ptr = gc->brush;
+ hid_cache_color(1, name, &bval, &bcache);
+ }
+
+ gdImageSetBrush(gcode_im, gc->brush);
+ lastbrush = gc->brush;
+
+ }
+#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
+ if (lastcolor != CBLEND(gc)) {
+ if (is_drill || is_mask) {
+#ifdef FIXME
+ fprintf(f, "%d gray\n", gc->erase ? 0 : 1);
+#endif
+ lastcolor = 0;
+ }
+ else {
+ double r, g, b;
+ r = gc->r;
+ g = gc->g;
+ b = gc->b;
+ if (gc->faded) {
+ r = 0.8 * 255 + 0.2 * r;
+ g = 0.8 * 255 + 0.2 * g;
+ b = 0.8 * 255 + 0.2 * b;
+ }
+#ifdef FIXME
+ if (gc->r == gc->g && gc->g == gc->b)
+ fprintf(f, "%g gray\n", r / 255.0);
+ else
+ fprintf(f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0);
+#endif
+ lastcolor = CBLEND(gc);
+ }
+ }
+}
+
+static void gcode_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
+{
+ use_gc(gc);
+ gdImageRectangle(gcode_im,
+ pcb_to_gcode(x1 - gcode_toolradius),
+ pcb_to_gcode(y1 - gcode_toolradius),
+ pcb_to_gcode(x2 + gcode_toolradius), pcb_to_gcode(y2 + gcode_toolradius), gc->color->c);
+/* printf("Rect %d %d %d %d\n",x1,y1,x2,y2); */
+}
+
+static void gcode_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
+{
+ use_gc(gc);
+ gdImageSetThickness(gcode_im, 0);
+ linewidth = 0;
+ gdImageFilledRectangle(gcode_im,
+ pcb_to_gcode(x1 - gcode_toolradius),
+ pcb_to_gcode(y1 - gcode_toolradius),
+ pcb_to_gcode(x2 + gcode_toolradius), pcb_to_gcode(y2 + gcode_toolradius), gc->color->c);
+/* printf("FillRect %d %d %d %d\n",x1,y1,x2,y2); */
+}
+
+static void gcode_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
+{
+ if (x1 == x2 && y1 == y2) {
+ Coord w = gc->width / 2;
+ gcode_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w);
+ return;
+ }
+ use_gc(gc);
+
+ gdImageSetThickness(gcode_im, 0);
+ linewidth = 0;
+ gdImageLine(gcode_im, pcb_to_gcode(x1), pcb_to_gcode(y1), pcb_to_gcode(x2), pcb_to_gcode(y2), gdBrushed);
+}
+
+static void gcode_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle)
+{
+ Angle sa, ea;
+
+ /*
+ * in gdImageArc, 0 degrees is to the right and +90 degrees is down
+ * in pcb, 0 degrees is to the left and +90 degrees is down
+ */
+ start_angle = 180 - start_angle;
+ delta_angle = -delta_angle;
+ if (delta_angle > 0) {
+ sa = start_angle;
+ ea = start_angle + delta_angle;
+ }
+ else {
+ sa = start_angle + delta_angle;
+ ea = start_angle;
+ }
+
+ /*
+ * make sure we start between 0 and 360 otherwise gd does strange
+ * things
+ */
+ sa = NormalizeAngle(sa);
+ ea = NormalizeAngle(ea);
+
+#if 0
+ printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea);
+ printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
+ im, SCALE_X(cx), SCALE_Y(cy), SCALE(width), SCALE(height), sa, ea, gc->color->c);
+#endif
+ use_gc(gc);
+ gdImageSetThickness(gcode_im, 0);
+ linewidth = 0;
+ gdImageArc(gcode_im, pcb_to_gcode(cx), pcb_to_gcode(cy),
+ pcb_to_gcode(2 * width + gcode_toolradius * 2),
+ pcb_to_gcode(2 * height + gcode_toolradius * 2), sa, ea, gdBrushed);
+}
+
+static void gcode_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius)
+{
+ use_gc(gc);
+
+ gdImageSetThickness(gcode_im, 0);
+ linewidth = 0;
+ gdImageFilledEllipse(gcode_im, pcb_to_gcode(cx), pcb_to_gcode(cy),
+ pcb_to_gcode(2 * radius + gcode_toolradius * 2),
+ pcb_to_gcode(2 * radius + gcode_toolradius * 2), gc->color->c);
+ if (save_drill && is_drill) {
+ if (n_drill == nmax_drill) {
+ drill = (struct drill_struct *) realloc(drill, (nmax_drill + 100) * sizeof(struct drill_struct));
+ nmax_drill += 100;
+ }
+ drill[n_drill].x = COORD_TO_INCH(PCB->MaxWidth - cx); /* convert to inch, flip: will drill from bottom side */
+ drill[n_drill].y = COORD_TO_INCH(PCB->MaxHeight - cy); /* PCB reverses y axis */
+ n_drill++;
+/* printf("Circle %d %d\n",cx,cy); */
+ }
+}
+
+static void gcode_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y)
+{
+ int i;
+ gdPoint *points;
+
+ points = (gdPoint *) malloc(n_coords * sizeof(gdPoint));
+ if (points == NULL) {
+ fprintf(stderr, "ERROR: gcode_fill_polygon(): malloc failed\n");
+ exit(1);
+ }
+ use_gc(gc);
+ for (i = 0; i < n_coords; i++) {
+ points[i].x = pcb_to_gcode(x[i]);
+ points[i].y = pcb_to_gcode(y[i]);
+ }
+ gdImageSetThickness(gcode_im, 0);
+ linewidth = 0;
+ gdImageFilledPolygon(gcode_im, points, n_coords, gc->color->c);
+ free(points);
+/* printf("FillPoly\n"); */
+}
+
+static void gcode_calibrate(double xval, double yval)
+{
+ CRASH;
+}
+
+static void gcode_set_crosshair(int x, int y, int a)
+{
+}
+
+/* *** Miscellaneous ******************************************************* */
+
+#include "dolists.h"
+
+HID gcode_hid;
+
+pcb_uninit_t hid_export_gcode_init()
+{
+ memset(&gcode_hid, 0, sizeof(HID));
+
+ common_nogui_init(&gcode_hid);
+ common_draw_helpers_init(&gcode_hid);
+
+ gcode_hid.struct_size = sizeof(HID);
+ gcode_hid.name = "gcode";
+ gcode_hid.description = "G-CODE export";
+ gcode_hid.exporter = 1;
+ gcode_hid.poly_before = 1;
+
+ gcode_hid.get_export_options = gcode_get_export_options;
+ gcode_hid.do_export = gcode_do_export;
+ gcode_hid.parse_arguments = gcode_parse_arguments;
+ gcode_hid.set_layer = gcode_set_layer;
+ gcode_hid.make_gc = gcode_make_gc;
+ gcode_hid.destroy_gc = gcode_destroy_gc;
+ gcode_hid.use_mask = gcode_use_mask;
+ gcode_hid.set_color = gcode_set_color;
+ gcode_hid.set_line_cap = gcode_set_line_cap;
+ gcode_hid.set_line_width = gcode_set_line_width;
+ gcode_hid.set_draw_xor = gcode_set_draw_xor;
+ gcode_hid.set_draw_faded = gcode_set_draw_faded;
+ gcode_hid.draw_line = gcode_draw_line;
+ gcode_hid.draw_arc = gcode_draw_arc;
+ gcode_hid.draw_rect = gcode_draw_rect;
+ gcode_hid.fill_circle = gcode_fill_circle;
+ gcode_hid.fill_polygon = gcode_fill_polygon;
+ gcode_hid.fill_rect = gcode_fill_rect;
+ gcode_hid.calibrate = gcode_calibrate;
+ gcode_hid.set_crosshair = gcode_set_crosshair;
+
+ hid_register_hid(&gcode_hid);
+
+ return NULL;
+}
Index: trunk/src_plugins/export_gcode/gcode.h
===================================================================
--- trunk/src_plugins/export_gcode/gcode.h (nonexistent)
+++ trunk/src_plugins/export_gcode/gcode.h (revision 1269)
@@ -0,0 +1,3 @@
+/* $Id: nelma.h,v 1.2 2007/04/20 11:31:15 danmc Exp $ */
+extern const char *gcode_cookie;
+extern HID gcode_hid;
Index: trunk/src_plugins/export_gcode/lists.h
===================================================================
--- trunk/src_plugins/export_gcode/lists.h (nonexistent)
+++ trunk/src_plugins/export_gcode/lists.h (revision 1269)
@@ -0,0 +1,285 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+/* $Id: lists.h 147 2007-04-09 00:44:09Z selinger $ */
+
+#ifndef PCB_HID_GCODE_LISTS_H
+#define PCB_HID_GCODE_LISTS_H
+
+/* here we define some general list macros. Because they are macros,
+ they should work on any datatype with a "->next" component. Some of
+ them use a "hook". If elt and list are of type t* then hook is of
+ type t**. A hook stands for an insertion point in the list, i.e.,
+ either before the first element, or between two elements, or after
+ the last element. If an operation "sets the hook" for an element,
+ then the hook is set to just before the element. One can insert
+ something at a hook. One can also unlink at a hook: this means,
+ unlink the element just after the hook. By "to unlink", we mean the
+ element is removed from the list, but not deleted. Thus, it and its
+ components still need to be freed. */
+
+/* Note: these macros are somewhat experimental. Only the ones that
+ are actually *used* have been tested. So be careful to test any
+ that you use. Looking at the output of the preprocessor, "gcc -E"
+ (possibly piped though "indent"), might help too. Also: these
+ macros define some internal (local) variables that start with
+ "_". */
+
+/* we enclose macro definitions whose body consists of more than one
+ statement in MACRO_BEGIN and MACRO_END, rather than '{' and '}'. The
+ reason is that we want to be able to use the macro in a context
+ such as "if (...) macro(...); else ...". If we didn't use this obscure
+ trick, we'd have to omit the ";" in such cases. */
+
+#define MACRO_BEGIN do {
+#define MACRO_END } while (0)
+
+/* ---------------------------------------------------------------------- */
+/* macros for singly-linked lists */
+
+/* traverse list. At the end, elt is set to NULL. */
+#define list_forall(elt, list) for (elt=list; elt!=NULL; elt=elt->next)
+
+/* set elt to the first element of list satisfying boolean condition
+ c, or NULL if not found */
+#define list_find(elt, list, c) \
+ MACRO_BEGIN list_forall(elt, list) if (c) break; MACRO_END
+
+/* like forall, except also set hook for elt. */
+#define list_forall2(elt, list, hook) \
+ for (elt=list, hook=&list; elt!=NULL; hook=&elt->next, elt=elt->next)
+
+/* same as list_find, except also set hook for elt. */
+#define list_find2(elt, list, c, hook) \
+ MACRO_BEGIN list_forall2(elt, list, hook) if (c) break; MACRO_END
+
+/* same, except only use hook. */
+#define _list_forall_hook(list, hook) \
+ for (hook=&list; *hook!=NULL; hook=&(*hook)->next)
+
+/* same, except only use hook. Note: c may only refer to *hook, not elt. */
+#define _list_find_hook(list, c, hook) \
+ MACRO_BEGIN _list_forall_hook(list, hook) if (c) break; MACRO_END
+
+/* insert element after hook */
+#define list_insert_athook(elt, hook) \
+ MACRO_BEGIN elt->next = *hook; *hook = elt; MACRO_END
+
+/* insert element before hook */
+#define list_insert_beforehook(elt, hook) \
+ MACRO_BEGIN elt->next = *hook; *hook = elt; hook=&elt->next; MACRO_END
+
+/* unlink element after hook, let elt be unlinked element, or NULL.
+ hook remains. */
+#define list_unlink_athook(list, elt, hook) \
+ MACRO_BEGIN \
+ elt = hook ? *hook : NULL; if (elt) { *hook = elt->next; elt->next = NULL; }\
+ MACRO_END
+
+/* unlink the specific element, if it is in the list. Otherwise, set
+ elt to NULL */
+#define list_unlink(listtype, list, elt) \
+ MACRO_BEGIN \
+ listtype **_hook; \
+ _list_find_hook(list, *_hook==elt, _hook); \
+ list_unlink_athook(list, elt, _hook); \
+ MACRO_END
+
+/* prepend elt to list */
+#define list_prepend(list, elt) \
+ MACRO_BEGIN elt->next = list; list = elt; MACRO_END
+
+/* append elt to list. */
+#define list_append(listtype, list, elt) \
+ MACRO_BEGIN \
+ listtype **_hook; \
+ _list_forall_hook(list, _hook) {} \
+ list_insert_athook(elt, _hook); \
+ MACRO_END
+
+/* unlink the first element that satisfies the condition. */
+#define list_unlink_cond(listtype, list, elt, c) \
+ MACRO_BEGIN \
+ listtype **_hook; \
+ list_find2(elt, list, c, _hook); \
+ list_unlink_athook(list, elt, _hook); \
+ MACRO_END
+
+/* let elt be the nth element of the list, starting to count from 0.
+ Return NULL if out of bounds. */
+#define list_nth(elt, list, n) \
+ MACRO_BEGIN \
+ int _x; /* only evaluate n once */ \
+ for (_x=(n), elt=list; _x && elt; _x--, elt=elt->next) {} \
+ MACRO_END
+
+/* let elt be the nth element of the list, starting to count from 0.
+ Return NULL if out of bounds. */
+#define list_nth_hook(elt, list, n, hook) \
+ MACRO_BEGIN \
+ int _x; /* only evaluate n once */ \
+ for (_x=(n), elt=list, hook=&list; _x && elt; _x--, hook=&elt->next, elt=elt->next) {} \
+ MACRO_END
+
+/* set n to the length of the list */
+#define list_length(listtype, list, n) \
+ MACRO_BEGIN \
+ listtype *_elt; \
+ n=0; \
+ list_forall(_elt, list) \
+ n++; \
+ MACRO_END
+
+/* set n to the index of the first element satisfying cond, or -1 if
+ none found. Also set elt to the element, or NULL if none found. */
+#define list_index(list, n, elt, c) \
+ MACRO_BEGIN \
+ n=0; \
+ list_forall(elt, list) { \
+ if (c) break; \
+ n++; \
+ } \
+ if (!elt) \
+ n=-1; \
+ MACRO_END
+
+/* set n to the number of elements in the list that satisfy condition c */
+#define list_count(list, n, elt, c) \
+ MACRO_BEGIN \
+ n=0; \
+ list_forall(elt, list) { \
+ if (c) n++; \
+ } \
+ MACRO_END
+
+/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
+#define list_forall_unlink(elt, list) \
+ for (elt=list; elt ? (list=elt->next, elt->next=NULL), 1 : 0; elt=list)
+
+/* reverse a list (efficient) */
+#define list_reverse(listtype, list) \
+ MACRO_BEGIN \
+ listtype *_list1=NULL, *elt; \
+ list_forall_unlink(elt, list) \
+ list_prepend(_list1, elt); \
+ list = _list1; \
+ MACRO_END
+
+/* insert the element ELT just before the first element TMP of the
+ list for which COND holds. Here COND must be a condition of ELT and
+ TMP. Typical usage is to insert an element into an ordered list:
+ for instance, list_insert_ordered(listtype, list, elt, tmp,
+ elt->size <= tmp->size). Note: if we give a "less than or equal"
+ condition, the new element will be inserted just before a sequence
+ of equal elements. If we give a "less than" condition, the new
+ element will be inserted just after a list of equal elements.
+ Note: it is much more efficient to construct a list with
+ list_prepend and then order it with list_merge_sort, than to
+ construct it with list_insert_ordered. */
+#define list_insert_ordered(listtype, list, elt, tmp, cond) \
+ MACRO_BEGIN \
+ listtype **_hook; \
+ _list_find_hook(list, (tmp=*_hook, (cond)), _hook); \
+ list_insert_athook(elt, _hook); \
+ MACRO_END
+
+/* sort the given list, according to the comparison condition.
+ Typical usage is list_sort(listtype, list, a, b, a->size <
+ b->size). Note: if we give "less than or equal" condition, each
+ segment of equal elements will be reversed in order. If we give a
+ "less than" condition, each segment of equal elements will retain
+ the original order. The latter is slower but sometimes
+ prettier. Average running time: n*n/2. */
+#define list_sort(listtype, list, a, b, cond) \
+ MACRO_BEGIN \
+ listtype *_newlist=NULL; \
+ list_forall_unlink(a, list) \
+ list_insert_ordered(listtype, _newlist, a, b, cond); \
+ list = _newlist; \
+ MACRO_END
+
+/* a much faster sort algorithm (merge sort, n log n worst case). It
+ is required that the list type has an additional, unused next1
+ component. Note there is no curious reversal of order of equal
+ elements as for list_sort. */
+
+#define list_mergesort(listtype, list, a, b, cond) \
+ MACRO_BEGIN \
+ listtype *_elt, **_hook1; \
+ \
+ for (_elt=list; _elt; _elt=_elt->next1) { \
+ _elt->next1 = _elt->next; \
+ _elt->next = NULL; \
+ } \
+ do { \
+ _hook1 = &(list); \
+ while ((a = *_hook1) != NULL && (b = a->next1) != NULL ) { \
+ _elt = b->next1; \
+ _list_merge_cond(listtype, a, b, cond, *_hook1); \
+ _hook1 = &((*_hook1)->next1); \
+ *_hook1 = _elt; \
+ } \
+ } while (_hook1 != &(list)); \
+ MACRO_END
+
+/* merge two sorted lists. Store result at &result */
+#define _list_merge_cond(listtype, a, b, cond, result) \
+ MACRO_BEGIN \
+ listtype **_hook; \
+ _hook = &(result); \
+ while (1) { \
+ if (a==NULL) { \
+ *_hook = b; \
+ break; \
+ } else if (b==NULL) { \
+ *_hook = a; \
+ break; \
+ } else if (cond) { \
+ *_hook = a; \
+ _hook = &(a->next); \
+ a = a->next; \
+ } else { \
+ *_hook = b; \
+ _hook = &(b->next); \
+ b = b->next; \
+ } \
+ } \
+ MACRO_END
+
+/* ---------------------------------------------------------------------- */
+/* macros for doubly-linked lists */
+
+#define dlist_append(head, end, elt) \
+ MACRO_BEGIN \
+ elt->prev = end; \
+ elt->next = NULL; \
+ if (end) { \
+ end->next = elt; \
+ } else { \
+ head = elt; \
+ } \
+ end = elt; \
+ MACRO_END
+
+/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
+#define dlist_forall_unlink(elt, head, end) \
+ for (elt=head; elt ? (head=elt->next, elt->next=NULL, elt->prev=NULL), 1 : (end=NULL, 0); elt=head)
+
+/* unlink the first element of the list */
+#define dlist_unlink_first(head, end, elt) \
+ MACRO_BEGIN \
+ elt = head; \
+ if (head) { \
+ head = head->next; \
+ if (head) { \
+ head->prev = NULL; \
+ } else { \
+ end = NULL; \
+ } \
+ elt->prev = NULL; \
+ elt->next = NULL; \
+ } \
+ MACRO_END
+
+#endif /* PCB_HID_GCODE_LISTS_H */
Index: trunk/src_plugins/export_gcode/potracelib.h
===================================================================
--- trunk/src_plugins/export_gcode/potracelib.h (nonexistent)
+++ trunk/src_plugins/export_gcode/potracelib.h (revision 1269)
@@ -0,0 +1,130 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+#ifndef POTRACELIB_H
+#define POTRACELIB_H
+
+/* this file defines the API for the core Potrace library. For a more
+ detailed description of the API, see doc/potracelib.txt */
+
+/* ---------------------------------------------------------------------- */
+/* tracing parameters */
+
+/* turn policies */
+#define POTRACE_TURNPOLICY_BLACK 0
+#define POTRACE_TURNPOLICY_WHITE 1
+#define POTRACE_TURNPOLICY_LEFT 2
+#define POTRACE_TURNPOLICY_RIGHT 3
+#define POTRACE_TURNPOLICY_MINORITY 4
+#define POTRACE_TURNPOLICY_MAJORITY 5
+#define POTRACE_TURNPOLICY_RANDOM 6
+
+/* structure to hold progress bar callback data */
+struct potrace_progress_s {
+ void (*callback) (double progress, void *privdata); /* callback fn */
+ void *data; /* callback function's private data */
+ double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */
+ double epsilon; /* granularity: can skip smaller increments */
+};
+typedef struct potrace_progress_s potrace_progress_t;
+
+/* structure to hold tracing parameters */
+struct potrace_param_s {
+ int turdsize; /* area of largest path to be ignored */
+ int turnpolicy; /* resolves ambiguous turns in path decomposition */
+ double alphamax; /* corner threshold */
+ int opticurve; /* use curve optimization? */
+ double opttolerance; /* curve optimization tolerance */
+ potrace_progress_t progress; /* progress callback function */
+};
+typedef struct potrace_param_s potrace_param_t;
+
+/* ---------------------------------------------------------------------- */
+/* bitmaps */
+
+/* native word size */
+typedef unsigned long potrace_word;
+
+/* Internal bitmap format. The n-th scanline starts at scanline(n) =
+ (map + n*dy). Raster data is stored as a sequence of potrace_words
+ (NOT bytes). The leftmost bit of scanline n is the most significant
+ bit of scanline(n)[0]. */
+struct potrace_bitmap_s {
+ int w, h; /* width and height, in pixels */
+ int dy; /* words per scanline (not bytes) */
+ potrace_word *map; /* raw data, dy*h words */
+};
+typedef struct potrace_bitmap_s potrace_bitmap_t;
+
+/* ---------------------------------------------------------------------- */
+/* curves */
+
+/* point */
+struct potrace_dpoint_s {
+ double x, y;
+};
+typedef struct potrace_dpoint_s potrace_dpoint_t;
+
+/* segment tags */
+#define POTRACE_CURVETO 1
+#define POTRACE_CORNER 2
+
+/* closed curve segment */
+struct potrace_curve_s {
+ int n; /* number of segments */
+ int *tag; /* tag[n]: POTRACE_CURVETO or POTRACE_CORNER */
+ potrace_dpoint_t(*c)[3]; /* c[n][3]: control points.
+ c[n][0] is unused for tag[n]=POTRACE_CORNER */
+};
+typedef struct potrace_curve_s potrace_curve_t;
+
+/* Linked list of signed curve segments. Also carries a tree structure. */
+struct potrace_path_s {
+ int area; /* area of the bitmap path */
+ int sign; /* '+' or '-', depending on orientation */
+ potrace_curve_t curve; /* this path's vector data */
+
+ struct potrace_path_s *next; /* linked list structure */
+
+ struct potrace_path_s *childlist; /* tree structure */
+ struct potrace_path_s *sibling; /* tree structure */
+
+ struct potrace_privpath_s *priv; /* private state */
+};
+typedef struct potrace_path_s potrace_path_t;
+
+/* ---------------------------------------------------------------------- */
+/* Potrace state */
+
+#define POTRACE_STATUS_OK 0
+#define POTRACE_STATUS_INCOMPLETE 1
+
+struct potrace_state_s {
+ int status;
+ potrace_path_t *plist; /* vector data */
+
+ struct potrace_privstate_s *priv; /* private state */
+};
+typedef struct potrace_state_s potrace_state_t;
+
+/* ---------------------------------------------------------------------- */
+/* API functions */
+
+/* get default parameters */
+potrace_param_t *potrace_param_default(void);
+
+/* free parameter set */
+void potrace_param_free(potrace_param_t * p);
+
+/* trace a bitmap*/
+potrace_state_t *potrace_trace(const potrace_param_t * param, const potrace_bitmap_t * bm);
+
+/* free a Potrace state */
+void potrace_state_free(potrace_state_t * st);
+
+/* return a static plain text version string identifying this version
+ of potracelib */
+char *potrace_version(void);
+
+#endif /* POTRACELIB_H */
Index: trunk/src_plugins/export_gcode/trace.c
===================================================================
--- trunk/src_plugins/export_gcode/trace.c (nonexistent)
+++ trunk/src_plugins/export_gcode/trace.c (revision 1269)
@@ -0,0 +1,1292 @@
+/* This file was slightly modified by Alberto Maccioni to be used with PCB G-CODE exporter*/
+
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+/* $Id: trace.c 147 2007-04-09 00:44:09Z selinger $ */
+/* transform jaggy paths into smooth curves */
+
+#include
+#include
+#include
+#include
+
+#include "global.h"
+#include "potracelib.h"
+#include "curve.h"
+#include "lists.h"
+#include "auxiliary.h"
+#include "trace.h"
+/*#include "progress.h"*/
+
+#define INFTY 10000000 /* it suffices that this is longer than any
+ path; it need not be really infinite */
+#define COS179 -0.999847695156 /* the cosine of 179 degrees */
+
+/* ---------------------------------------------------------------------- */
+#define SAFE_MALLOC(var, n, typ) \
+ if ((var = (typ *)malloc((n)*sizeof(typ))) == NULL) goto malloc_error
+
+/* ---------------------------------------------------------------------- */
+/* auxiliary functions */
+
+/* return a direction that is 90 degrees counterclockwise from p2-p0,
+ but then restricted to one of the major wind directions (n, nw, w, etc) */
+static inline point_t dorth_infty(dpoint_t p0, dpoint_t p2)
+{
+ point_t r;
+
+ r.y = sign(p2.x - p0.x);
+ r.x = -sign(p2.y - p0.y);
+
+ return r;
+}
+
+/* return (p1-p0)x(p2-p0), the area of the parallelogram */
+static inline double dpara(dpoint_t p0, dpoint_t p1, dpoint_t p2)
+{
+ double x1, y1, x2, y2;
+
+ x1 = p1.x - p0.x;
+ y1 = p1.y - p0.y;
+ x2 = p2.x - p0.x;
+ y2 = p2.y - p0.y;
+
+ return x1 * y2 - x2 * y1;
+}
+
+/* ddenom/dpara have the property that the square of radius 1 centered
+ at p1 intersects the line p0p2 iff |dpara(p0,p1,p2)| <= ddenom(p0,p2) */
+static inline double ddenom(dpoint_t p0, dpoint_t p2)
+{
+ point_t r = dorth_infty(p0, p2);
+
+ return r.y * (p2.x - p0.x) - r.x * (p2.y - p0.y);
+}
+
+/* return 1 if a <= b < c < a, in a cyclic sense (mod n) */
+static inline int cyclic(int a, int b, int c)
+{
+ if (a <= c) {
+ return (a <= b && b < c);
+ }
+ else {
+ return (a <= b || b < c);
+ }
+}
+
+/* determine the center and slope of the line i..j. Assume ilen;
+ sums_t *sums = pp->sums;
+
+ double x, y, x2, xy, y2;
+ double k;
+ double a, b, c, lambda2, l;
+ int r = 0; /* rotations from i to j */
+
+ while (j >= n) {
+ j -= n;
+ r += 1;
+ }
+ while (i >= n) {
+ i -= n;
+ r -= 1;
+ }
+ while (j < 0) {
+ j += n;
+ r -= 1;
+ }
+ while (i < 0) {
+ i += n;
+ r += 1;
+ }
+
+ x = sums[j + 1].x - sums[i].x + r * sums[n].x;
+ y = sums[j + 1].y - sums[i].y + r * sums[n].y;
+ x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2;
+ xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy;
+ y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2;
+ k = j + 1 - i + r * n;
+
+ ctr->x = x / k;
+ ctr->y = y / k;
+
+ a = (x2 - (double) x * x / k) / k;
+ b = (xy - (double) x * y / k) / k;
+ c = (y2 - (double) y * y / k) / k;
+
+ lambda2 = (a + c + sqrt((a - c) * (a - c) + 4 * b * b)) / 2; /* larger e.value */
+
+ /* now find e.vector for lambda2 */
+ a -= lambda2;
+ c -= lambda2;
+
+ if (fabs(a) >= fabs(c)) {
+ l = sqrt(a * a + b * b);
+ if (l != 0) {
+ dir->x = -b / l;
+ dir->y = a / l;
+ }
+ }
+ else {
+ l = sqrt(c * c + b * b);
+ if (l != 0) {
+ dir->x = -c / l;
+ dir->y = b / l;
+ }
+ }
+ if (l == 0) {
+ dir->x = dir->y = 0; /* sometimes this can happen when k=4:
+ the two eigenvalues coincide */
+ }
+}
+
+/* the type of (affine) quadratic forms, represented as symmetric 3x3
+ matrices. The value of the quadratic form at a vector (x,y) is v^t
+ Q v, where v = (x,y,1)^t. */
+typedef double quadform_t[3][3];
+
+/* Apply quadratic form Q to vector w = (w.x,w.y) */
+static inline double quadform(quadform_t Q, dpoint_t w)
+{
+ double v[3];
+ int i, j;
+ double sum;
+
+ v[0] = w.x;
+ v[1] = w.y;
+ v[2] = 1;
+ sum = 0.0;
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ sum += v[i] * Q[i][j] * v[j];
+ }
+ }
+ return sum;
+}
+
+/* calculate p1 x p2 */
+static inline int xprod(point_t p1, point_t p2)
+{
+ return p1.x * p2.y - p1.y * p2.x;
+}
+
+/* calculate (p1-p0)x(p3-p2) */
+static inline double cprod(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3)
+{
+ double x1, y1, x2, y2;
+
+ x1 = p1.x - p0.x;
+ y1 = p1.y - p0.y;
+ x2 = p3.x - p2.x;
+ y2 = p3.y - p2.y;
+
+ return x1 * y2 - x2 * y1;
+}
+
+/* calculate (p1-p0)*(p2-p0) */
+static inline double iprod(dpoint_t p0, dpoint_t p1, dpoint_t p2)
+{
+ double x1, y1, x2, y2;
+
+ x1 = p1.x - p0.x;
+ y1 = p1.y - p0.y;
+ x2 = p2.x - p0.x;
+ y2 = p2.y - p0.y;
+
+ return x1 * x2 + y1 * y2;
+}
+
+/* calculate (p1-p0)*(p3-p2) */
+static inline double iprod1(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3)
+{
+ double x1, y1, x2, y2;
+
+ x1 = p1.x - p0.x;
+ y1 = p1.y - p0.y;
+ x2 = p3.x - p2.x;
+ y2 = p3.y - p2.y;
+
+ return x1 * x2 + y1 * y2;
+}
+
+/* calculate distance between two points */
+static inline double ddist(dpoint_t p, dpoint_t q)
+{
+ return sqrt(sq(p.x - q.x) + sq(p.y - q.y));
+}
+
+/* calculate point of a bezier curve */
+static inline dpoint_t bezier(double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3)
+{
+ double s = 1 - t;
+ dpoint_t res;
+
+ /* Note: a good optimizing compiler (such as gcc-3) reduces the
+ following to 16 multiplications, using common subexpression
+ elimination. */
+
+ res.x = s * s * s * p0.x + 3 * (s * s * t) * p1.x + 3 * (t * t * s) * p2.x + t * t * t * p3.x;
+ res.y = s * s * s * p0.y + 3 * (s * s * t) * p1.y + 3 * (t * t * s) * p2.y + t * t * t * p3.y;
+
+ return res;
+}
+
+/* calculate the point t in [0..1] on the (convex) bezier curve
+ (p0,p1,p2,p3) which is tangent to q1-q0. Return -1.0 if there is no
+ solution in [0..1]. */
+static double tangent(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3, dpoint_t q0, dpoint_t q1)
+{
+ double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */
+ double a, b, c; /* a t^2 + b t + c = 0 */
+ double d, s, r1, r2;
+
+ A = cprod(p0, p1, q0, q1);
+ B = cprod(p1, p2, q0, q1);
+ C = cprod(p2, p3, q0, q1);
+
+ a = A - 2 * B + C;
+ b = -2 * A + 2 * B;
+ c = A;
+
+ d = b * b - 4 * a * c;
+
+ if (a == 0 || d < 0) {
+ return -1.0;
+ }
+
+ s = sqrt(d);
+
+ r1 = (-b + s) / (2 * a);
+ r2 = (-b - s) / (2 * a);
+
+ if (r1 >= 0 && r1 <= 1) {
+ return r1;
+ }
+ else if (r2 >= 0 && r2 <= 1) {
+ return r2;
+ }
+ else {
+ return -1.0;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Preparation: fill in the sum* fields of a path (used for later
+ rapid summing). Return 0 on success, 1 with errno set on
+ failure. */
+static int calc_sums(privpath_t * pp)
+{
+ int i, x, y;
+ int n = pp->len;
+
+ SAFE_MALLOC(pp->sums, pp->len + 1, sums_t);
+
+ /* origin */
+ pp->x0 = pp->pt[0].x;
+ pp->y0 = pp->pt[0].y;
+
+ /* preparatory computation for later fast summing */
+ pp->sums[0].x2 = pp->sums[0].xy = pp->sums[0].y2 = pp->sums[0].x = pp->sums[0].y = 0;
+ for (i = 0; i < n; i++) {
+ x = pp->pt[i].x - pp->x0;
+ y = pp->pt[i].y - pp->y0;
+ pp->sums[i + 1].x = pp->sums[i].x + x;
+ pp->sums[i + 1].y = pp->sums[i].y + y;
+ pp->sums[i + 1].x2 = pp->sums[i].x2 + x * x;
+ pp->sums[i + 1].xy = pp->sums[i].xy + x * y;
+ pp->sums[i + 1].y2 = pp->sums[i].y2 + y * y;
+ }
+ return 0;
+
+malloc_error:
+ return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Stage 1: determine the straight subpaths (Sec. 2.2.1). Fill in the
+ "lon" component of a path object (based on pt/len). For each i,
+ lon[i] is the furthest index such that a straight line can be drawn
+ from i to lon[i]. Return 1 on error with errno set, else 0. */
+
+/* this algorithm depends on the fact that the existence of straight
+ subpaths is a triplewise property. I.e., there exists a straight
+ line through squares i0,...,in iff there exists a straight line
+ through i,j,k, for all i0<=i= 0 and xprod(constraint[1],
+ cur) <= 0. */
+
+/* Remark for Potrace 1.1: the current implementation of calc_lon is
+ more complex than the implementation found in Potrace 1.0, but it
+ is considerably faster. The introduction of the "nc" data structure
+ means that we only have to test the constraints for "corner"
+ points. On a typical input file, this speeds up the calc_lon
+ function by a factor of 31.2, thereby decreasing its time share
+ within the overall Potrace algorithm from 72.6% to 7.82%, and
+ speeding up the overall algorithm by a factor of 3.36. On another
+ input file, calc_lon was sped up by a factor of 6.7, decreasing its
+ time share from 51.4% to 13.61%, and speeding up the overall
+ algorithm by a factor of 1.78. In any case, the savings are
+ substantial. */
+
+/* returns 0 on success, 1 on error with errno set */
+static int calc_lon(privpath_t * pp)
+{
+ point_t *pt = pp->pt;
+ int n = pp->len;
+ int i, j, k, k1;
+ int ct[4], dir;
+ point_t constraint[2];
+ point_t cur;
+ point_t off;
+ int *pivk = NULL; /* pivk[n] */
+ int *nc = NULL; /* nc[n]: next corner */
+ point_t dk; /* direction of k-k1 */
+ int a, b, c, d;
+
+ SAFE_MALLOC(pivk, n, int);
+ SAFE_MALLOC(nc, n, int);
+
+ /* initialize the nc data structure. Point from each point to the
+ furthest future point to which it is connected by a vertical or
+ horizontal segment. We take advantage of the fact that there is
+ always a direction change at 0 (due to the path decomposition
+ algorithm). But even if this were not so, there is no harm, as
+ in practice, correctness does not depend on the word "furthest"
+ above. */
+ k = 0;
+ for (i = n - 1; i >= 0; i--) {
+ if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) {
+ k = i + 1; /* necessarily ilon, n, int);
+
+ /* determine pivot points: for each i, let pivk[i] be the furthest k
+ such that all j with i= 0; i--) {
+ ct[0] = ct[1] = ct[2] = ct[3] = 0;
+
+ /* keep track of "directions" that have occurred */
+ dir = (3 + 3 * (pt[mod(i + 1, n)].x - pt[i].x) + (pt[mod(i + 1, n)].y - pt[i].y)) / 2;
+ ct[dir]++;
+
+ constraint[0].x = 0;
+ constraint[0].y = 0;
+ constraint[1].x = 0;
+ constraint[1].y = 0;
+
+ /* find the next k such that no straight line from i to k */
+ k = nc[i];
+ k1 = i;
+ while (1) {
+
+ dir = (3 + 3 * sign(pt[k].x - pt[k1].x) + sign(pt[k].y - pt[k1].y)) / 2;
+ ct[dir]++;
+
+ /* if all four "directions" have occurred, cut this path */
+ if (ct[0] && ct[1] && ct[2] && ct[3]) {
+ pivk[i] = k1;
+ goto foundk;
+ }
+
+ cur.x = pt[k].x - pt[i].x;
+ cur.y = pt[k].y - pt[i].y;
+
+ /* see if current constraint is violated */
+ if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) {
+ goto constraint_viol;
+ }
+
+ /* else, update constraint */
+ if (abs(cur.x) <= 1 && abs(cur.y) <= 1) {
+ /* no constraint */
+ }
+ else {
+ off.x = cur.x + ((cur.y >= 0 && (cur.y > 0 || cur.x < 0)) ? 1 : -1);
+ off.y = cur.y + ((cur.x <= 0 && (cur.x < 0 || cur.y < 0)) ? 1 : -1);
+ if (xprod(constraint[0], off) >= 0) {
+ constraint[0] = off;
+ }
+ off.x = cur.x + ((cur.y <= 0 && (cur.y < 0 || cur.x < 0)) ? 1 : -1);
+ off.y = cur.y + ((cur.x >= 0 && (cur.x > 0 || cur.y < 0)) ? 1 : -1);
+ if (xprod(constraint[1], off) <= 0) {
+ constraint[1] = off;
+ }
+ }
+ k1 = k;
+ k = nc[k1];
+ if (!cyclic(k, i, k1)) {
+ break;
+ }
+ }
+ constraint_viol:
+ /* k1 was the last "corner" satisfying the current constraint, and
+ k is the first one violating it. We now need to find the last
+ point along k1..k which satisfied the constraint. */
+ dk.x = sign(pt[k].x - pt[k1].x);
+ dk.y = sign(pt[k].y - pt[k1].y);
+ cur.x = pt[k1].x - pt[i].x;
+ cur.y = pt[k1].y - pt[i].y;
+ /* find largest integer j such that xprod(constraint[0], cur+j*dk)
+ >= 0 and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity
+ of xprod. */
+ a = xprod(constraint[0], cur);
+ b = xprod(constraint[0], dk);
+ c = xprod(constraint[1], cur);
+ d = xprod(constraint[1], dk);
+ /* find largest integer j such that a+j*b>=0 and c+j*d<=0. This
+ can be solved with integer arithmetic. */
+ j = INFTY;
+ if (b < 0) {
+ j = floordiv(a, -b);
+ }
+ if (d > 0) {
+ j = min(j, floordiv(-c, d));
+ }
+ pivk[i] = mod(k1 + j, n);
+ foundk:
+ ;
+ } /* for i */
+
+ /* clean up: for each i, let lon[i] be the largest k such that for
+ all i' with i<=i'lon[n - 1] = j;
+ for (i = n - 2; i >= 0; i--) {
+ if (cyclic(i + 1, pivk[i], j)) {
+ j = pivk[i];
+ }
+ pp->lon[i] = j;
+ }
+
+ for (i = n - 1; cyclic(mod(i + 1, n), j, pp->lon[i]); i--) {
+ pp->lon[i] = j;
+ }
+
+ free(pivk);
+ free(nc);
+ return 0;
+
+malloc_error:
+ free(pivk);
+ free(nc);
+ return 1;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* Stage 2: calculate the optimal polygon (Sec. 2.2.2-2.2.4). */
+
+/* Auxiliary function: calculate the penalty of an edge from i to j in
+ the given path. This needs the "lon" and "sum*" data. */
+
+static double penalty3(privpath_t * pp, int i, int j)
+{
+ int n = pp->len;
+ point_t *pt = pp->pt;
+ sums_t *sums = pp->sums;
+
+ /* assume 0<=i= n) {
+ j -= n;
+ r += 1;
+ }
+
+ x = sums[j + 1].x - sums[i].x + r * sums[n].x;
+ y = sums[j + 1].y - sums[i].y + r * sums[n].y;
+ x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2;
+ xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy;
+ y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2;
+ k = j + 1 - i + r * n;
+
+ px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x;
+ py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y;
+ ey = (pt[j].x - pt[i].x);
+ ex = -(pt[j].y - pt[i].y);
+
+ a = ((x2 - 2 * x * px) / k + px * px);
+ b = ((xy - x * py - y * px) / k + px * py);
+ c = ((y2 - 2 * y * py) / k + py * py);
+
+ s = ex * ex * a + 2 * ex * ey * b + ey * ey * c;
+
+ return sqrt(s);
+}
+
+/* find the optimal polygon. Fill in the m and po components. Return 1
+ on failure with errno set, else 0. Non-cyclic version: assumes i=0
+ is in the polygon. Fixme: ### implement cyclic version. */
+static int bestpolygon(privpath_t * pp)
+{
+ int i, j, m, k;
+ int n = pp->len;
+ double *pen = NULL; /* pen[n+1]: penalty vector */
+ int *prev = NULL; /* prev[n+1]: best path pointer vector */
+ int *clip0 = NULL; /* clip0[n]: longest segment pointer, non-cyclic */
+ int *clip1 = NULL; /* clip1[n+1]: backwards segment pointer, non-cyclic */
+ int *seg0 = NULL; /* seg0[m+1]: forward segment bounds, m<=n */
+ int *seg1 = NULL; /* seg1[m+1]: backward segment bounds, m<=n */
+ double thispen;
+ double best;
+ int c;
+
+ SAFE_MALLOC(pen, n + 1, double);
+ SAFE_MALLOC(prev, n + 1, int);
+ SAFE_MALLOC(clip0, n, int);
+ SAFE_MALLOC(clip1, n + 1, int);
+ SAFE_MALLOC(seg0, n + 1, int);
+ SAFE_MALLOC(seg1, n + 1, int);
+
+ /* calculate clipped paths */
+ for (i = 0; i < n; i++) {
+ c = mod(pp->lon[mod(i - 1, n)] - 1, n);
+ if (c == i) {
+ c = mod(i + 1, n);
+ }
+ if (c < i) {
+ clip0[i] = n;
+ }
+ else {
+ clip0[i] = c;
+ }
+ }
+
+ /* calculate backwards path clipping, non-cyclic. j <= clip0[i] iff
+ clip1[j] <= i, for i,j=0..n. */
+ j = 1;
+ for (i = 0; i < n; i++) {
+ while (j <= clip0[i]) {
+ clip1[j] = i;
+ j++;
+ }
+ }
+
+ /* calculate seg0[j] = longest path from 0 with j segments */
+ i = 0;
+ for (j = 0; i < n; j++) {
+ seg0[j] = i;
+ i = clip0[i];
+ }
+ seg0[j] = n;
+ m = j;
+
+ /* calculate seg1[j] = longest path to n with m-j segments */
+ i = n;
+ for (j = m; j > 0; j--) {
+ seg1[j] = i;
+ i = clip1[i];
+ }
+ seg1[0] = 0;
+
+ /* now find the shortest path with m segments, based on penalty3 */
+ /* note: the outer 2 loops jointly have at most n interations, thus
+ the worst-case behavior here is quadratic. In practice, it is
+ close to linear since the inner loop tends to be short. */
+ pen[0] = 0;
+ for (j = 1; j <= m; j++) {
+ for (i = seg1[j]; i <= seg0[j]; i++) {
+ best = -1;
+ for (k = seg0[j - 1]; k >= clip1[i]; k--) {
+ thispen = penalty3(pp, k, i) + pen[k];
+ if (best < 0 || thispen < best) {
+ prev[i] = k;
+ best = thispen;
+ }
+ }
+ pen[i] = best;
+ }
+ }
+
+ pp->m = m;
+ SAFE_MALLOC(pp->po, m, int);
+
+ /* read off shortest path */
+ for (i = n, j = m - 1; i > 0; j--) {
+ i = prev[i];
+ pp->po[j] = i;
+ }
+
+ free(pen);
+ free(prev);
+ free(clip0);
+ free(clip1);
+ free(seg0);
+ free(seg1);
+ return 0;
+
+malloc_error:
+ free(pen);
+ free(prev);
+ free(clip0);
+ free(clip1);
+ free(seg0);
+ free(seg1);
+ return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Stage 3: vertex adjustment (Sec. 2.3.1). */
+
+/* Adjust vertices of optimal polygon: calculate the intersection of
+ the two "optimal" line segments, then move it into the unit square
+ if it lies outside. Return 1 with errno set on error; 0 on
+ success. */
+
+static int adjust_vertices(privpath_t * pp)
+{
+ int m = pp->m;
+ int *po = pp->po;
+ int n = pp->len;
+ point_t *pt = pp->pt;
+ int x0 = pp->x0;
+ int y0 = pp->y0;
+
+ dpoint_t *ctr = NULL; /* ctr[m] */
+ dpoint_t *dir = NULL; /* dir[m] */
+ quadform_t *q = NULL; /* q[m] */
+ double v[3];
+ double d;
+ int i, j, k, l;
+ dpoint_t s;
+ int r;
+
+ SAFE_MALLOC(ctr, m, dpoint_t);
+ SAFE_MALLOC(dir, m, dpoint_t);
+ SAFE_MALLOC(q, m, quadform_t);
+
+ r = privcurve_init(&pp->curve, m);
+ if (r) {
+ goto malloc_error;
+ }
+
+ /* calculate "optimal" point-slope representation for each line
+ segment */
+ for (i = 0; i < m; i++) {
+ j = po[mod(i + 1, m)];
+ j = mod(j - po[i], n) + po[i];
+ pointslope(pp, po[i], j, &ctr[i], &dir[i]);
+ }
+
+ /* represent each line segment as a singular quadratic form; the
+ distance of a point (x,y) from the line segment will be
+ (x,y,1)Q(x,y,1)^t, where Q=q[i]. */
+ for (i = 0; i < m; i++) {
+ d = sq(dir[i].x) + sq(dir[i].y);
+ if (d == 0.0) {
+ for (j = 0; j < 3; j++) {
+ for (k = 0; k < 3; k++) {
+ q[i][j][k] = 0;
+ }
+ }
+ }
+ else {
+ v[0] = dir[i].y;
+ v[1] = -dir[i].x;
+ v[2] = -v[1] * ctr[i].y - v[0] * ctr[i].x;
+ for (l = 0; l < 3; l++) {
+ for (k = 0; k < 3; k++) {
+ q[i][l][k] = v[l] * v[k] / d;
+ }
+ }
+ }
+ }
+
+ /* now calculate the "intersections" of consecutive segments.
+ Instead of using the actual intersection, we find the point
+ within a given unit square which minimizes the square distance to
+ the two lines. */
+ for (i = 0; i < m; i++) {
+ quadform_t Q;
+ dpoint_t w;
+ double dx, dy;
+ double det;
+ double min, cand; /* minimum and candidate for minimum of quad. form */
+ double xmin, ymin; /* coordinates of minimum */
+ int z;
+
+ /* let s be the vertex, in coordinates relative to x0/y0 */
+ s.x = pt[po[i]].x - x0;
+ s.y = pt[po[i]].y - y0;
+
+ /* intersect segments i-1 and i */
+
+ j = mod(i - 1, m);
+
+ /* add quadratic forms */
+ for (l = 0; l < 3; l++) {
+ for (k = 0; k < 3; k++) {
+ Q[l][k] = q[j][l][k] + q[i][l][k];
+ }
+ }
+
+ while (1) {
+ /* minimize the quadratic form Q on the unit square */
+ /* find intersection */
+
+#ifdef HAVE_GCC_LOOP_BUG
+ /* work around gcc bug #12243 */
+ free(NULL);
+#endif
+
+ det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0];
+ if (det != 0.0) {
+ w.x = (-Q[0][2] * Q[1][1] + Q[1][2] * Q[0][1]) / det;
+ w.y = (Q[0][2] * Q[1][0] - Q[1][2] * Q[0][0]) / det;
+ break;
+ }
+
+ /* matrix is singular - lines are parallel. Add another,
+ orthogonal axis, through the center of the unit square */
+ if (Q[0][0] > Q[1][1]) {
+ v[0] = -Q[0][1];
+ v[1] = Q[0][0];
+ }
+ else if (Q[1][1]) {
+ v[0] = -Q[1][1];
+ v[1] = Q[1][0];
+ }
+ else {
+ v[0] = 1;
+ v[1] = 0;
+ }
+ d = sq(v[0]) + sq(v[1]);
+ v[2] = -v[1] * s.y - v[0] * s.x;
+ for (l = 0; l < 3; l++) {
+ for (k = 0; k < 3; k++) {
+ Q[l][k] += v[l] * v[k] / d;
+ }
+ }
+ }
+ dx = fabs(w.x - s.x);
+ dy = fabs(w.y - s.y);
+ if (dx <= .5 && dy <= .5) {
+ pp->curve.vertex[i].x = w.x + x0;
+ pp->curve.vertex[i].y = w.y + y0;
+ continue;
+ }
+
+ /* the minimum was not in the unit square; now minimize quadratic
+ on boundary of square */
+ min = quadform(Q, s);
+ xmin = s.x;
+ ymin = s.y;
+
+ if (Q[0][0] == 0.0) {
+ goto fixx;
+ }
+ for (z = 0; z < 2; z++) { /* value of the y-coordinate */
+ w.y = s.y - 0.5 + z;
+ w.x = -(Q[0][1] * w.y + Q[0][2]) / Q[0][0];
+ dx = fabs(w.x - s.x);
+ cand = quadform(Q, w);
+ if (dx <= .5 && cand < min) {
+ min = cand;
+ xmin = w.x;
+ ymin = w.y;
+ }
+ }
+ fixx:
+ if (Q[1][1] == 0.0) {
+ goto corners;
+ }
+ for (z = 0; z < 2; z++) { /* value of the x-coordinate */
+ w.x = s.x - 0.5 + z;
+ w.y = -(Q[1][0] * w.x + Q[1][2]) / Q[1][1];
+ dy = fabs(w.y - s.y);
+ cand = quadform(Q, w);
+ if (dy <= .5 && cand < min) {
+ min = cand;
+ xmin = w.x;
+ ymin = w.y;
+ }
+ }
+ corners:
+ /* check four corners */
+ for (l = 0; l < 2; l++) {
+ for (k = 0; k < 2; k++) {
+ w.x = s.x - 0.5 + l;
+ w.y = s.y - 0.5 + k;
+ cand = quadform(Q, w);
+ if (cand < min) {
+ min = cand;
+ xmin = w.x;
+ ymin = w.y;
+ }
+ }
+ }
+
+ pp->curve.vertex[i].x = xmin + x0;
+ pp->curve.vertex[i].y = ymin + y0;
+ continue;
+ }
+
+ free(ctr);
+ free(dir);
+ free(q);
+ return 0;
+
+malloc_error:
+ free(ctr);
+ free(dir);
+ free(q);
+ return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Stage 4: smoothing and corner analysis (Sec. 2.3.3) */
+
+/* Always succeeds and returns 0 */
+static int
+ATTRIBUTE_UNUSED smooth(privcurve_t * curve, int sign, double alphamax)
+{
+ int m = curve->n;
+
+ int i, j, k;
+ double dd, denom, alpha;
+ dpoint_t p2, p3, p4;
+
+ if (sign == '-') {
+ /* reverse orientation of negative paths */
+ for (i = 0, j = m - 1; i < j; i++, j--) {
+ dpoint_t tmp;
+ tmp = curve->vertex[i];
+ curve->vertex[i] = curve->vertex[j];
+ curve->vertex[j] = tmp;
+ }
+ }
+
+ /* examine each vertex and find its best fit */
+ for (i = 0; i < m; i++) {
+ j = mod(i + 1, m);
+ k = mod(i + 2, m);
+ p4 = interval(1 / 2.0, curve->vertex[k], curve->vertex[j]);
+
+ denom = ddenom(curve->vertex[i], curve->vertex[k]);
+ if (denom != 0.0) {
+ dd = dpara(curve->vertex[i], curve->vertex[j], curve->vertex[k]) / denom;
+ dd = fabs(dd);
+ alpha = dd > 1 ? (1 - 1.0 / dd) : 0;
+ alpha = alpha / 0.75;
+ }
+ else {
+ alpha = 4 / 3.0;
+ }
+ curve->alpha0[j] = alpha; /* remember "original" value of alpha */
+
+ if (alpha > alphamax) { /* pointed corner */
+ curve->tag[j] = POTRACE_CORNER;
+ curve->c[j][1] = curve->vertex[j];
+ curve->c[j][2] = p4;
+ }
+ else {
+ if (alpha < 0.55) {
+ alpha = 0.55;
+ }
+ else if (alpha > 1) {
+ alpha = 1;
+ }
+ p2 = interval(.5 + .5 * alpha, curve->vertex[i], curve->vertex[j]);
+ p3 = interval(.5 + .5 * alpha, curve->vertex[k], curve->vertex[j]);
+ curve->tag[j] = POTRACE_CURVETO;
+ curve->c[j][0] = p2;
+ curve->c[j][1] = p3;
+ curve->c[j][2] = p4;
+ }
+ curve->alpha[j] = alpha; /* store the "cropped" value of alpha */
+ curve->beta[j] = 0.5;
+ }
+ curve->alphacurve = 1;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Stage 5: Curve optimization (Sec. 2.4) */
+
+/* a private type for the result of opti_penalty */
+struct opti_s {
+ double pen; /* penalty */
+ dpoint_t c[2]; /* curve parameters */
+ double t, s; /* curve parameters */
+ double alpha; /* curve parameter */
+};
+typedef struct opti_s opti_t;
+
+/* calculate best fit from i+.5 to j+.5. Assume icurve.n;
+ int k, k1, k2, conv, i1;
+ double area, alpha, d, d1, d2;
+ dpoint_t p0, p1, p2, p3, pt;
+ double A, R, A1, A2, A3, A4;
+ double s, t;
+
+ /* check convexity, corner-freeness, and maximum bend < 179 degrees */
+
+ if (i == j) { /* sanity - a full loop can never be an opticurve */
+ return 1;
+ }
+
+ k = i;
+ i1 = mod(i + 1, m);
+ k1 = mod(k + 1, m);
+ conv = convc[k1];
+ if (conv == 0) {
+ return 1;
+ }
+ d = ddist(pp->curve.vertex[i], pp->curve.vertex[i1]);
+ for (k = k1; k != j; k = k1) {
+ k1 = mod(k + 1, m);
+ k2 = mod(k + 2, m);
+ if (convc[k1] != conv) {
+ return 1;
+ }
+ if (sign(cprod(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2])) != conv) {
+ return 1;
+ }
+ if (iprod1
+ (pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1],
+ pp->curve.vertex[k2]) < d * ddist(pp->curve.vertex[k1], pp->curve.vertex[k2]) * COS179) {
+ return 1;
+ }
+ }
+
+ /* the curve we're working in: */
+ p0 = pp->curve.c[mod(i, m)][2];
+ p1 = pp->curve.vertex[mod(i + 1, m)];
+ p2 = pp->curve.vertex[mod(j, m)];
+ p3 = pp->curve.c[mod(j, m)][2];
+
+ /* determine its area */
+ area = areac[j] - areac[i];
+ area -= dpara(pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2]) / 2;
+ if (i >= j) {
+ area += areac[m];
+ }
+
+ /* find intersection o of p0p1 and p2p3. Let t,s such that o =
+ interval(t,p0,p1) = interval(s,p3,p2). Let A be the area of the
+ triangle (p0,o,p3). */
+
+ A1 = dpara(p0, p1, p2);
+ A2 = dpara(p0, p1, p3);
+ A3 = dpara(p0, p2, p3);
+ /* A4 = dpara(p1, p2, p3); */
+ A4 = A1 + A3 - A2;
+
+ if (A2 == A1) { /* this should never happen */
+ return 1;
+ }
+
+ t = A3 / (A3 - A4);
+ s = A2 / (A2 - A1);
+ A = A2 * t / 2.0;
+
+ if (A == 0.0) { /* this should never happen */
+ return 1;
+ }
+
+ R = area / A; /* relative area */
+ alpha = 2 - sqrt(4 - R / 0.3); /* overall alpha for p0-o-p3 curve */
+
+ res->c[0] = interval(t * alpha, p0, p1);
+ res->c[1] = interval(s * alpha, p3, p2);
+ res->alpha = alpha;
+ res->t = t;
+ res->s = s;
+
+ p1 = res->c[0];
+ p2 = res->c[1]; /* the proposed curve is now (p0,p1,p2,p3) */
+
+ res->pen = 0;
+
+ /* calculate penalty */
+ /* check tangency with edges */
+ for (k = mod(i + 1, m); k != j; k = k1) {
+ k1 = mod(k + 1, m);
+ t = tangent(p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1]);
+ if (t < -.5) {
+ return 1;
+ }
+ pt = bezier(t, p0, p1, p2, p3);
+ d = ddist(pp->curve.vertex[k], pp->curve.vertex[k1]);
+ if (d == 0.0) { /* this should never happen */
+ return 1;
+ }
+ d1 = dpara(pp->curve.vertex[k], pp->curve.vertex[k1], pt) / d;
+ if (fabs(d1) > opttolerance) {
+ return 1;
+ }
+ if (iprod(pp->curve.vertex[k], pp->curve.vertex[k1], pt) < 0 || iprod(pp->curve.vertex[k1], pp->curve.vertex[k], pt) < 0) {
+ return 1;
+ }
+ res->pen += sq(d1);
+ }
+
+ /* check corners */
+ for (k = i; k != j; k = k1) {
+ k1 = mod(k + 1, m);
+ t = tangent(p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2]);
+ if (t < -.5) {
+ return 1;
+ }
+ pt = bezier(t, p0, p1, p2, p3);
+ d = ddist(pp->curve.c[k][2], pp->curve.c[k1][2]);
+ if (d == 0.0) { /* this should never happen */
+ return 1;
+ }
+ d1 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pt) / d;
+ d2 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pp->curve.vertex[k1]) / d;
+ d2 *= 0.75 * pp->curve.alpha[k1];
+ if (d2 < 0) {
+ d1 = -d1;
+ d2 = -d2;
+ }
+ if (d1 < d2 - opttolerance) {
+ return 1;
+ }
+ if (d1 < d2) {
+ res->pen += sq(d1 - d2);
+ }
+ }
+
+ return 0;
+}
+
+/* optimize the path p, replacing sequences of Bezier segments by a
+ single segment when possible. Return 0 on success, 1 with errno set
+ on failure. */
+static int
+ATTRIBUTE_UNUSED opticurve(privpath_t * pp, double opttolerance)
+{
+ int m = pp->curve.n;
+ int *pt = NULL; /* pt[m+1] */
+ double *pen = NULL; /* pen[m+1] */
+ int *len = NULL; /* len[m+1] */
+ opti_t *opt = NULL; /* opt[m+1] */
+ int om;
+ int i, j, r;
+ opti_t o;
+ dpoint_t p0;
+ int i1;
+ double area;
+ double alpha;
+ double *s = NULL;
+ double *t = NULL;
+
+ int *convc = NULL; /* conv[m]: pre-computed convexities */
+ double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */
+
+ SAFE_MALLOC(pt, m + 1, int);
+ SAFE_MALLOC(pen, m + 1, double);
+ SAFE_MALLOC(len, m + 1, int);
+ SAFE_MALLOC(opt, m + 1, opti_t);
+ SAFE_MALLOC(convc, m, int);
+ SAFE_MALLOC(areac, m + 1, double);
+
+ /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
+ for (i = 0; i < m; i++) {
+ if (pp->curve.tag[i] == POTRACE_CURVETO) {
+ convc[i] = sign(dpara(pp->curve.vertex[mod(i - 1, m)], pp->curve.vertex[i], pp->curve.vertex[mod(i + 1, m)]));
+ }
+ else {
+ convc[i] = 0;
+ }
+ }
+
+ /* pre-calculate areas */
+ area = 0.0;
+ areac[0] = 0.0;
+ p0 = pp->curve.vertex[0];
+ for (i = 0; i < m; i++) {
+ i1 = mod(i + 1, m);
+ if (pp->curve.tag[i1] == POTRACE_CURVETO) {
+ alpha = pp->curve.alpha[i1];
+ area += 0.3 * alpha * (4 - alpha) * dpara(pp->curve.c[i][2], pp->curve.vertex[i1], pp->curve.c[i1][2]) / 2;
+ area += dpara(p0, pp->curve.c[i][2], pp->curve.c[i1][2]) / 2;
+ }
+ areac[i + 1] = area;
+ }
+
+ pt[0] = -1;
+ pen[0] = 0;
+ len[0] = 0;
+
+ /* Fixme: we always start from a fixed point -- should find the best
+ curve cyclically ### */
+
+ for (j = 1; j <= m; j++) {
+ /* calculate best path from 0 to j */
+ pt[j] = j - 1;
+ pen[j] = pen[j - 1];
+ len[j] = len[j - 1] + 1;
+
+ for (i = j - 2; i >= 0; i--) {
+ r = opti_penalty(pp, i, mod(j, m), &o, opttolerance, convc, areac);
+ if (r) {
+ break;
+ }
+ if (len[j] > len[i] + 1 || (len[j] == len[i] + 1 && pen[j] > pen[i] + o.pen)) {
+ pt[j] = i;
+ pen[j] = pen[i] + o.pen;
+ len[j] = len[i] + 1;
+ opt[j] = o;
+ }
+ }
+ }
+ om = len[m];
+ r = privcurve_init(&pp->ocurve, om);
+ if (r) {
+ goto malloc_error;
+ }
+ SAFE_MALLOC(s, om, double);
+ SAFE_MALLOC(t, om, double);
+
+ j = m;
+ for (i = om - 1; i >= 0; i--) {
+ if (pt[j] == j - 1) {
+ pp->ocurve.tag[i] = pp->curve.tag[mod(j, m)];
+ pp->ocurve.c[i][0] = pp->curve.c[mod(j, m)][0];
+ pp->ocurve.c[i][1] = pp->curve.c[mod(j, m)][1];
+ pp->ocurve.c[i][2] = pp->curve.c[mod(j, m)][2];
+ pp->ocurve.vertex[i] = pp->curve.vertex[mod(j, m)];
+ pp->ocurve.alpha[i] = pp->curve.alpha[mod(j, m)];
+ pp->ocurve.alpha0[i] = pp->curve.alpha0[mod(j, m)];
+ pp->ocurve.beta[i] = pp->curve.beta[mod(j, m)];
+ s[i] = t[i] = 1.0;
+ }
+ else {
+ pp->ocurve.tag[i] = POTRACE_CURVETO;
+ pp->ocurve.c[i][0] = opt[j].c[0];
+ pp->ocurve.c[i][1] = opt[j].c[1];
+ pp->ocurve.c[i][2] = pp->curve.c[mod(j, m)][2];
+ pp->ocurve.vertex[i] = interval(opt[j].s, pp->curve.c[mod(j, m)][2], pp->curve.vertex[mod(j, m)]);
+ pp->ocurve.alpha[i] = opt[j].alpha;
+ pp->ocurve.alpha0[i] = opt[j].alpha;
+ s[i] = opt[j].s;
+ t[i] = opt[j].t;
+ }
+ j = pt[j];
+ }
+
+ /* calculate beta parameters */
+ for (i = 0; i < om; i++) {
+ i1 = mod(i + 1, om);
+ pp->ocurve.beta[i] = s[i] / (s[i] + t[i1]);
+ }
+ pp->ocurve.alphacurve = 1;
+
+ free(pt);
+ free(pen);
+ free(len);
+ free(opt);
+ free(s);
+ free(t);
+ free(convc);
+ free(areac);
+ return 0;
+
+malloc_error:
+ free(pt);
+ free(pen);
+ free(len);
+ free(opt);
+ free(s);
+ free(t);
+ free(convc);
+ free(areac);
+ return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+double plotpolygon(privpath_t * pp, FILE * f, double scale)
+{
+ int i;
+ int m = pp->m;
+ int *po = pp->po;
+ point_t *pt = pp->pt;
+ /* double scale=1.0/dpi; */
+ double dm = 0;
+
+ if (!m)
+ return 0;
+
+ po = pp->po;
+ pt = pp->pt;
+
+ fprintf(f, "G0 X%f Y%f (start point)\n", pt[po[0]].x * scale, pt[po[0]].y * scale);
+ fprintf(f, "G1 Z#101\n");
+ for (i = 1; i < m; i++) {
+ fprintf(f, "G1 X%f Y%f\n", pt[po[i]].x * scale, pt[po[i]].y * scale);
+ dm +=
+ sqrt((pt[po[i]].x - pt[po[i - 1]].x) * scale * (pt[po[i]].x -
+ pt[po[i - 1]].x) *
+ scale + (pt[po[i]].y - pt[po[i - 1]].y) * scale * (pt[po[i]].y - pt[po[i - 1]].y) * scale);
+ }
+ fprintf(f, "G1 X%f Y%f\n", pt[po[0]].x * scale, pt[po[0]].y * scale);
+ fprintf(f, "G0 Z#100\n");
+ dm +=
+ sqrt((pt[po[m - 1]].x - pt[po[0]].x) * scale * (pt[po[m - 1]].x -
+ pt[po[0]].x) * scale +
+ (pt[po[m - 1]].y - pt[po[0]].y) * scale * (pt[po[m - 1]].y - pt[po[0]].y) * scale);
+ fprintf(f, "(polygon end, distance %.2f)\n", dm);
+ return dm;
+}
+
+#define TRY(x) if (x) goto try_error
+
+/* return distance on success, -1 on error with errno set. */
+double process_path(path_t * plist, const potrace_param_t * param, const potrace_bitmap_t * bm, FILE * f, double scale)
+{
+ path_t *p;
+ double dm = 0;
+ int n = 0;
+ /* call downstream function with each path */
+ list_forall(p, plist) {
+ TRY(calc_sums(p->priv));
+ TRY(calc_lon(p->priv));
+ TRY(bestpolygon(p->priv));
+ TRY(adjust_vertices(p->priv));
+ fprintf(f, "(polygon %d)\n", ++n);
+ dm += plotpolygon(p->priv, f, scale);
+/* No need to extract curves
+ TRY(smooth(&p->priv->curve, p->sign, param->alphamax));
+ if (param->opticurve) {
+ TRY(opticurve(p->priv, param->opttolerance));
+ p->priv->fcurve = &p->priv->ocurve;
+ } else {
+ p->priv->fcurve = &p->priv->curve;
+ }
+ privcurve_to_curve(p->priv->fcurve, &p->curve);*/
+ }
+/* fprintf(f,"(end, total distance %.2fmm = %.2fin)\n",25.4*dm,dm); */
+ return dm;
+
+try_error:
+ return -1;
+}
Index: trunk/src_plugins/export_gcode/trace.h
===================================================================
--- trunk/src_plugins/export_gcode/trace.h (nonexistent)
+++ trunk/src_plugins/export_gcode/trace.h (revision 1269)
@@ -0,0 +1,14 @@
+/* Copyright (C) 2001-2007 Peter Selinger.
+ This file is part of Potrace. It is free software and it is covered
+ by the GNU General Public License. See the file COPYING for details. */
+
+/* $Id: trace.h 147 2007-04-09 00:44:09Z selinger $ */
+
+#ifndef TRACE_H
+#define TRACE_H
+
+#include "potracelib.h"
+
+double process_path(path_t * plist, const potrace_param_t * param, const potrace_bitmap_t * bm, FILE * f, double scale);
+
+#endif /* TRACE_H */
Index: trunk/src_plugins/export_lpr/Makefile
===================================================================
--- trunk/src_plugins/export_lpr/Makefile (revision 1268)
+++ trunk/src_plugins/export_lpr/Makefile (revision 1269)
@@ -1,5 +1,5 @@
all:
- cd ../../src && make mod_export_ps
+ cd ../../src && make mod_export_lpr
clean:
rm *.o *.so 2>/dev/null ; true
Index: trunk/src_plugins/export_nelma/Makefile
===================================================================
--- trunk/src_plugins/export_nelma/Makefile (nonexistent)
+++ trunk/src_plugins/export_nelma/Makefile (revision 1269)
@@ -0,0 +1,5 @@
+all:
+ cd ../../src && make mod_export_nelma
+
+clean:
+ rm *.o *.so 2>/dev/null ; true
Index: trunk/src_plugins/export_nelma/Plug.tmpasm
===================================================================
--- trunk/src_plugins/export_nelma/Plug.tmpasm (nonexistent)
+++ trunk/src_plugins/export_nelma/Plug.tmpasm (revision 1269)
@@ -0,0 +1,15 @@
+append /local/pcb/export_nelma/enable {}
+append /local/pcb/export_nelma/buildin {}
+
+put /local/pcb/mod {export_nelma}
+put /local/pcb/mod/OBJS [@ $(PLUGDIR)/export_nelma/nelma.o @]
+
+if /local/pcb/export_nelma/enable then
+ if /local/pcb/export_nelma/buildin then
+ include {Makefile.in.mod/Buildin}
+ else
+ include {Makefile.in.mod/Plugin}
+ end
+else
+ include {Makefile.in.mod/Disable}
+end
Index: trunk/src_plugins/export_nelma/README
===================================================================
--- trunk/src_plugins/export_nelma/README (nonexistent)
+++ trunk/src_plugins/export_nelma/README (revision 1269)
@@ -0,0 +1,4 @@
+Export to nelma (Numerical capacitance calculator)
+
+#state: works
+#default: buildin
Index: trunk/src_plugins/export_nelma/nelma.c
===================================================================
--- trunk/src_plugins/export_nelma/nelma.c (nonexistent)
+++ trunk/src_plugins/export_nelma/nelma.c (revision 1269)
@@ -0,0 +1,1035 @@
+/*
+ * COPYRIGHT
+ *
+ * PCB, interactive printed circuit board design
+ *
+ * NELMA (Numerical capacitance calculator) export HID
+ * Copyright (C) 2006 Tomaz Solc (tomaz.solc@tablix.org)
+ *
+ * PNG export code is based on the PNG export HID
+ * Copyright (C) 2006 Dan McMahill
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * This HID exports a PCB layout into: o One layer mask file (PNG format) per
+ * copper layer. o Nelma configuration file that contains netlist and pin
+ * information.
+ */
+
+/*
+ * FIXME:
+ *
+ * If you have a section of a net that does not contain any pins then that
+ * section will be missing from the Nelma's copper geometry.
+ *
+ * For example:
+ *
+ * this section will be ignored by Nelma | |
+ *
+ * || ||=======|| || component layer ||
+ * || || || ||=============|| ||============||
+ * solder layer
+ *
+ * pin1 via via pin2
+ *
+ * Single layer layouts are always exported correctly.
+ *
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "global.h"
+#include "error.h" /* Message() */
+#include "data.h"
+#include "misc.h"
+#include "rats.h"
+#include "plugins.h"
+
+#include "hid.h"
+#include "../hidint.h"
+#include "hid/common/hidnogui.h"
+#include "hid/common/draw_helpers.h"
+
+#include
+
+#include "hid/common/hidinit.h"
+
+
+RCSID("$Id$");
+
+const char *nelma_cookie = "nelma HID";
+
+#define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
+
+/* Needed for PNG export */
+
+struct color_struct {
+ /* the descriptor used by the gd library */
+ int c;
+
+ /* so I can figure out what rgb value c refers to */
+ unsigned int r, g, b;
+};
+
+struct hid_gc_struct {
+ HID *me_pointer;
+ EndCapStyle cap;
+ Coord width;
+ unsigned char r, g, b;
+ int erase;
+ int faded;
+ struct color_struct *color;
+ gdImagePtr brush;
+};
+
+static HID nelma_hid;
+
+static struct color_struct *black = NULL, *white = NULL;
+static Coord linewidth = -1;
+static gdImagePtr lastbrush = (gdImagePtr) ((void *) -1);
+static int lastcolor = -1;
+
+/* gd image and file for PNG export */
+static gdImagePtr nelma_im = NULL;
+static FILE *nelma_f = NULL;
+
+static int is_mask;
+static int is_drill;
+
+/*
+ * Which groups of layers to export into PNG layer masks. 1 means export, 0
+ * means do not export.
+ */
+static int nelma_export_group[MAX_LAYER];
+
+/* Group that is currently exported. */
+static int nelma_cur_group;
+
+/* Filename prefix that will be used when saving files. */
+static const char *nelma_basename = NULL;
+
+/* Horizontal DPI (grid points per inch) */
+static int nelma_dpi = -1;
+
+/* Height of the copper layers in micrometers. */
+
+/*
+ * The height of the copper layer is currently taken as the vertical grid
+ * step, since this is the smallest vertical feature in the layout.
+ */
+static int nelma_copperh = -1;
+/* Height of the substrate layers in micrometers. */
+static int nelma_substrateh = -1;
+/* Relative permittivity of the substrate. */
+static double nelma_substratee = -1;
+
+/* Permittivity of empty space (As/Vm) */
+static const double nelma_air_epsilon = 8.85e-12;
+
+HID_Attribute nelma_attribute_list[] = {
+ /* other HIDs expect this to be first. */
+
+/* %start-doc options "nelma Options"
+@ftable @code
+@item -- basename
+File name prefix.
+@end ftable
+%end-doc
+*/
+ {"basename", "File name prefix",
+ HID_String, 0, 0, {0, 0, 0}, 0, 0},
+#define HA_basename 0
+
+/* %start-doc options "nelma Options"
+@ftable @code
+@item --dpi
+Horizontal scale factor (grid points/inch).
+@end ftable
+%end-doc
+*/
+ {"dpi", "Horizontal scale factor (grid points/inch)",
+ HID_Integer, 0, 1000, {100, 0, 0}, 0, 0},
+#define HA_dpi 1
+
+/* %start-doc options "nelma Options"
+@ftable @code
+@item --copper-height
+Copper layer height (um).
+@end ftable
+%end-doc
+*/
+ {"copper-height", "Copper layer height (um)",
+ HID_Integer, 0, 200, {100, 0, 0}, 0, 0},
+#define HA_copperh 2
+
+/* %start-doc options "nelma Options"
+@ftable @code
+@item --substrate-height
+Substrate layer height (um).
+@end ftable
+%end-doc
+*/
+ {"substrate-height", "Substrate layer height (um)",
+ HID_Integer, 0, 10000, {2000, 0, 0}, 0, 0},
+#define HA_substrateh 3
+
+/* %start-doc options "nelma Options"
+@ftable @code
+@item --substrate-epsilon
+Substrate relative epsilon.
+@end ftable
+%end-doc
+*/
+ {"substrate-epsilon", "Substrate relative epsilon",
+ HID_Real, 0, 100, {0, 0, 4.0}, 0, 0},
+#define HA_substratee 4
+};
+
+#define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0]))
+
+REGISTER_ATTRIBUTES(nelma_attribute_list, nelma_cookie)
+ static HID_Attr_Val nelma_values[NUM_OPTIONS];
+
+/* *** Utility funcions **************************************************** */
+
+/* convert from default PCB units to nelma units */
+ static int pcb_to_nelma(Coord pcb)
+{
+ return COORD_TO_INCH(pcb) * nelma_dpi;
+}
+
+static char *nelma_get_png_name(const char *basename, const char *suffix)
+{
+ char *buf;
+ int len;
+
+ len = strlen(basename) + strlen(suffix) + 6;
+ buf = (char *) malloc(sizeof(*buf) * len);
+
+ sprintf(buf, "%s.%s.png", basename, suffix);
+
+ return buf;
+}
+
+/* Retrieves coordinates (in default PCB units) of a pin or pad. */
+/* Copied from netlist.c */
+static int pin_name_to_xy(LibraryEntryType * pin, Coord * x, Coord * y)
+{
+ ConnectionType conn;
+ if (!SeekPad(pin, &conn, false))
+ return 1;
+ switch (conn.type) {
+ case PIN_TYPE:
+ *x = ((PinType *) (conn.ptr2))->X;
+ *y = ((PinType *) (conn.ptr2))->Y;
+ return 0;
+ case PAD_TYPE:
+ *x = ((PadType *) (conn.ptr2))->Point1.X;
+ *y = ((PadType *) (conn.ptr2))->Point1.Y;
+ return 0;
+ }
+ return 1;
+}
+
+/* *** Exporting netlist data and geometry to the nelma config file ******** */
+
+static void nelma_write_space(FILE * out)
+{
+ double xh, zh;
+
+ int z;
+ int i, idx;
+ const char *ext;
+
+ xh = 2.54e-2 / ((double) nelma_dpi);
+ zh = nelma_copperh * 1e-6;
+
+ fprintf(out, "\n/* **** Space **** */\n\n");
+
+ fprintf(out, "space pcb {\n");
+ fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh);
+ fprintf(out, "\tlayers = {\n");
+
+ fprintf(out, "\t\t\"air-top\",\n");
+ fprintf(out, "\t\t\"air-bottom\"");
+
+ z = 10;
+ for (i = 0; i < MAX_LAYER; i++)
+ if (nelma_export_group[i]) {
+ idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
+ ext = layer_type_to_file_name(idx, FNS_fixed);
+
+ if (z != 10) {
+ fprintf(out, ",\n");
+ fprintf(out, "\t\t\"substrate-%d\"", z);
+ z++;
+ }
+ fprintf(out, ",\n");
+ fprintf(out, "\t\t\"%s\"", ext);
+ z++;
+ }
+ fprintf(out, "\n\t}\n");
+ fprintf(out, "}\n");
+}
+
+
+static void nelma_write_material(FILE * out, char *name, char *type, double e)
+{
+ fprintf(out, "material %s {\n", name);
+ fprintf(out, "\ttype = \"%s\"\n", type);
+ fprintf(out, "\tpermittivity = %e\n", e);
+ fprintf(out, "\tconductivity = 0.0\n");
+ fprintf(out, "\tpermeability = 0.0\n");
+ fprintf(out, "}\n");
+}
+
+static void nelma_write_materials(FILE * out)
+{
+ fprintf(out, "\n/* **** Materials **** */\n\n");
+
+ nelma_write_material(out, "copper", "metal", nelma_air_epsilon);
+ nelma_write_material(out, "air", "dielectric", nelma_air_epsilon);
+ nelma_write_material(out, "composite", "dielectric", nelma_air_epsilon * nelma_substratee);
+}
+
+static void nelma_write_nets(FILE * out)
+{
+ LibraryType netlist;
+ LibraryMenuTypePtr net;
+ LibraryEntryTypePtr pin;
+
+ int n, m, i, idx;
+
+ const char *ext;
+
+ netlist = PCB->NetlistLib[NETLIST_EDITED];
+
+ fprintf(out, "\n/* **** Nets **** */\n\n");
+
+ for (n = 0; n < netlist.MenuN; n++) {
+ net = &netlist.Menu[n];
+
+ /* Weird, but correct */
+ fprintf(out, "net %s {\n", &net->Name[2]);
+
+ fprintf(out, "\tobjects = {\n");
+
+ for (m = 0; m < net->EntryN; m++) {
+ pin = &net->Entry[m];
+
+ /* pin_name_to_xy(pin, &x, &y); */
+
+ for (i = 0; i < MAX_LAYER; i++)
+ if (nelma_export_group[i]) {
+ idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
+ ext = layer_type_to_file_name(idx, FNS_fixed);
+
+ if (m != 0 || i != 0)
+ fprintf(out, ",\n");
+ fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, ext);
+ }
+ }
+
+ fprintf(out, "\n");
+ fprintf(out, "\t}\n");
+ fprintf(out, "}\n");
+ }
+}
+
+static void nelma_write_layer(FILE * out, int z, int h, const char *name, int full, char *mat)
+{
+ LibraryType netlist;
+ LibraryMenuTypePtr net;
+ LibraryEntryTypePtr pin;
+
+ int n, m;
+
+ fprintf(out, "layer %s {\n", name);
+ fprintf(out, "\theight = %d\n", h);
+ fprintf(out, "\tz-order = %d\n", z);
+ fprintf(out, "\tmaterial = \"%s\"\n", mat);
+
+ if (full) {
+ fprintf(out, "\tobjects = {\n");
+ netlist = PCB->NetlistLib[NETLIST_EDITED];
+
+ for (n = 0; n < netlist.MenuN; n++) {
+ net = &netlist.Menu[n];
+
+ for (m = 0; m < net->EntryN; m++) {
+ pin = &net->Entry[m];
+
+ if (m != 0 || n != 0)
+ fprintf(out, ",\n");
+ fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, name);
+ }
+
+ }
+ fprintf(out, "\n\t}\n");
+ }
+ fprintf(out, "}\n");
+}
+
+static void nelma_write_layers(FILE * out)
+{
+ int i, idx;
+ int z;
+
+ const char *ext;
+ char buf[100];
+
+ int subh;
+
+ subh = nelma_substrateh / nelma_copperh;
+
+ fprintf(out, "\n/* **** Layers **** */\n\n");
+
+ /* Air layers on top and bottom of the stack */
+ /* Their height is double substrate height. */
+ nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air");
+ nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air");
+
+ z = 10;
+ for (i = 0; i < MAX_LAYER; i++)
+ if (nelma_export_group[i]) {
+ idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
+ ext = layer_type_to_file_name(idx, FNS_fixed);
+
+ if (z != 10) {
+ sprintf(buf, "substrate-%d", z);
+ nelma_write_layer(out, z, subh, buf, 0, "composite");
+ z++;
+ }
+ /*
+ * FIXME: for layers that are not on top or bottom,
+ * the material should be "composite"
+ */
+ nelma_write_layer(out, z, 1, ext, 1, "air");
+
+ z++;
+ }
+}
+
+static void nelma_write_object(FILE * out, LibraryEntryTypePtr pin)
+{
+ int i, idx;
+ Coord px = 0, py = 0;
+ int x, y;
+
+ char *f;
+ const char *ext;
+
+ pin_name_to_xy(pin, &px, &py);
+
+ x = pcb_to_nelma(px);
+ y = pcb_to_nelma(py);
+
+ for (i = 0; i < MAX_LAYER; i++)
+ if (nelma_export_group[i]) {
+ idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
+ ext = layer_type_to_file_name(idx, FNS_fixed);
+
+ fprintf(out, "object %s-%s {\n", pin->ListEntry, ext);
+ fprintf(out, "\tposition = { 0, 0 }\n");
+ fprintf(out, "\tmaterial = \"copper\"\n");
+ fprintf(out, "\ttype = \"image\"\n");
+ fprintf(out, "\trole = \"net\"\n");
+
+ f = nelma_get_png_name(nelma_basename, ext);
+
+ fprintf(out, "\tfile = \"%s\"\n", f);
+
+ free(f);
+
+ fprintf(out, "\tfile-pos = { %d, %d }\n", x, y);
+ fprintf(out, "}\n");
+ }
+}
+
+static void nelma_write_objects(FILE * out)
+{
+ LibraryType netlist;
+ LibraryMenuTypePtr net;
+ LibraryEntryTypePtr pin;
+
+ int n, m;
+
+ netlist = PCB->NetlistLib[NETLIST_EDITED];
+
+ fprintf(out, "\n/* **** Objects **** */\n\n");
+
+ for (n = 0; n < netlist.MenuN; n++) {
+ net = &netlist.Menu[n];
+
+ for (m = 0; m < net->EntryN; m++) {
+ pin = &net->Entry[m];
+
+ nelma_write_object(out, pin);
+ }
+ }
+}
+
+/* *** Main export callback ************************************************ */
+
+static void nelma_parse_arguments(int *argc, char ***argv)
+{
+ hid_register_attributes(nelma_attribute_list, sizeof(nelma_attribute_list) / sizeof(nelma_attribute_list[0]), nelma_cookie);
+ hid_parse_command_line(argc, argv);
+}
+
+static HID_Attribute *nelma_get_export_options(int *n)
+{
+ static char *last_made_filename = 0;
+
+ if (PCB) {
+ derive_default_filename(PCB->Filename, &nelma_attribute_list[HA_basename], ".nelma", &last_made_filename);
+ }
+ if (n) {
+ *n = NUM_OPTIONS;
+ }
+ return nelma_attribute_list;
+}
+
+/* Populates nelma_export_group array */
+void nelma_choose_groups()
+{
+ int n, m;
+ LayerType *layer;
+
+ /* Set entire array to 0 (don't export any layer groups by default */
+ memset(nelma_export_group, 0, sizeof(nelma_export_group));
+
+ for (n = 0; n < max_copper_layer; n++) {
+ layer = &PCB->Data->Layer[n];
+
+ if (!LAYER_IS_EMPTY(layer)) {
+ /* layer isn't empty */
+
+ /*
+ * is this check necessary? It seems that special
+ * layers have negative indexes?
+ */
+
+ if (SL_TYPE(n) == 0) {
+ /* layer is a copper layer */
+ m = GetLayerGroupNumberByNumber(n);
+
+ /* the export layer */
+ nelma_export_group[m] = 1;
+ }
+ }
+ }
+}
+
+static void nelma_alloc_colors()
+{
+ /*
+ * Allocate white and black -- the first color allocated becomes the
+ * background color
+ */
+
+ white = (struct color_struct *) malloc(sizeof(*white));
+ white->r = white->g = white->b = 255;
+ white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b);
+
+ black = (struct color_struct *) malloc(sizeof(*black));
+ black->r = black->g = black->b = 0;
+ black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b);
+}
+
+static void nelma_start_png(const char *basename, const char *suffix)
+{
+ int h, w;
+ char *buf;
+
+ buf = nelma_get_png_name(basename, suffix);
+
+ h = pcb_to_nelma(PCB->MaxHeight);
+ w = pcb_to_nelma(PCB->MaxWidth);
+
+ /* nelma_im = gdImageCreate (w, h); */
+
+ /* Nelma only works with true color images */
+ nelma_im = gdImageCreate(w, h);
+ nelma_f = fopen(buf, "wb");
+
+ nelma_alloc_colors();
+
+ free(buf);
+}
+
+static void nelma_finish_png()
+{
+#ifdef HAVE_GDIMAGEPNG
+ gdImagePng(nelma_im, nelma_f);
+#else
+ Message("NELMA: PNG not supported by gd. Can't write layer mask.\n");
+#endif
+ gdImageDestroy(nelma_im);
+ fclose(nelma_f);
+
+ free(white);
+ free(black);
+
+ nelma_im = NULL;
+ nelma_f = NULL;
+}
+
+void nelma_start_png_export()
+{
+ BoxType region;
+
+ region.X1 = 0;
+ region.Y1 = 0;
+ region.X2 = PCB->MaxWidth;
+ region.Y2 = PCB->MaxHeight;
+
+ linewidth = -1;
+ lastbrush = (gdImagePtr) ((void *) -1);
+ lastcolor = -1;
+
+ hid_expose_callback(&nelma_hid, ®ion, 0);
+}
+
+static void nelma_do_export(HID_Attr_Val * options)
+{
+ int save_ons[MAX_LAYER + 2];
+ int i, idx;
+ FILE *nelma_config;
+ char *buf;
+ int len;
+
+ time_t t;
+
+ if (!options) {
+ nelma_get_export_options(0);
+ for (i = 0; i < NUM_OPTIONS; i++) {
+ nelma_values[i] = nelma_attribute_list[i].default_val;
+ }
+ options = nelma_values;
+ }
+ nelma_basename = options[HA_basename].str_value;
+ if (!nelma_basename) {
+ nelma_basename = "pcb-out";
+ }
+ nelma_dpi = options[HA_dpi].int_value;
+ if (nelma_dpi < 0) {
+ fprintf(stderr, "ERROR: dpi may not be < 0\n");
+ return;
+ }
+ nelma_copperh = options[HA_copperh].int_value;
+ nelma_substrateh = options[HA_substrateh].int_value;
+ nelma_substratee = options[HA_substratee].real_value;
+
+ nelma_choose_groups();
+
+ for (i = 0; i < MAX_LAYER; i++) {
+ if (nelma_export_group[i]) {
+
+ nelma_cur_group = i;
+
+ /* magic */
+ idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i;
+
+ nelma_start_png(nelma_basename, layer_type_to_file_name(idx, FNS_fixed));
+
+ hid_save_and_show_layer_ons(save_ons);
+ nelma_start_png_export();
+ hid_restore_layer_ons(save_ons);
+
+ nelma_finish_png();
+ }
+ }
+
+ len = strlen(nelma_basename) + 4;
+ buf = (char *) malloc(sizeof(*buf) * len);
+
+ sprintf(buf, "%s.em", nelma_basename);
+ nelma_config = fopen(buf, "w");
+
+ free(buf);
+
+ fprintf(nelma_config, "/* Made with PCB Nelma export HID */");
+ t = time(NULL);
+ fprintf(nelma_config, "/* %s */", ctime(&t));
+
+ nelma_write_nets(nelma_config);
+ nelma_write_objects(nelma_config);
+ nelma_write_layers(nelma_config);
+ nelma_write_materials(nelma_config);
+ nelma_write_space(nelma_config);
+
+ fclose(nelma_config);
+}
+
+/* *** PNG export (slightly modified code from PNG export HID) ************* */
+
+static int nelma_set_layer(const char *name, int group, int empty)
+{
+ int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group;
+
+ if (name == 0) {
+ name = PCB->Data->Layer[idx].Name;
+ }
+ if (strcmp(name, "invisible") == 0) {
+ return 0;
+ }
+ is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL);
+ is_mask = (SL_TYPE(idx) == SL_MASK);
+
+ if (is_mask) {
+ /* Don't print masks */
+ return 0;
+ }
+ if (is_drill) {
+ /*
+ * Print 'holes', so that we can fill gaps in the copper
+ * layer
+ */
+ return 1;
+ }
+ if (group == nelma_cur_group) {
+ return 1;
+ }
+ return 0;
+}
+
+static hidGC nelma_make_gc(void)
+{
+ hidGC rv = (hidGC) malloc(sizeof(struct hid_gc_struct));
+ rv->me_pointer = &nelma_hid;
+ rv->cap = Trace_Cap;
+ rv->width = 1;
+ rv->color = (struct color_struct *) malloc(sizeof(*rv->color));
+ rv->color->r = rv->color->g = rv->color->b = 0;
+ rv->color->c = 0;
+ return rv;
+}
+
+static void nelma_destroy_gc(hidGC gc)
+{
+ free(gc);
+}
+
+static void nelma_use_mask(int use_it)
+{
+ /* does nothing */
+}
+
+static void nelma_set_color(hidGC gc, const char *name)
+{
+ if (nelma_im == NULL) {
+ return;
+ }
+ if (name == NULL) {
+ name = "#ff0000";
+ }
+ if (!strcmp(name, "drill")) {
+ gc->color = black;
+ gc->erase = 0;
+ return;
+ }
+ if (!strcmp(name, "erase")) {
+ /* FIXME -- should be background, not white */
+ gc->color = white;
+ gc->erase = 1;
+ return;
+ }
+ gc->color = black;
+ gc->erase = 0;
+ return;
+}
+
+static void nelma_set_line_cap(hidGC gc, EndCapStyle style)
+{
+ gc->cap = style;
+}
+
+static void nelma_set_line_width(hidGC gc, Coord width)
+{
+ gc->width = width;
+}
+
+static void nelma_set_draw_xor(hidGC gc, int xor_)
+{
+ ;
+}
+
+static void nelma_set_draw_faded(hidGC gc, int faded)
+{
+ gc->faded = faded;
+}
+
+static void use_gc(hidGC gc)
+{
+ int need_brush = 0;
+
+ if (gc->me_pointer != &nelma_hid) {
+ fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n");
+ abort();
+ }
+ if (linewidth != gc->width) {
+ /* Make sure the scaling doesn't erase lines completely */
+ /*
+ if (SCALE (gc->width) == 0 && gc->width > 0)
+ gdImageSetThickness (im, 1);
+ else
+ */
+ gdImageSetThickness(nelma_im, pcb_to_nelma(gc->width));
+ linewidth = gc->width;
+ need_brush = 1;
+ }
+ if (lastbrush != gc->brush || need_brush) {
+ static void *bcache = 0;
+ hidval bval;
+ char name[256];
+ char type;
+ int r;
+
+ switch (gc->cap) {
+ case Round_Cap:
+ case Trace_Cap:
+ type = 'C';
+ r = pcb_to_nelma(gc->width / 2);
+ break;
+ default:
+ case Square_Cap:
+ r = pcb_to_nelma(gc->width);
+ type = 'S';
+ break;
+ }
+ sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r);
+
+ if (hid_cache_color(0, name, &bval, &bcache)) {
+ gc->brush = (gdImagePtr) bval.ptr;
+ }
+ else {
+ int bg, fg;
+ if (type == 'C')
+ gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1);
+ else
+ gc->brush = gdImageCreate(r + 1, r + 1);
+ bg = gdImageColorAllocate(gc->brush, 255, 255, 255);
+ fg = gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g, gc->color->b);
+ gdImageColorTransparent(gc->brush, bg);
+
+ /*
+ * if we shrunk to a radius/box width of zero, then just use
+ * a single pixel to draw with.
+ */
+ if (r == 0)
+ gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg);
+ else {
+ if (type == 'C')
+ gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg);
+ else
+ gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg);
+ }
+ bval.ptr = gc->brush;
+ hid_cache_color(1, name, &bval, &bcache);
+ }
+
+ gdImageSetBrush(nelma_im, gc->brush);
+ lastbrush = gc->brush;
+
+ }
+#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
+ if (lastcolor != CBLEND(gc)) {
+ if (is_drill || is_mask) {
+#ifdef FIXME
+ fprintf(f, "%d gray\n", gc->erase ? 0 : 1);
+#endif
+ lastcolor = 0;
+ }
+ else {
+ double r, g, b;
+ r = gc->r;
+ g = gc->g;
+ b = gc->b;
+ if (gc->faded) {
+ r = 0.8 * 255 + 0.2 * r;
+ g = 0.8 * 255 + 0.2 * g;
+ b = 0.8 * 255 + 0.2 * b;
+ }
+#ifdef FIXME
+ if (gc->r == gc->g && gc->g == gc->b)
+ fprintf(f, "%g gray\n", r / 255.0);
+ else
+ fprintf(f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0);
+#endif
+ lastcolor = CBLEND(gc);
+ }
+ }
+}
+
+static void nelma_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
+{
+ use_gc(gc);
+ gdImageRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
+}
+
+static void nelma_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
+{
+ use_gc(gc);
+ gdImageSetThickness(nelma_im, 0);
+ linewidth = 0;
+ gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
+}
+
+static void nelma_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
+{
+ if (x1 == x2 && y1 == y2) {
+ Coord w = gc->width / 2;
+ nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w);
+ return;
+ }
+ use_gc(gc);
+
+ gdImageSetThickness(nelma_im, 0);
+ linewidth = 0;
+ gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed);
+}
+
+static void nelma_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle)
+{
+ Angle sa, ea;
+
+ /*
+ * in gdImageArc, 0 degrees is to the right and +90 degrees is down
+ * in pcb, 0 degrees is to the left and +90 degrees is down
+ */
+ start_angle = 180 - start_angle;
+ delta_angle = -delta_angle;
+ if (delta_angle > 0) {
+ sa = start_angle;
+ ea = start_angle + delta_angle;
+ }
+ else {
+ sa = start_angle + delta_angle;
+ ea = start_angle;
+ }
+
+ /*
+ * make sure we start between 0 and 360 otherwise gd does strange
+ * things
+ */
+ sa = NormalizeAngle(sa);
+ ea = NormalizeAngle(ea);
+
+#if 0
+ printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea);
+ printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
+ im, SCALE_X(cx), SCALE_Y(cy), SCALE(width), SCALE(height), sa, ea, gc->color->c);
+#endif
+ use_gc(gc);
+ gdImageSetThickness(nelma_im, 0);
+ linewidth = 0;
+ gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
+ pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed);
+}
+
+static void nelma_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius)
+{
+ use_gc(gc);
+
+ gdImageSetThickness(nelma_im, 0);
+ linewidth = 0;
+ gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
+ pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), gc->color->c);
+
+}
+
+static void nelma_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y)
+{
+ int i;
+ gdPoint *points;
+
+ points = (gdPoint *) malloc(n_coords * sizeof(gdPoint));
+ if (points == NULL) {
+ fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n");
+ exit(1);
+ }
+ use_gc(gc);
+ for (i = 0; i < n_coords; i++) {
+ points[i].x = pcb_to_nelma(x[i]);
+ points[i].y = pcb_to_nelma(y[i]);
+ }
+ gdImageSetThickness(nelma_im, 0);
+ linewidth = 0;
+ gdImageFilledPolygon(nelma_im, points, n_coords, gc->color->c);
+ free(points);
+}
+
+static void nelma_calibrate(double xval, double yval)
+{
+ CRASH;
+}
+
+static void nelma_set_crosshair(int x, int y, int a)
+{
+}
+
+/* *** Miscellaneous ******************************************************* */
+
+#include "dolists.h"
+
+pcb_uninit_t hid_export_nelma_init()
+{
+ memset(&nelma_hid, 0, sizeof(HID));
+
+ common_nogui_init(&nelma_hid);
+ common_draw_helpers_init(&nelma_hid);
+
+ nelma_hid.struct_size = sizeof(HID);
+ nelma_hid.name = "nelma";
+ nelma_hid.description = "Numerical analysis package export";
+ nelma_hid.exporter = 1;
+ nelma_hid.poly_before = 1;
+
+ nelma_hid.get_export_options = nelma_get_export_options;
+ nelma_hid.do_export = nelma_do_export;
+ nelma_hid.parse_arguments = nelma_parse_arguments;
+ nelma_hid.set_layer = nelma_set_layer;
+ nelma_hid.make_gc = nelma_make_gc;
+ nelma_hid.destroy_gc = nelma_destroy_gc;
+ nelma_hid.use_mask = nelma_use_mask;
+ nelma_hid.set_color = nelma_set_color;
+ nelma_hid.set_line_cap = nelma_set_line_cap;
+ nelma_hid.set_line_width = nelma_set_line_width;
+ nelma_hid.set_draw_xor = nelma_set_draw_xor;
+ nelma_hid.set_draw_faded = nelma_set_draw_faded;
+ nelma_hid.draw_line = nelma_draw_line;
+ nelma_hid.draw_arc = nelma_draw_arc;
+ nelma_hid.draw_rect = nelma_draw_rect;
+ nelma_hid.fill_circle = nelma_fill_circle;
+ nelma_hid.fill_polygon = nelma_fill_polygon;
+ nelma_hid.fill_rect = nelma_fill_rect;
+ nelma_hid.calibrate = nelma_calibrate;
+ nelma_hid.set_crosshair = nelma_set_crosshair;
+
+ hid_register_hid(&nelma_hid);
+ return NULL;
+}
Index: trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/actions/actions.c
===================================================================
--- trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/actions/actions.c (revision 1268)
+++ trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_pkg/actions/actions.c (revision 1269)
@@ -81,7 +81,7 @@
ctx->module = gpmi_get_current_module();
ctx->next = NULL;
- hid_register_action(&ctx->action, &gpmi_cookie);
+ hid_register_action(&ctx->action, gpmi_cookie);
gpmi_mod_cleanup_insert(ctx->module, cleanup_action, "p", ctx);
Index: trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_plugin.c
===================================================================
--- trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_plugin.c (revision 1268)
+++ trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_plugin.c (revision 1269)
@@ -13,7 +13,7 @@
extern char *homedir; /* detected by pcn-rnd in InitPaths() */
-char *gpmi_cookie = "GPMI plugin cookie";
+const char *gpmi_cookie = "GPMI plugin cookie";
/* This function is used to print a detailed GPMI error message */
void gpmi_hid_print_error(gpmi_err_stack_t *entry, char *string)
@@ -118,7 +118,7 @@
act.description = "Manage gpmi scripts";
act.syntax = "TODO";
act.trigger_cb = action_gpmi_scripts;
- hid_register_action(&act, &gpmi_cookie);
+ hid_register_action(&act, gpmi_cookie);
act.name = "rehash";
act.need_coord_msg = NULL;
@@ -125,7 +125,7 @@
act.description = "Reload all gpmi scripts";
act.syntax = "TODO";
act.trigger_cb = action_gpmi_rehash;
- hid_register_action(&act, &gpmi_cookie);
+ hid_register_action(&act, gpmi_cookie);
}
#ifndef PLUGIN_INIT_NAME
@@ -181,7 +181,7 @@
*gpmi_asm_scriptname = gpmi_hid_asm_scriptname;
register_actions();
- event_bind(EVENT_GUI_INIT, ev_gui_init, NULL, &gpmi_cookie);
+ event_bind(EVENT_GUI_INIT, ev_gui_init, NULL, gpmi_cookie);
hid_gpmi_load_dir(libdirh, 0);
hid_gpmi_load_dir(libdirg, 0);
@@ -210,8 +210,8 @@
static void plugin_gpmi_uninit(void)
{
- event_unbind_allcookie(&gpmi_cookie);
- hid_remove_actions_by_cookie(&gpmi_cookie);
+ event_unbind_allcookie(gpmi_cookie);
+ hid_remove_actions_by_cookie(gpmi_cookie);
hid_gpmi_script_info_uninit();
gpmi_pkg_unload(pkg_scripts);
gpmi_uninit();
Index: trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_plugin.h
===================================================================
--- trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_plugin.h (revision 1268)
+++ trunk/src_plugins/gpmi/pcb-gpmi/gpmi_plugin/gpmi_plugin.h (revision 1269)
@@ -1,4 +1,4 @@
-extern char *gpmi_cookie;
+extern const char *gpmi_cookie;
extern int gpmi_hid_gui_inited; /* whether the gui is already initialzied */
void gpmi_hid_print_error(gpmi_err_stack_t *entry, char *string);
|
---|