diff --git a/eeshow/Makefile b/eeshow/Makefile index 02e0b11..5a65a8b 100644 --- a/eeshow/Makefile +++ b/eeshow/Makefile @@ -16,6 +16,7 @@ NAME = eeshow OBJS = main.o version.o \ kicad/sch-parse.o kicad/sch-render.o kicad/lib-parse.o \ kicad/lib-render.o kicad/dwg.o kicad/delta.o kicad/sexpr.o \ + kicad/pl-parse.o kicad/pl-render.o \ gui/gui.o gui/over.o gui/style.o gui/aoi.o gui/fmt-pango.o gui/input.o \ gui/progress.o gui/glabel.o gui/sheet.o gui/history.o gui/render.o \ gui/help.o gui/icons.o \ diff --git a/eeshow/kicad/pl-parse.c b/eeshow/kicad/pl-parse.c new file mode 100644 index 0000000..b8376f5 --- /dev/null +++ b/eeshow/kicad/pl-parse.c @@ -0,0 +1,304 @@ +/* + * kicad/pl-parse.c - KiCad page layout parser + * + * Written 2016 by Werner Almesberger + * Copyright 2016 by Werner Almesberger + * + * 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. + */ + + +#include +#include +#include + +#include "misc/util.h" +#include "misc/diag.h" +#include "file/file.h" +#include "kicad/sexpr.h" +#include "kicad/pl-common.h" +#include "kicad/pl.h" + + +static bool get_coord(const struct expr *e, + float *x, float *y, int *dx, int *dy) +{ + unsigned n = 0; + + *dx = -1; + *dy = -1; + for (; e; e = e->next) { + if (e->e) + continue; + if (!strcmp(e->s, "ltcorner")) { + *dx = *dy = 1; + } else if (!strcmp(e->s, "lbcorner")) { + *dx = 1; + *dy = -1; + } else if (!strcmp(e->s, "rtcorner")) { + *dx = -1; + *dy = 1; + } else if (!strcmp(e->s, "rbcorner")) { + *dx = *dy = -1; + } else { + char *end; + float f = strtof(e->s, &end); + + if (*end) { + error("no a number \"%s\"\n", e->s); + return 0; + } + if (n++) + *y = f; + else + *x = f; + } + } + + switch (n) { + case 0: + case 1: + error("no enough coordinates\n"); + return 0; + case 2: + return 1; + default: + error("too many coordinates\n"); + return 0; + } +} + + +static bool get_float(const struct expr *e, float *f) +{ + for (; e; e = e->next) + if (e->s) { + *f = atof(e->s); // @@@ error checking + return 1; + } + error("no number found\n"); + return 0; +} + + + +static bool get_int(const struct expr *e, int *n) +{ + for (; e; e = e->next) + if (e->s) { + *n = atoi(e->s); // @@@ error checking + return 1; + } + error("no number found\n"); + return 0; +} + + +static bool process_setup(struct pl_ctx *p, const struct expr *e) +{ + const char *s; + const struct expr *next; + + for (; e; e = e->next) { + if (!e->e) { + warning("ignoring non-list\n"); + continue; + } + + s = e->e->s; + next = e->e->next; + + if (!strcmp(s, "comment")) + continue; + + if (!strcmp(s, "textsize")) { + // meh + } else if (!strcmp(s, "linewidth")) { + // meh + } else if (!strcmp(s, "textlinewidth")) { + // meh + } else if (!strcmp(s, "left_margin")) { + if (!get_float(next, &p->l)) + return 0; + } else if (!strcmp(s, "right_margin")) { + if (!get_float(next, &p->r)) + return 0; + } else if (!strcmp(s, "top_margin")) { + if (!get_float(next, &p->t)) + return 0; + } else if (!strcmp(s, "bottom_margin")) { + if (!get_float(next, &p->b)) + return 0; + } else { + warning("ignoring \"%s\"\n", s); + } + } + return 1; +} + + +static bool process_obj(struct pl_ctx *pl, const struct expr *e, + enum pl_obj_type type) +{ + struct pl_obj *obj; + const char *s; + const struct expr *next; + + obj = alloc_type(struct pl_obj); + obj->type = type; + obj->s = NULL; + obj->repeat = 1; + obj->x = obj->y = obj->ex = obj->ey = 0; + obj->dx = obj->dy = 0; + obj->incrx = 0; + obj->incry = 0; + obj->incrlabel = 0; + + for (; e; e = e->next) { + if (!e->e) { + warning("ignoring non-list\n"); + continue; + } + + s = e->e->s; + next = e->e->next; + + if (!strcmp(s, "comment")) + continue; + if (!strcmp(s, "name")) + continue; + + if (!strcmp(s, "linewidth")) { + // meh + } else if (!strcmp(s, "start") || !strcmp(s, "pos")) { + if (!get_coord(next, &obj->x, &obj->y, + &obj->dx, &obj->dy)) + return 0; + } else if (!strcmp(s, "end")) { + if (!get_coord(next, &obj->ex, &obj->ey, + &obj->edx, &obj->edy)) + return 0; + } else if (!strcmp(s, "repeat")) { + if (!get_int(next, &obj->repeat)) + return 0; + } else if (!strcmp(s, "incrx")) { + if (!get_float(next, &obj->incrx)) + return 0; + } else if (!strcmp(s, "incry")) { + if (!get_float(next, &obj->incry)) + return 0; + } else if (!strcmp(s, "incrlabel")) { + if (!get_int(next, &obj->incrlabel)) + return 0; + } else + warning("ignoring \"%s\"\n", s); + } + + obj->next = pl->objs; + pl->objs = obj; + + return 1; +} + + +static bool process_layout(struct pl_ctx *pl, const struct expr *e) +{ + const char *s; + const struct expr *next; + + for (; e; e = e->next) { + if (!e->e) { + warning("ignoring non-list\n"); + continue; + } + + s = e->e->s; + next = e->e->next; + + if (!strcmp(s, "comment")) + continue; + if (!strcmp(s, "setup")) { + if (!process_setup(pl, next)) + return 0; + } else if (!strcmp(s, "rect")) { + if (!process_obj(pl, next, pl_obj_rect)) + return 0; + } else if (!strcmp(s, "line")) { + if (!process_obj(pl, next, pl_obj_line)) + return 0; + } else if (!strcmp(s, "tbtext")) { + if (!process_obj(pl, next, pl_obj_text)) + return 0; + } else { + warning("ignoring \"%s\"\n", s); + } + } + return 1; +} + + +static bool process(struct pl_ctx *p, const struct expr *e) +{ + while (e) { + if (e->e && e->e->s && !strcmp(e->e->s, "page_layout") && + e->e->next && e->e->next->e) + return process_layout(p, e->e->next); + e = e->next; + } + error("no layout information found\n"); + return 0; +} + + +static bool pl_parse_line(const struct file *file, + void *user, const char *line) +{ + struct pl_ctx *pl = user; + + return sexpr_parse(pl->sexpr_ctx, line); +} + + +struct pl_ctx *pl_parse(struct file *file) +{ + struct pl_ctx *pl; + struct expr *e = NULL; + + pl = alloc_type(struct pl_ctx); + pl->sexpr_ctx = sexpr_new(); + pl->l = pl->r = pl->t = pl->b = 0; + pl->objs = NULL; + + if (!file_read(file, pl_parse_line, pl)) { + sexpr_abort(pl->sexpr_ctx); + goto fail; + } + if (!sexpr_finish(pl->sexpr_ctx, &e)) + goto fail; + if (!process(pl, e)) + goto fail; + free_expr(e); + return pl; + +fail: + free_expr(e); + free(pl); + return 0; +} + + +void pl_free(struct pl_ctx *pl) +{ + struct pl_obj *next; + + while (pl->objs) { + next = pl->objs->next; + free((void *) pl->objs->s); + free(pl->objs); + pl->objs = next; + } + free(pl); +} diff --git a/eeshow/kicad/pl-render.c b/eeshow/kicad/pl-render.c new file mode 100644 index 0000000..a6723cd --- /dev/null +++ b/eeshow/kicad/pl-render.c @@ -0,0 +1,104 @@ +/* + * kicad/pl-render.c - RenderKiCad page layout + * + * Written 2016 by Werner Almesberger + * Copyright 2016 by Werner Almesberger + * + * 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. + */ + + +#include +#include +#include + +#include "misc/util.h" +#include "misc/diag.h" +#include "gfx/style.h" +#include "gfx/gfx.h" +#include "kicad/pl-common.h" +#include "kicad/pl.h" + + +/* + * Eeschema works in mil + * Page layouts are in mm + */ + + +static int mil(float mm) +{ + return mm / 25.4 * 1000; +} + + +static int cx(int x, int dx, int xo, int xe) +{ + return dx >= 0 ? xo + x : xe - x; +} + + +static int cy(int y, int dy, int yo, int ye) +{ + return dy >= 0 ? yo + y : ye - y; +} + + +static void render_obj(const struct pl_ctx *pl, const struct pl_obj *obj, + unsigned i, int w, int h) +{ + int xo = mil(pl->l); + int yo = mil(pl->r); + int xe = w - mil(pl->t); + int ye = h - mil(pl->b); + int x = mil(obj->x + i * obj->incrx); + int y = mil(obj->y + i * obj->incry); + int ex = mil(obj->ex + i * obj->incrx); + int ey = mil(obj->ey + i * obj->incry); + int ww = xe - xo; + int hh = ye - yo; + + if (x < 0 || y < 0 || ex < 0 || ey < 0) + return; + if (x > ww || y > hh || ex > ww || ey > hh) + return; + + switch (obj->type) { + case pl_obj_rect: + gfx_rect( + cx(x, obj->dx, xo, xe), cy(y, obj->dy, yo, ye), + cx(ex, obj->edx, xo, xe), cy(ey, obj->edy, yo, ye), + COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG); + break; + case pl_obj_line: { + int vx[] = { + cx(x, obj->dx, xo, xe), + cx(ex, obj->edx, xo, xe) + }; + int vy[] = { + cy(y, obj->dy, yo, ye), + cy(ey, obj->edy, yo, ye) + }; + + gfx_poly(2, vx, vy, + COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG); + } + break; + default: + break; + } +} + + +void pl_render(struct pl_ctx *pl, int w, int h) +{ + const struct pl_obj *obj; + int i; + + for (obj = pl->objs; obj; obj = obj->next) + for (i = 0; i != obj->repeat; i++) + render_obj(pl, obj, i, w, h); +} diff --git a/eeshow/kicad/pl.h b/eeshow/kicad/pl.h new file mode 100644 index 0000000..74c71d3 --- /dev/null +++ b/eeshow/kicad/pl.h @@ -0,0 +1,28 @@ +/* + * kicad/pl.h - KiCad page layout + * + * Written 2016 by Werner Almesberger + * Copyright 2016 by Werner Almesberger + * + * 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. + */ + + +#ifndef KICAD_PL_H +#define KICAD_PL_H + +#include "file/file.h" + + +struct pl_ctx; + + +void pl_render(struct pl_ctx *pl, int w, int h); + +struct pl_ctx *pl_parse(struct file *file); +void pl_free(struct pl_ctx *pl); + +#endif /* !KICAD_PL_H */