gbranden pushed a commit to branch master
in repository groff.
commit 77b5075cc2e35b8dc83c8dd3638ab9bc9418fcd8
Author: Duncan Losin <[email protected]>
AuthorDate: Tue Nov 19 03:57:55 2024 +0000
[pic]: Extend to allow drawing arbitrary polygons.
* src/preproc/pic/lex.cpp (get_token_after_dot): Add new checks for
`.v[er[tex]]` and `.p[oint]` syntax for polygons.
* src/preproc/pic/object.h (enum object_type):
* src/preproc/pic/pic.ypp (object_type, object_type_name):
* src/preproc/pic/lex.cpp (lookup_keyword): Add `polygon` keyword and
object type.
* src/preproc/pic/object.h (struct object): Declare new virtual
functions for determining polygon vertices and edge midpoints.
* src/preproc/pic/object.h (class path): Add new `vertex_number` and
`is_edge` member variables to determine what position should be
accessed.
* src/preproc/pic/pic.ypp (tokens): Add new tokens `POLYGON`, `DOT_P`,
and `DOT_V`.
* src/preproc/pic/pic.ypp (object_spec): Add new rule `POLYGON` to
create new object_spec of type `POLYGON_OBJECT`. Add new rule
`object_spec WITH vertex` to locate polygons.
* src/preproc/pic/pic.ypp (place): Add new rules `label vertex` and
`vertex OF label` to locate polygons.
* src/preproc/pic/pic.ypp (vertex):
* src/preproc/pic/object.h (struct vertex): Define new `vertex`
structure and grammar rule for describing polygon vertices and edge
midpoints.
* src/preproc/pic/object.cpp (object::vertex, object::point)
(object::set_vertex_number): Define default behavior for new
functions.
* src/preproc/pic/object.cpp (object_spec::object_spec): Set defaults
for `vertex_number` and `is_edge`.
* src/preproc/pic/object.cpp (class polygon_object)
(polygon_object::polygon_object)
(polygon_object::center)
(polygon_object::point)
(polygon_object::set_fill)
(polygon_object::set_vertex_number)
(polygon_object::vertex)
(polygon_object::print): Add new `polygon` class and implement member
functions.
* src/preproc/pic/object.cpp (object_spec::make_line): Modify line
segment array from n-1 to n segments if a polygon has been requested.
Create offsets for positioning new polygons.
* src/preproc/pic/object.cpp (object_spec::make_object): Add check for
the `POLYGON_OBJECT` object type.
* doc/pic.ms:
* src/preproc/pic/pic.1.man (Other changes): Document it.
Fixes <https://savannah.gnu.org/bugs/?66458>.
---
ChangeLog | 63 ++++++++++++++++++++
doc/pic.ms | 143 +++++++++++++++++++++++++++++++++++++++++++--
src/preproc/pic/lex.cpp | 51 ++++++++++++++++
src/preproc/pic/object.cpp | 136 +++++++++++++++++++++++++++++++++++++++++-
src/preproc/pic/object.h | 12 ++++
src/preproc/pic/pic.1.man | 39 +++++++++++++
src/preproc/pic/pic.ypp | 67 ++++++++++++++++++++-
7 files changed, 502 insertions(+), 9 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 7a82a37d3..70ab81fd2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,66 @@
+2024-11-19 Duncan Losin <[email protected]>
+
+ [pic]: Extend to allow drawing arbitrary polygons.
+
+ * src/preproc/pic/lex.cpp (get_token_after_dot): Add new checks
+ for `.v[er[tex]]` and `.p[oint]` syntax for polygons.
+
+ * src/preproc/pic/object.h (enum object_type, object_type)
+ (object_type_name):
+ * src/preproc/pic/lex.cpp (lookup_keyword): Add `polygon`
+ keyword and object type.
+
+ * src/preproc/pic/object.h (struct object): Declare new virtual
+ functions for determining polygon vertices and edge midpoints.
+
+ * src/preproc/pic/object.h (class path): Add new `vertex_number`
+ and `is_edge` member variables to determine what position should
+ be accessed.
+
+ * src/preproc/pic/pic.ypp (tokens): Add new tokens `POLYGON`,
+ `DOT_P`, and `DOT_V`.
+
+ * src/preproc/pic/pic.ypp (object_spec): Add new rule `POLYGON`
+ to create new object_spec of type `POLYGON_OBJECT`. Add new
+ rule `object_spec WITH vertex` to locate polygons.
+
+ * src/preproc/pic/pic.ypp (place): Add new rules `label vertex`
+ and `vertex OF label` to locate polygons.
+
+ * src/preproc/pic/pic.ypp (vertex):
+ * src/preproc/pic/object.h (struct vertex): Define new `vertex`
+ structure and grammar rule for describing polygon vertices and
+ edge midpoints.
+
+ * src/preproc/pic/object.cpp (object::vertex, object::point):
+ (object::set_vertex_number): Define default behavior for new
+ functions.
+
+ * src/preproc/pic/object.cpp (object_spec::object_spec): Set
+ defaults for `vertex_number` and `is_edge`.
+
+ * src/preproc/pic/object.cpp (class polygon_object)
+ (polygon_object::polygon_object)
+ (polygon_object::center)
+ (polygon_object::point)
+ (polygon_object::set_fill)
+ (polygon_object::set_vertex_number)
+ (polygon_object::vertex)
+ (polygon_object::print): Add new `polygon` class and implement
+ member functions.
+
+ * src/preproc/pic/object.cpp (object_spec::make_line): Modify
+ line segment array from n-1 to n segments if a polygon has been
+ requested. Create offsets for positioning new polygons.
+
+ * src/preproc/pic/object.cpp (object_spec::make_object): Add
+ check for the `POLYGON_OBJECT` object type.
+
+ * doc/pic.ms:
+ * src/preproc/pic/pic.1.man (Other changes): Document it.
+
+ Fixes <https://savannah.gnu.org/bugs/?66458>.
+
2025-06-06 G. Branden Robinson <[email protected]>
* src/roff/troff/input.cpp (is_char_usable_as_delimiter): Loosen
diff --git a/doc/pic.ms b/doc/pic.ms
index 3fd1a42c2..11ec36247 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,
@@ -644,6 +646,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
@@ -835,7 +852,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.
@@ -1262,6 +1279,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
@@ -2658,6 +2721,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
@@ -2878,6 +3000,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
@@ -3012,7 +3135,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
@@ -3038,6 +3163,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
@@ -3063,6 +3197,7 @@ There are lots of different ways to specify positions:
box
circle
ellipse
+ polygon
arc
line
arrow
diff --git a/src/preproc/pic/lex.cpp b/src/preproc/pic/lex.cpp
index c437e2b30..43131c6a8 100644
--- a/src/preproc/pic/lex.cpp
+++ b/src/preproc/pic/lex.cpp
@@ -531,6 +531,7 @@ int lookup_keyword(const char *str, int len)
{ "outline", OUTLINED },
{ "outlined", OUTLINED },
{ "plot", PLOT },
+ { "polygon", POLYGON },
{ "print", PRINT },
{ "rad", RADIUS },
{ "radius", RADIUS },
@@ -863,6 +864,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 9ebf4bbae..7e70e89ca 100644
--- a/src/preproc/pic/object.cpp
+++ b/src/preproc/pic/object.cpp
@@ -371,6 +371,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;
@@ -419,6 +433,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;
@@ -1451,6 +1467,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;
@@ -1522,17 +1604,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;
@@ -1563,6 +1687,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);
}
@@ -1906,6 +2035,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 98eb638b8..ee99877e6 100644
--- a/src/preproc/pic/object.h
+++ b/src/preproc/pic/object.h
@@ -26,6 +26,7 @@ enum object_type {
ARC_OBJECT,
SPLINE_OBJECT,
LINE_OBJECT,
+ POLYGON_OBJECT,
ARROW_OBJECT,
MOVE_OBJECT,
TEXT_OBJECT,
@@ -55,6 +56,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();
@@ -73,6 +77,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;
@@ -190,6 +200,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 b98518b50..b53de3d54 100644
--- a/src/preproc/pic/pic.1.man
+++ b/src/preproc/pic/pic.1.man
@@ -1309,6 +1309,45 @@ for i = 1 to 3 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 ba26996db..69c99ca43 100644
--- a/src/preproc/pic/pic.ypp
+++ b/src/preproc/pic/pic.ypp
@@ -110,6 +110,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;
@@ -134,6 +135,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
@@ -177,6 +179,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
@@ -264,14 +268,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
@@ -295,6 +299,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
@@ -694,6 +699,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);
@@ -900,6 +912,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;
@@ -1286,6 +1306,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);
@@ -1298,6 +1325,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;
@@ -1388,6 +1422,8 @@ object_type:
{ $$ = ARC_OBJECT; }
| LINE
{ $$ = LINE_OBJECT; }
+ | POLYGON
+ { $$ = POLYGON_OBJECT; }
| ARROW
{ $$ = ARROW_OBJECT; }
| SPLINE
@@ -1524,6 +1560,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; }
@@ -1909,6 +1970,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:
_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit