Next: , Previous: Sample C Drawings, Up: C Programming


9.2.5 Simple paths and compound paths

The most sophisticated sort of graphical object that libplot can draw is a path. In this section we explain the fine details of constructing paths. The other three sorts of graphical object (text strings, marker symbols, and points [i.e., pixels]) are discussed elsewhere.

As in Postscript, paths may be simple or compound. A simple path is a contiguous sequence of line segments, circular arcs, elliptic arcs, quadratic Bezier curves, and/or cubic Bezier curves. A simple path may also be a circle, an ellipse, or a rectangle. A compound path consists of one or more simple paths, which must be nested: they should not intersect each other. This is more restrictive than in Postscript.

libplot's drawing model is significantly different from Postscript's, and is more user-friendly. Before drawing a path by invoking libplot operations, you do not need to call any special function. You would specify the attributes of the path before drawing, however. Attributes include pen color, line type, line width, cap type, join type, and miter limit. If the path is to be filled, the fill color and fill rule would be specified too. All these attributes are `modal': their values are preserved from path to path.

In principle, you would end any path you construct, and request that it be drawn on the graphics display, by invoking the endpath operation. But endpath is called automatically when any path-related attribute is changed, when move is called to change the graphics cursor position, and before any other object is constructed and drawn. It is also called at the end of each page of graphics, i.e., when closepl is invoked. So invoking endpath explicitly is usually unnecessary. This is quite different from Postscript, where an explicit command to stroke or fill a path is required.

libplot also differs from Postscript in the way it constructs and draws compound paths. In libplot, you would end each of the constituent simple paths of a compound path by invoking the endsubpath operation. After all simple paths are drawn, the compound path as a whole would be drawn by invoking endpath. After each of the calls to endsubpath, you are allowed to call move to reposition the graphics cursor, prior to beginning the next simple path. Immediately after an invocation of endsubpath, a call to move will not automatically invoke endpath.

The following sample program uses a Postscript Plotter to produce Postscript output. It draws a typical compound path, which consists of 17 simple paths. The first simple path is a large box. This box contains 7 circles, nested within each other, and a separate set of 7 circles that are also nested within each other. Within each of the two sets of nested circles is a pair of contiguous line segments, which make up an additional simple path. The compound path is drawn in green, and it is filled. The fill color is light blue.

     #include <stdio.h>
     #include <plot.h>
     
     int main ()
     {
       int i, j;
       plPlotter *plotter;
       plPlotterParams *plotter_params;
     
       /* set a Plotter parameter */
       plotter_params = pl_newplparams ();
       pl_setplparam (plotter_params, "PAGESIZE", "letter");
       /* create a Postscript Plotter that writes to standard output */
       plotter = pl_newpl_r ("ps", stdin, stdout, stderr, plotter_params);
       /* open Plotter, i.e. begin a page of graphics */
       pl_openpl_r (plotter);
     
       pl_fspace_r (plotter, 0.0, 0.0, 1000.0, 1000.0); /* set coor system */
       pl_flinewidth_r (plotter, 5.0);  /* set line thickness */
       pl_pencolorname_r (plotter, "green");
       pl_fillcolorname_r (plotter, "light blue");
       pl_filltype_r (plotter, 1);      /* do filling, full strength */
       pl_erase_r (plotter);            /* erase graphics display */
     
       /* draw a compound path consisting of 17 simple paths */
     
       /* draw the first simple path: a large box */
       pl_orientation_r (plotter, 1);
       pl_fbox_r (plotter, 50.0, 50.0, 950.0, 950.0);
       pl_endsubpath_r (plotter);
       for (i = 0; i < 2; i++)
         /* draw 8 simple paths that are nested inside the box */
         {
           /* first, draw 7 simple paths: nested circles */
           for (j = 9; j >= 3; j--)
             {
               pl_orientation_r (plotter, j % 2 ? -1 : 1);
               pl_fcircle_r (plotter, 250.0 + 500 * i, 500.0, j * 20.0);
               pl_endsubpath_r (plotter);
             }
           /* draw an open simple path comprising two line segments */
           pl_fmove_r (plotter, 225.0 + 500 * i, 475.0);
           pl_fcont_r (plotter, 250.0 + 500 * i, 525.0);
           pl_fcont_r (plotter, 275.0 + 500 * i, 475.0);
           pl_endsubpath_r (plotter);
         }
       /* formally end the compound path (not actually necessary) */
       pl_endpath_r (plotter);
     
       /* close Plotter, i.e. end page of graphics */
       pl_closepl_r (plotter);
       /* delete Plotter */
       if (pl_deletepl_r (plotter) < 0)
         {
           fprintf (stderr, "Couldn't delete Plotter\n");
           return 1;
         }
       return 0;
     }

As you will see if you run this program, the filling of the compound path takes place in a visually pleasing way: alternating annular regions are filled. That is because libplot's default fill rule is "even-odd". Since a compound path's constituent simple paths must always be nested, it is easy for libplot to determine which regions between them are `even' and which are `odd'. It is the latter that are filled.

The above program includes many invocations of orientation. The value of the modal `orientation' attribute (1, meaning counterclockwise, or −1, meaning clockwise) applies to subsequently drawn boxes, circles, and ellipses. If "even-odd" filling is used, they have no effect. But if the fill rule for the compound path is set to "nonzero-winding" by an initial call to fillmod, these calls to orientation will arrange matters so that alternating annular regions are filled, just as if "even-odd" filling were used.

If the preceding paragraph is mysterious, it would be wise to consult a good book on Postscript programming, or any other reference on the subject of `winding numbers'.