1 /* This file is part of the GNU plotutils package.  Copyright (C) 1995,
2    1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3 
4    The GNU plotutils package is free software.  You may redistribute it
5    and/or modify it under the terms of the GNU General Public License as
6    published by the Free Software foundation; either version 2, or (at your
7    option) any later version.
8 
9    The GNU plotutils package is distributed in the hope that it will be
10    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with the GNU plotutils package; see the file COPYING.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17    Boston, MA 02110-1301, USA. */
18 
19 /* This file contains the internal path_is_flushable() method, which is
20    invoked after any path segment is added to the segment list, provided
21    (0) the segment list has become greater than or equal to the
22    `max_unfilled_path_length' Plotter parameter, (1) the path isn't to be
23    filled.  In most Plotters, this operation simply returns true. */
24 
25 /* This file also contains the internal maybe_prepaint_segments() method.
26    It is called immediately after any segment is added to a path.  Some
27    Plotters, at least under some circumstances, treat endpath() as a no-op.
28    Instead, they plot the segments of a path in real time.  */
29 
30 /**********************************************************************/
31 
32 /* This version of the internal method path_is_flushable() is for Tektronix
33    Plotters, which (1) reduce all paths to line segments as they are
34    constructed, and (2) plot the resulting line segments ("vectors") in
35    real time.  Unlike the generic version, which returns true, this version
36    returns false. */
37 
38 #include "sys-defines.h"
39 #include "extern.h"
40 
41 bool
_pl_t_path_is_flushable(S___ (Plotter * _plotter))42 _pl_t_path_is_flushable (S___(Plotter *_plotter))
43 {
44   return false;
45 }
46 
47 /**********************************************************************/
48 
49 /* This version of the internal method maybe_prepaint_segments() is for
50    Tektronix Plotters, which (1) reduce all paths to line segments as they
51    are constructed, and (2) plot the resulting line segments ("vectors") in
52    real time.  This is what does all the painting of line segments on a
53    Tektronix display. */
54 
55 /* for Cohen-Sutherland clipper, see g_clipper.c */
56 enum { ACCEPTED = 0x1, CLIPPED_FIRST = 0x2, CLIPPED_SECOND = 0x4 };
57 
58 void
_pl_t_maybe_prepaint_segments(R___ (Plotter * _plotter)int prev_num_segments)59 _pl_t_maybe_prepaint_segments (R___(Plotter *_plotter) int prev_num_segments)
60 {
61   int i;
62 
63   /* sanity check */
64   if (_plotter->drawstate->path->num_segments < 2)
65     return;
66 
67   if (_plotter->drawstate->path->num_segments == prev_num_segments)
68     /* nothing to paint */
69     return;
70 
71   /* skip drawing if pen level is set to `0' */
72   if (_plotter->drawstate->pen_type == 0)
73     return;
74 
75   /* Skip drawing if the pen color is white.  Since our TekPlotter class
76      doesn't support filling, this is ok to do if the Tektronix isn't a
77      kermit emulator (the kermit emulator supports color). */
78   if (_plotter->tek_display_type != TEK_DPY_KERMIT
79       && _plotter->drawstate->fgcolor.red == 0xffff
80       && _plotter->drawstate->fgcolor.green == 0xffff
81       && _plotter->drawstate->fgcolor.blue == 0xffff)
82     return;
83 
84   /* iterate over all new segments, i.e. segments to be painted */
85 
86   for (i = IMAX(1, prev_num_segments);
87        i < _plotter->drawstate->path->num_segments;
88        i++)
89     {
90       plPoint start, end;	/* endpoints of line seg. (in device coors) */
91       plIntPoint istart, iend;	/* same, quantized to integer Tek coors */
92       int clipval;
93       bool same_point, force;
94 
95       /* nominal starting point and ending point for new line segment, in
96 	 floating point device coordinates */
97       start.x = XD(_plotter->drawstate->path->segments[i-1].p.x,
98 		   _plotter->drawstate->path->segments[i-1].p.y);
99       start.y = YD(_plotter->drawstate->path->segments[i-1].p.x,
100 		   _plotter->drawstate->path->segments[i-1].p.y);
101       end.x = XD(_plotter->drawstate->path->segments[i].p.x,
102 		 _plotter->drawstate->path->segments[i].p.y);
103       end.y = YD(_plotter->drawstate->path->segments[i].p.x,
104 		 _plotter->drawstate->path->segments[i].p.y);
105       same_point = (start.x == end.x && start.y == end.y) ? true : false;
106 
107       /* clip line segment to rectangular clipping region in device frame */
108       clipval = _clip_line (&start.x, &start.y, &end.x, &end.y,
109 			    TEK_DEVICE_X_MIN_CLIP, TEK_DEVICE_X_MAX_CLIP,
110 			    TEK_DEVICE_Y_MIN_CLIP, TEK_DEVICE_Y_MAX_CLIP);
111       if (!(clipval & ACCEPTED))	/* line segment is OOB */
112 	continue;
113 
114       /* convert clipped starting point, ending point to integer Tek coors */
115       istart.x = IROUND(start.x);
116       istart.y = IROUND(start.y);
117       iend.x = IROUND(end.x);
118       iend.y = IROUND(end.y);
119 
120       if (i == 1)
121 	/* New polyline is beginning, so start to draw it on the display:
122 	   move to starting point of the first line segment, in Tek space.
123 	   As a side-effect, the escape sequence emitted by _pl_t_tek_move()
124 	   will shift the Tektronix to the desired mode, either PLOT or
125 	   POINT.  Note that if we are already in the desired mode,
126 	   emitting the escape sequence will prevent a line being drawn at
127 	   the time of the move (the "dark vector" concept).  That is of
128 	   course what we want. */
129 	_pl_t_tek_move (R___(_plotter) istart.x, istart.y);
130       else
131 	/* A polyline is underway, >=1 line segments already.  So check
132 	   whether the position on the Tektronix is the same as the
133 	   starting point of the new line segment; if it differs, move to
134 	   the latter.  Such a difference can occur on account of clipping.
135 	   Also the Tektronix position could have changed on us if a
136 	   savestate()...restorestate() occurred since the last call to
137 	   cont(). */
138 	{
139 	  int correct_tek_mode =
140 	    _plotter->drawstate->points_are_connected ? TEK_MODE_PLOT : TEK_MODE_POINT;
141 
142 	  if (_plotter->tek_position_is_unknown
143 	      || _plotter->tek_pos.x != istart.x
144 	      || _plotter->tek_pos.y != istart.y
145 	      || _plotter->tek_mode_is_unknown
146 	      || _plotter->tek_mode != correct_tek_mode)
147 	    /* Move to desired position.  This automatically shifts the
148 	       Tektronix to correct mode, PLOT or POINT; see comment
149 	       above. */
150 	    _pl_t_tek_move (R___(_plotter) istart.x, istart.y);
151 	}
152 
153       /* Sync Tek's linestyle with ours; an escape sequence is emitted only
154 	 if necessary.  Linestyle could have changed on us if a
155 	 savestate()...restorestate() occurred since the last call to
156 	 cont().  Sync Tek's color and background color too (significant
157 	 only for kermit Tek emulator). */
158       _pl_t_set_attributes (S___(_plotter));
159       _pl_t_set_pen_color (S___(_plotter));
160       _pl_t_set_bg_color (S___(_plotter));
161 
162       /* If this is initial line segment of a polyline, force output of a
163 	 vector even if line segment has zero length, so that something
164 	 visible will appear on the display.  We do this only if (1) the
165 	 line segment in the user frame was of nonzero length, or (2) it
166 	 was of zero length but the cap mode is "round".  This more or less
167 	 agrees with our convention, on bitmap Plotters (X, PNM, GIF,
168 	 etc.), for dealing with device-frame vectors that are of
169 	 (quantized) zero length.  */
170       if (i == 1
171 	  && (same_point == false
172 	      || (same_point == true
173 		  && _plotter->drawstate->cap_type == PL_CAP_ROUND)))
174 	force = true;
175       else
176 	force = false;
177 
178       /* continue polyline by drawing vector on Tek display */
179       _pl_t_tek_vector_compressed (R___(_plotter)
180 				   iend.x, iend.y, istart.x, istart.y, force);
181 
182       /* update our notion of Tek's notion of position */
183       _plotter->tek_pos.x = iend.x;
184       _plotter->tek_pos.y = iend.y;
185     }
186 }
187