Hi folks, I have written a patch to add support for drawing arbitrary polygons in pic using the existing syntax for multi-segment lines. They can be shaded and filled as expected of other closed objects. Examples attached in polygon.pdf.
There is also new syntax for referencing the positions of the vertices and edge midpoints: - .v[er[tex]] expr - .v[er[tex]] `expr' - .p[oint] expr - .p[oint] `expr' I must admit I have a very limited computer science education, so I expect my implementation could use some improvements; feedback would be appreciated. I'm not entirely pleased with how vertex_number is set, but I struggled with polygon_object not being instanced until the end of object_spec::make_line. That seems to be the general structure of the program so I didn't want to change it, but perhaps there's a better way to set the value, among other things. I've also included the following small documentation update. Where referring to ordinals the documentation included the characters " ` " and " ' " i.e. the grave accent and apostrophe. These are the correct characters, but groff draws these as the left and right quotation marks, which confused me when I tried to use this feature. I've updated those characters to the appropriate escape sequences "\[ga]" and "\[aq]" so that they appear properly. Future Work: If I understand it correctly (big if), PostScript interprets all polygons as a path, much like how pic draws multi-line segments. PostScript however can include arcs and splines as segments and fill the resulting shape. It doesn't look like it would be terribly difficult to implement this in pic, but it would be a lot of work. I believe pic, groff, and grops would all need to updated to accommodate the new drawing command. This process is all quite new to me so I appreciate your patience. Happy to make any changes required. Thanks, Duncan
polygon.pdf
Description: Adobe PDF document
diff --git a/doc/pic.ms b/doc/pic.ms index fc97ee63a..1d330f14f 100644 --- a/doc/pic.ms +++ b/doc/pic.ms @@ -260,7 +260,7 @@ In general, the order of command arguments and modifiers like \[lq]width 1.2\[rq] or \[lq]dashed\[rq] doesn't matter, except that the order of text arguments is significant. .PP -Here are all but one of the basic \fBpic\fP objects at their default sizes: +Here are all but two of the basic \fBpic\fP objects at their default sizes: .KS .PS box "box"; @@ -277,14 +277,16 @@ arc; down; move; "arc" .PE .CE "2: Basic \fBpic\fP objects" .PP -The missing simple object type is a \fIspline\fP. +The missing simple object types are \fIspline\fP and \fIpolygon\fP. There is also a way to collect objects into \fIblock composites\fP which allows you to treat the whole group as a single object (resembling a box) for many purposes. -We'll describe both of these later on. +We'll describe all of these later on. .PP The box, ellipse, circle, and block composite objects are \fIclosed\/\fR; lines, arrows, arcs and splines are \fIopen\fP. +Polygons are a special case drawn using the syntax of open objects, +but with most of the attributes of closed objects. This distinction is often important in explaining command modifiers. .PP Figure \n[H1]-2 was produced by the following \fBpic\fP program, @@ -350,8 +352,10 @@ line "1" "2" "3"; line "1" "2" "3" "4"; line "1" "2" "3" "4" "5"; .PE +.rs .sp 2 .CE "4: Effects of multiple text arguments" +.KS .PP The last line of Figure 3-2's program, `\fBarc; down; move; "arc"\fP', describing the captioned arc, introduces several new ideas. @@ -359,7 +363,6 @@ Firstly, we see how to change the direction in which objects are joined. Had we written \fBarc; move; "arc"\fP, omitting \fBdown\fP the caption would have been joined to the top of the arc, like this: -.KS .PS arc; move; "arc"; .PE @@ -413,6 +416,7 @@ If you don't like inches, it's possible to set a global style variable Setting \fBscale = 2.54\fP effectively changes the internal unit to centimeters (all other size variable values are scaled correspondingly). . +.bp .NH 2 Default Sizes of Objects .PP @@ -483,13 +487,13 @@ There is also a \[lq]height\[rq] modifier that changes a box's height. The \fBwidth\fP keyword may be abbreviated to \fBwid\fP; the \fBheight\fP keyword to \fBht\fP. . +.KS .NH 2 Resizing Other Object Types .PP To change the size of a circle, give it a \fBrad[ius]\fP or \fBdiam[eter]\fP modifier; this changes the radius or diameter of the circle, according to the numeric argument that follows. -.KS .PS {circle rad 0.1; move down 0.2 from last circle .s; "0.1"}; move; circle rad 0.2 "0.2"; move; circle rad 0.3 "0.3"; @@ -544,6 +548,7 @@ box; box wid 1 ht 1; box same; box .CE "5: The \fBsame\fP keyword" . . +.KS .NH 1 Generalized Lines and Splines . @@ -555,7 +560,6 @@ It is possible to specify diagonal lines or arrows by adding multiple \fBup\fP, Any of these can have a multiplier. To understand the effects, think of the drawing area as being gridded with standard-sized boxes. -.KS .PS # Draw a demonstration up left arrow with grid box overlay define gridarrow @@ -644,6 +648,21 @@ Arrowheads can be applied naturally to any path-based object, line or spline. We'll see how in the next section. . +.NH 2 +Polygon Objects +.PP +GNU \fBgpic\fP supports arbitrary polygons constructed with the same syntax as multi-segment lines. The final line segment connecting back to the starting point is included automatically and should be omitted. +.KS +.PS +POLY: polygon up 1 then down 0.5 right 1; +"up 1" rjust at POLY.p`1' + (-0.1, 0.0); +"down 0.5 right 1" ljust at POLY.p`2' + (0.0, 0.1); +"automatically drawn" ljust at POLY.p`3' + (0.0, -0.1); +.PE +.CE "5: \fBpolygon up 1 then down 0.5 right 1\fP" +.LP +Polygons are decorated like closed objects as described in the next section. +. . .NH 1 Decorating Objects @@ -702,6 +721,7 @@ box dashed 0.2 "0.2"; .PE .CE "1: Dashed objects" . +.KS .NH 2 Dotted Objects .PP @@ -711,7 +731,6 @@ GNU \fBgpic\fP permits you to dot or dash ellipses, circles, and arcs dashing of lines and boxes. It too can be suffixed with a number to specify the interval between dots: -.KS .PS box dotted "default"; move; @@ -835,7 +854,7 @@ this way. .NH 2 Filled Objects .PP -It is possible to fill boxes, circles, and ellipses. +It is possible to fill boxes, circles, ellipses, and polygons. The modifier \fBfill[ed]\fP accomplishes this. You can suffix it with a fill value; the default is given by the style variable \fBfillval\fP. @@ -1059,12 +1078,12 @@ Objects are also numbered backward by type from the last one. You can say \fB2nd last box\fP to get the second-to-last box, or \fB3rd last ellipse\fP to get the third-to-last ellipse. .PP -In places where \fIn\/\fBth\fR is allowed, \fB`\fIexpr\/\fB'th\fR is +In places where \fIn\/\fBth\fR is allowed, \fB\[ga]\fIexpr\/\fB\[aq]th\fR is also allowed. Note that -.B 'th +.B \[aq]th is a single token: no space is allowed between the -.B ' +.B \[aq] and the \fBth\fP. For example, .IP @@ -1072,7 +1091,7 @@ For example, .DS .CW for i = 1 to 4 do { - line from `i'th box.nw to `i+1'th box.se + line from \[ga]i\[aq]th box.nw to \[ga]i+1\[aq]th box.se } .DE .R @@ -1262,6 +1281,52 @@ critical(spline right 1 then up right then left then left 1); .CE "2: Special points on open objects" .PP . +.NH 4 +Locations Relative to Polygons +.PP +Polygons have three types of named points: (\fB.vertex\fP, \fB.ver\fP, \fB.v\fP), (\fB.point\fP, \fB.p\fP), and (\fB.center\fP, \fB.c\fP). +They can also be used without leading dots in the \fBof\fP prefix form. +The center of a polygon is the centroid, and may give unexpected results for non-simple polygons. +.PP +\fB.v\fP and \fB.p\fP locate the vertices and mid-points of the edges, respectively. They can be used in the forms \fB.v\fP \fIexpr\fR +, or \fB.v\fP \[ga]\fIexpr\fR\[aq]. +The latter is required when the vertex/point expression is followed by an additional expression, +as \fBpic\fP will otherwise attempt to reduce them to a single expression. +For example, +.IP +.KS +.DS +.CW +for i = 1 to n do { + circle rad 0.05 fill 1 at last polygon.vi +} +circle rad 0.05 fill 1 at last polygon.p \[ga]1\[aq] + (0.0,0.1) +.DE +.R +.KE +.LP +would draw a dot 0.1i above the mid-point of the first edge at the default scale, and one at each vertex for a polygon with n vertices. +.KS +.PS +define vertices { + [ VER: $1; + dot(VER.c); "\fB.center\fP" at VER.center + (0.0, 0.1) + for i = 1 to $2 do { + dot(VER.vi); + dot(VER.pi); + } + "\fB.v1\fP" at VER.v`1' + (-0.1, -0.1); + "\fB.v2\fP" at VER.v`2' + (-0.1, 0.1); + "\fB.v3\fP" at VER.v`3' + (0.1, 0.1); + "\fB.p1\fP" at VER.p`1' + (-0.1, 0.1); + "\fB.p2\fP" at VER.p`2' + (0.1, 0.1); + "\fB.p3\fP" at VER.p`3' + (0.1, -0.1); + ] +} +vertices(polygon up 1 then down 0.5 right 1, 3); +.PE +.CE "3: Special points on polygons" +. .NH 2 Ways of Composing Positions .PP @@ -2657,6 +2722,65 @@ tblock(.5, 1, "Slave"); .ft R .KE . +.KS +.PP +Here is a flow chart with source code to demonstrate how a polygon attaches to other objects: +.DS +.CW +\&.PS +down; +h = 0.25; +w = 0.375; +l = 0.75; +r = 0.1; +box rad r fill 0.3 outlined "green"; +"Start" at last box; +arrow down l from last box.s; +polygon \e + down h right w \e + then down h left w \e + then up h left w \e + with .v1 at last arrow.end \e + fill 0.3 outlined "blue"; +"Done?" at last polygon.c; +arrow down l from last polygon.v3 " Yes" ljust; +box rad r fill 0.3 outlined "green"; +"End" at last box.c; +move to last polygon.v2; +line right "" "No"; +arrow up l - h/2 then left lineht + w; +\&.PE +. +.DE +.ft R +.KE +. +.KS +.PS +down; +h = 0.25; +w = 0.375; +l = 0.75; +r = 0.1; +box rad r fill 0.3 outlined "green"; +"Start" at last box; +arrow down l from last box.s; +polygon \ + down h right w \ + then down h left w \ + then up h left w \ + with .v1 at last arrow.end \ + fill 0.3 outlined "blue"; +"Done?" at last polygon.c; +arrow down l from last polygon.v3 " Yes" ljust; +box rad r fill 0.3 outlined "green"; +"End" at last box.c; +move to last polygon.v2; +line right "" "No"; +arrow up l - h/2 then left 0.5 + w; +.PE +.CE "3: Flowchart for demonstrating polygon attachment" +.bp . . .NH 1 @@ -2877,6 +3001,7 @@ empty string is considered as `false' for `&&' and `|\||'. box \fR# closed object \[em] rectangle\fP circle \fR# closed object \[em] circle\fP ellipse \fR# closed object \[em] ellipse\fP + polygon \fR# closed object \[em] polygon\fP arc \fR# open object \[em] quarter-circle\fP line \fR# open object \[em] line\fP arrow \fR# open object \[em] line with arrowhead\fP @@ -3011,7 +3136,9 @@ There are lots of different ways to specify positions: <place> ::= <label> <label> <corner> + <label> <vertex> <corner> [of] <label> + <vertex> of <label> Here .R .DE @@ -3037,6 +3164,15 @@ There are lots of different ways to specify positions: .DE .DS .CW +<vertex> ::= + .v[er[tex]] <expr> + .v[er[tex]] \[ga] <expr> \[aq] + .p[oint] <expr> + .p[oint] \[ga] <expr> \[aq] +.R +.DE +.DS +.CW <\,\f(CIxxx\/\fP-of> ::= \f(CIxxx\fP \fR# followed by `of'\fP .R @@ -3053,7 +3189,7 @@ There are lots of different ways to specify positions: <ordinal> ::= INT th INT st | INT nd | INT rd - ` <any-expr> 'th + \[ga] <any-expr> \[aq]th .R .DE .DS @@ -3062,6 +3198,7 @@ There are lots of different ways to specify positions: box circle ellipse + polygon arc line arrow @@ -3076,7 +3213,7 @@ barbaric, synonyms like \fB1st\fP and \fB3rd\fP are accepted as well.\[rq] Objects of a given type are numbered from 1 upward in order of declaration; the \fBlast\fP modifier counts backward. .PP -The \[lq]'th\[rq] form (which allows you to select a previous object with +The \[lq]\^\[aq]th\[rq] form (which allows you to select a previous object with an expression, as opposed to a numeric literal) is not documented in DWB's \fIpic\/\fR(1). .PP @@ -3118,6 +3255,7 @@ Here the special rules for the `with' keyword using a path: . LABEL [. LABEL ...] [<corner>] .R .DE +.bp .PP The following style variables control output: .TS H diff --git a/src/preproc/pic/lex.cpp b/src/preproc/pic/lex.cpp index 91802f595..479745d2d 100644 --- a/src/preproc/pic/lex.cpp +++ b/src/preproc/pic/lex.cpp @@ -520,6 +520,7 @@ int lookup_keyword(const char *str, int len) { "outline", OUTLINED }, { "outlined", OUTLINED }, { "plot", PLOT }, + { "polygon", POLYGON }, { "print", PRINT }, { "rad", RADIUS }, { "radius", RADIUS }, @@ -852,6 +853,56 @@ int get_token_after_dot(int c) } context_buffer = ".b"; return DOT_S; + case 'v': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'e') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'r') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'e') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'x') { + input_stack::get_char(); + context_buffer = ".vertex"; + return DOT_V; + } + } + context_buffer = ".ver"; + return DOT_V; + } + } + } + context_buffer = ".v"; + return DOT_V; + case 'p': + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'o') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'i') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 'n') { + input_stack::get_char(); + c = input_stack::peek_char(); + if (c == 't') { + input_stack::get_char(); + context_buffer = ".point"; + return DOT_P; + } + } + } + } + context_buffer = ".p"; + return DOT_P; default: context_buffer = '.'; return '.'; diff --git a/src/preproc/pic/object.cpp b/src/preproc/pic/object.cpp index d0b648c27..580738e0b 100644 --- a/src/preproc/pic/object.cpp +++ b/src/preproc/pic/object.cpp @@ -369,6 +369,20 @@ position object::center() return origin(); } +position object::vertex() +{ + return origin(); +} + +position object::point() +{ + return origin(); +} + +void object::set_vertex_number(int vnum) +{ +} + double object::width() { return 0.0; @@ -417,6 +431,8 @@ object_spec::object_spec(object_type t) : type(t) shaded = 0; xslanted = 0; yslanted = 0; + vertex_number = 1; + is_edge = 0; outlined = 0; with = 0; dir = RIGHT_DIRECTION; @@ -1447,6 +1463,72 @@ line_object::~line_object() delete[] v; } +class polygon_object : public line_object { +protected: + double fill; // < 0 if not filled + char *color_fill; // = 0 if not colored + int vertex_number; +public: + polygon_object(const position &s, const position &e, position *, int); + position point(); // Select center point between two vertices + position vertex(); // Select vertex + position center(); // Calculate centroid of the polygon + void set_vertex_number(int); + object_type type() { return POLYGON_OBJECT; } + void print(); + void set_fill(double); + void set_fill_color(char *fill); +}; + +polygon_object::polygon_object(const position &s, const position &e, + position *p, int i) +: line_object(s, e, p, i) +{ + fill = -1.0; + color_fill = 0; +} + +position polygon_object::center() { + position tmp; + for (int i = 0; i < n; i++) { + tmp += v[i]; + } + return tmp/n; +} + +position polygon_object::point() { + if (vertex_number == n) + return (v[vertex_number-1] + v[0])/2.0; + return (v[vertex_number] + v[vertex_number-1])/2.0; +} + +void polygon_object::set_fill(double f) +{ + assert(f >= 0.0); + fill = f; +} + +void polygon_object::set_fill_color(char *f) +{ + color_fill = strsave(f); +} + +void polygon_object::set_vertex_number(int vnum) { + vertex_number = vnum; +} + +position polygon_object::vertex() { + return v[vertex_number-1]; +} + +void polygon_object::print() { + if (lt.type == line_type::invisible) + return; + out->set_color(color_fill, graphic_object::get_outline_color()); + out->polygon(v, n, lt, fill); + out->reset_color(); +} + linear_object *object_spec::make_line(position *curpos, direction *dirp) { static position last_line; @@ -1516,17 +1598,59 @@ linear_object *object_spec::make_line(position *curpos, direction *dirp) if (!with->follow(here, &offset)) return 0; pos -= offset; - for (s = segment_list; s; s = s->next) + + if (type == POLYGON_OBJECT) { + int i = 0; + if (is_edge) { + pos = at; + // Offset start position by the difference between it and the + // midpoint of the desired edge. + for (s = segment_list; s; s = s->next) { + if (vertex_number == 1) { // First edge + pos -= (pos + s->pos)/2.0; + break; + } else if (vertex_number != 1 && vertex_number != nsegments+1) { // Any other edge + pos -= (s->pos + s->next->pos)/2.0; + break; + } else if (vertex_number == nsegments+1 && i == vertex_number-2) { // Last edge + pos -= (pos + s->pos)/2.0; + break; + } + i++; + } + } + // Offset start position by the difference between it and the desired + // vertex. + if (vertex_number != 1 && !is_edge) { + pos = at; + for (s = segment_list; s; s = s->next) { + if (i == vertex_number-2) { + pos -= s->pos; + break; + } + i++; + } + } + } + + for (s = segment_list; s; s = s->next) { s->pos += pos; + } startpos += pos; endpos += pos; } // handle chop line_object *p = 0; - position *v = new position[nsegments]; + // build array of size n+1 if building a polygon, assign v[0] later int i = 0; - for (s = segment_list; s; s = s->next, i++) + if (type == POLYGON_OBJECT) { + nsegments += 1; + i = 1; + } + position *v = new position[nsegments]; + for (s = segment_list; s; s = s->next, i++) { v[i] = s->pos; + } if (flags & IS_DEFAULT_CHOPPED) { lookup_variable("circlerad", &start_chop); end_chop = start_chop; @@ -1557,6 +1681,11 @@ linear_object *object_spec::make_line(position *curpos, direction *dirp) case LINE_OBJECT: p = new line_object(startpos, endpos, v, nsegments); break; + case POLYGON_OBJECT: + v[0] = startpos; + p = new polygon_object(startpos, endpos, v, nsegments); + p->set_vertex_number(vertex_number); + break; default: assert(0); } @@ -1900,6 +2029,7 @@ object *object_spec::make_object(position *curpos, direction *dirp) case MOVE_OBJECT: obj = make_move(curpos, dirp); break; + case POLYGON_OBJECT: case ARC_OBJECT: case LINE_OBJECT: case SPLINE_OBJECT: diff --git a/src/preproc/pic/object.h b/src/preproc/pic/object.h index e39b6a6cf..098f02e09 100644 --- a/src/preproc/pic/object.h +++ b/src/preproc/pic/object.h @@ -27,6 +27,7 @@ enum object_type { ARC_OBJECT, SPLINE_OBJECT, LINE_OBJECT, + POLYGON_OBJECT, ARROW_OBJECT, MOVE_OBJECT, TEXT_OBJECT, @@ -56,6 +57,9 @@ struct object { virtual position start(); virtual position end(); virtual position center(); + virtual position vertex(); + virtual position point(); + virtual void set_vertex_number(int); virtual place *find_label(const char *); virtual void move_by(const position &); virtual int blank(); @@ -74,6 +78,12 @@ struct place { struct string_list; +struct vertex { + corner crn; + int vertex_number; + bool is_edge; // 0 for vertex, 1 for edge +}; + class path { position pos; corner crn; @@ -191,6 +201,8 @@ struct object_spec { double fill; double xslanted; double yslanted; + int vertex_number; + bool is_edge; char *shaded; char *outlined; direction dir; diff --git a/src/preproc/pic/pic.1.man b/src/preproc/pic/pic.1.man index e463ba9af..172224975 100644 --- a/src/preproc/pic/pic.1.man +++ b/src/preproc/pic/pic.1.man @@ -1298,6 +1298,45 @@ for i = 1 to 4 do { .EE . . +.LP +Arbitrary polygons can be drawn using the +.BR polygon +keyword followed by a series of n-1 line segments, where n is the number +of edges of the polygon. This allows groff to interpret the line +segments as a complete object such that the filled and shaded attributes +may be used. +The final drawing position and direction are specified by the last +user-specified line segment. +For example, a triangle can be drawn and filled with the following: +.IP +.EX +polygon up 1 then right 1 down 0.5 fill 0.5 +.EE +.LP +To position polygons, two new suffixes are available: +.RB \[lq] .v +.IR expr \[rq] +for locating the vertices, and +.RB \[lq] .p +.IR expr \[rq] +for locating the center-points of edges. For example, +.IP +.EX +arrow down +polygon up 0.5 right 1 \[rs] +then down 0.5 right 1 \[rs] +then down 0.5 left 1 \[rs] +with .v2 at last line.end +arrow down from last polygon.v4 +.EE +.LP +creates and correctly places a flowchart decision diamond. +Note that +.BR .c +is also available but the compass points will not work as expected and +should not be used. +. +. .\" ==================================================================== .SS "Converting \f[I]pic\f[] to other image formats" .\" ==================================================================== diff --git a/src/preproc/pic/pic.ypp b/src/preproc/pic/pic.ypp index b2fa6dcf5..4fb4fdaa7 100644 --- a/src/preproc/pic/pic.ypp +++ b/src/preproc/pic/pic.ypp @@ -74,6 +74,7 @@ char *do_sprintf(const char *fmt, const double *v, int nv); place pl; object *obj; corner crn; + vertex ver; path *pth; object_spec *spec; saved_state *pstate; @@ -98,6 +99,7 @@ char *do_sprintf(const char *fmt, const double *v, int nv); %token ELLIPSE %token ARC %token LINE +%token POLYGON %token ARROW %token MOVE %token SPLINE @@ -141,6 +143,8 @@ char *do_sprintf(const char *fmt, const double *v, int nv); %token DOT_NW %token DOT_SW %token DOT_C +%token DOT_P +%token DOT_V %token DOT_START %token DOT_END %token DOT_X @@ -228,14 +232,14 @@ parses properly. */ %left VARIABLE NUMBER '(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND SRAND LAST %left ORDINAL HERE '`' -%left BOX CIRCLE ELLIPSE ARC LINE ARROW SPLINE '[' +%left BOX CIRCLE ELLIPSE ARC LINE POLYGON ARROW SPLINE '[' /* these need to be lower than '-' */ %left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS /* these must have higher precedence than CHOP so that 'label %prec CHOP' works */ -%left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C +%left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C DOT_P DOT_V %left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER %left UPPER LOWER NORTH SOUTH EAST WEST CENTER START END @@ -259,6 +263,7 @@ works */ %type <if_data> simple_if %type <obj> nth_primitive %type <crn> corner +%type <ver> vertex %type <pth> path label_path relative_path %type <pl> place label element element_list middle_element_list %type <spec> object_spec @@ -658,6 +663,13 @@ object_spec: lookup_variable("linewid", & $$->segment_width); $$->dir = current_direction; } + | POLYGON + { + $$ = new object_spec(POLYGON_OBJECT); + lookup_variable("lineht", & $$->segment_height); + lookup_variable("linewid", & $$->segment_width); + $$->dir = current_direction; + } | ARROW { $$ = new object_spec(ARROW_OBJECT); @@ -864,6 +876,14 @@ object_spec: $$->flags |= HAS_WITH; $$->with = $3; } + | object_spec WITH vertex + { + $$ = $1; + $$->flags |= HAS_WITH; + $$->with = new path($3.crn); + $$->vertex_number = $3.vertex_number; + $$->is_edge = $3.is_edge; + } | object_spec WITH position %prec ',' { $$ = $1; @@ -1250,6 +1270,13 @@ place: if (!pth.follow($1, & $$)) YYABORT; } + | label vertex + { + $1.obj->set_vertex_number($2.vertex_number); + path pth($2.crn); + if (!pth.follow($1, & $$)) + YYABORT; + } | corner label { path pth($1); @@ -1262,6 +1289,13 @@ place: if (!pth.follow($3, & $$)) YYABORT; } + | vertex OF label + { + $3.obj->set_vertex_number($1.vertex_number); + path pth($1.crn); + if (!pth.follow($3, & $$)) + YYABORT; + } | HERE { $$.x = current_position.x; @@ -1352,6 +1386,8 @@ object_type: { $$ = ARC_OBJECT; } | LINE { $$ = LINE_OBJECT; } + | POLYGON + { $$ = POLYGON_OBJECT; } | ARROW { $$ = ARROW_OBJECT; } | SPLINE @@ -1433,7 +1469,7 @@ corner: | DOT_NE { $$ = &object::north_east; } | DOT_SE - { $$ = &object:: south_east; } + { $$ = &object::south_east; } | DOT_NW { $$ = &object::north_west; } | DOT_SW @@ -1488,6 +1524,31 @@ corner: { $$ = &object::end; } ; +vertex: + DOT_V expr + { + $$.crn = &object::vertex; + $$.vertex_number = $2; + } + | DOT_V '`' expr '\'' + { + $$.crn = &object::vertex; + $$.vertex_number = $3; + } + | DOT_P expr + { + $$.crn = &object::point; + $$.vertex_number = $2; + $$.is_edge = 1; + } + | DOT_P '`' expr '\'' + { + $$.crn = &object::point; + $$.vertex_number = $3; + $$.is_edge = 1; + } + ; + expr: expr_lower_than { $$ = $1; } @@ -1875,6 +1936,8 @@ const char *object_type_name(object_type type) return "spline"; case LINE_OBJECT: return "line"; + case POLYGON_OBJECT: + return "polygon"; case ARROW_OBJECT: return "arrow"; case MOVE_OBJECT:
.PS define dot { circle diam 0.05 fill 1 } define triangle { polygon up 1 \ then down 0.5 right 0.6 \ shaded "blue" \ thickness 1 \ } define hexagon { polygon up 0.5 right 0.5 \ then right 1 \ then right 0.5 down 0.5 \ then down 0.5 left 0.5 \ then left 1 \ fill 0.5 \ } line TRI1: triangle with .p1 at last line.end line right 1.5 from TRI1.v3 for i = 1 to 3 do { dot at TRI1.vi dot at TRI1.pi } "P1" at TRI1.p`1' + (-0.1, 0.1) "P2" at TRI1.p`2' + (0.1, 0.1) "P3" at TRI1.p`3' + (0.1, -0.1) "V1" at TRI1.v`1' + (-0.1, -0.1) "V2" at TRI1.v`2' + (-0.1, 0.1) "V3" at TRI1.v`3' + (0.1, 0.1) HEX1: hexagon with .v1 at last line.end "Hex" for i = 1 to 6 do { dot at HEX1.vi dot at HEX1.pi } line right from HEX1.v4 "P1" at HEX1.p`1' + (-0.1, 0.1) "P2" at HEX1.p`2' + (0.0, 0.1) "P3" at HEX1.p`3' + (0.1, 0.1) "P4" at HEX1.p`4' + (0.1, -0.1) "P5" at HEX1.p`5' + (0.0, -0.1) "P6" at HEX1.p`6' + (-0.1, -0.1) "V1" at HEX1.v`1' + (-0.1, 0.1) "V2" at HEX1.v`2' + (-0.1, 0.1) "V3" at HEX1.v`3' + (0.1, 0.1) "V4" at HEX1.v`4' + (0.1, 0.1) "V5" at HEX1.v`5' + (0.1, -0.1) "V6" at HEX1.v`6' + (-0.1, -0.1) .PE .PS polygon right 2 \ then down 1 left 1.5 \ then up 2 right 0.5 \ fill 0.5 circle rad 0.05 fill 1 at last polygon.c "\s'+4'.c (centroid)\s'-4'" at last polygon.c + (0.5, 0.1) .PE .PS polygon right 2 \ then down 1.3 left 1.5 \ then up 2 right 0.5 \ then down 2 right 0.5 \ fill 0.5 .PE
polygon_ChangeLog
Description: Binary data