From d046f9306c326a17e730780f1dfe534052bb955a Mon Sep 17 00:00:00 2001 From: werner Date: Fri, 7 Aug 2009 13:37:51 +0000 Subject: [PATCH] - fpd.y: fixed check for empty part name - added new-style measurements (experimental) git-svn-id: http://svn.openmoko.org/trunk/eda/fped@5400 99fdad57-331a-0410-800a-d7fa5415bdb3 --- Makefile | 2 +- README | 42 ++++++++++++ fpd.l | 12 ++++ fpd.y | 127 +++++++++++++++++++++++++++++++++-- gui_inst.c | 42 +++++++++--- inst.c | 18 +++-- inst.h | 6 +- meas.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++ meas.fpd | 24 +++++++ meas.h | 46 +++++++++++++ obj.c | 11 ++- obj.h | 9 ++- sc89.fpd | 14 ++-- 13 files changed, 511 insertions(+), 35 deletions(-) create mode 100644 meas.c create mode 100644 meas.fpd create mode 100644 meas.h diff --git a/Makefile b/Makefile index b1d0672..7483df3 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ # OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \ - unparse.o dump.o \ + unparse.o dump.o meas.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_tools.o diff --git a/README b/README index 1edc104..eaea297 100644 --- a/README +++ b/README @@ -427,3 +427,45 @@ To delete an object, select it and press Delete. Deleted objects can be undeleted by pressing "u". If any other changes have been made since deletion, fped may misbehave. If deleting a vector, all items that reference it are deleted. + + +Experimental: new-style measurements +------------------------------------ + +New-style measurements can measure the distance between various pairs +of points, not only between points in the same instance and the same +frame. They operate on the set of points produced during instantiation. + +New-style measurements are placed in the root frame after all other +items. + +Known issues: +- they are currently not dumped and they can't be entered or edited + through the GUI +- + +Syntax: + + + +Types: +- measxy: measure diagonally +- measx: measure along the X axis +- measy: measure along the y axis + +Note that the type also affects the selection of the points. E.g., +measx will select maximum x values. + +Operators: +- A -> B: smallest value of A and smallest B greater than A +- A <- B: like A -> B, but normal (for offset and text) is inverted +- A >> B: smallest value of A and greatest value of B +- A << B: like A -> B, but normal (for offset and text) is inverted + +Operands are qualified vector names. Vectors in the root frame are +referenced by their name. Vectors in other frames are prefixed with +the name of the frame followed by a dot. + +Example: + +measx pad.sw -> pad.se 1mm diff --git a/fpd.l b/fpd.l index cdff32d..90a6656 100644 --- a/fpd.l +++ b/fpd.l @@ -18,6 +18,7 @@ #include "coord.h" #include "expr.h" #include "error.h" +#include "meas.h" #include "y.tab.h" @@ -94,6 +95,12 @@ SP [\t ]* return TOK_ARC; } "meas" { BEGIN(NOKEYWORD); return TOK_MEAS; } +"measxy" { BEGIN(NOKEYWORD); + return TOK_MEASXY; } +"measx" { BEGIN(NOKEYWORD); + return TOK_MEASX; } +"measy" { BEGIN(NOKEYWORD); + return TOK_MEASY; } [a-zA-Z_][a-zA-Z_0-9]*: { *strchr(yytext, ':') = 0; yylval.id = unique(yytext); @@ -118,6 +125,11 @@ SP [\t ]* yylval.str = stralloc(yytext+1); return STRING; } +"->" return TOK_NEXT; +"<-" return TOK_NEXT_INVERTED; +">>" return TOK_MAX; +"<<" return TOK_MAX_INVERTED; + {SP} ; \n { if (!disable_keywords) BEGIN(INITIAL); diff --git a/fpd.y b/fpd.y index fee92c9..b336628 100644 --- a/fpd.y +++ b/fpd.y @@ -18,6 +18,7 @@ #include "error.h" #include "expr.h" #include "obj.h" +#include "meas.h" extern struct expr *expr_result; @@ -48,11 +49,11 @@ static struct frame *find_frame(const char *name) } -static struct vec *find_vec(const char *name) +static struct vec *find_vec(const struct frame *frame, const char *name) { struct vec *v; - for (v = curr_frame->vecs; v; v = v->next) + for (v = frame->vecs; v; v = v->next) if (v->name == name) return v; return NULL; @@ -140,12 +141,20 @@ static struct obj *new_obj(enum obj_type type) struct value *value; struct vec *vec; struct obj *obj; + struct meas *meas; + enum meas_type mt; + struct { + int inverted; + int max; + } mo; }; %token START_FPD START_EXPR %token TOK_SET TOK_LOOP TOK_PART TOK_FRAME TOK_TABLE TOK_VEC -%token TOK_PAD TOK_RECT TOK_LINE TOK_CIRC TOK_ARC TOK_MEAS +%token TOK_PAD TOK_RECT TOK_LINE TOK_CIRC TOK_ARC +%token TOK_MEAS TOK_MEASXY TOK_MEASX TOK_MEASY +%token TOK_NEXT TOK_NEXT_INVERTED TOK_MAX TOK_MAX_INVERTED %token NUMBER %token STRING @@ -155,9 +164,13 @@ static struct obj *new_obj(enum obj_type type) %type vars var %type rows %type row value -%type vec base +%type vec base qbase %type obj %type expr opt_expr add_expr mult_expr unary_expr primary_expr +%type measurements meas +%type opt_string +%type meas_type +%type meas_op %% @@ -191,7 +204,7 @@ part_name: { const char *p; - if (!*p) { + if (!*$2) { yyerrorf("invalid part name"); YYABORT; } @@ -232,6 +245,10 @@ frame_def: ; frame_items: + measurements + { + measurements = $1; + } | frame_item frame_items ; @@ -248,7 +265,7 @@ frame_item: | vec | LABEL vec { - if (find_vec($1)) { + if (find_vec(curr_frame, $1)) { yyerrorf("duplicate vector \"%s\"", $1); YYABORT; } @@ -370,6 +387,7 @@ vec: $$->y = $6; $$->frame = curr_frame; $$->next = NULL; + $$->samples = NULL; last_vec = $$; *next_vec = $$; next_vec = &$$->next; @@ -391,7 +409,7 @@ base: } | ID { - $$ = find_vec($1); + $$ = find_vec(curr_frame, $1); if (!$$) { yyerrorf("unknown vector \"%s\"", $1); YYABORT; @@ -463,6 +481,101 @@ obj: } ; +measurements: + { + $$ = NULL; + } + | meas measurements + { + $$ = $1; + $$->next = $2; + } + ; + +meas: + meas_type opt_string qbase meas_op qbase expr + { + $$ = alloc_type(struct meas); + $$->type = $4.max ? $1+3 : $1; + $$->label = $2; + $$->low = $3; + $$->inverted = $4.inverted; + $$->high = $5; + $$->offset = $6; + $$->next = NULL; + } + ; + +qbase: + ID + { + $$ = find_vec(root_frame, $1); + if (!$$) { + yyerrorf("unknown vector \"%s\"", $1); + YYABORT; + } + } + | ID '.' ID + { + const struct frame *frame; + + frame = find_frame($1); + $$ = frame ? find_vec(frame, $3) : NULL; + if (!$$) { + yyerrorf("unknown vector \"%s.%s\"", $1, $3); + YYABORT; + } + } + ; + +meas_type: + TOK_MEASXY + { + $$ = mt_xy_next; + } + | TOK_MEASX + { + $$ = mt_x_next; + } + | TOK_MEASY + { + $$ = mt_y_next; + } + ; + +meas_op: + TOK_NEXT + { + $$.max = 0; + $$.inverted = 0; + } + | TOK_NEXT_INVERTED + { + $$.max = 0; + $$.inverted = 1; + } + | TOK_MAX + { + $$.max = 1; + $$.inverted = 0; + } + | TOK_MAX_INVERTED + { + $$.max = 1; + $$.inverted = 1; + } + ; + +opt_string: + { + $$ = NULL; + } + | STRING + { + $$ = $1; + } + ; + opt_expr: { $$ = NULL; diff --git a/gui_inst.c b/gui_inst.c index 5a9ee0e..c56ba8e 100644 --- a/gui_inst.c +++ b/gui_inst.c @@ -16,6 +16,7 @@ #include #include "util.h" +#include "coord.h" #include "inst.h" #include "gui.h" #include "gui_util.h" @@ -329,13 +330,12 @@ void gui_draw_arc(struct inst *self, struct draw_ctx *ctx) /* ----- meas -------------------------------------------------------------- */ -static struct coord offset_vec(const struct inst *self) +static struct coord offset_vec(struct coord a, struct coord b, + const struct inst *self) { - struct coord a, b, res; + struct coord res; double f; - a = self->base; - b = self->u.meas.end; res.x = a.y-b.y; res.y = b.x-a.x; if (res.x == 0 && res.y == 0) @@ -352,7 +352,7 @@ unit_type gui_dist_meas(struct inst *self, struct coord pos, unit_type scale) struct coord a, b, off; unit_type d; - off = offset_vec(self); + off = offset_vec(self->base, self->u.meas.end, self); a = add_vec(self->base, off); b = add_vec(self->u.meas.end, off); d = dist_line(pos, a, b)/scale; @@ -364,13 +364,34 @@ void gui_draw_meas(struct inst *self, struct draw_ctx *ctx) { struct coord a0, b0, a1, b1, off, c, d; GdkGC *gc; + double len; + const char *label = self->u.meas.meas ? + self->u.meas.meas->label ? self->u.meas.meas->label : "" : ""; char *s; - off = offset_vec(self); a0 = translate(ctx, self->base); b0 = translate(ctx, self->u.meas.end); - a1 = translate(ctx, add_vec(self->base, off)); - b1 = translate(ctx, add_vec(self->u.meas.end, off)); + a1 = self->base; + b1 = self->u.meas.end; + switch (self->u.meas.meas ? self->u.meas.meas->type : mt_xy_next) { + case mt_xy_next: + case mt_xy_max: + break; + case mt_x_next: + case mt_x_max: + b1.y = a1.y; + break; + case mt_y_next: + case mt_y_max: + b1.x = a1.x; + break; + default: + abort(); + } + off = offset_vec(a1, b1, self); + len = units_to_mm(dist_point(a1, b1)); + a1 = translate(ctx, add_vec(a1, off)); + b1 = translate(ctx, add_vec(b1, off)); gc = gc_meas[get_mode(self)]; gdk_draw_line(DA, gc, a0.x, a0.y, a1.x, a1.y); gdk_draw_line(DA, gc, b0.x, b0.y, b1.x, b1.y); @@ -379,9 +400,8 @@ void gui_draw_meas(struct inst *self, struct draw_ctx *ctx) draw_arrow(ctx, gc, FALSE, b1, a1, MEAS_ARROW_LEN, MEAS_ARROW_ANGLE); c = add_vec(a1, b1); - d = sub_vec(b0, a0); - s = stralloc_printf("%lgmm", - units_to_mm(dist_point(self->base, self->u.meas.end))); + d = sub_vec(b1, a1); + s = stralloc_printf("%s%lgmm", label, len); render_text(DA, gc, c.x/2, c.y/2, -atan2(d.y, d.x)/M_PI*180, s, MEAS_FONT, 0.5, -MEAS_BASELINE_OFFSET, dist_point(a1, b1)-1.5*MEAS_ARROW_LEN, 0); diff --git a/inst.c b/inst.c index ad8ec87..dd4346e 100644 --- a/inst.c +++ b/inst.c @@ -291,8 +291,11 @@ static void update_bbox(struct bbox *bbox, struct coord coord) static void propagate_bbox(const struct inst *inst) { - update_bbox(&curr_frame->bbox, inst->bbox.min); - update_bbox(&curr_frame->bbox, inst->bbox.max); + /* @@@ for new-style measurements */ + struct inst *frame = curr_frame ? curr_frame : insts[ip_frame]; + + update_bbox(&frame->bbox, inst->bbox.min); + update_bbox(&frame->bbox, inst->bbox.max); } @@ -640,6 +643,8 @@ static void meas_op_select(struct inst *self) rect_status(self->bbox.min, self->bbox.max, -1); status_set_type_entry("offset ="); status_set_name("%5.2f mm", units_to_mm(self->u.meas.offset)); + if (!self->obj) + return; /* @@@ new-style measurements */ edit_expr(&self->obj->u.meas.offset, 0); } @@ -648,6 +653,8 @@ static int meas_op_anchors(struct inst *inst, struct vec ***anchors) { struct obj *obj = inst->obj; + if (!inst->obj) + return 0; /* @@@ new-style measurements */ anchors[0] = &obj->base; anchors[1] = &obj->u.meas.other; return 2; @@ -664,8 +671,8 @@ static struct inst_ops meas_ops = { }; -int inst_meas(struct obj *obj, struct coord from, struct coord to, - unit_type offset) +int inst_meas(struct obj *obj, struct meas *meas, + struct coord from, struct coord to, unit_type offset) { struct inst *inst; @@ -673,6 +680,9 @@ int inst_meas(struct obj *obj, struct coord from, struct coord to, inst->obj = obj; inst->u.meas.end = to; inst->u.meas.offset = offset; + inst->u.meas.meas = meas; + if (!obj) + inst->active = 1; /* @@@ new-style measurements */ /* @@@ our bbox is actually a bit more complex than this */ update_bbox(&inst->bbox, to); propagate_bbox(inst); diff --git a/inst.h b/inst.h index 24ec873..a5b4e64 100644 --- a/inst.h +++ b/inst.h @@ -18,6 +18,7 @@ #include "coord.h" #include "obj.h" +#include "meas.h" enum mode { @@ -70,6 +71,7 @@ struct inst { struct { struct coord end; double offset; + struct meas *meas; /* new-style measurement */ } meas; } u; struct inst *next; @@ -95,8 +97,8 @@ int inst_rect(struct obj *obj, struct coord a, struct coord b, unit_type width); int inst_pad(struct obj *obj, const char *name, struct coord a, struct coord b); int inst_arc(struct obj *obj, struct coord center, struct coord start, struct coord stop, unit_type width); -int inst_meas(struct obj *obj, struct coord from, struct coord to, - unit_type offset); +int inst_meas(struct obj *obj, struct meas *meas, + struct coord from, struct coord to, unit_type offset); void inst_begin_active(int active); void inst_end_active(void); diff --git a/meas.c b/meas.c new file mode 100644 index 0000000..f676c8d --- /dev/null +++ b/meas.c @@ -0,0 +1,193 @@ +/* + * meas.c - Measurements + * + * 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 "util.h" +#include "coord.h" +#include "expr.h" +#include "obj.h" +#include "inst.h" +#include "meas.h" + + +struct num eval_unit(const struct expr *expr, const struct frame *frame); + +struct sample { + struct coord pos; + struct sample *next; +}; + +struct meas *measurements = NULL; + + +static void reset_samples(struct sample **samples) +{ + struct sample *next; + + while (*samples) { + next = (*samples)->next; + free(*samples); + *samples = next; + } +} + + +void meas_start(void) +{ + struct frame *frame; + struct vec *vec; + + for (frame = frames; frame; frame = frame->next) + for (vec = frame->vecs; vec; vec = vec->next) + reset_samples(&vec->samples); +} + + +void meas_post(struct vec *vec, struct coord pos) +{ + struct sample **walk, *new; + + for (walk = &vec->samples; *walk; walk = &(*walk)->next) { + if (pos.y < (*walk)->pos.y) + break; + if (pos.y > (*walk)->pos.y) + continue; + if (pos.x < (*walk)->pos.x) + break; + if (pos.x == (*walk)->pos.x) + return; + } + new = alloc_type(struct sample); + new->pos = pos; + new->next = *walk; + *walk = new; +} + + +static int lt_x(struct coord a, struct coord b) +{ + return a.x < b.x; +} + + +static int lt_y(struct coord a, struct coord b) +{ + return a.y < b.y; +} + + +static int lt_xy(struct coord a, struct coord b) +{ + return a.y < b.y || (a.y == b.y && a.x < b.x); +} + + +static int (*lt_op[mt_n])(struct coord a, struct coord b) = { + lt_xy, + lt_x, + lt_y, + lt_xy, + lt_x, + lt_y +}; + + +static int is_next[mt_n] = { + 1, 1, 1, + 0, 0, 0 +}; + + +static int better_next(int (*lt)(struct coord a, struct coord b), + struct coord a0, struct coord b0, struct coord b) +{ + /* if we don't have any suitable point A0 < B0 yet, use this one */ + if (!lt(a0, b0)) + return 1; + + /* B must be strictly greater than A0 */ + if (!lt(a0, b)) + return 0; + + /* if we can get closer to A0, do so */ + if (lt(b, b0)) + return 1; + + /* reject B > B0 */ + if (lt(b0, b)) + return 0; + + /* + * B == B0 along the coordinate we measure. Now give the other + * coordinate a chance. This gives us a stable sort order and it + * makes meas/measx/measy usually select the same point. + */ + if (lt == lt_xy) + return 0; + if (lt == lt_x) + return better_next(lt_y, a0, b0, b); + if (lt == lt_y) + return better_next(lt_x, a0, b0, b); + abort(); +} + + +int instantiate_meas(void) +{ + struct meas *meas; + struct coord a0, b0; + const struct sample *a, *b; + int (*lt)(struct coord a, struct coord b); + struct num offset; + + for (meas = measurements; meas; meas = meas->next) { + if (!meas->low->samples || !meas->high->samples) + continue; + + lt = lt_op[meas->type]; + + /* + * In order to obtain a stable order, we sort points equal on + * the measured coordinate also by xy: + * + * if (*a < a0) use *a + * else if (*a == a0 && *a low->samples->pos; + for (a = meas->low->samples; a; a = a->next) + if (lt(a->pos, a0) || + (!lt(a0, a->pos) && lt_xy(a->pos, a0))) + a0 = a->pos; + + b0 = meas->high->samples->pos; + for (b = meas->high->samples; b; b = b->next) { + if (is_next[meas->type]) { + if (better_next(lt, a0, b0, b->pos)) + b0 = b->pos; + } else { + if (lt(b0, b->pos) || + (!lt(b->pos, b0) && lt_xy(b0, b->pos))) + b0 = b->pos; + } + } + + offset = eval_unit(meas->offset, root_frame); + if (is_undef(offset)) + return 0; + inst_meas(NULL, meas, + meas->inverted ? b0 : a0, meas->inverted ? a0 : b0, + offset.n); + } + return 1; +} diff --git a/meas.fpd b/meas.fpd new file mode 100644 index 0000000..c2ad1d2 --- /dev/null +++ b/meas.fpd @@ -0,0 +1,24 @@ +/* + * new-style measurements demo + */ + +part "measurements" +loop x = -2, 2 +A: vec @(0mm, 0mm) +B: vec @(x*2mm, 2mm) +C: vec @(0mm, 4mm) + +/* + * If we measure (x, y), y trumps x + */ +measxy "A -> B = " A -> B 0.2mm +measxy "A <- B = " A <- B 0.5mm + +measxy "A >> B = " A >> B 1.5mm + +measx "x(A -> B) = " A -> B -0.5mm +measx "x(A >> B) = " A >> B -1mm +measy "y(A -> B) = " A -> B -2mm +measy "y(A >> B) = " A >> B -4.5mm + +measxy "B -> C = " B -> C 0.5mm diff --git a/meas.h b/meas.h new file mode 100644 index 0000000..5919a0a --- /dev/null +++ b/meas.h @@ -0,0 +1,46 @@ +/* + * meas.h - Measurements + * + * 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 MEAS_H +#define MEAS_H + +#include "obj.h" + + +struct meas { + enum meas_type { + mt_xy_next, + mt_x_next, + mt_y_next, + mt_xy_max, + mt_x_max, + mt_y_max, + mt_n + } type; + char *label; /* or NULL */ + int inverted; + struct vec *low; + struct vec *high; + struct expr *offset; + struct meas *next; +}; + + +extern struct meas *measurements; + + +void meas_start(void); +void meas_post(struct vec *vec, struct coord pos); +int instantiate_meas(void); + +#endif /* !MEAS_H */ diff --git a/obj.c b/obj.c index 6b2aa5e..7cef142 100644 --- a/obj.c +++ b/obj.c @@ -18,6 +18,7 @@ #include "util.h" #include "error.h" #include "expr.h" +#include "meas.h" #include "inst.h" #include "obj.h" @@ -37,7 +38,8 @@ static int generate_frame(struct frame *frame, struct coord base, const struct frame *parent, struct obj *frame_ref, int active); -static struct num eval_unit(const struct expr *expr, const struct frame *frame) +struct num eval_unit(const struct expr *expr, const struct frame *frame); +/*static*/ struct num eval_unit(const struct expr *expr, const struct frame *frame) { struct num d; @@ -78,6 +80,7 @@ static int generate_vecs(struct frame *frame, struct coord base) vec->pos.y += y.n; if (!inst_vec(vec, vec_base)) return 0; + meas_post(vec, vec->pos); } return 1; } @@ -144,7 +147,8 @@ static int generate_objs(struct frame *frame, struct coord base, int active) offset = eval_unit(obj->u.meas.offset, frame); if (is_undef(offset)) return 0; - if (!inst_meas(obj, obj->base ? obj->base->pos : base, + if (!inst_meas(obj, NULL, + obj->base ? obj->base->pos : base, obj->u.meas.other ? obj->u.meas.other->pos : base, offset.n)) return 0; @@ -261,7 +265,10 @@ int instantiate(void) int ok; inst_start(); + meas_start(); ok = generate_frame(root_frame, zero, NULL, NULL, 1); + if (ok) + ok = instantiate_meas(); if (ok) inst_commit(); else diff --git a/obj.h b/obj.h index 0f1944e..e0704a3 100644 --- a/obj.h +++ b/obj.h @@ -84,6 +84,8 @@ struct loop { int initialized; }; +struct sample; + struct vec { const char *name; /* NULL if anonymous */ struct expr *x; @@ -96,6 +98,9 @@ struct vec { /* used when editing */ struct frame *frame; + + /* samples for measurements */ + struct sample *samples; }; struct frame { @@ -147,7 +152,7 @@ struct arc { struct expr *width; }; -struct meas { +struct old_meas { struct vec *other; /* NULL if frame origin */ struct expr *offset; }; @@ -160,7 +165,7 @@ struct obj { struct rect line; struct pad pad; struct arc arc; - struct meas meas; + struct old_meas meas; } u; struct frame *frame; struct vec *base; diff --git a/sc89.fpd b/sc89.fpd index dcf6fbe..054ec3f 100644 --- a/sc89.fpd +++ b/sc89.fpd @@ -1,12 +1,12 @@ /* MACHINE-GENERATED ! */ frame pad { - _pad_0: vec @(-Px/2, -Py/2) - _pad_1: vec .(Px, 0mm) - _pad_2: vec _pad_0(0mm, Py) - pad "$pad" _pad_1 _pad_2 - meas _pad_0 _pad_1 -0.1mm - meas _pad_0 _pad_2 0.1mm + sw: vec @(-Px/2, -Py/2) + se: vec sw(Px, 0mm) + nw: vec sw(0mm, Py) + pad "$pad" se nw +// meas sw se -0.1mm +// meas sw nw 0.1mm } frame pad_ne { @@ -41,3 +41,5 @@ __2: vec @(Gx/2, -Gy/2) frame pad_sc __0 frame pad_nw __1 frame pad_ne __2 + +measx pad.sw -> pad.se 1mm