diff --git a/Makefile b/Makefile index d1fcba0..fcc14d2 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ UPLOAD = werner@sita.openmoko.org:public_html/fped/ OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \ unparse.o file.o dump.o kicad.o postscript.o meas.o \ + layer.o overlap.o \ cpp.o lex.yy.o y.tab.o \ gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \ gui_tool.o gui_over.o gui_meas.o gui_frame.o diff --git a/gui_inst.c b/gui_inst.c index f1c28cd..4d59a22 100644 --- a/gui_inst.c +++ b/gui_inst.c @@ -107,7 +107,7 @@ static void draw_arrow(GdkGC *gc, int fill, } -static enum mode get_mode(struct inst *self) +static enum mode get_mode(const struct inst *self) { if (selected_inst == self) return mode_selected; @@ -257,23 +257,26 @@ static void gui_draw_pad_text(struct inst *self) } +static GdkGC *pad_gc(const struct inst *inst) +{ + switch (layers_to_pad_type(inst->u.pad.layers)) { + case pt_bare: + return gc_pad_bare[get_mode(inst)]; + case pt_mask: + return gc_pad_mask[get_mode(inst)]; + default: + return gc_pad[get_mode(inst)]; + } +} + + void gui_draw_pad(struct inst *self) { struct coord min = translate(self->base); struct coord max = translate(self->u.pad.other); GdkGC *gc; - switch (self->obj->u.pad.type) { - case pt_bare: - gc = gc_pad_bare[get_mode(self)]; - break; - case pt_mask: - gc = gc_pad_mask[get_mode(self)]; - break; - default: - gc = gc_pad[get_mode(self)]; - break; - } + gc = pad_gc(self); sort_coord(&min, &max); gdk_draw_rectangle(DA, gc, TRUE, min.x, min.y, max.x-min.x, max.y-min.y); @@ -289,17 +292,7 @@ void gui_draw_rpad(struct inst *self) GdkGC *gc; unit_type h, w, r; - switch (self->obj->u.pad.type) { - case pt_bare: - gc = gc_pad_bare[get_mode(self)]; - break; - case pt_mask: - gc = gc_pad_mask[get_mode(self)]; - break; - default: - gc = gc_pad[get_mode(self)]; - break; - } + gc = pad_gc(self); sort_coord(&min, &max); h = max.y-min.y; w = max.x-min.x; diff --git a/inst.c b/inst.c index d371105..2bb7a7f 100644 --- a/inst.c +++ b/inst.c @@ -18,6 +18,7 @@ #include "util.h" #include "coord.h" #include "expr.h" +#include "layer.h" #include "obj.h" #include "delete.h" #include "gui_util.h" @@ -802,6 +803,7 @@ int inst_pad(struct obj *obj, const char *name, struct coord a, struct coord b) inst->obj = obj; inst->u.pad.name = stralloc(name); inst->u.pad.other = b; + inst->u.pad.layers = pad_type_to_layers(obj->u.pad.type); update_bbox(&inst->bbox, b); propagate_bbox(inst); return 1; diff --git a/inst.h b/inst.h index 8b264f1..a6f7cd5 100644 --- a/inst.h +++ b/inst.h @@ -14,6 +14,7 @@ #ifndef INST_H #define INST_H +#include #include #include "coord.h" @@ -95,6 +96,7 @@ struct inst { struct { char *name; struct coord other; + layer_type layers; /* bit-set of layers */ } pad; struct { unit_type r; diff --git a/kicad.c b/kicad.c index 2c30097..2f058e0 100644 --- a/kicad.c +++ b/kicad.c @@ -20,44 +20,10 @@ #include "kicad.h" -enum kicad_layer { - layer_bottom, /* "copper" */ - layer_l15, - layer_l14, - layer_l13, - layer_l12, - layer_l11, - layer_l10, - layer_l9, - layer_l8, - layer_l7, - layer_l6, - layer_l5, - layer_l4, - layer_l3, - layer_l2, - layer_top, /* "component" */ - layer_glue_bottom, /* adhesive, copper side */ - layer_glue_top, /* adhesive, component side */ - layer_paste_bottom, /* solder paste */ - layer_paste_top, - layer_silk_bottom, /* silk screen */ - layer_silk_top, - layer_mask_bottom, /* solder mask */ - layer_mask_top, - layer_draw, /* general drawing */ - layer_comment, - layer_eco1, - layer_eco2, - layer_edge, /* edge */ -}; - - static void kicad_pad(FILE *file, const struct inst *inst) { struct coord min, max; unit_type tmp; - int layers; min.x = units_to_kicad(inst->base.x); min.y = units_to_kicad(inst->base.y); @@ -87,24 +53,7 @@ static void kicad_pad(FILE *file, const struct inst *inst) /* * Attributes: pad type, N, layer mask */ - layers = 0; - switch (inst->obj->u.pad.type) { - case pt_normal: - layers = 1 << layer_paste_top; - /* fall through */ - case pt_bare: - layers |= (1 << layer_top) | (1 << layer_mask_top); - break; - case pt_paste: - layers = 1 << layer_paste_top; - break; - case pt_mask: - layers = 1 << layer_mask_top; - break; - default: - abort(); - } - fprintf(file, "At SMD N %8.8X\n", layers); + fprintf(file, "At SMD N %8.8X\n", (unsigned) inst->u.pad.layers); /* * Position: Xpos, Ypos diff --git a/layer.c b/layer.c new file mode 100644 index 0000000..2d47f45 --- /dev/null +++ b/layer.c @@ -0,0 +1,56 @@ +/* + * layer.c - PCB layers on a pad + * + * Written 2009 by Werner Almesberger + * Copyright 2009 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 "layer.h" + + +layer_type pad_type_to_layers(enum pad_type type) +{ + layer_type layers = 0; + + switch (type) { + case pt_normal: + layers = LAYER_PASTE; + /* fall through */ + case pt_bare: + layers |= LAYER_COPPER | LAYER_MASK; + break; + case pt_paste: + layers = LAYER_PASTE; + break; + case pt_mask: + layers = LAYER_MASK; + break; + default: + abort(); + } + return layers; +} + + +enum pad_type layers_to_pad_type(layer_type layers) +{ + if (layers & LAYER_COPPER) { + if (layers & LAYER_PASTE) + return pt_normal; + return pt_bare; + } else { + if (layers & LAYER_PASTE) + return pt_paste; + if (layers & LAYER_MASK) + return pt_mask; + abort(); + } +} diff --git a/layer.h b/layer.h new file mode 100644 index 0000000..90b1399 --- /dev/null +++ b/layer.h @@ -0,0 +1,85 @@ +/* + * layer.h - PCB layers on a pad + * + * Written 2009 by Werner Almesberger + * Copyright 2009 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 LAYER_H +#define LAYER_H + +#include + + +typedef uint32_t layer_type; + + +enum kicad_layer { + layer_bottom, /* "copper" */ + layer_l15, + layer_l14, + layer_l13, + layer_l12, + layer_l11, + layer_l10, + layer_l9, + layer_l8, + layer_l7, + layer_l6, + layer_l5, + layer_l4, + layer_l3, + layer_l2, + layer_top, /* "component" */ + layer_glue_bottom, /* adhesive, copper side */ + layer_glue_top, /* adhesive, component side */ + layer_paste_bottom, /* solder paste */ + layer_paste_top, + layer_silk_bottom, /* silk screen */ + layer_silk_top, + layer_mask_bottom, /* solder mask */ + layer_mask_top, + layer_draw, /* general drawing */ + layer_comment, + layer_eco1, + layer_eco2, + layer_edge, /* edge */ +}; + + +enum pad_type { + pt_normal, /* copper and solder mask */ + pt_bare, /* only copper (and finish) */ + pt_paste, /* only solder paste */ + pt_mask, /* only solder mask */ + pt_n +}; + + +/* + * Shorthands for the layers we use in a general sense. + */ + +#define LAYER_COPPER (1 << layer_top) +#define LAYER_PASTE (1 << layer_paste_top) +#define LAYER_MASK (1 << layer_mask_top) + + +/* + * pad_type_to_layers returns the initial set of layers. This set can then be + * modified by overlaying other pads. For display purposes, we translate back + * to the effective pad type with layers_to_pad_type. + * + * What this basically means is that pt_normal becomes pt_bare if its solder + * paste mask has been removed. + */ + +layer_type pad_type_to_layers(enum pad_type type); +enum pad_type layers_to_pad_type(layer_type layers); + +#endif /* !LAYER_H */ diff --git a/obj.h b/obj.h index 4bfddbf..6ea4499 100644 --- a/obj.h +++ b/obj.h @@ -20,6 +20,7 @@ #include "expr.h" #include "coord.h" #include "meas.h" +#include "layer.h" struct var { @@ -139,14 +140,6 @@ enum obj_type { ot_meas, }; -enum pad_type { - pt_normal, /* copper and solder mask */ - pt_bare, /* only copper (and finish) */ - pt_paste, /* only solder paste */ - pt_mask, /* only solder mask */ - pt_n -}; - struct frame_ref { struct frame *ref; int lineno; diff --git a/overlap.c b/overlap.c new file mode 100644 index 0000000..fb9cdca --- /dev/null +++ b/overlap.c @@ -0,0 +1,173 @@ +/* + * overlap.c - Test for overlaps + * + * Written 2009 by Werner Almesberger + * Copyright 2009 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 "coord.h" +#include "obj.h" +#include "inst.h" +#include "overlap.h" + + +/* + * @@@ result may be too optimistic if "b" is arounded pad. + */ + +int inside(const struct inst *a, const struct inst *b) +{ + struct coord min_a, max_a; + struct coord min_b, max_b; + + min_a = a->base; + max_a = a->u.pad.other; + sort_coord(&min_a, &max_a); + + min_b = b->base; + max_b = b->u.pad.other; + sort_coord(&min_b, &max_b); + + return min_a.x >= min_b.x && max_a.x <= max_b.x && + min_a.y >= min_b.y && max_a.y <= max_b.y; +} + + +/* ----- Overlap test for primitives --------------------------------------- */ + + +struct shape { + int circle; + struct coord center; + unit_type r; + struct coord min, max; +}; + + +static int circle_circle_overlap(struct coord c1, unit_type r1, + struct coord c2, unit_type r2) +{ + return dist_point(c1, c2) <= r1+r2; +} + + +static int circle_rect_overlap(struct coord c, unit_type r, + struct coord min, struct coord max) +{ + if (c.x < min.x-r || c.x > max.x+r) + return 0; + if (c.y < min.y-r || c.y > max.y+r) + return 0; + return 1; +} + + +static int rect_rect_overlap(struct coord min1, struct coord max1, + struct coord min2, struct coord max2) +{ + if (max1.x < min2.x || max2.x < min1.x) + return 0; + if (max1.y < min2.y || max2.y < min1.y) + return 0; + return 1; +} + + +static int shapes_overlap(const struct shape *a, const struct shape *b) +{ + if (a->circle && !b->circle) + return shapes_overlap(b, a); + if (a->circle) /* b must be circle, too */ + return circle_circle_overlap(a->center, a->r, b->center, b->r); + if (b->circle) /* a must be rect */ + return circle_rect_overlap(b->center, b->r, a->min, a->max); + return rect_rect_overlap(a->min, a->max, b->min, b->max); +} + + +/* ----- Recursive overlap tester ------------------------------------------ */ + + +static int test_overlap(const struct inst *a, const struct inst *b, + const struct shape *other); + + +static int do_circle(const struct inst *next, const struct shape *other, + unit_type x, unit_type y, unit_type r) +{ + struct shape shape = { + .circle = 1, + .center = { + .x = x, + .y = y, + }, + .r = r, + }; + + if (next) + return test_overlap(next, NULL, &shape); + return shapes_overlap(other, &shape); +} + + +static int do_rect(const struct inst *next, const struct shape *other, + unit_type x, unit_type y, unit_type w, unit_type h) +{ + struct shape shape = { + .circle = 0, + .min = { + .x = x, + .y = y, + }, + .max = { + .x = x+w, + .y = y+w, + }, + }; + + if (next) + return test_overlap(next, NULL, &shape); + return shapes_overlap(other, &shape); +} + + +static int test_overlap(const struct inst *a, const struct inst *b, + const struct shape *other) +{ + struct coord min, max; + unit_type h, w, r; + + min = a->base; + max = a->u.pad.other; + sort_coord(&min, &max); + + h = max.y-min.y; + w = max.x-min.x; + + if (!a->obj->u.pad.rounded) + return do_rect(b, other, min.x, min.y, w, h); + + if (h > w) { + r = w/2; + return do_circle(b, other, min.x+r, max.y-r, r) || + do_rect(b, other, min.x, min.y+r, w, h-2*r) || + do_circle(b, other, min.x+r, min.y+r, r); + } else { + r = h/2; + return do_circle(b, other, min.x+r, max.y+r, r) || + do_rect(b, other, min.x+r, min.y, w-2*r, h) || + do_circle(b, other, min.x-r, min.y+r, r); + } +} + + +int overlap(const struct inst *a, const struct inst *b) +{ + return test_overlap(a, b, NULL); +} diff --git a/overlap.h b/overlap.h new file mode 100644 index 0000000..78ce565 --- /dev/null +++ b/overlap.h @@ -0,0 +1,32 @@ +/* + * overlap.h - Test for overlaps + * + * Written 2009 by Werner Almesberger + * Copyright 2009 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 OVERLAP_H +#define OVERLAP_H + +#include "inst.h" + + +/* + * "inside" returns 1 if "a" is completely enclosed by "b". If "a" == "b", + * that also counts as "a" being inside "b". + */ + +int inside(const struct inst *a, const struct inst *b); + +/* + * "overlap" returns 1 if "a" and "b" have at least one point in common. + */ + +int overlap(const struct inst *a, const struct inst *b); + +#endif /* !OVERLAP_H */ diff --git a/postscript.c b/postscript.c index e88e111..9a04d67 100644 --- a/postscript.c +++ b/postscript.c @@ -16,6 +16,7 @@ #include "util.h" #include "coord.h" +#include "layer.h" #include "obj.h" #include "inst.h" #include "unparse.h" @@ -189,9 +190,9 @@ static void ps_pad_name(FILE *file, const struct inst *inst) } -static const char *hatch(enum pad_type type) +static const char *hatch(layer_type layers) { - switch (type) { + switch (layers_to_pad_type(layers)) { case pt_normal: return "crosspath"; case pt_bare: @@ -217,7 +218,7 @@ static void ps_pad(FILE *file, const struct inst *inst, int show_name) fprintf(file, " %d %d lineto\n", b.x, b.y); fprintf(file, " %d %d lineto\n", a.x, b.y); fprintf(file, " closepath gsave %s grestore stroke\n", - hatch(inst->obj->u.pad.type)); + hatch(inst->u.pad.layers)); if (show_name) ps_pad_name(file, inst); @@ -248,7 +249,7 @@ static void ps_rpad(FILE *file, const struct inst *inst, int show_name) fprintf(file, " %d %d %d 90 270 arc\n", a.x+r, a.y+r, r); } fprintf(file, " closepath gsave %s grestore stroke\n", - hatch(inst->obj->u.pad.type)); + hatch(inst->u.pad.layers)); if (show_name) ps_pad_name(file, inst);