File: p_endpath.c

package info (click to toggle)
plotutils 2.0-2
  • links: PTS
  • area: main
  • in suites: hamm
  • size: 5,964 kB
  • ctags: 2,522
  • sloc: ansic: 38,416; sh: 1,853; yacc: 856; makefile: 181; lex: 144
file content (305 lines) | stat: -rw-r--r-- 11,401 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/* This file contains the endpath() method, which is a GNU extension to
   libplot.  A polyline object may be constructed incrementally, by
   repeated invocations of the cont() routine.  (See the comments in
   g_cont.c.)  The construction may be terminated, and the polyline object
   finalized, by an explicit invocation of endpath().

   If endpath() is invoked when no polyline is under construction, it has
   no effect. */

#include "sys-defines.h"
#include "plot.h"
#include "extern.h"

/* 16-bit brush patterns for idraw (1 = on, 0 = off): */
const long _ps_line_type_bit_vector[] = 
/* solid, dotted, dotdashed, shortdashed, longdashed */
{ 0xffff, 0x8888, 0xc3f0, 0xf0f0, 0xffc0 };

/* corresponding dash arrays for PS (cylically used, on/off/on/off... */
const char *_ps_line_type_setdash[] =
/* these on/off bit patterns are those used by our X11 driver, and also by
   the xterm Tektronix emulator, except that the emulator seems incorrectly
   to have on and off interchanged */
{ "", "1 3", "1 3 4 3", "4 4", "7 4" };

/* PS join styles, indexed by internal join type number (miter/rd./bevel) */
const int _ps_join_style[] =
{ PS_JOIN_MITER, PS_JOIN_ROUND, PS_JOIN_BEVEL };

/* PS cap styles, indexed by internal cap type number (butt/rd./project) */
const int _ps_cap_style[] =
{ PS_CAP_BUTT, PS_CAP_ROUND, PS_CAP_PROJECT };

int
#ifdef _HAVE_PROTOS
_p_endpath (void)
#else
_p_endpath ()
#endif
{
  int i, capstyle, joinstyle, numpoints;
  bool closed, singular_map;
  double linewidth, invnorm = 0.0, granularity = 1.0;

  if (!_plotter->open)
    {
      _plotter->error ("endpath: invalid operation");
      return -1;
    }

  /* If a circular arc has been stashed rather than drawn, force it to be
     drawn by invoking farc() with the `immediate' flag set.  Note that
     if an arc is stashed, PointsInLine must be zero. */
  if (_plotter->drawstate->arc_stashed) 
    { 
      double axc = _plotter->drawstate->axc;
      double ayc = _plotter->drawstate->ayc;
      double ax0 = _plotter->drawstate->ax0;
      double ay0 = _plotter->drawstate->ay0;
      double ax1 = _plotter->drawstate->ax1;
      double ay1 = _plotter->drawstate->ay1;

      _plotter->drawstate->arc_immediate = true; 
      _plotter->drawstate->arc_polygonal = false; /* advisory only */
      _plotter->farc (axc, ayc, ax0, ay0, ax1, ay1);
      _plotter->drawstate->arc_immediate = false;
      _plotter->drawstate->arc_stashed = false;
    }

  if (_plotter->drawstate->PointsInLine == 0)	/* nothing to do */
    return 0;
  if (_plotter->drawstate->PointsInLine == 1)	/* shouldn't happen */
    {
      /* just reset polyline storage buffer */
      free (_plotter->drawstate->datapoints);
      _plotter->drawstate->datapoints_len = 0;
      _plotter->drawstate->PointsInLine = 0;
      return 0;
    }
  
  if ((_plotter->drawstate->PointsInLine >= 3) /* check for closure */
      && (_plotter->drawstate->datapoints[_plotter->drawstate->PointsInLine - 1].x == _plotter->drawstate->datapoints[0].x)
      && (_plotter->drawstate->datapoints[_plotter->drawstate->PointsInLine - 1].y == _plotter->drawstate->datapoints[0].y))
    closed = true;
  else
    closed = false;		/* 2-point ones should be open */
  
  /* Special case: disconnected points, no real polyline.  We switch to a
     temporary datapoints buffer for this.  This is a hack, needed because
     (in this library) point() calls endpath(), which would mess the real
     databuffer up, if we didn't do something like this. */
  if (!_plotter->drawstate->points_are_connected)
    {
      Point saved_pos;
      Point *saved_datapoints = _plotter->drawstate->datapoints;
      int saved_PointsInLine = _plotter->drawstate->PointsInLine;
      
      saved_pos = _plotter->drawstate->pos;

      _plotter->drawstate->datapoints = NULL;
      _plotter->drawstate->datapoints_len = 0;
      _plotter->drawstate->PointsInLine = 0;
      _plotter->drawstate->points_are_connected = true; /* for duration */

      for (i = 0; i < saved_PointsInLine - (closed ? 1 : 0); i++)
	_plotter->fpoint (saved_datapoints[i].x,
			  saved_datapoints[i].y);

      free (saved_datapoints);
      _plotter->drawstate->points_are_connected = false;
      _plotter->drawstate->pos = saved_pos; /* restore graphics cursor */
      return 0;
    }
  
  /* general case: points are vertices of a polyline */

  /* compute reciprocal norm of user->device affine transformation; need
     this because transformation matrices we'll emit must be normalized */
  {
    double det, norm;
    
    det = _plotter->drawstate->transform.m[0] * _plotter->drawstate->transform.m[3]
      - _plotter->drawstate->transform.m[1] * _plotter->drawstate->transform.m[2];
    norm = sqrt(fabs(det));
    /* 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;
  }

  /* includes idraw instruction: start of MLine or Poly */
  if (closed)
    strcpy (_plotter->outbuf.current, "Begin %I Poly\n");
  else
    strcpy (_plotter->outbuf.current, "Begin %I MLine\n");
  _update_buffer (&_plotter->outbuf);

  /* 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;
      double linewidth_adjust;

      /* adjustment needed, due to our specifying line widths as integers */
      if (integer_linewidth != 0)
	linewidth_adjust = double_linewidth / integer_linewidth;
      else
	linewidth_adjust = 1.0;

      sprintf (_plotter->outbuf.current, "[");
      _update_buffer (&_plotter->outbuf);

      for (i = 0; i < 4; i++)
	{
	  sprintf (_plotter->outbuf.current, "%.7g ", 
		   linewidth_adjust * invnorm * _plotter->drawstate->transform.m[i]);
	  _update_buffer (&_plotter->outbuf);
	}
      _update_buffer (&_plotter->outbuf);
      sprintf (_plotter->outbuf.current, 
	       "0 0 ] trueoriginalCTM originalCTM\n concatmatrix pop\n");
      _update_buffer (&_plotter->outbuf);
    }

  /* specify cap style and join style */
  sprintf (_plotter->outbuf.current, "%d setlinecap %d setlinejoin\n",
	   _ps_cap_style[_plotter->drawstate->cap_type], 
	   _ps_join_style[_plotter->drawstate->join_type]);
  _update_buffer (&_plotter->outbuf);

  /* idraw instruction: line type bit vector */
  sprintf (_plotter->outbuf.current, "%%I b %ld\n", 
	   _ps_line_type_bit_vector[_plotter->drawstate->line_type]);
  _update_buffer (&_plotter->outbuf);

  /* PS instruction: SetB (i.e. setbrush), with args
     LineWidth, LeftArrow, RightArrow, DashArray, DashOffset. */
  /* Note LineWidth must be an integer for idraw compatibility. */
  sprintf (_plotter->outbuf.current, "%d 0 0 [ %s ] 0 SetB\n", 
	   _plotter->drawstate->quantized_device_line_width,
	   _ps_line_type_setdash[_plotter->drawstate->line_type]);
  _update_buffer (&_plotter->outbuf);
  
  /* idraw instruction: set foreground color */
  _plotter->set_pen_color();  /* invoked lazily, i.e. when needed */
  sprintf (_plotter->outbuf.current, "%%I cfg %s\n%g %g %g SetCFg\n",
	   _idraw_stdcolornames[_plotter->drawstate->idraw_fgcolor],
	   _plotter->drawstate->ps_fgcolor_red, 
	   _plotter->drawstate->ps_fgcolor_green, 
	   _plotter->drawstate->ps_fgcolor_blue);
  _update_buffer (&_plotter->outbuf);
  
  /* idraw instruction: set background color */
  _plotter->set_fill_color();  /* invoked lazily, i.e. when needed */
  sprintf (_plotter->outbuf.current, "%%I cbg %s\n%g %g %g SetCBg\n",
	   _idraw_stdcolornames[_plotter->drawstate->idraw_bgcolor],
	   _plotter->drawstate->ps_fillcolor_red, 
	   _plotter->drawstate->ps_fillcolor_green, 
	   _plotter->drawstate->ps_fillcolor_blue);
  _update_buffer (&_plotter->outbuf);
  
  /* includes idraw instruction: set fill pattern */
  if (_plotter->drawstate->fill_level == 0)	/* transparent */
    sprintf (_plotter->outbuf.current, "%%I p\nnone SetP\n");
  else	/* filled, i.e. shaded, in the sense of idraw */
    sprintf (_plotter->outbuf.current, "%%I p\n%f SetP\n", 
	     _idraw_stdshadings[_plotter->drawstate->idraw_shading]);
  _update_buffer (&_plotter->outbuf);
  
  /* includes idraw instruction: transformation matrix (all 6 elements) */
  sprintf (_plotter->outbuf.current, "%%I t\n[");
  _update_buffer (&_plotter->outbuf);
  for (i = 0; i < 6; i++)
    {
      if ((i==0) || (i==1) || (i==2) || (i==3))
	sprintf (_plotter->outbuf.current, "%.7g ", _plotter->drawstate->transform.m[i] / granularity);
      else
	sprintf (_plotter->outbuf.current, "%.7g ", _plotter->drawstate->transform.m[i]);
      _update_buffer (&_plotter->outbuf);
    }
  sprintf (_plotter->outbuf.current, "] concat\n");
  _update_buffer (&_plotter->outbuf);
  
  /* idraw instruction: number of points in line */
  sprintf (_plotter->outbuf.current, "%%I %d\n", 
	   _plotter->drawstate->PointsInLine - (closed ? 1 : 0));
  _update_buffer (&_plotter->outbuf);

  linewidth = _plotter->drawstate->line_width;
  capstyle = _ps_cap_style[_plotter->drawstate->cap_type];
  joinstyle = _ps_join_style[_plotter->drawstate->join_type];
  /* number of points to be output */
  numpoints = _plotter->drawstate->PointsInLine - (closed ? 1 : 0);
  for (i=0; i < numpoints; i++)
    {
      /* output the data point */
      sprintf (_plotter->outbuf.current, "%d %d\n",
	       IROUND(granularity * (_plotter->drawstate->datapoints[i]).x),
	       IROUND(granularity * (_plotter->drawstate->datapoints[i]).y));
      _update_buffer (&_plotter->outbuf);
      
      /* update bounding box */
      if (!closed && ((i == 0) || (i == numpoints - 1)))
	/* an end rather than a join */
	{
	  int otherp;
	  
	  otherp = (i == 0 ? 1 : numpoints - 2);
	  _set_line_end_bbox (_plotter->drawstate->datapoints[i].x,
			      _plotter->drawstate->datapoints[i].y,
			      _plotter->drawstate->datapoints[otherp].x,
			      _plotter->drawstate->datapoints[otherp].y,
			      linewidth, capstyle);
	}
      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->drawstate->datapoints[a].x,
			      _plotter->drawstate->datapoints[a].y,
			      _plotter->drawstate->datapoints[b].x,
			      _plotter->drawstate->datapoints[b].y,
			      _plotter->drawstate->datapoints[c].x,
			      _plotter->drawstate->datapoints[c].y,
			      linewidth, joinstyle);
	}
    }
  
  if (closed)
    sprintf (_plotter->outbuf.current, "%d Poly\nEnd\n\n", numpoints);
  else
    sprintf (_plotter->outbuf.current, "%d MLine\nEnd\n\n", numpoints);
  _update_buffer (&_plotter->outbuf);
  
  /* reset polyline storage buffer */
  free (_plotter->drawstate->datapoints);
  _plotter->drawstate->datapoints_len = 0;
  _plotter->drawstate->PointsInLine = 0;

  return 0;
}