/* * lib.c - Parse Eeschema .lib file * * 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 #include #include "util.h" #include "misc.h" #include "style.h" #include "fig.h" #include "text.h" #include "sch.h" #include "lib.h" enum text_style { text_normal, }; struct obj { enum obj_type { obj_poly, obj_rect, obj_circ, obj_arc, obj_text, obj_pin, } type; unsigned unit; unsigned convert; union { struct poly_obj { int thick; char fill; int points; int *x; int *y; } poly; struct rect_obj { int thick; char fill; int sx, sy; int ex, ey; } rect; struct circ_obj { int x, y; int r; int thick; char fill; } circ; struct arc_obj { int x, y; int r; int start_a, end_a; int thick; char fill; } arc; struct text_obj { int orient; int x, y; int dim; char *s; enum text_style style; char hor_align; char vert_align; } text; struct pin_obj { char *name; char *number; int x, y; int length; char orient; int number_size; int name_size; char etype; // @@@ shape } pin; } u; struct obj *next; }; /* ----- Drawing ----------------------------------------------------------- */ static struct comp *comps = NULL; static struct comp *curr_comp; /* current component */ static struct comp **next_comp = &comps; static struct obj **next_obj; static void draw_poly(const struct poly_obj *poly, int m[6]) { int n = poly->points; int x[n]; int y[n]; int i; for (i = 0; i != n; i++) { x[i] = mx(poly->x[i], poly->y[i], m); y[i] = my(poly->x[i], poly->y[i], m); } fig_poly(n, x, y, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG); switch (poly->fill) { case 'N': break; case 'F': fig_poly(n, x, y, COLOR_NONE, COLOR_COMP_DWG, LAYER_COMP_DWG_BG); break; case 'f': fig_poly(n, x, y, COLOR_NONE, COLOR_COMP_DWG_BG, LAYER_COMP_DWG_BG); break; default: abort(); } } static void draw_rect(const struct rect_obj *rect, int m[6]) { int sx = mx(rect->sx, rect->sy, m); int sy = my(rect->sx, rect->sy, m); int ex = mx(rect->ex, rect->ey, m); int ey = my(rect->ex, rect->ey, m); fig_rect(sx, sy, ex, ey, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG); switch (rect->fill) { case 'N': break; case 'F': fig_rect(sx, sy, ex, ey, COLOR_NONE, COLOR_COMP_DWG, LAYER_COMP_DWG_BG); break; case 'f': fig_rect(sx, sy, ex, ey, COLOR_NONE, COLOR_COMP_DWG_BG, LAYER_COMP_DWG_BG); break; default: abort(); } } static void draw_circ(const struct circ_obj *circ, int m[6]) { int x = mx(circ->x, circ->y, m); int y = my(circ->x, circ->y, m); int r = circ->r; fig_circ(x, y, r, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG); switch (circ->fill) { case 'N': break; case 'F': fig_circ(x, y, r, COLOR_NONE, COLOR_COMP_DWG, LAYER_COMP_DWG_BG); break; case 'f': fig_circ(x, y, r, COLOR_NONE, COLOR_COMP_DWG_BG, LAYER_COMP_DWG_BG); break; default: abort(); } } static void draw_arc(const struct arc_obj *arc, int m[6]) { int a = matrix_to_angle(m); int x = mx(arc->x, arc->y, m); int y = my(arc->x, arc->y, m); int sa = angle_add(arc->start_a, a); int ea = angle_add(arc->end_a, a); fig_arc(x, y, arc->r, sa, ea, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG); assert(arc->fill == 'N'); } static void draw_pin_name(const struct comp *comp, const struct pin_obj *pin, int m[6], int dx, int dy, int rot, enum text_align hor) { int ox, oy, sx, sy; if (comp->name_offset) { ox = dx * (pin->length + comp->name_offset); oy = dy * (pin->length + comp->name_offset); sx = sy = 0; } else { ox = dx * pin->length / 2; oy = dy * pin->length / 2; sx = mxr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m); sy = myr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m); if (sx > 0) sx = -sx; if (sy > 0) sy = -sy; } struct text txt = { .s = pin->name, .x = mx(pin->x + ox, pin->y + oy, m) + sx, .y = my(pin->x + ox, pin->y + oy, m) + sy, .size = pin->name_size, .rot = rot, .hor = comp->name_offset ? hor : text_mid, .vert = comp->name_offset ? text_mid : text_min, }; text_rot(&txt, matrix_to_angle(m)); if (matrix_is_mirrored(m)) { if ((txt.rot % 180) == 0) txt.hor = text_flip(txt.hor); else txt.vert = text_flip(txt.vert); } switch (txt.rot) { case 180: case 270: text_flip_x(&txt); break; default: break; } text_fig(&txt, COLOR_PIN_NAME, LAYER_PIN_NAME); } static void draw_pin_num(const struct comp *comp, const struct pin_obj *pin, int m[6], int dx, int dy, int rot, enum text_align hor) { int ox, oy, sx, sy; ox = dx * pin->length / 2; oy = dy * pin->length / 2; sx = mxr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m); sy = myr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m); if (sx > 0) sx = -sx; if (sy > 0) sy = -sy; if (!comp->name_offset) { sx = -sx; sy = -sy; } struct text txt = { .s = pin->number, .x = mx(pin->x + ox, pin->y + oy, m) + sx, .y = my(pin->x + ox, pin->y + oy, m) + sy, .size = pin->number_size, .rot = rot, .hor = text_mid, .vert = comp->name_offset ? text_min : text_max, }; text_rot(&txt, matrix_to_angle(m) % 180); if (matrix_is_mirrored(m)) { switch (txt.rot) { case 0: txt.hor = text_flip(txt.hor); break; case 90: break; case 180: txt.hor = text_flip(txt.hor); break; case 270: break; } } switch (txt.rot) { case 180: case 270: text_flip_x(&txt); break; default: break; } text_fig(&txt, COLOR_PIN_NUMBER, LAYER_PIN_NUMBER); } static void draw_pin(const struct comp *comp, const struct pin_obj *pin, int m[6]) { int x[2], y[2]; int dx = 0, dy = 0; int rot; enum text_align hor; switch (pin->orient) { case 'U': dy = 1; rot = 90; hor = text_min; break; case 'D': dy = -1; rot = 90; hor = text_max; break; case 'R': dx = 1; rot = 0; hor = text_min; break; case 'L': dx = -1; rot = 0; hor = text_max; break; default: abort(); } x[0] = mx(pin->x, pin->y, m); y[0] = my(pin->x, pin->y, m); x[1] = mx(pin->x + dx * pin->length, pin->y + dy * pin->length, m); y[1] = my(pin->x + dx * pin->length, pin->y + dy * pin->length, m); fig_poly(2, x, y, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG); if (comp->show_pin_name) draw_pin_name(comp, pin, m, dx, dy, rot, hor); if (comp->show_pin_num) draw_pin_num(comp, pin, m, dx, dy, rot, hor); } static void draw_text(const struct text_obj *text, int m[6]) { struct text txt = { .s = text->s, .size = text->dim, .x = mx(text->x, text->y, m), .y = my(text->x, text->y, m), .rot = angle_add(text->orient / 10, matrix_to_angle(m)), }; decode_alignment(&txt, text->hor_align, text->vert_align); switch (txt.rot) { case 180: case 270: text_flip_x(&txt); break; default: break; } text_fig(&txt, COLOR_COMP_DWG, WIDTH_COMP_DWG); } static void draw(const struct comp *comp, const struct obj *obj, int m[6]) { switch (obj->type) { case obj_poly: draw_poly(&obj->u.poly, m); break; case obj_rect: draw_rect(&obj->u.rect, m); break; case obj_circ: draw_circ(&obj->u.circ, m); break; case obj_arc: draw_arc(&obj->u.arc, m); break; case obj_text: draw_text(&obj->u.text, m); break; case obj_pin: draw_pin(comp, &obj->u.pin, m); break; default: abort(); } } const struct comp *lib_find(const char *name) { const struct comp *comp; for (comp = comps; comp; comp = comp->next) if (!strcmp(comp->name, name)) return comp; fprintf(stderr, "\"%s\" not found\n", name); exit(1); } bool lib_field_visible(const struct comp *comp, int n) { return (comp->visible >> n) & 1; } void lib_exec(const struct comp *comp, unsigned unit, int m[4]) { const struct obj *obj; if (!unit) unit = 1; for (obj = comp->objs; obj; obj = obj->next) { if (obj->unit && obj->unit != unit) continue; draw(comp, obj, m); } } /* ----- Text -------------------------------------------------------------- */ static enum text_style decode_style(const char *s) { if (!strcmp(s, "Normal")) return text_normal; assert(0); } /* ----- Polygons ---------------------------------------------------------- */ static bool parse_poly(struct poly_obj *poly, const char *line, int points) { int i, n; poly->points = points; poly->x = alloc_size(sizeof(int) * points); poly->y = alloc_size(sizeof(int) * points); for (i = 0; i != points; i++) { if (sscanf(line, "%d %d %n", poly->x + i, poly->y + i, &n) != 2) return 0; line += n; } if (sscanf(line, "%c", &poly->fill) != 1) return 0; return 1; } /* ----- Definitions ------------------------------------------------------- */ static bool parse_def(const char *line) { char *s; char draw_num, draw_name; unsigned name_offset; unsigned units; if (sscanf(line, "DEF %ms %*s %*d %u %c %c %u", &s, &name_offset, &draw_num, &draw_name, &units) != 5) return 0; curr_comp = alloc_type(struct comp); if (*s == '~') s++; curr_comp->name = s; curr_comp->units = units; curr_comp->visible = 0; curr_comp->show_pin_name = draw_name == 'Y'; curr_comp->show_pin_num = draw_num == 'Y'; curr_comp->name_offset = name_offset; curr_comp->objs = NULL; next_obj = &curr_comp->objs; curr_comp->next = NULL; *next_comp = curr_comp; next_comp = &curr_comp->next; return 1; } /* ----- Arcs -------------------------------------------------------------- */ static bool parse_arc(struct obj *obj, const char *line) { struct arc_obj *arc = &obj->u.arc; int a1, a2; if (sscanf(line, "A %d %d %d %d %d %u %u %u %c", &arc->x, &arc->y, &arc->r, &a1, &a2, &obj->unit, &obj->convert, &arc->thick, &arc->fill) != 9) return 0; /* * KiCad arcs can be clockwise or counter-clockwise. They must always * be smaller than 180 degrees. */ while (a1 < 0) a1 += 3600; while (a2 < 0) a2 += 3600; a1 %= 3600; a2 %= 3600; if (a2 < a1) a2 += 3600; assert(a2 - a1 != 1800); if (a2 - a1 > 1800) swap(a1, a2); arc->start_a = (a1 % 3600) / 10; arc->end_a = (a2 % 3600) / 10; return 1; } /* ----- Library parser ---------------------------------------------------- */ bool lib_parse(struct lib_ctx *ctx, const char *line) { int n = 0; unsigned points; struct obj *obj; char *style; unsigned zero1, zero2; char vis; ctx->lineno++; switch (ctx->state) { case lib_skip: if (parse_def(line)) { ctx->state = lib_def; return 1; } return 1; case lib_def: if (sscanf(line, "DRAW%n", &n) == 0 && n) { ctx->state = lib_draw; return 1; } if (sscanf(line, "F%d \"\" %*d %*d %*d %*c %c", &n, &vis) == 2 || sscanf(line, "F%d \"%*[^\"]\" %*d %*d %*d %*c %c", &n, &vis) == 2) { if (vis == 'V') curr_comp->visible |= 1 << n; return 1; } /* @@@ explicitly ignore FPLIST */ return 1; case lib_draw: if (sscanf(line, "ENDDRAW%n", &n) == 0 && n) { ctx->state = lib_skip; return 1; } obj = alloc_type(struct obj); obj->next = NULL; *next_obj = obj; next_obj = &obj->next; if (sscanf(line, "P %u %u %u %u %n", &points, &obj->unit, &obj->convert, &obj->u.poly.thick, &n) == 4) { obj->type = obj_poly; if (parse_poly(&obj->u.poly, line + n, points)) return 1; break; } if (sscanf(line, "S %d %d %d %d %u %u %d %c", &obj->u.rect.sx, &obj->u.rect.sy, &obj->u.rect.ex, &obj->u.rect.ey, &obj->unit, &obj->convert, &obj->u.rect.thick, &obj->u.rect.fill) == 8) { obj->type = obj_rect; return 1; } if (sscanf(line, "C %d %d %d %u %u %d %c", &obj->u.circ.x, &obj->u.circ.y, &obj->u.circ.r, &obj->unit, &obj->convert, &obj->u.circ.thick, &obj->u.circ.fill) == 7) { obj->type = obj_circ; return 1; } if (parse_arc(obj, line)) { obj->type = obj_arc; return 1; } n = sscanf(line, "T %d %d %d %d %u %u %u \"%m[^\"]\" %ms %u %c %c", &obj->u.text.orient, &obj->u.text.x, &obj->u.text.y, &obj->u.text.dim, &zero1, &obj->unit, &obj->convert, &obj->u.text.s, &style, &zero2, &obj->u.text.hor_align, &obj->u.text.vert_align); if (n != 12) { n = sscanf(line, "T %d %d %d %d %u %u %u %ms %ms %u %c %c", &obj->u.text.orient, &obj->u.text.x, &obj->u.text.y, &obj->u.text.dim, &zero1, &obj->unit, &obj->convert, &obj->u.text.s, &style, &zero2, &obj->u.text.hor_align, &obj->u.text.vert_align); while (n == 12) { char *tilde; tilde = strchr(obj->u.text.s, '~'); if (!tilde) break; *tilde = ' '; } } /* * zero2 seems to be the font style: 0 = normal, 1 = bold ? */ if (n == 12) { if (zero1) { fprintf(stderr, "%u: only understand 0 x x\n" "\"%s\"\n", ctx->lineno, line); exit(1); } obj->u.text.style = decode_style(style); obj->type = obj_text; return 1; } if (sscanf(line, "X %ms %ms %d %d %d %c %d %d %u %u %c", &obj->u.pin.name, &obj->u.pin.number, &obj->u.pin.x, &obj->u.pin.y, &obj->u.pin.length, &obj->u.pin.orient, &obj->u.pin.number_size, &obj->u.pin.name_size, &obj->unit, &obj->convert, &obj->u.pin.etype) == 11) { obj->type = obj_pin; return 1; } break; default: abort(); } fprintf(stderr, "%u: cannot parse\n\"%s\"\n", ctx->lineno, line); exit(1); } void lib_init(struct lib_ctx *ctx) { ctx->state = lib_skip; ctx->lineno = 0; }