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 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
|
/* This file contains the internal paint_path() and paint_paths() methods,
which the public method endpath() is a wrapper around. */
/* This version is for AIPlotters. By construction, for AIPlotters our
path storage buffer may include only a segment list: a list of line
segments and/or cubic Bezier segments. No primitives such as ellipses,
circles, and boxes are allowed: any such primitive, if drawn, is
replaced by a segment list at a higher level. */
#include "sys-defines.h"
#include "extern.h"
/* Maximum value for squared sine of angle between two segments, if their
juncture is to be a `smooth point' rather than a corner point. (In
Illustrator, smooth points have only one direction handle; not two.) */
#define MAX_SQUARED_SINE (1e-6)
void
#ifdef _HAVE_PROTOS
_a_paint_path (S___(Plotter *_plotter))
#else
_a_paint_path (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
if (_plotter->drawstate->pen_type == 0
&& _plotter->drawstate->fill_type == 0)
/* nothing to draw */
return;
switch ((int)_plotter->drawstate->path->type)
{
case (int)PATH_SEGMENT_LIST:
{
int i, numpoints;
bool closed;
double linewidth;
/* 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 */
/* set fill color and pen color */
if (_plotter->drawstate->fill_type)
/* will be filling the path */
_a_set_fill_color (R___(_plotter) false);
else
/* won't be filling the path, but set AI's fill color anyway; in
particular, to be the same as the pen color (this is a
convenience for AI users who may wish e.g. to switch from
stroking to filling) */
_a_set_fill_color (R___(_plotter) true);
_a_set_pen_color (S___(_plotter));
/* update line attributes (cap style, join style, line width), if
necessary */
_a_set_attributes (S___(_plotter));
linewidth = _plotter->drawstate->line_width;
numpoints = _plotter->drawstate->path->num_segments;
/* loop over segments in path */
for (i = 0; i < numpoints; i++)
{
bool smooth_join_point; /* if a path join point, a smooth one? */
/* update bounding box to take into account the segment's
terminal point (which is either a path join point or a path
end point) */
if (!closed && (i == 0 || i == numpoints - 1))
/* for the path, an end rather than a join */
{
double xcurrent, ycurrent, xother, yother;
smooth_join_point = false;
/* compute path end point, and a nearby point, the vector
to which will determine the shape of the path end */
xcurrent = _plotter->drawstate->path->segments[i].p.x;
ycurrent = _plotter->drawstate->path->segments[i].p.y;
if (i == 0) /* i = 0, initial end point */
{
if (_plotter->drawstate->path->segments[i+1].type == S_CUBIC)
{
xother = _plotter->drawstate->path->segments[i+1].pc.x;
yother = _plotter->drawstate->path->segments[i+1].pc.y;
}
else /* line segment */
{
xother = _plotter->drawstate->path->segments[i+1].p.x;
yother = _plotter->drawstate->path->segments[i+1].p.y;
}
}
else /* i = numpoints - 1, final end point */
{
if (_plotter->drawstate->path->segments[i].type == S_CUBIC)
{
xother = _plotter->drawstate->path->segments[i].pd.x;
yother = _plotter->drawstate->path->segments[i].pd.y;
}
else /* line segment */
{
xother = _plotter->drawstate->path->segments[i-1].p.x;
yother = _plotter->drawstate->path->segments[i-1].p.y;
}
}
/* take path end into account: update bounding box */
_set_line_end_bbox (_plotter->data->page,
xcurrent, ycurrent, xother, yother,
linewidth, _plotter->drawstate->cap_type,
_plotter->drawstate->transform.m);
}
else
/* for the path, a join rather than an end */
{
int a, b, c;
double xcurrent, ycurrent, xleft, yleft, xright, yright;
if (closed && (i == 0 || i == numpoints - 1)) /* wrap */
{
a = numpoints - 2;
b = numpoints - 1;
c = 1;
}
else /* normal join */
{
a = i - 1;
b = i;
c = i + 1;
}
xcurrent = _plotter->drawstate->path->segments[b].p.x;
ycurrent = _plotter->drawstate->path->segments[b].p.y;
/* compute points to left and right, vectors to which will
determine the shape of the path join */
switch ((int)_plotter->drawstate->path->segments[b].type)
{
case (int)S_LINE:
default:
xleft = _plotter->drawstate->path->segments[a].p.x;
yleft = _plotter->drawstate->path->segments[a].p.y;
break;
case (int)S_CUBIC:
xleft = _plotter->drawstate->path->segments[b].pd.x;
yleft = _plotter->drawstate->path->segments[b].pd.y;
break;
}
switch ((int)_plotter->drawstate->path->segments[c].type)
{
case (int)S_LINE:
default:
xright = _plotter->drawstate->path->segments[c].p.x;
yright = _plotter->drawstate->path->segments[c].p.y;
break;
case (int)S_CUBIC:
xright = _plotter->drawstate->path->segments[c].pc.x;
yright = _plotter->drawstate->path->segments[c].pc.y;
break;
}
/* take path join into account: update bounding box */
_set_line_join_bbox(_plotter->data->page,
xleft, yleft, xcurrent, ycurrent, xright, yright,
linewidth,
_plotter->drawstate->join_type,
_plotter->drawstate->miter_limit,
_plotter->drawstate->transform.m);
/* is join smooth? */
{
double ux, uy, vx, vy, cross, dot, uselfdot, vselfdot;
ux = xleft - xcurrent;
uy = yleft - ycurrent;
vx = xright - xcurrent;
vy = yright - ycurrent;
cross = ux * vy - uy * vx;
dot = ux * vx + uy * vy;
uselfdot = ux * ux + uy * uy;
vselfdot = vx * vx + vy * vy;
if (cross * cross < MAX_SQUARED_SINE * uselfdot * vselfdot
&& dot < 0.0)
smooth_join_point = true;
else
smooth_join_point = false;
}
}
/* output to Illustrator the points that define this segment */
if (i != 0
&& (_plotter->drawstate->path->segments)[i].type == S_CUBIC)
/* cubic Bezier segment, so output control points */
{
sprintf (_plotter->data->page->point,
"%.4f %.4f %.4f %.4f ",
XD(_plotter->drawstate->path->segments[i].pc.x,
_plotter->drawstate->path->segments[i].pc.y),
YD(_plotter->drawstate->path->segments[i].pc.x,
_plotter->drawstate->path->segments[i].pc.y),
XD(_plotter->drawstate->path->segments[i].pd.x,
_plotter->drawstate->path->segments[i].pd.y),
YD(_plotter->drawstate->path->segments[i].pd.x,
_plotter->drawstate->path->segments[i].pd.y));
_update_buffer (_plotter->data->page);
/* update bounding box due to extremal x/y values in device
frame */
_set_bezier3_bbox (_plotter->data->page,
_plotter->drawstate->path->segments[i-1].p.x,
_plotter->drawstate->path->segments[i-1].p.y,
_plotter->drawstate->path->segments[i].pc.x,
_plotter->drawstate->path->segments[i].pc.y,
_plotter->drawstate->path->segments[i].pd.x,
_plotter->drawstate->path->segments[i].pd.y,
_plotter->drawstate->path->segments[i].p.x,
_plotter->drawstate->path->segments[i].p.y,
_plotter->drawstate->device_line_width,
_plotter->drawstate->transform.m);
}
/* output terminal point of segment */
sprintf (_plotter->data->page->point,
"%.4f %.4f ",
XD(_plotter->drawstate->path->segments[i].p.x,
_plotter->drawstate->path->segments[i].p.y),
YD(_plotter->drawstate->path->segments[i].p.x,
_plotter->drawstate->path->segments[i].p.y));
_update_buffer (_plotter->data->page);
/* tell Illustrator what sort of path segment this is */
if (i == 0)
/* start of path, so just move to point */
sprintf (_plotter->data->page->point, "m\n");
else
/* append line segment or Bezier segment to path */
switch ((int)_plotter->drawstate->path->segments[i].type)
{
case (int)S_LINE:
default:
sprintf (_plotter->data->page->point,
smooth_join_point ? "l\n" : "L\n");
break;
case (int)S_CUBIC:
sprintf (_plotter->data->page->point,
smooth_join_point ? "c\n" : "C\n");
break;
}
_update_buffer (_plotter->data->page);
} /* end of loop over segments */
if (_plotter->drawstate->pen_type)
/* have a pen to draw with */
{
/* emit `closepath' if path is closed; stroke and maybe fill */
if (_plotter->drawstate->fill_type)
{
if (closed)
/* close path, fill and stroke */
sprintf (_plotter->data->page->point, "b\n");
else
/* fill and stroke */
sprintf (_plotter->data->page->point, "B\n");
}
else
{
if (closed)
/* close path, stroke */
sprintf (_plotter->data->page->point, "s\n");
else
/* stroke */
sprintf (_plotter->data->page->point, "S\n");
}
}
else
/* no pen to draw with, but we may do filling */
{
/* emit `closepath' if path is closed; don't stroke */
if (_plotter->drawstate->fill_type)
{
if (closed)
/* close path, fill */
sprintf (_plotter->data->page->point, "f\n");
else
/* fill */
sprintf (_plotter->data->page->point, "F\n");
}
}
_update_buffer (_plotter->data->page);
}
break;
default: /* shouldn't happen */
break;
}
}
bool
#ifdef _HAVE_PROTOS
_a_paint_paths (S___(Plotter *_plotter))
#else
_a_paint_paths (S___(_plotter))
S___(Plotter *_plotter;)
#endif
{
return false;
}
|