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

Reply via email to