1 /* $Id: plline.c,v 1.3 2007/05/08 09:09:37 rice Exp $
2
3 Routines dealing with line generation.
4
5 Copyright (C) 2004 Maurice LeBrun
6
7 This file is part of PLplot.
8
9 PLplot is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Library General Public License as published
11 by the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 PLplot is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public License
20 along with PLplot; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
23 */
24
25 #include "plplotP.h"
26
27 #define INSIDE(ix,iy) (BETW(ix,xmin,xmax) && BETW(iy,ymin,ymax))
28
29 static PLINT xline[PL_MAXPOLY], yline[PL_MAXPOLY];
30
31 static PLINT lastx = PL_UNDEFINED, lasty = PL_UNDEFINED;
32
33 /* Function prototypes */
34
35 /* Draws a polyline within the clip limits. */
36
37 static void
38 pllclp(PLINT *x, PLINT *y, PLINT npts);
39
40 /* Get clipped endpoints */
41
42 static int
43 clipline(PLINT *p_x1, PLINT *p_y1, PLINT *p_x2, PLINT *p_y2,
44 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax);
45
46 /* General line-drawing routine. Takes line styles into account. */
47
48 static void
49 genlin(short *x, short *y, PLINT npts);
50
51 /* Draws a dashed line to the specified point from the previous one. */
52
53 static void
54 grdashline(short *x, short *y);
55
56 /* Determines if a point is inside a polygon or not */
57
58 static int
59 pointinpolygon( int n, PLINT *x, PLINT *y, PLINT xp, PLINT yp );
60
61 /*----------------------------------------------------------------------*\
62 * void pljoin()
63 *
64 * Draws a line segment from (x1, y1) to (x2, y2).
65 \*----------------------------------------------------------------------*/
66
67 void
c_pljoin(PLFLT xx1,PLFLT yy1,PLFLT xx2,PLFLT yy2)68 c_pljoin(PLFLT xx1, PLFLT yy1, PLFLT xx2, PLFLT yy2)
69 {
70 plP_movwor(xx1, yy1);
71 plP_drawor(xx2, yy2);
72 }
73
74 /*----------------------------------------------------------------------*\
75 * void plline()
76 *
77 * Draws line segments connecting a series of points.
78 \*----------------------------------------------------------------------*/
79
80 void
c_plline(PLINT n,PLFLT * x,PLFLT * y)81 c_plline(PLINT n, PLFLT *x, PLFLT *y)
82 {
83 if (plsc->level < 3) {
84 plabort("plline: Please set up window first");
85 return;
86 }
87 plP_drawor_poly(x, y, n);
88 }
89
90 /*----------------------------------------------------------------------*\
91 * void plline3(n, x, y, z)
92 *
93 * Draws a line in 3 space. You must first set up the viewport, the
94 * 2d viewing window (in world coordinates), and the 3d normalized
95 * coordinate box. See x18c.c for more info.
96 *
97 * This version adds clipping against the 3d bounding box specified in plw3d
98 \*----------------------------------------------------------------------*/
99 void
c_plline3(PLINT n,PLFLT * x,PLFLT * y,PLFLT * z)100 c_plline3(PLINT n, PLFLT *x, PLFLT *y, PLFLT *z)
101 {
102 int i;
103 PLFLT vmin[3], vmax[3], zscale;
104
105 if (plsc->level < 3) {
106 plabort("plline3: Please set up window first");
107 return;
108 }
109
110 /* get the bounding box in 3d */
111 plP_gdom(&vmin[0], &vmax[0], &vmin[1], &vmax[1]);
112 plP_grange(&zscale, &vmin[2], &vmax[2]);
113
114 /* interate over the vertices */
115 for( i=0; i < n-1; i++ ) {
116 PLFLT p0[3], p1[3];
117 int axis;
118
119 /* copy the end points of the segment to allow clipping */
120 p0[0] = x[i]; p0[1] = y[i]; p0[2] = z[i];
121 p1[0] = x[i+1]; p1[1] = y[i+1]; p1[2] = z[i+1];
122
123 /* check against each axis of the bounding box */
124 for(axis = 0; axis < 3; axis++) {
125 if(p0[axis] < vmin[axis]) { /* first out */
126 if(p1[axis] < vmin[axis]) {
127 break; /* both endpoints out so quit */
128 } else {
129 int j;
130 /* interpolate to find intersection with box */
131 PLFLT t = (vmin[axis] - p0[axis]) / (p1[axis] - p0[axis]);
132 p0[axis] = vmin[axis];
133 for(j = 1; j<3; j++) {
134 int k = (axis+j)%3;
135 p0[k] = (1-t)*p0[k] + t*p1[k];
136 }
137 }
138 } else if(p1[axis] < vmin[axis]) { /* second out */
139 int j;
140 /* interpolate to find intersection with box */
141 PLFLT t = (vmin[axis] - p0[axis]) / (p1[axis] - p0[axis]);
142 p1[axis] = vmin[axis];
143 for(j = 1; j<3; j++) {
144 int k = (axis+j)%3;
145 p1[k] = (1-t)*p0[k] + t*p1[k];
146 }
147 }
148 if(p0[axis] > vmax[axis]) { /* first out */
149 if(p1[axis] > vmax[axis]) {
150 break; /* both out so quit */
151 } else {
152 int j;
153 /* interpolate to find intersection with box */
154 PLFLT t = (vmax[axis] - p0[axis]) / (p1[axis] - p0[axis]);
155 p0[axis] = vmax[axis];
156 for(j = 1; j<3; j++) {
157 int k = (axis+j)%3;
158 p0[k] = (1-t)*p0[k] + t*p1[k];
159 }
160 }
161 } else if(p1[axis] > vmax[axis]) { /* second out */
162 int j;
163 /* interpolate to find intersection with box */
164 PLFLT t = (vmax[axis] - p0[axis]) / (p1[axis] - p0[axis]);
165 p1[axis] = vmax[axis];
166 for(j = 1; j<3; j++) {
167 int k = (axis+j)%3;
168 p1[k] = (1-t)*p0[k] + t*p1[k];
169 }
170 }
171 }
172 /* if we made it to here without "break"ing out of the loop, the
173 remaining segment is visible */
174 if( axis == 3 ) { /* not clipped away */
175 PLFLT u0, v0, u1, v1;
176 u0 = plP_wcpcx(plP_w3wcx( p0[0], p0[1], p0[2] ));
177 v0 = plP_wcpcy(plP_w3wcy( p0[0], p0[1], p0[2] ));
178 u1 = plP_wcpcx(plP_w3wcx( p1[0], p1[1], p1[2] ));
179 v1 = plP_wcpcy(plP_w3wcy( p1[0], p1[1], p1[2] ));
180 plP_movphy(u0,v0);
181 plP_draphy(u1,v1);
182 }
183 }
184 return;
185 }
186 /*----------------------------------------------------------------------*\
187 * void plpoly3( n, x, y, z, draw, ifcc )
188 *
189 * Draws a polygon in 3 space. This differs from plline3() in that
190 * this attempts to determine if the polygon is viewable. If the back
191 * of polygon is facing the viewer, then it isn't drawn. If this
192 * isn't what you want, then use plline3 instead.
193 *
194 * n specifies the number of points. They are assumed to be in a
195 * plane, and the directionality of the plane is determined from the
196 * first three points. Additional points do not /have/ to lie on the
197 * plane defined by the first three, but if they do not, then the
198 * determiniation of visibility obviously can't be 100% accurate...
199 * So if you're 3 space polygons are too far from planar, consider
200 * breaking them into smaller polygons. "3 points define a plane" :-).
201 *
202 * For ifcc == 1, the directionality of the polygon is determined by assuming
203 * the points are laid out in counter-clockwise order.
204 *
205 * For ifcc == 0, the directionality of the polygon is determined by assuming
206 * the points are laid out in clockwise order.
207 *
208 * BUGS: If one of the first two segments is of zero length, or if
209 * they are colinear, the calculation of visibility has a 50/50 chance
210 * of being correct. Avoid such situations :-). See x18c for an
211 * example of this problem. (Search for "20.1").
212 \*----------------------------------------------------------------------*/
213
214 void
c_plpoly3(PLINT n,PLFLT * x,PLFLT * y,PLFLT * z,PLBOOL * draw,PLBOOL ifcc)215 c_plpoly3(PLINT n, PLFLT *x, PLFLT *y, PLFLT *z, PLBOOL *draw, PLBOOL ifcc)
216 {
217 int i;
218 PLFLT vmin[3], vmax[3], zscale;
219 PLFLT u1, v1, u2, v2, u3, v3;
220 PLFLT c;
221
222 if (plsc->level < 3) {
223 plabort("plpoly3: Please set up window first");
224 return;
225 }
226
227 if ( n < 3 ) {
228 plabort("plpoly3: Must specify at least 3 points");
229 return;
230 }
231
232 /* Now figure out which side this is. */
233
234 u1 = plP_wcpcx(plP_w3wcx( x[0], y[0], z[0] ));
235 v1 = plP_wcpcy(plP_w3wcy( x[0], y[0], z[0] ));
236
237 u2 = plP_wcpcx(plP_w3wcx( x[1], y[1], z[1] ));
238 v2 = plP_wcpcy(plP_w3wcy( x[1], y[1], z[1] ));
239
240 u3 = plP_wcpcx(plP_w3wcx( x[2], y[2], z[2] ));
241 v3 = plP_wcpcy(plP_w3wcy( x[2], y[2], z[2] ));
242
243 c = (u1-u2)*(v3-v2)-(v1-v2)*(u3-u2);
244
245 if ( c *(1 - 2*ABS(ifcc)) < 0. )
246 return;
247
248 /* get the bounding box in 3d */
249 plP_gdom(&vmin[0], &vmax[0], &vmin[1], &vmax[1]);
250 plP_grange(&zscale, &vmin[2], &vmax[2]);
251
252 /* interate over the vertices */
253 for( i=0; i < n-1; i++ ) {
254 PLFLT p0[3], p1[3];
255 int axis;
256
257 /* copy the end points of the segment to allow clipping */
258 p0[0] = x[i]; p0[1] = y[i]; p0[2] = z[i];
259 p1[0] = x[i+1]; p1[1] = y[i+1]; p1[2] = z[i+1];
260
261 /* check against each axis of the bounding box */
262 for(axis = 0; axis < 3; axis++) {
263 if(p0[axis] < vmin[axis]) { /* first out */
264 if(p1[axis] < vmin[axis]) {
265 break; /* both endpoints out so quit */
266 } else {
267 int j;
268 /* interpolate to find intersection with box */
269 PLFLT t = (vmin[axis] - p0[axis]) / (p1[axis] - p0[axis]);
270 p0[axis] = vmin[axis];
271 for(j = 1; j<3; j++) {
272 int k = (axis+j)%3;
273 p0[k] = (1-t)*p0[k] + t*p1[k];
274 }
275 }
276 } else if(p1[axis] < vmin[axis]) { /* second out */
277 int j;
278 /* interpolate to find intersection with box */
279 PLFLT t = (vmin[axis] - p0[axis]) / (p1[axis] - p0[axis]);
280 p1[axis] = vmin[axis];
281 for(j = 1; j<3; j++) {
282 int k = (axis+j)%3;
283 p1[k] = (1-t)*p0[k] + t*p1[k];
284 }
285 }
286 if(p0[axis] > vmax[axis]) { /* first out */
287 if(p1[axis] > vmax[axis]) {
288 break; /* both out so quit */
289 } else {
290 int j;
291 /* interpolate to find intersection with box */
292 PLFLT t = (vmax[axis] - p0[axis]) / (p1[axis] - p0[axis]);
293 p0[axis] = vmax[axis];
294 for(j = 1; j<3; j++) {
295 int k = (axis+j)%3;
296 p0[k] = (1-t)*p0[k] + t*p1[k];
297 }
298 }
299 } else if(p1[axis] > vmax[axis]) { /* second out */
300 int j;
301 /* interpolate to find intersection with box */
302 PLFLT t = (vmax[axis] - p0[axis]) / (p1[axis] - p0[axis]);
303 p1[axis] = vmax[axis];
304 for(j = 1; j<3; j++) {
305 int k = (axis+j)%3;
306 p1[k] = (1-t)*p0[k] + t*p1[k];
307 }
308 }
309 }
310 /* if we made it to here without "break"ing out of the loop, the
311 remaining segment is visible */
312 if( axis == 3 && draw[i] ) { /* not clipped away */
313 PLFLT myu0, myv0, myu1, myv1;
314 myu0 = plP_wcpcx(plP_w3wcx( p0[0], p0[1], p0[2] ));
315 myv0 = plP_wcpcy(plP_w3wcy( p0[0], p0[1], p0[2] ));
316 myu1 = plP_wcpcx(plP_w3wcx( p1[0], p1[1], p1[2] ));
317 myv1 = plP_wcpcy(plP_w3wcy( p1[0], p1[1], p1[2] ));
318 plP_movphy(myu0,myv0);
319 plP_draphy(myu1,myv1);
320 }
321 }
322 return;
323 }
324
325 /*----------------------------------------------------------------------*\
326 * void plstyl()
327 *
328 * Set up a new line style of "nms" elements, with mark and space
329 * lengths given by arrays "mark" and "space".
330 \*----------------------------------------------------------------------*/
331
332 void
c_plstyl(PLINT nms,PLINT * mark,PLINT * space)333 c_plstyl(PLINT nms, PLINT *mark, PLINT *space)
334 {
335 short int i;
336
337 if (plsc->level < 1) {
338 plabort("plstyl: Please call plinit first");
339 return;
340 }
341 if ((nms < 0) || (nms > 10)) {
342 plabort("plstyl: Broken lines cannot have <0 or >10 elements");
343 return;
344 }
345 for (i = 0; i < nms; i++) {
346 if ((mark[i] < 0) || (space[i] < 0)) {
347 plabort("plstyl: Mark and space lengths must be > 0");
348 return;
349 }
350 }
351
352 plsc->nms = nms;
353 for (i = 0; i < nms; i++) {
354 plsc->mark[i] = mark[i];
355 plsc->space[i] = space[i];
356 }
357
358 plsc->curel = 0;
359 plsc->pendn = 1;
360 plsc->timecnt = 0;
361 plsc->alarm = nms > 0 ? mark[0] : 0;
362 }
363
364 /*----------------------------------------------------------------------*\
365 * void plP_movphy()
366 *
367 * Move to physical coordinates (x,y).
368 \*----------------------------------------------------------------------*/
369
370 void
plP_movphy(PLINT x,PLINT y)371 plP_movphy(PLINT x, PLINT y)
372 {
373 plsc->currx = x;
374 plsc->curry = y;
375 }
376
377 /*----------------------------------------------------------------------*\
378 * void plP_draphy()
379 *
380 * Draw to physical coordinates (x,y).
381 \*----------------------------------------------------------------------*/
382
383 void
plP_draphy(PLINT x,PLINT y)384 plP_draphy(PLINT x, PLINT y)
385 {
386 xline[0] = plsc->currx;
387 xline[1] = x;
388 yline[0] = plsc->curry;
389 yline[1] = y;
390
391 pllclp(xline, yline, 2);
392 }
393
394 /*----------------------------------------------------------------------*\
395 * void plP_movwor()
396 *
397 * Move to world coordinates (x,y).
398 \*----------------------------------------------------------------------*/
399
400 void
plP_movwor(PLFLT x,PLFLT y)401 plP_movwor(PLFLT x, PLFLT y)
402 {
403 plsc->currx = plP_wcpcx(x);
404 plsc->curry = plP_wcpcy(y);
405 }
406
407 /*----------------------------------------------------------------------*\
408 * void plP_drawor()
409 *
410 * Draw to world coordinates (x,y).
411 \*----------------------------------------------------------------------*/
412
413 void
plP_drawor(PLFLT x,PLFLT y)414 plP_drawor(PLFLT x, PLFLT y)
415 {
416 xline[0] = plsc->currx;
417 xline[1] = plP_wcpcx(x);
418 yline[0] = plsc->curry;
419 yline[1] = plP_wcpcy(y);
420
421 pllclp(xline, yline, 2);
422 }
423
424 /*----------------------------------------------------------------------*\
425 * void plP_draphy_poly()
426 *
427 * Draw polyline in physical coordinates.
428 * Need to draw buffers in increments of (PL_MAXPOLY-1) since the
429 * last point must be repeated (for solid lines).
430 \*----------------------------------------------------------------------*/
431
432 void
plP_draphy_poly(PLINT * x,PLINT * y,PLINT n)433 plP_draphy_poly(PLINT *x, PLINT *y, PLINT n)
434 {
435 PLINT i, j, ib, ilim;
436
437 for (ib = 0; ib < n; ib += PL_MAXPOLY - 1) {
438 ilim = MIN(PL_MAXPOLY, n - ib);
439
440 for (i = 0; i < ilim; i++) {
441 j = ib + i;
442 xline[i] = x[j];
443 yline[i] = y[j];
444 }
445 pllclp(xline, yline, ilim);
446 }
447 }
448
449 /*----------------------------------------------------------------------*\
450 * void plP_drawor_poly()
451 *
452 * Draw polyline in world coordinates.
453 * Need to draw buffers in increments of (PL_MAXPOLY-1) since the
454 * last point must be repeated (for solid lines).
455 \*----------------------------------------------------------------------*/
456
457 void
plP_drawor_poly(PLFLT * x,PLFLT * y,PLINT n)458 plP_drawor_poly(PLFLT *x, PLFLT *y, PLINT n)
459 {
460 PLINT i, j, ib, ilim;
461
462 for (ib = 0; ib < n; ib += PL_MAXPOLY - 1) {
463 ilim = MIN(PL_MAXPOLY, n - ib);
464
465 for (i = 0; i < ilim; i++) {
466 j = ib + i;
467 xline[i] = plP_wcpcx(x[j]);
468 yline[i] = plP_wcpcy(y[j]);
469 }
470 pllclp(xline, yline, ilim);
471 }
472 }
473
474 /*----------------------------------------------------------------------*\
475 * void pllclp()
476 *
477 * Draws a polyline within the clip limits.
478 * Merely a front-end to plP_pllclp().
479 \*----------------------------------------------------------------------*/
480
481 static void
pllclp(PLINT * x,PLINT * y,PLINT npts)482 pllclp(PLINT *x, PLINT *y, PLINT npts)
483 {
484 plP_pllclp(x, y, npts, plsc->clpxmi, plsc->clpxma,
485 plsc->clpymi, plsc->clpyma, genlin);
486 }
487
488 /*----------------------------------------------------------------------*\
489 * void plP_pllclp()
490 *
491 * Draws a polyline within the clip limits.
492 *
493 * (AM)
494 * Wanted to change the type of xclp, yclp to avoid overflows!
495 * But that changes the type for the drawing routines too!
496 \*----------------------------------------------------------------------*/
497
498 void
plP_pllclp(PLINT * x,PLINT * y,PLINT npts,PLINT xmin,PLINT xmax,PLINT ymin,PLINT ymax,void (* draw)(short *,short *,PLINT))499 plP_pllclp(PLINT *x, PLINT *y, PLINT npts,
500 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax,
501 void (*draw) (short *, short *, PLINT))
502 {
503 PLINT xx1, xx2, yy1, yy2;
504 PLINT i, iclp = 0;
505
506 short _xclp[PL_MAXPOLY], _yclp[PL_MAXPOLY];
507 short *xclp, *yclp;
508 int drawable;
509
510 if ( npts < PL_MAXPOLY ) {
511 xclp = _xclp;
512 yclp = _yclp;
513 } else {
514 xclp = (short *) malloc( npts*sizeof(short) ) ;
515 yclp = (short *) malloc( npts*sizeof(short) ) ;
516 }
517
518 for (i = 0; i < npts - 1; i++) {
519 xx1 = x[i];
520 xx2 = x[i + 1];
521 yy1 = y[i];
522 yy2 = y[i + 1];
523
524 drawable = (INSIDE(xx1, yy1) && INSIDE(xx2, yy2));
525 if ( ! drawable)
526 drawable = ! clipline(&xx1, &yy1, &xx2, &yy2, xmin,
527 xmax, ymin, ymax);
528
529 if (drawable) {
530
531 /* First point of polyline. */
532
533 if (iclp == 0) {
534 xclp[iclp] = xx1;
535 yclp[iclp] = yy1;
536 iclp++;
537 xclp[iclp] = xx2;
538 yclp[iclp] = yy2;
539 }
540
541 /* Not first point. Check if first point of this segment matches up to
542 previous point, and if so, add it to the current polyline buffer. */
543
544 else if (xx1 == xclp[iclp] && yy1 == yclp[iclp]) {
545 iclp++;
546 xclp[iclp] = xx2;
547 yclp[iclp] = yy2;
548 }
549
550 /* Otherwise it's time to start a new polyline */
551
552 else {
553 if (iclp + 1 >= 2)
554 (*draw)(xclp, yclp, iclp + 1);
555 iclp = 0;
556 xclp[iclp] = xx1;
557 yclp[iclp] = yy1;
558 iclp++;
559 xclp[iclp] = xx2;
560 yclp[iclp] = yy2;
561 }
562 }
563 }
564
565 /* Handle remaining polyline */
566
567 if (iclp + 1 >= 2)
568 (*draw)(xclp, yclp, iclp + 1);
569
570 plsc->currx = x[npts-1];
571 plsc->curry = y[npts-1];
572
573 if ( xclp != _xclp ) {
574 free( xclp );
575 free( yclp );
576 }
577 }
578
579 /*----------------------------------------------------------------------*\
580 * int circulation()
581 *
582 * Returns the circulation direction for a given polyline: positive is
583 * counterclockwise, negative is clockwise (right hand rule).
584 *
585 * Used to get the circulation of the fill polygon around the bounding box,
586 * when the fill polygon is larger than the bounding box. Counts left
587 * (positive) vs right (negative) hand turns using a cross product, instead of
588 * performing all the expensive trig calculations needed to get this 100%
589 * correct. For the fill cases encountered in plplot, this treatment should
590 * give the correct answer most of the time, by far. When used with plshades,
591 * the typical return value is 3 or -3, since 3 turns are necessary in order
592 * to complete the fill region. Only for really oddly shaped fill regions
593 * will it give the wrong answer.
594 *
595 * AM:
596 * Changed the computation: use the outer product to compute the surface
597 * area, the sign determines if the polygon is followed clockwise or
598 * counterclockwise. This is more reliable. Floating-point numbers
599 * are used to avoid overflow.
600 \*----------------------------------------------------------------------*/
601
602 static int
circulation(PLINT * x,PLINT * y,PLINT npts)603 circulation(PLINT *x, PLINT *y, PLINT npts)
604 {
605 PLFLT xproduct;
606 int direction = 0;
607 PLFLT xx1, yy1, xx2, yy2, xx3, yy3;
608 int i;
609
610 xproduct = 0.0 ;
611 for (i = 0; i < npts - 1; i++) {
612 xx1 = x[i]; xx2 = x[i+1];
613 yy1 = y[i]; yy2 = y[i+1];
614 if (i < npts-2) {
615 xx3 = x[i+2]; yy3 = y[i+2];
616 } else {
617 xx3 = x[0]; yy3 = y[0];
618 }
619 xproduct = xproduct + (xx2-xx1)*(yy3-yy2) - (yy2-yy1)*(xx3-xx2);
620 }
621
622 if (xproduct > 0.0) direction = 1;
623 if (xproduct < 0.0) direction = -1;
624 return direction;
625 }
626
627 /*----------------------------------------------------------------------*\
628 * void plP_plfclp()
629 *
630 * Fills a polygon within the clip limits.
631 \*----------------------------------------------------------------------*/
632
633 void
plP_plfclp(PLINT * x,PLINT * y,PLINT npts,PLINT xmin,PLINT xmax,PLINT ymin,PLINT ymax,void (* draw)(short *,short *,PLINT))634 plP_plfclp(PLINT *x, PLINT *y, PLINT npts,
635 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax,
636 void (*draw) (short *, short *, PLINT))
637 {
638 PLINT i, xx1, xx2, yy1, yy2;
639 int iclp = 0, iout = 2;
640 short _xclp[2*PL_MAXPOLY+2], _yclp[2*PL_MAXPOLY+2];
641 short *xclp, *yclp;
642 int drawable;
643 int crossed_xmin1 = 0, crossed_xmax1 = 0;
644 int crossed_ymin1 = 0, crossed_ymax1 = 0;
645 int crossed_xmin2 = 0, crossed_xmax2 = 0;
646 int crossed_ymin2 = 0, crossed_ymax2 = 0;
647 int crossed_up = 0, crossed_down = 0;
648 int crossed_left = 0, crossed_right = 0;
649 int inside_lb ;
650 int inside_lu ;
651 int inside_rb ;
652 int inside_ru ;
653
654 /* Must have at least 3 points and draw() specified */
655 if (npts < 3 || !draw) return;
656
657 if ( npts < PL_MAXPOLY ) {
658 xclp = _xclp;
659 yclp = _yclp;
660 } else {
661 xclp = (short *) malloc( (2*npts+2)*sizeof(short) ) ;
662 yclp = (short *) malloc( (2*npts+2)*sizeof(short) ) ;
663 }
664
665
666 inside_lb = pointinpolygon(npts,x,y,xmin,ymin) ;
667 inside_lu = pointinpolygon(npts,x,y,xmin,ymax) ;
668 inside_rb = pointinpolygon(npts,x,y,xmax,ymin) ;
669 inside_ru = pointinpolygon(npts,x,y,xmax,ymax) ;
670
671 for (i = 0; i < npts - 1; i++) {
672 xx1 = x[i]; xx2 = x[i+1];
673 yy1 = y[i]; yy2 = y[i+1];
674
675 drawable = (INSIDE(xx1, yy1) && INSIDE(xx2, yy2));
676 if ( ! drawable)
677 drawable = ! clipline(&xx1, &yy1, &xx2, &yy2,
678 xmin, xmax, ymin, ymax);
679
680 if (drawable) {
681 /* Boundary crossing condition -- coming in. */
682 crossed_xmin2 = (xx1 == xmin); crossed_xmax2 = (xx1 == xmax);
683 crossed_ymin2 = (yy1 == ymin); crossed_ymax2 = (yy1 == ymax);
684
685 crossed_left = (crossed_left || crossed_xmin2);
686 crossed_right = (crossed_right || crossed_xmax2);
687 crossed_down = (crossed_down || crossed_ymin2);
688 crossed_up = (crossed_up || crossed_ymax2);
689 iout = iclp+2;
690 /* If the first segment, just add it. */
691
692 if (iclp == 0) {
693 xclp[iclp] = xx1; yclp[iclp] = yy1; iclp++;
694 xclp[iclp] = xx2; yclp[iclp] = yy2; iclp++;
695 }
696
697 /* Not first point. If first point of this segment matches up to the
698 previous point, just add it. */
699
700 else if (xx1 == xclp[iclp-1] && yy1 == yclp[iclp-1]) {
701 xclp[iclp] = xx2; yclp[iclp] = yy2; iclp++;
702 }
703
704 /* Otherwise, we need to add both points, to connect the points in the
705 * polygon along the clip boundary. If we encircled a corner, we have
706 * to add that first.
707 */
708
709 else {
710 /* Treat the case where we encircled two corners:
711 Construct a polygon out of the subset of vertices
712 Note that the direction is important too when adding
713 the extra points */
714 xclp[iclp+1] = xx2; yclp[iclp+1] = yy2;
715 xclp[iclp+2] = xx1; yclp[iclp+2] = yy1;
716 iout = iout - iclp + 1;
717 /* Upper two */
718 if ( ((crossed_xmin1 && crossed_xmax2) ||
719 (crossed_xmin2 && crossed_xmax1)) &&
720 inside_lu )
721 {
722 if ( crossed_xmin1 )
723 {
724 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
725 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
726 } else {
727 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
728 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
729 }
730 }
731 /* Lower two */
732 else if ( ((crossed_xmin1 && crossed_xmax2) ||
733 (crossed_xmin2 && crossed_xmax1)) &&
734 inside_lb )
735 {
736 if ( crossed_xmin1 )
737 {
738 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
739 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
740 } else {
741 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
742 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
743 }
744 }
745 /* Left two */
746 else if ( ((crossed_ymin1 && crossed_ymax2) ||
747 (crossed_ymin2 && crossed_ymax1)) &&
748 inside_lb )
749 {
750 if ( crossed_ymin1 )
751 {
752 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
753 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
754 } else {
755 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
756 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
757 }
758 }
759 /* Right two */
760 else if ( ((crossed_ymin1 && crossed_ymax2) ||
761 (crossed_ymin2 && crossed_ymax1)) &&
762 inside_rb )
763 {
764 if ( crossed_ymin1 )
765 {
766 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
767 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
768 } else {
769 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
770 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
771 }
772 }
773 /* Now the case where we encircled one corner */
774 /* Lower left */
775 else if ( (crossed_xmin1 && crossed_ymin2) ||
776 (crossed_ymin1 && crossed_xmin2) )
777 {
778 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
779 }
780 /* Lower right */
781 else if ( (crossed_xmax1 && crossed_ymin2) ||
782 (crossed_ymin1 && crossed_xmax2) )
783 {
784 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
785 }
786 /* Upper left */
787 else if ( (crossed_xmin1 && crossed_ymax2) ||
788 (crossed_ymax1 && crossed_xmin2) )
789 {
790 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
791 }
792 /* Upper right */
793 else if ( (crossed_xmax1 && crossed_ymax2) ||
794 (crossed_ymax1 && crossed_xmax2) )
795 {
796 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
797 }
798
799 /* Now add current segment. */
800 xclp[iclp] = xx1; yclp[iclp] = yy1; iclp++;
801 xclp[iclp] = xx2; yclp[iclp] = yy2; iclp++;
802 }
803
804 /* Boundary crossing condition -- going out. */
805 crossed_xmin1 = (xx2 == xmin); crossed_xmax1 = (xx2 == xmax);
806 crossed_ymin1 = (yy2 == ymin); crossed_ymax1 = (yy2 == ymax);
807 }
808 }
809
810 /* Limit case - all vertices are outside of bounding box. So just fill entire
811 box, *if* the bounding box is completely encircled.
812 */
813
814 if (iclp == 0) {
815 PLINT xmin1, xmax1, ymin1, ymax1;
816 xmin1 = xmax1 = x[0];
817 ymin1 = ymax1 = y[0];
818 for (i = 1; i < npts; i++) {
819 if (x[i] < xmin1) xmin1 = x[i];
820 if (x[i] > xmax1) xmax1 = x[i];
821 if (y[i] < ymin1) ymin1 = y[i];
822 if (y[i] > ymax1) ymax1 = y[i];
823 }
824 if (xmin1 <= xmin && xmax1 >= xmax && ymin1 <= ymin && ymax1 >= ymax ) {
825 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
826 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
827 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
828 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
829 (*draw)(xclp, yclp, iclp);
830
831 if ( xclp != _xclp ) {
832 free( xclp );
833 free( yclp );
834 }
835
836
837 return;
838 }
839 }
840
841 /* Now handle cases where fill polygon intersects two sides of the box */
842
843 if (iclp >= 2) {
844 int debug=0;
845 int dir = circulation(x, y, npts);
846 if (debug) {
847 if ( (xclp[0] == xmin && xclp[iclp-1] == xmax) ||
848 (xclp[0] == xmax && xclp[iclp-1] == xmin) ||
849 (yclp[0] == ymin && yclp[iclp-1] == ymax) ||
850 (yclp[0] == ymax && yclp[iclp-1] == ymin) ||
851 (xclp[0] == xmin && yclp[iclp-1] == ymin) ||
852 (yclp[0] == ymin && xclp[iclp-1] == xmin) ||
853 (xclp[0] == xmax && yclp[iclp-1] == ymin) ||
854 (yclp[0] == ymin && xclp[iclp-1] == xmax) ||
855 (xclp[0] == xmax && yclp[iclp-1] == ymax) ||
856 (yclp[0] == ymax && xclp[iclp-1] == xmax) ||
857 (xclp[0] == xmin && yclp[iclp-1] == ymax) ||
858 (yclp[0] == ymax && xclp[iclp-1] == xmin) ) {
859 printf("dir=%d, clipped points:\n", dir);
860 for (i=0; i < iclp; i++)
861 printf(" x[%d]=%d y[%d]=%d", i, xclp[i], i, yclp[i]);
862 printf("\n");
863 printf("pre-clipped points:\n");
864 for (i=0; i < npts; i++)
865 printf(" x[%d]=%d y[%d]=%d", i, x[i], i, y[i]);
866 printf("\n");
867 }
868 }
869
870 /* The cases where the fill region is divided 2/2 */
871 /* Divided horizontally */
872 if (xclp[0] == xmin && xclp[iclp-1] == xmax)
873 {
874 if (dir > 0) {
875 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
876 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
877 }
878 else {
879 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
880 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
881 }
882 }
883 else if (xclp[0] == xmax && xclp[iclp-1] == xmin)
884 {
885 if (dir > 0) {
886 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
887 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
888 }
889 else {
890 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
891 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
892 }
893 }
894
895 /* Divided vertically */
896 else if (yclp[0] == ymin && yclp[iclp-1] == ymax)
897 {
898 if (dir > 0) {
899 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
900 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
901 }
902 else {
903 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
904 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
905 }
906 }
907 else if (yclp[0] == ymax && yclp[iclp-1] == ymin)
908 {
909 if (dir > 0) {
910 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
911 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
912 }
913 else {
914 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
915 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
916 }
917 }
918
919 /* The cases where the fill region is divided 3/1 --
920 LL LR UR UL
921 +-----+ +-----+ +-----+ +-----+
922 | | | | | \| |/ |
923 | | | | | | | |
924 |\ | | /| | | | |
925 +-----+ +-----+ +-----+ +-----+
926
927 Note when we go the long way around, if the direction is reversed the
928 three vertices must be visited in the opposite order.
929 */
930 /* LL, short way around */
931 else if ((xclp[0] == xmin && yclp[iclp-1] == ymin && dir < 0) ||
932 (yclp[0] == ymin && xclp[iclp-1] == xmin && dir > 0) )
933 {
934 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
935 }
936 /* LL, long way around, counterclockwise */
937 else if ((xclp[0] == xmin && yclp[iclp-1] == ymin && dir > 0))
938 {
939 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
940 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
941 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
942 }
943 /* LL, long way around, clockwise */
944 else if ((yclp[0] == ymin && xclp[iclp-1] == xmin && dir < 0))
945 {
946 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
947 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
948 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
949 }
950 /* LR, short way around */
951 else if ((xclp[0] == xmax && yclp[iclp-1] == ymin && dir > 0) ||
952 (yclp[0] == ymin && xclp[iclp-1] == xmax && dir < 0) )
953 {
954 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
955 }
956 /* LR, long way around, counterclockwise */
957 else if (yclp[0] == ymin && xclp[iclp-1] == xmax && dir > 0)
958 {
959 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
960 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
961 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
962 }
963 /* LR, long way around, clockwise */
964 else if (xclp[0] == xmax && yclp[iclp-1] == ymin && dir < 0)
965 {
966 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
967 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
968 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
969 }
970 /* UR, short way around */
971 else if ((xclp[0] == xmax && yclp[iclp-1] == ymax && dir < 0) ||
972 (yclp[0] == ymax && xclp[iclp-1] == xmax && dir > 0) )
973 {
974 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
975 }
976 /* UR, long way around, counterclockwise */
977 else if (xclp[0] == xmax && yclp[iclp-1] == ymax && dir > 0)
978 {
979 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
980 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
981 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
982 }
983 /* UR, long way around, clockwise */
984 else if (yclp[0] == ymax && xclp[iclp-1] == xmax && dir < 0)
985 {
986 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
987 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
988 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
989 }
990 /* UL, short way around */
991 else if ((xclp[0] == xmin && yclp[iclp-1] == ymax && dir > 0) ||
992 (yclp[0] == ymax && xclp[iclp-1] == xmin && dir < 0) )
993 {
994 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
995 }
996 /* UL, long way around, counterclockwise */
997 else if (yclp[0] == ymax && xclp[iclp-1] == xmin && dir > 0)
998 {
999 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
1000 xclp[iclp] = xmax; yclp[iclp] = ymin; iclp++;
1001 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
1002 }
1003 /* UL, long way around, clockwise */
1004 else if (xclp[0] == xmin && yclp[iclp-1] == ymax && dir < 0)
1005 {
1006 xclp[iclp] = xmax; yclp[iclp] = ymax; iclp++;
1007 xclp[iclp] = xmin; yclp[iclp] = ymax; iclp++;
1008 xclp[iclp] = xmin; yclp[iclp] = ymin; iclp++;
1009 }
1010 }
1011
1012 /* Check for the case that only one side has been crossed
1013 (AM) Just checking a single point turns out not to be
1014 enough, apparently the crossed_*1 and crossed_*2 variables
1015 are not quite what I expected.
1016 */
1017 if ( crossed_left+crossed_right+crossed_down+crossed_up == 1 &&
1018 inside_lb+inside_rb+inside_lu+inside_ru == 4 ) {
1019 int dir = circulation(x, y, npts);
1020 PLINT xlim[4], ylim[4];
1021 int insert;
1022 int incr;
1023
1024 xlim[0] = xmin ; ylim[0] = ymin ;
1025 xlim[1] = xmax ; ylim[1] = ymin ;
1026 xlim[2] = xmax ; ylim[2] = ymax ;
1027 xlim[3] = xmin ; ylim[3] = ymax ;
1028 if ( dir > 0 ) {
1029 incr = 1;
1030 insert = 0*crossed_left + 1*crossed_down + 2*crossed_right +
1031 3*crossed_up ;
1032 } else {
1033 incr = -1;
1034 insert = 3*crossed_left + 2*crossed_up + 1*crossed_right +
1035 0*crossed_down ;
1036 }
1037 for ( i=0; i < 4; i ++ ) {
1038 xclp[iclp] = xlim[insert] ;
1039 yclp[iclp] = ylim[insert] ;
1040 iclp ++ ;
1041 insert += incr ;
1042 if ( insert > 3 ) insert = 0 ;
1043 if ( insert < 0 ) insert = 3 ;
1044 }
1045 }
1046
1047 /* Draw the sucker */
1048 if (iclp >= 3)
1049 (*draw)(xclp, yclp, iclp);
1050
1051 if ( xclp != _xclp ) {
1052 free( xclp );
1053 free( yclp );
1054 }
1055 }
1056
1057 /*----------------------------------------------------------------------*\
1058 * int clipline()
1059 *
1060 * Get clipped endpoints
1061 \*----------------------------------------------------------------------*/
1062
1063 static int
clipline(PLINT * p_x1,PLINT * p_y1,PLINT * p_x2,PLINT * p_y2,PLINT xmin,PLINT xmax,PLINT ymin,PLINT ymax)1064 clipline(PLINT *p_x1, PLINT *p_y1, PLINT *p_x2, PLINT *p_y2,
1065 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
1066 {
1067 PLINT t, dx, dy, flipx, flipy;
1068 double dydx = 0, dxdy = 0;
1069
1070 /* If both points are outside clip region with no hope of intersection,
1071 return with an error */
1072
1073 if ((*p_x1 <= xmin && *p_x2 <= xmin) ||
1074 (*p_x1 >= xmax && *p_x2 >= xmax) ||
1075 (*p_y1 <= ymin && *p_y2 <= ymin) ||
1076 (*p_y1 >= ymax && *p_y2 >= ymax))
1077 return 1;
1078
1079 flipx = 0;
1080 flipy = 0;
1081
1082 if (*p_x2 < *p_x1) {
1083 *p_x1 = 2 * xmin - *p_x1;
1084 *p_x2 = 2 * xmin - *p_x2;
1085 xmax = 2 * xmin - xmax;
1086 t = xmax;
1087 xmax = xmin;
1088 xmin = t;
1089 flipx = 1;
1090 }
1091
1092 if (*p_y2 < *p_y1) {
1093 *p_y1 = 2 * ymin - *p_y1;
1094 *p_y2 = 2 * ymin - *p_y2;
1095 ymax = 2 * ymin - ymax;
1096 t = ymax;
1097 ymax = ymin;
1098 ymin = t;
1099 flipy = 1;
1100 }
1101
1102 dx = *p_x2 - *p_x1;
1103 dy = *p_y2 - *p_y1;
1104
1105 if (dx != 0 && dy != 0) {
1106 dydx = (double) dy / (double) dx;
1107 dxdy = 1./ dydx;
1108 }
1109
1110 if (*p_x1 < xmin) {
1111 if (dx != 0 && dy != 0)
1112 *p_y1 = *p_y1 + ROUND((xmin - *p_x1) * dydx);
1113 *p_x1 = xmin;
1114 }
1115
1116 if (*p_y1 < ymin) {
1117 if (dx != 0 && dy != 0)
1118 *p_x1 = *p_x1 + ROUND((ymin - *p_y1) * dxdy);
1119 *p_y1 = ymin;
1120 }
1121
1122 if (*p_x1 >= xmax || *p_y1 >= ymax)
1123 return 1;
1124
1125 if (*p_y2 > ymax) {
1126 if (dx != 0 && dy != 0)
1127 *p_x2 = *p_x2 - ROUND((*p_y2 - ymax) * dxdy);
1128 *p_y2 = ymax;
1129 }
1130
1131 if (*p_x2 > xmax) {
1132 if (dx != 0 && dy != 0)
1133 *p_y2 = *p_y2 - ROUND((*p_x2 - xmax) * dydx);
1134 *p_x2 = xmax;
1135 }
1136
1137 if (flipx) {
1138 *p_x1 = 2 * xmax - *p_x1;
1139 *p_x2 = 2 * xmax - *p_x2;
1140 }
1141
1142 if (flipy) {
1143 *p_y1 = 2 * ymax - *p_y1;
1144 *p_y2 = 2 * ymax - *p_y2;
1145 }
1146
1147 return 0;
1148 }
1149
1150 /*----------------------------------------------------------------------*\
1151 * void genlin()
1152 *
1153 * General line-drawing routine. Takes line styles into account.
1154 * If only 2 points are in the polyline, it is more efficient to use
1155 * plP_line() rather than plP_polyline().
1156 \*----------------------------------------------------------------------*/
1157
1158 static void
genlin(short * x,short * y,PLINT npts)1159 genlin(short *x, short *y, PLINT npts)
1160 {
1161 /* Check for solid line */
1162
1163 if (plsc->nms == 0) {
1164 if (npts== 2)
1165 plP_line(x, y);
1166 else
1167 plP_polyline(x, y, npts);
1168 }
1169
1170 /* Right now dashed lines don't use polyline capability -- this
1171 should be improved */
1172
1173 else {
1174
1175 PLINT i;
1176
1177 /* Call escape sequence to draw dashed lines, only for drivers
1178 that have this capability */
1179 if (plsc->dev_dash) {
1180 plsc->dev_npts = npts;
1181 plsc->dev_x = x;
1182 plsc->dev_y = y;
1183 plP_esc(PLESC_DASH, NULL);
1184 return;
1185 }
1186
1187 for (i = 0; i < npts - 1; i++) {
1188 grdashline(x+i, y+i);
1189 }
1190 }
1191 }
1192
1193 /*----------------------------------------------------------------------*\
1194 * void grdashline()
1195 *
1196 * Draws a dashed line to the specified point from the previous one.
1197 \*----------------------------------------------------------------------*/
1198
1199 static void
grdashline(short * x,short * y)1200 grdashline(short *x, short *y)
1201 {
1202 PLINT nx, ny, nxp, nyp, incr, temp;
1203 PLINT modulo, dx, dy, i, xtmp, ytmp;
1204 PLINT tstep, pix_distance, j;
1205 int loop_x;
1206 short xl[2], yl[2];
1207 double nxstep, nystep;
1208
1209 /* Check if pattern needs to be restarted */
1210
1211 if (x[0] != lastx || y[0] != lasty) {
1212 plsc->curel = 0;
1213 plsc->pendn = 1;
1214 plsc->timecnt = 0;
1215 plsc->alarm = plsc->mark[0];
1216 }
1217
1218 lastx = xtmp = x[0];
1219 lasty = ytmp = y[0];
1220
1221 if (x[0] == x[1] && y[0] == y[1])
1222 return;
1223
1224 nx = x[1] - x[0];
1225 dx = (nx > 0) ? 1 : -1;
1226 nxp = ABS(nx);
1227
1228 ny = y[1] - y[0];
1229 dy = (ny > 0) ? 1 : -1;
1230 nyp = ABS(ny);
1231
1232 if (nyp > nxp) {
1233 modulo = nyp;
1234 incr = nxp;
1235 loop_x = 0;
1236 }
1237 else {
1238 modulo = nxp;
1239 incr = nyp;
1240 loop_x = 1;
1241 }
1242
1243 temp = modulo / 2;
1244
1245 /* Compute the timer step */
1246
1247 nxstep = nxp * plsc->umx;
1248 nystep = nyp * plsc->umy;
1249 tstep = sqrt( nxstep * nxstep + nystep * nystep ) / modulo;
1250 if (tstep < 1) tstep = 1;
1251
1252 /* tstep is distance per pixel moved */
1253
1254 i = 0;
1255 while (i < modulo) {
1256 pix_distance = (plsc->alarm - plsc->timecnt + tstep - 1) / tstep;
1257 i += pix_distance;
1258 if (i > modulo)
1259 pix_distance -= (i - modulo);
1260 plsc->timecnt += pix_distance * tstep;
1261
1262 temp += pix_distance * incr;
1263 j = temp / modulo;
1264 temp = temp % modulo;
1265
1266 if (loop_x) {
1267 xtmp += pix_distance * dx;
1268 ytmp += j * dy;
1269 }
1270 else {
1271 xtmp += j * dx;
1272 ytmp += pix_distance * dy;
1273 }
1274 if (plsc->pendn != 0) {
1275 xl[0] = lastx;
1276 yl[0] = lasty;
1277 xl[1] = xtmp;
1278 yl[1] = ytmp;
1279 plP_line(xl, yl);
1280 }
1281
1282 /* Update line style variables when alarm goes off */
1283
1284 while (plsc->timecnt >= plsc->alarm) {
1285 if (plsc->pendn != 0) {
1286 plsc->pendn = 0;
1287 plsc->timecnt -= plsc->alarm;
1288 plsc->alarm = plsc->space[plsc->curel];
1289 }
1290 else {
1291 plsc->pendn = 1;
1292 plsc->timecnt -= plsc->alarm;
1293 plsc->curel++;
1294 if (plsc->curel >= plsc->nms)
1295 plsc->curel = 0;
1296 plsc->alarm = plsc->mark[plsc->curel];
1297 }
1298 }
1299 lastx = xtmp;
1300 lasty = ytmp;
1301 }
1302 }
1303
1304 /*----------------------------------------------------------------------*\
1305 * int pointinpolygon()
1306 *
1307 * Returns 1 if the point is inside the polygon, 0 otherwise
1308 * Note:
1309 * Points on the polygon are considered to be outside
1310 \*----------------------------------------------------------------------*/
1311
1312 static int
pointinpolygon(int n,PLINT * x,PLINT * y,PLINT xp,PLINT yp)1313 pointinpolygon( int n, PLINT *x, PLINT *y, PLINT xp, PLINT yp )
1314 {
1315 int i;
1316 int count_crossings;
1317 PLFLT xx1, yy1, xx2, yy2, xpp, ypp, xout, yout, xmax;
1318 PLFLT xvp, yvp, xvv, yvv, xv1, yv1, xv2, yv2;
1319 PLFLT inprod1, inprod2;
1320
1321 xpp = (PLFLT) xp;
1322 ypp = (PLFLT) yp;
1323
1324 count_crossings = 0;
1325
1326
1327 /* Determine a point outside the polygon */
1328
1329 xmax = x[0] ;
1330 xout = x[0] ;
1331 yout = y[0] ;
1332 for ( i = 0; i < n ; i ++ ) {
1333 if ( xout > x[i] ) {
1334 xout = x[i] ;
1335 }
1336 if ( xmax < x[i] ) {
1337 xmax = x[i] ;
1338 }
1339 }
1340 xout = xout - (xmax-xout) ;
1341
1342 /* Determine for each side whether the line segment between
1343 our two points crosses the vertex */
1344
1345 xpp = (PLFLT) xp;
1346 ypp = (PLFLT) yp;
1347
1348 xvp = xpp - xout;
1349 yvp = ypp - yout;
1350
1351 for ( i = 0; i < n; i ++ ) {
1352 xx1 = (PLFLT) x[i] ;
1353 yy1 = (PLFLT) y[i] ;
1354 if ( i < n-1 ) {
1355 xx2 = (PLFLT) x[i+1] ;
1356 yy2 = (PLFLT) y[i+1] ;
1357 } else {
1358 xx2 = (PLFLT) x[0] ;
1359 yy2 = (PLFLT) y[0] ;
1360 }
1361
1362 /* Skip zero-length segments */
1363 if ( xx1 == xx2 && yy1 == yy2 ) {
1364 continue;
1365 }
1366
1367 /* Line through the two fixed points:
1368 Are x1 and x2 on either side? */
1369 xv1 = xx1 - xout;
1370 yv1 = yy1 - yout;
1371 xv2 = xx2 - xout;
1372 yv2 = yy2 - yout;
1373 inprod1 = xv1*yvp - yv1*xvp; /* Well, with the normal vector */
1374 inprod2 = xv2*yvp - yv2*xvp;
1375 if ( inprod1 * inprod2 >= 0.0 ) {
1376 /* No crossing possible! */
1377 continue;
1378 }
1379
1380 /* Line through the two vertices:
1381 Are xout and xpp on either side? */
1382 xvv = xx2 - xx1;
1383 yvv = yy2 - yy1;
1384 xv1 = xpp - xx1;
1385 yv1 = ypp - yy1;
1386 xv2 = xout - xx1;
1387 yv2 = yout - yy1;
1388 inprod1 = xv1*yvv - yv1*xvv;
1389 inprod2 = xv2*yvv - yv2*xvv;
1390 if ( inprod1 * inprod2 >= 0.0 ) {
1391 /* No crossing possible! */
1392 continue;
1393 }
1394
1395 /* We do have a crossing */
1396 count_crossings ++;
1397 }
1398
1399 /* Return the result: an even number of crossings means the
1400 point is outside the polygon */
1401
1402 return (count_crossings%2);
1403 }
1404