#include #include #include #include #include #include "unit.h" #include "pcb_bool.h" #include "rtree.h" #include "polyarea.h" #include "polygon.h" pcb_polyarea_t *pa['Z'-'A']; extern void pcb_poly_insert_holes(jmp_buf * e1, pcb_polyarea_t * dest, pcb_pline_t ** src); pcb_polyarea_t *pcb_poly_from_contour(pcb_pline_t * contour) { pcb_polyarea_t *p; pcb_poly_contour_pre(contour, pcb_true); if (!(p = pcb_polyarea_create())) return NULL; pcb_polyarea_contour_include(p, contour); return p; } static void update_bbox(pcb_pline_t *c, pcb_coord_t *minx, pcb_coord_t *miny, pcb_coord_t *maxx, pcb_coord_t *maxy) { pcb_vnode_t *v, *n; pcb_vnode_t *pl = &c->head; #define update_minmax(min, max, val) \ if (val < (min)) (min) = val; \ if (val > (max)) (max) = val; v = pl; do { n = v->next; update_minmax(*minx, *maxx, v->point[0]); update_minmax(*miny, *maxy, v->point[1]); update_minmax(*minx, *maxx, n->point[0]); update_minmax(*miny, *maxy, n->point[1]); } while ((v = v->next) != pl); #undef update_minmax } static void draw_(pcb_pline_t *c) { pcb_vnode_t *v, *n; pcb_vnode_t *pl = &c->head; v = pl; do { n = v->next; printf("line %ld %ld %ld %ld\n", (long)v->point[0], (long)v->point[1], (long)n->point[0], (long)n->point[1]); } while ((v = v->next) != pl); } static void draw(const char *arg) { pcb_pline_t *c; pcb_coord_t minx = COORD_MAX, miny = COORD_MAX, maxx = -COORD_MAX, maxy = -COORD_MAX, w, h; int drw['Z' - 'A']; int cnt = 0, n; while(*arg != '\0') { int a; while(isspace(*arg)) arg++; if (*arg == '\0') break; a = toupper(*arg); if ((a < 'A') || (a > 'Z')) { fprintf(stderr, "Error: invalid index in draw: '%c' (%d)\n", a, a); return; } drw[cnt] = a - 'A'; if ((pa[drw[cnt]] == NULL) || (pa[drw[cnt]]->contours == NULL)) { fprintf(stderr, "Error: invalid index in draw: '%c': empty poly \n", a); return; } update_bbox(pa[drw[cnt]]->contours, &minx, &miny, &maxx, &maxy); cnt++; arg++; } printf("!!!animator start\n"); w = maxx - minx; h = maxy - miny; printf("ident\nscale 1 -1\n"); printf("viewport %f %f - %f %f\n", (minx - w/20.0), (miny - h/20.0), (maxx + w/20.0), (maxy + h/20.0)); printf("frame\n"); for(n = 0; n < cnt; n++) { pcb_polyarea_t *p = pa[drw[n]]; printf("dash 0xffff\n"); draw_(p->contours); for (c = p->contours->next; c != NULL; c = c->next) { printf("dash 0x3333\n"); draw_(c); } } printf("flush\n"); printf("!!!animator end\n"); } static void pline_update_bbox(pcb_pline_t *pl) { pcb_vnode_t *n; n = &pl->head; pl->xmin = pl->xmax = n->point[0]; pl->ymin = pl->ymax = n->point[1]; for (n = n->next; n != &pl->head; n = n->next) { pcb_coord_t x = n->point[0], y = n->point[1]; if (x < pl->xmin) pl->xmin = x; if (y < pl->ymin) pl->ymin = y; if (x > pl->xmax) pl->xmax = x; if (y > pl->ymax) pl->ymax = y; } } static void fix_contour(pcb_pline_t *c) { pcb_poly_contour_pre(c, 0); if (c->Flags.orient != PCB_PLF_DIR) pcb_poly_contour_inv(c); } pcb_polyarea_t *ply_parse(const char *vect) { pcb_pline_t *contour = NULL; long int x, y; int len; pcb_vector_t v; pcb_polyarea_t *pa = NULL; pcb_pline_t *holes[2] = { NULL, NULL }; if (sscanf(vect, "%ld %ld%n", &x, &y, &len) != 2) return NULL; vect += len; v[0] = x; v[1] = y; if ((contour = pcb_poly_contour_new(v)) == NULL) return NULL; for(;;) { while(isspace(*vect)) vect++; if (*vect == 'h') { if (pa == NULL) { fix_contour(contour); pa = pcb_poly_from_contour(contour); } else { pline_update_bbox(holes[0]); pcb_poly_insert_holes(NULL, pa, holes); } vect++; if (sscanf(vect, "%ld %ld%n", &x, &y, &len) != 2) { fprintf(stderr, "Syntax error: no points after 'h' in polygon\n"); exit(1); } vect += len; v[0] = x; v[1] = y; holes[0] = pcb_poly_contour_new(v); contour = holes[0]; } if (sscanf(vect, "%ld %ld%n", &x, &y, &len) != 2) break; vect += len; v[0] = x; v[1] = y; pcb_poly_vertex_include(contour->head.prev, pcb_poly_node_create(v)); } if (pa == NULL) { fix_contour(contour); pa = pcb_poly_from_contour(contour); } else { pline_update_bbox(holes[0]); pcb_poly_insert_holes(NULL, pa, holes); } return pa; } static void valid_report(pcb_pline_t *c, pcb_vnode_t *pl) { if (c->Flags.orient == PCB_PLF_INV) fprintf(stderr, "failed orient\n"); if (pcb_polyarea_contour_check(c)) fprintf(stderr, "failed self-intersection\n"); } pcb_bool poly_valid(pcb_polyarea_t * p) { pcb_pline_t *c; if ((p == NULL) || (p->contours == NULL)) { fprintf(stderr, "Empty poly\n"); return pcb_false; } if (p->contours->Flags.orient == PCB_PLF_INV || pcb_polyarea_contour_check(p->contours)) { fprintf(stderr, "Invalid Outer pcb_pline_t\n"); valid_report(p->contours, &p->contours->head); return pcb_false; } for (c = p->contours->next; c != NULL; c = c->next) { if (c->Flags.orient == PCB_PLF_DIR || pcb_polyarea_contour_check(c) || !pcb_poly_contour_in_contour(p->contours, c)) { fprintf(stderr, "Invalid Inner pcb_pline_t orient = %d\n", c->Flags.orient); valid_report(c, &c->head); return pcb_false; } } return pcb_true; } #include "polygon_fix.c" /*****************/ #define get_idx_(idx) \ idx = toupper(arg[0]); \ if (!isspace(arg[1])) { \ fprintf(stderr, "ERROR: invalid polygon index: not a single character\n"); \ continue; \ } \ if ((idx < 'A') || (idx > 'Z')) { \ fprintf(stderr, "ERROR: invalid polygon index %c: out of range\n", idx); \ continue; \ } \ idx -= 'A'; \ arg += 2; #define get_idx() int idx = get_idx_(idx) int main(int argc, char *argv[]) { char line[8192], *cmd, *arg; while(fgets(line, sizeof(line), stdin) != NULL) { cmd = line; while(isspace(*cmd)) cmd++; if ((*cmd == '#') || (*cmd == '\0')) continue; arg = strpbrk(cmd, " \t\r\n"); if (arg != NULL) { *arg = '\0'; arg++; while(isspace(*arg)) arg++; } if (strcmp(cmd, "polygon") == 0) { get_idx(); pa[idx] = ply_parse(arg); if ((pa[idx] == NULL) || (pa[idx]->contours == NULL)) fprintf(stderr, "poly parse error\n"); } else if (strcmp(cmd, "draw") == 0) draw(arg); else if (strcmp(cmd, "echo") == 0) printf(arg); else if (strcmp(cmd, "check") == 0) { get_idx(); printf("%s\n", poly_valid(pa[idx]) ? "!check: valid" : "!check: INVALID"); } else if (strcmp(cmd, "cleanup") == 0) { int input_idx, output_idx; get_idx_(input_idx); get_idx_(output_idx); printf("!cleanup: %d\n", pcb_polygon_cleanup(pa[input_idx], &pa[output_idx], ('Z' - 'A') - output_idx)); } else fprintf(stderr, "syntax error\n"); } return 0; }