123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- /* This file is part of the GNU plotutils package. Copyright (C) 1995,
- 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
- The GNU plotutils package is free software. You may 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, or (at your
- option) any later version.
- The GNU plotutils package is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with the GNU plotutils package; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
- Boston, MA 02110-1301, USA. */
- /* This file contains the internal paint_path() and paint_paths() methods,
- which the public method endpath() is a wrapper around. */
- /* This version is for PSPlotters. By construction, for PSPlotters our
- path storage buffer, if it contains a path of segment array type,
- contains a sequence of line segments only (no other path elements such
- as arcs or Beziers are allowed). That's because our PS driver draws
- objects by calling PS functions defined in the idraw header, and the
- header doesn't include functions that draw arcs or Beziers. */
- #include "sys-defines.h"
- #include "extern.h"
- /* 16-bit brush patterns for idraw (1 = on, 0 = off), indexed by our
- internal numbering of line types, i.e. by L_{SOLID,DOTTED,DOTDASHED,
- SHORTDASHED,LONGDASHED,DOTDOTDASHED,DOTDOTDOTDASHED} */
- static const long idraw_brush_pattern[PL_NUM_LINE_TYPES] =
- { 0xffff, 0x8888, 0xfc30, 0xf0f0, 0xffc0, 0xfccc, 0xfdb6 };
- /* PS join styles, indexed by internal number (miter/rd./bevel/triangular) */
- static const int ps_join_style[PL_NUM_JOIN_TYPES] =
- { PS_LINE_JOIN_MITER, PS_LINE_JOIN_ROUND, PS_LINE_JOIN_BEVEL, PS_LINE_JOIN_ROUND };
- /* PS cap styles, indexed by internal number (butt/rd./project/triangular) */
- static const int ps_cap_style[PL_NUM_CAP_TYPES] =
- { PS_LINE_CAP_BUTT, PS_LINE_CAP_ROUND, PS_LINE_CAP_PROJECT, PS_LINE_CAP_ROUND };
- void
- _pl_p_paint_path (S___(Plotter *_plotter))
- {
- double granularity;
- if (_plotter->drawstate->pen_type == 0
- && _plotter->drawstate->fill_type == 0)
- /* nothing to draw */
- return;
- /* Compute `granularity': factor by which user-frame coordinates will be
- scaled up, so that when they're emitted as integers (which idraw
- requires), resolution loss won't be excessive. CTM factors will be
- scaled down by this factor. */
- {
- /* compute norm of user->device affine transformation */
- double norm, min_sing_val, max_sing_val;
-
- /* This minimum singular value isn't really the norm. But it's the
- nominal device-frame line width divided by the actual user-frame
- line-width (see g_linewidth.c), and that's what we need. */
- _matrix_sing_vals (_plotter->drawstate->transform.m,
- &min_sing_val, &max_sing_val);
- norm = min_sing_val;
-
- granularity = norm / (PS_MIN_RESOLUTION);
- }
- if (granularity == 0.0)
- /* must have norm = 0, quit now to avoid division by zero */
- return;
- switch ((int)_plotter->drawstate->path->type)
- {
- case (int)PATH_SEGMENT_LIST:
- {
- bool closed, closed_int;
- int i, numpoints, index_start, index_increment;
- int polyline_len;
- plIntPoint *xarray;
-
- /* sanity checks */
- if (_plotter->drawstate->path->num_segments == 0)/* nothing to do */
- break;
- if (_plotter->drawstate->path->num_segments == 1) /*shouldn't happen */
- break;
- if ((_plotter->drawstate->path->num_segments >= 3)/*check for closure*/
- && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.x == _plotter->drawstate->path->segments[0].p.x)
- && (_plotter->drawstate->path->segments[_plotter->drawstate->path->num_segments - 1].p.y == _plotter->drawstate->path->segments[0].p.y))
- closed = true;
- else
- closed = false; /* 2-point ones should be open */
-
- /* scale up each point coordinate by granularity factor and round
- it to closest integer, removing runs of points with the same
- scaled integer coordinates */
- xarray = (plIntPoint *)_pl_xmalloc (_plotter->drawstate->path->num_segments * sizeof(plIntPoint));
- polyline_len = 0;
- for (i = 0; i < _plotter->drawstate->path->num_segments; i++)
- {
- plPoint datapoint;
- int x_int, y_int;
-
- datapoint = _plotter->drawstate->path->segments[i].p;
- x_int = IROUND(granularity * datapoint.x);
- y_int = IROUND(granularity * datapoint.y);
-
- if ((polyline_len == 0)
- || (x_int != xarray[polyline_len-1].x)
- || (y_int != xarray[polyline_len-1].y))
- /* add point, in integer coordinates, to the array */
- {
- xarray[polyline_len].x = x_int;
- xarray[polyline_len].y = y_int;
- polyline_len++;
- }
- }
- /* Handle awkward cases: due to rounding and elimination of runs,
- may be only 1 or 2 distinct vertices left in the polyline. */
- if (polyline_len == 1)
- /* add a second point */
- {
- xarray[1] = xarray[0];
- polyline_len = 2;
- }
- if (polyline_len == 2)
- closed_int = false; /* 2-point ones should be open */
- else
- closed_int = closed;
- /* number of points to be output, given that we're quantizing
- coordinates and removing runs */
- numpoints = polyline_len - (closed_int ? 1 : 0);
- /* emit prolog and idraw instructions: start of MLine or Poly */
- if (closed_int)
- strcpy (_plotter->data->page->point, "Begin %I Poly\n");
- else
- strcpy (_plotter->data->page->point, "Begin %I MLine\n");
- _update_buffer (_plotter->data->page);
-
- /* emit common attributes: CTM, fill rule, cap and join styles and
- miter limit, dash array, foreground and background colors, and
- idraw brush. */
- _pl_p_emit_common_attributes (S___(_plotter));
-
- /* emit transformation matrix (all 6 elements) */
- strcpy (_plotter->data->page->point, "%I t\n[");
- _update_buffer (_plotter->data->page);
- for (i = 0; i < 6; i++)
- {
- if ((i==0) || (i==1) || (i==2) || (i==3))
- sprintf (_plotter->data->page->point, "%.7g ", _plotter->drawstate->transform.m[i] / granularity);
- else
- sprintf (_plotter->data->page->point, "%.7g ", _plotter->drawstate->transform.m[i]);
- _update_buffer (_plotter->data->page);
- }
- strcpy (_plotter->data->page->point, "\
- ] concat\n");
- _update_buffer (_plotter->data->page);
-
- /* emit idraw instruction: number of points in line */
- sprintf (_plotter->data->page->point, "\
- %%I %d\n",
- numpoints);
- _update_buffer (_plotter->data->page);
-
- /* if polyline is closed, loop through points _backward_, since the
- `Poly' function in the idraw prologue draws closed polylines in
- reverse, and we want the dasharray to be interpreted correctly */
- if (closed_int)
- {
- index_start = numpoints - 1;
- index_increment = -1;
- }
- else
- {
- index_start = 0;
- index_increment = 1;
- }
- for (i = index_start;
- i >= 0 && i <= numpoints - 1;
- i += index_increment)
- {
- /* output the data point */
- sprintf (_plotter->data->page->point, "\
- %d %d\n",
- xarray[i].x, xarray[i].y);
- _update_buffer (_plotter->data->page);
- }
-
- if (closed_int)
- sprintf (_plotter->data->page->point, "\
- %d Poly\n\
- End\n\n", numpoints);
- else
- sprintf (_plotter->data->page->point, "\
- %d MLine\n\
- End\n\n", numpoints);
- _update_buffer (_plotter->data->page);
- /* free temporary storage for quantized points */
- free (xarray);
- /* Update bounding box, by iterating over segments in the original
- segment array (no quantizing, please). But for consistency,
- iterate in much the same way as above. */
- /* number of points that we'd have emitted, had we not quantized
- and removed runs */
- numpoints =
- _plotter->drawstate->path->num_segments - (closed ? 1 : 0);
- if (closed)
- {
- index_start = numpoints - 1;
- index_increment = -1;
- }
- else
- {
- index_start = 0;
- index_increment = 1;
- }
- for (i = index_start;
- i >= 0 && i <= numpoints - 1;
- i += index_increment)
- {
- if (!closed && ((i == 0) || (i == numpoints - 1)))
- /* an end rather than a join */
- {
- int j;
-
- j = (i == 0 ? 1 : numpoints - 2);
- _set_line_end_bbox (_plotter->data->page,
- _plotter->drawstate->path->segments[i].p.x,
- _plotter->drawstate->path->segments[i].p.y,
- _plotter->drawstate->path->segments[j].p.x,
- _plotter->drawstate->path->segments[j].p.y,
- _plotter->drawstate->line_width,
- _plotter->drawstate->cap_type,
- _plotter->drawstate->transform.m);
- }
- else
- /* a join rather than an end */
- {
- int a, b, c;
-
- if (closed && i == 0) /* wrap */
- {
- a = numpoints - 1;
- b = 0;
- c = 1;
- }
- else /* normal join */
- {
- a = i - 1;
- b = i;
- c = i + 1;
- }
- _set_line_join_bbox(_plotter->data->page,
- _plotter->drawstate->path->segments[a].p.x,
- _plotter->drawstate->path->segments[a].p.y,
- _plotter->drawstate->path->segments[b].p.x,
- _plotter->drawstate->path->segments[b].p.y,
- _plotter->drawstate->path->segments[c].p.x,
- _plotter->drawstate->path->segments[c].p.y,
- _plotter->drawstate->line_width,
- _plotter->drawstate->join_type,
- _plotter->drawstate->miter_limit,
- _plotter->drawstate->transform.m);
- }
- }
- }
- break;
- case (int)PATH_BOX:
- {
- int i;
- /* emit prolog and idraw instructions: start of Rect */
- strcpy (_plotter->data->page->point, "Begin %I Rect\n");
- _update_buffer (_plotter->data->page);
-
- /* emit common attributes: CTM, fill rule, cap and join styles and
- miter limit, dash array, foreground and background colors, and
- idraw brush. */
- _pl_p_emit_common_attributes (S___(_plotter));
-
- /* emit transformation matrix (all 6 elements) */
- strcpy (_plotter->data->page->point, "%I t\n[");
- _update_buffer (_plotter->data->page);
- for (i = 0; i < 6; i++)
- {
- if ((i==0) || (i==1) || (i==2) || (i==3))
- sprintf (_plotter->data->page->point, "%.7g ", _plotter->drawstate->transform.m[i] / granularity);
- else
- sprintf (_plotter->data->page->point, "%.7g ", _plotter->drawstate->transform.m[i]);
- _update_buffer (_plotter->data->page);
- }
- strcpy (_plotter->data->page->point, "\
- ] concat\n");
- _update_buffer (_plotter->data->page);
-
- /* output the two defining vertices (preceded by an empty idraw
- instruction), and wind things up */
- sprintf (_plotter->data->page->point, "\
- %%I\n\
- %d %d %d %d Rect\n\
- End\n\n",
- IROUND(granularity * _plotter->drawstate->path->p0.x),
- IROUND(granularity * _plotter->drawstate->path->p0.y),
- IROUND(granularity * _plotter->drawstate->path->p1.x),
- IROUND(granularity * _plotter->drawstate->path->p1.y));
- _update_buffer (_plotter->data->page);
-
- /* update bounding box */
- _set_line_join_bbox(_plotter->data->page,
- _plotter->drawstate->path->p0.x,
- _plotter->drawstate->path->p1.y,
- _plotter->drawstate->path->p0.x,
- _plotter->drawstate->path->p0.y,
- _plotter->drawstate->path->p1.x,
- _plotter->drawstate->path->p0.y,
- _plotter->drawstate->line_width,
- _plotter->drawstate->join_type,
- _plotter->drawstate->miter_limit,
- _plotter->drawstate->transform.m);
- _set_line_join_bbox(_plotter->data->page,
- _plotter->drawstate->path->p0.x,
- _plotter->drawstate->path->p0.y,
- _plotter->drawstate->path->p1.x,
- _plotter->drawstate->path->p0.y,
- _plotter->drawstate->path->p1.x,
- _plotter->drawstate->path->p1.y,
- _plotter->drawstate->line_width,
- _plotter->drawstate->join_type,
- _plotter->drawstate->miter_limit,
- _plotter->drawstate->transform.m);
- _set_line_join_bbox(_plotter->data->page,
- _plotter->drawstate->path->p1.x,
- _plotter->drawstate->path->p0.y,
- _plotter->drawstate->path->p1.x,
- _plotter->drawstate->path->p1.y,
- _plotter->drawstate->path->p0.x,
- _plotter->drawstate->path->p1.y,
- _plotter->drawstate->line_width,
- _plotter->drawstate->join_type,
- _plotter->drawstate->miter_limit,
- _plotter->drawstate->transform.m);
- _set_line_join_bbox(_plotter->data->page,
- _plotter->drawstate->path->p1.x,
- _plotter->drawstate->path->p1.y,
- _plotter->drawstate->path->p0.x,
- _plotter->drawstate->path->p1.y,
- _plotter->drawstate->path->p0.x,
- _plotter->drawstate->path->p0.y,
- _plotter->drawstate->line_width,
- _plotter->drawstate->join_type,
- _plotter->drawstate->miter_limit,
- _plotter->drawstate->transform.m);
- }
- break;
- case (int)PATH_CIRCLE:
- {
- plPoint pc;
- double radius;
- pc = _plotter->drawstate->path->pc;
- radius = _plotter->drawstate->path->radius;
-
- /* final arg flags this for idraw as a circle, not an ellipse */
- _pl_p_fellipse_internal (R___(_plotter) pc.x, pc.y, radius, radius,
- 0.0, true);
- }
- break;
-
- case (int)PATH_ELLIPSE:
- {
- double x = _plotter->drawstate->path->pc.x;
- double y = _plotter->drawstate->path->pc.y;
- double rx = _plotter->drawstate->path->rx;
- double ry = _plotter->drawstate->path->ry;
- double angle = _plotter->drawstate->path->angle;
- /* final arg flags this for idraw as an ellipse, not a circle */
- _pl_p_fellipse_internal (R___(_plotter) x, y, rx, ry, angle, false);
- }
- break;
- default: /* shouldn't happen */
- break;
- }
- }
-
- /* ARGS: circlep = drawn as a circle in user frame? */
- void
- _pl_p_fellipse_internal (R___(Plotter *_plotter) double x, double y, double rx, double ry, double angle, bool circlep)
- {
- if (_plotter->drawstate->pen_type || _plotter->drawstate->fill_type)
- /* have something to draw */
- {
- double granularity;
- double costheta, sintheta;
- double offcenter_rotation_matrix[6];
- double ellipse_transformation_matrix[6];
- int i;
- /* emit prolog instruction and idraw directive: start of Elli or Circ */
- if (circlep)
- strcpy (_plotter->data->page->point, "Begin %I Circ\n");
- else
- strcpy (_plotter->data->page->point, "Begin %I Elli\n");
- _update_buffer(_plotter->data->page);
-
- /* emit common attributes: CTM, fill rule, cap and join styles and
- miter limit, dash array, foreground and background colors, and
- idraw brush. */
- granularity = _pl_p_emit_common_attributes (S___(_plotter));
- /* An affine tranformation must be applied to the ellipse produced by
- the Elli routine in the idraw prologue, to turn it into the
- ellipse we want. The Elli routine produces an ellipse with
- specified semi-axes, aligned parallel to the coordinate axes in
- user space, and centered on the point (x,y). I.e. it produces,
- symbolically,
- [unit circle centered on (0,0)] S T
- where S is a diagonal matrix that scales the unit circle to give
- the specified semi-axis lengths, and T translates (0,0) to (x,y).
- This is not what we want, since the ellipse is not rotated (it has
- zero inclination angle). What we want is
-
- [unit circle centered on (0,0)] S R T
- where R is a rotation matrix. This may be rewritten as
-
- [unit circle centered on (0,0)] S T (T^{-1} R T)
- where T^{-1} R T is a so-called offcenter rotation matrix, which
- rotates about the point (x,y). So the ellipse transformation
- matrix we'll place in the PS code will be (T^{-1} R T) times the
- matrix that transforms from user space to device space. */
- costheta = cos (M_PI * angle / 180.0);
- sintheta = sin (M_PI * angle / 180.0);
-
- offcenter_rotation_matrix[0] = costheta; /* 1st 4 els are those of R */
- offcenter_rotation_matrix[1] = sintheta;
- offcenter_rotation_matrix[2] = - sintheta;
- offcenter_rotation_matrix[3] = costheta;
- offcenter_rotation_matrix[4] = x * (1.0 - costheta) + y * sintheta;
- offcenter_rotation_matrix[5] = y * (1.0 - costheta) - x * sintheta;
-
- _matrix_product (offcenter_rotation_matrix,
- _plotter->drawstate->transform.m,
- ellipse_transformation_matrix);
-
- /* emit idraw directive: transformation matrix (all 6 elements) */
- sprintf (_plotter->data->page->point, "%%I t\n[");
- _update_buffer(_plotter->data->page);
- for (i = 0; i < 6; i++)
- {
- if ((i==0) || (i==1) || (i==2) || (i==3))
- sprintf (_plotter->data->page->point, "%.7g ",
- ellipse_transformation_matrix[i] / granularity);
- else
- sprintf (_plotter->data->page->point, "%.7g ",
- ellipse_transformation_matrix[i]);
- _update_buffer(_plotter->data->page);
- }
- sprintf (_plotter->data->page->point, "] concat\n");
- _update_buffer(_plotter->data->page);
-
- /* emit idraw directive: draw Elli, and end Elli (or same for Circ) */
- if (circlep)
- sprintf (_plotter->data->page->point, "%%I\n%d %d %d Circ\nEnd\n\n",
- IROUND(granularity * x), IROUND(granularity * y),
- IROUND(granularity * rx));
- else
- sprintf (_plotter->data->page->point, "%%I\n%d %d %d %d Elli\nEnd\n\n",
- IROUND(granularity * x), IROUND(granularity * y),
- IROUND(granularity * rx), IROUND(granularity * ry));
- _update_buffer(_plotter->data->page);
-
- /* update bounding box */
- _set_ellipse_bbox (_plotter->data->page, x, y, rx, ry, costheta, sintheta,
- _plotter->drawstate->line_width,
- _plotter->drawstate->transform.m);
- }
- }
- /* Emit the common attributes, for PS and idraw, of any path object, either
- polyline, ellipse, or box. This includes the CTM, fill rule, cap and
- join styles and miter limit, dash array, foreground and background
- colors, and idraw brush.
-
- Return value is the `granularity': a factor by which user-frame
- coordinates, when emitted to the output file as integers, should be
- scaled up. This is to avoid loss of precision when using integer
- coordinates. The CTM emitted here will automatically compensate for the
- granularity factor.
- Note: some of the functions that call this one (see _pl_p_paint_path()
- above) need to compute the granularity themselves, since they can't need
- to quit if the granularity is zero, without calling this function . */
- double
- _pl_p_emit_common_attributes (S___(Plotter *_plotter))
- {
- bool singular_map;
- int i;
- double invnorm = 0.0, granularity = 1.0;
- double linewidth_adjust = 1.0;
- double min_sing_val, max_sing_val, norm;
- /* compute norm of user->device affine transformation */
- /* This minimum singular value isn't really the norm. But it's the
- nominal device-frame line width divided by the actual user-frame
- line-width (see g_linewidth.c), and that's what we need. */
- _matrix_sing_vals (_plotter->drawstate->transform.m,
- &min_sing_val, &max_sing_val);
- norm = min_sing_val;
- /* granularity = scaleup factor for user coordinates, so that when
- they're emitted as integers, resolution loss won't be excessive.
- CTM entries will be scaled down by this factor. */
- granularity = norm / (PS_MIN_RESOLUTION);
- if (norm != 0.0)
- {
- /* invnorm is `norm' of device->user coordinate transformation */
- invnorm = 1.0 / norm;
- singular_map = false;
- }
- else
- singular_map = true;
- /* redefine `originalCTM' matrix, which is the CTM applied when the
- polyline is stroked (as opposed to drawn). We define it to be the
- same as the one in effect when the polyline was drawn. */
- if (singular_map != true)
- {
- int integer_linewidth = _plotter->drawstate->quantized_device_line_width;
- double double_linewidth = _plotter->drawstate->device_line_width;
- /* adjustment to CTM needed, due to our specifying line widths as
- integers */
- if (integer_linewidth != 0)
- linewidth_adjust = double_linewidth / integer_linewidth;
- else
- linewidth_adjust = 1.0;
- strcpy (_plotter->data->page->point, "[");
- _update_buffer (_plotter->data->page);
- for (i = 0; i < 4; i++)
- {
- sprintf (_plotter->data->page->point, "%.7g ",
- linewidth_adjust * invnorm * _plotter->drawstate->transform.m[i]);
- _update_buffer (_plotter->data->page);
- }
- _update_buffer (_plotter->data->page);
- strcpy (_plotter->data->page->point, "\
- 0 0 ] trueoriginalCTM originalCTM\n\
- concatmatrix pop\n");
- _update_buffer (_plotter->data->page);
- }
-
- /* specify cap style and join style, and miter limit if mitering */
- if (_plotter->drawstate->join_type == PL_JOIN_MITER)
- sprintf (_plotter->data->page->point, "\
- %d setlinecap %d setlinejoin %.4g setmiterlimit\n",
- ps_cap_style[_plotter->drawstate->cap_type],
- ps_join_style[_plotter->drawstate->join_type],
- _plotter->drawstate->miter_limit);
- else
- sprintf (_plotter->data->page->point, "\
- %d setlinecap %d setlinejoin\n",
- ps_cap_style[_plotter->drawstate->cap_type],
- ps_join_style[_plotter->drawstate->join_type]);
- _update_buffer (_plotter->data->page);
-
- /* specify fill rule (i.e. whether to use even-odd filling) */
- if (_plotter->drawstate->fill_rule_type == PL_FILL_NONZERO_WINDING)
- sprintf (_plotter->data->page->point, "\
- /eoFillRule false def\n");
- else
- sprintf (_plotter->data->page->point, "\
- /eoFillRule true def\n");
- _update_buffer (_plotter->data->page);
-
- if (_plotter->drawstate->pen_type != 0)
- /* pen is present, so will brush an outline of the path */
- {
- int num_dashes;
- double scale;
- double *dashbuf, dash_cycle_length, offset;
- if (_plotter->drawstate->dash_array_in_effect)
- /* have user-specified dash array */
- {
- /* idraw instruction: brush type (spec'd as bit vector, but for now
- we just use a solid brush */
- sprintf (_plotter->data->page->point, "\
- %%I b %ld\n",
- (long int)0xffff);
- _update_buffer (_plotter->data->page);
-
- num_dashes = _plotter->drawstate->dash_array_len;
- if (num_dashes > 0)
- dashbuf = (double *)_pl_xmalloc (num_dashes * sizeof(double));
- else
- dashbuf = NULL; /* solid line */
- /* take the adjustment to the CTM into account */
- scale = norm / linewidth_adjust;
-
- dash_cycle_length = 0.0;
- for (i = 0; i < num_dashes; i++)
- {
- double dashlen;
-
- dashlen = _plotter->drawstate->dash_array[i];
- dash_cycle_length += dashlen;
- dashbuf[i] = scale * dashlen;
- }
-
- if (dash_cycle_length > 0.0)
- /* choose an offset in range 0..true_cycle_length */
- {
- double true_cycle_length;
-
- offset = _plotter->drawstate->dash_offset;
- true_cycle_length =
- dash_cycle_length * (num_dashes % 2 == 1 ? 2 : 1);
- while (offset < 0.0)
- offset += true_cycle_length;
- offset = fmod (offset, true_cycle_length);
- offset *= scale;
- }
- else
- offset = 0.0;
- }
- else
- /* have one of the canonical line types */
- {
- /* idraw brush type (spec'd as bit vector) */
- sprintf (_plotter->data->page->point, "\
- %%I b %ld\n",
- idraw_brush_pattern[_plotter->drawstate->line_type]);
- _update_buffer (_plotter->data->page);
-
- if (_plotter->drawstate->line_type == PL_L_SOLID)
- {
- num_dashes = 0;
- dashbuf = NULL;
- offset = 0.0;
- }
- else
- {
- const int *dash_array;
- double display_size_in_points, min_dash_unit;
-
- /* compute PS dash array for this line type */
- dash_array =
- _pl_g_line_styles[_plotter->drawstate->line_type].dash_array;
- num_dashes =
- _pl_g_line_styles[_plotter->drawstate->line_type].dash_array_len;
- dashbuf = (double *)_pl_xmalloc (num_dashes * sizeof(double));
-
- /* scale the array of integers by line width (actually by
- floored line width) */
- display_size_in_points =
- DMIN(_plotter->data->xmax - _plotter->data->xmin,
- _plotter->data->ymax - _plotter->data->ymin);
- min_dash_unit = (PL_MIN_DASH_UNIT_AS_FRACTION_OF_DISPLAY_SIZE
- * display_size_in_points);
- scale = DMAX(min_dash_unit,
- _plotter->drawstate->device_line_width);
- /* take the adjustment to the CTM into account */
- scale /= linewidth_adjust;
-
- for (i = 0; i < num_dashes; i++)
- dashbuf[i] = scale * dash_array[i];
- offset = 0.0;
- }
- }
- /* PS instruction: SetB (i.e. setbrush), with args
- LineWidth, LeftArrow, RightArrow, DashArray, DashOffset. */
- /* Note LineWidth must be an integer for idraw compatibility. */
-
- /* emit dash array */
- sprintf (_plotter->data->page->point, "%d 0 0 [ ",
- _plotter->drawstate->quantized_device_line_width);
- _update_buffer (_plotter->data->page);
- for (i = 0; i < num_dashes; i++)
- {
- sprintf (_plotter->data->page->point, "%.3g ", dashbuf[i]);
- _update_buffer (_plotter->data->page);
- }
- sprintf (_plotter->data->page->point, "] %.3g SetB\n", offset);
- _update_buffer (_plotter->data->page);
- free (dashbuf);
- }
- else
- /* pen_type = 0, we have no pen to draw with (though we may do filling) */
- {
- sprintf (_plotter->data->page->point, "\
- %%I b n\n\
- none SetB\n");
- _update_buffer (_plotter->data->page);
- }
-
- /* idraw instruction: set foreground color */
- _pl_p_set_pen_color (S___(_plotter)); /* invoked lazily, when needed */
- sprintf (_plotter->data->page->point, "\
- %%I cfg %s\n\
- %g %g %g SetCFg\n",
- _pl_p_idraw_stdcolornames[_plotter->drawstate->ps_idraw_fgcolor],
- _plotter->drawstate->ps_fgcolor_red,
- _plotter->drawstate->ps_fgcolor_green,
- _plotter->drawstate->ps_fgcolor_blue);
- _update_buffer (_plotter->data->page);
-
- /* idraw instruction: set background color */
- _pl_p_set_fill_color (S___(_plotter)); /* invoked lazily, when needed */
- sprintf (_plotter->data->page->point, "\
- %%I cbg %s\n\
- %g %g %g SetCBg\n",
- _pl_p_idraw_stdcolornames[_plotter->drawstate->ps_idraw_bgcolor],
- _plotter->drawstate->ps_fillcolor_red,
- _plotter->drawstate->ps_fillcolor_green,
- _plotter->drawstate->ps_fillcolor_blue);
- _update_buffer (_plotter->data->page);
-
- /* includes idraw instruction: set fill pattern */
- if (_plotter->drawstate->fill_type == 0) /* transparent */
- sprintf (_plotter->data->page->point, "\
- %%I p\n\
- none SetP\n");
- else /* filled, i.e. shaded, in the sense of idraw */
- sprintf (_plotter->data->page->point, "\
- %%I p\n\
- %f SetP\n",
- _pl_p_idraw_stdshadings[_plotter->drawstate->ps_idraw_shading]);
- _update_buffer (_plotter->data->page);
-
- /* return factor we'll later use to scale up user-frame coordinates */
- return granularity;
- }
- bool
- _pl_p_paint_paths (S___(Plotter *_plotter))
- {
- return false;
- }
|