PLplot: plline.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plline.c
Go to the documentation of this file.
1 // $Id: plline.c 11973 2011-10-17 21:16:39Z andrewross $
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 // General line-drawing routine. Takes line styles into account.
41
42 static void
43 genlin( short *x, short *y, PLINT npts );
44
45 // Draws a dashed line to the specified point from the previous one.
46
47 static void
48 grdashline( short *x, short *y );
49
50 // Determines if a point is inside a polygon or not
51
52 // Interpolate between two points in n steps
53
54 static PLFLT *
55 interpolate_between( int n, PLFLT a, PLFLT b );
56
57 //--------------------------------------------------------------------------
58 // void pljoin()
59 //
60 // Draws a line segment from (x1, y1) to (x2, y2).
61 //--------------------------------------------------------------------------
62
63 void
64 c_pljoin( PLFLT x1, PLFLT y1, PLFLT x2, PLFLT y2 )
65 {
66 plP_movwor( x1, y1 );
67 plP_drawor( x2, y2 );
68 }
69
70 //--------------------------------------------------------------------------
71 // void plline()
72 //
73 // Draws line segments connecting a series of points.
74 //--------------------------------------------------------------------------
75
76 void
77 c_plline( PLINT n, const PLFLT *x, const PLFLT *y )
78 {
79 if ( plsc->level < 3 )
80 {
81 plabort( "plline: Please set up window first" );
82 return;
83 }
84 plP_drawor_poly( x, y, n );
85 }
86
87 //--------------------------------------------------------------------------
88 // void plpath()
89 //
90 // Draws a line segment from (x1, y1) to (x2, y2). If a coordinate
91 // transform is defined then break the line up in to n pieces to approximate
92 // the path. Otherwise it simply calls pljoin().
93 //--------------------------------------------------------------------------
94
95 void
96 c_plpath( PLINT n, PLFLT x1, PLFLT y1, PLFLT x2, PLFLT y2 )
97 {
98 PLFLT *xs, *ys;
99
100 if ( plsc->coordinate_transform == NULL )
101 {
102 // No transform, so fall back on pljoin for a normal straight line
103 pljoin( x1, y1, x2, y2 );
104 }
105 else
106 {
107 // Approximate the path in transformed space with a sequence of line
108 // segments.
109 xs = interpolate_between( n, x1, x2 );
110 ys = interpolate_between( n, y1, y2 );
111 if ( xs == NULL || ys == NULL )
112 {
113 plexit( "c_plpath: Insufficient memory" );
114 return;
115 }
116 plline( n, xs, ys );
117 // plP_interpolate allocates memory, so we have to free it here.
118 free( xs );
119 free( ys );
120 }
121 }
122
123 //--------------------------------------------------------------------------
124 // void plline3(n, x, y, z)
125 //
126 // Draws a line in 3 space. You must first set up the viewport, the
127 // 2d viewing window (in world coordinates), and the 3d normalized
128 // coordinate box. See x18c.c for more info.
129 //
130 // This version adds clipping against the 3d bounding box specified in plw3d
131 //--------------------------------------------------------------------------
132 void
133 c_plline3( PLINT n, const PLFLT *x, const PLFLT *y, const PLFLT *z )
134 {
135 int i;
136 PLFLT vmin[3], vmax[3], zscale;
137
138 if ( plsc->level < 3 )
139 {
140 plabort( "plline3: Please set up window first" );
141 return;
142 }
143
144 // get the bounding box in 3d
145 plP_gdom( &vmin[0], &vmax[0], &vmin[1], &vmax[1] );
146 plP_grange( &zscale, &vmin[2], &vmax[2] );
147
148 // interate over the vertices
149 for ( i = 0; i < n - 1; i++ )
150 {
151 PLFLT p0[3], p1[3];
152 int axis;
153
154 // copy the end points of the segment to allow clipping
155 p0[0] = x[i]; p0[1] = y[i]; p0[2] = z[i];
156 p1[0] = x[i + 1]; p1[1] = y[i + 1]; p1[2] = z[i + 1];
157
158 // check against each axis of the bounding box
159 for ( axis = 0; axis < 3; axis++ )
160 {
161 if ( p0[axis] < vmin[axis] ) // first out
162 {
163 if ( p1[axis] < vmin[axis] )
164 {
165 break; // both endpoints out so quit
166 }
167 else
168 {
169 int j;
170 // interpolate to find intersection with box
171 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
172 p0[axis] = vmin[axis];
173 for ( j = 1; j < 3; j++ )
174 {
175 int k = ( axis + j ) % 3;
176 p0[k] = ( 1 - t ) * p0[k] + t * p1[k];
177 }
178 }
179 }
180 else if ( p1[axis] < vmin[axis] ) // second out
181 {
182 int j;
183 // interpolate to find intersection with box
184 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
185 p1[axis] = vmin[axis];
186 for ( j = 1; j < 3; j++ )
187 {
188 int k = ( axis + j ) % 3;
189 p1[k] = ( 1 - t ) * p0[k] + t * p1[k];
190 }
191 }
192 if ( p0[axis] > vmax[axis] ) // first out
193 {
194 if ( p1[axis] > vmax[axis] )
195 {
196 break; // both out so quit
197 }
198 else
199 {
200 int j;
201 // interpolate to find intersection with box
202 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
203 p0[axis] = vmax[axis];
204 for ( j = 1; j < 3; j++ )
205 {
206 int k = ( axis + j ) % 3;
207 p0[k] = ( 1 - t ) * p0[k] + t * p1[k];
208 }
209 }
210 }
211 else if ( p1[axis] > vmax[axis] ) // second out
212 {
213 int j;
214 // interpolate to find intersection with box
215 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
216 p1[axis] = vmax[axis];
217 for ( j = 1; j < 3; j++ )
218 {
219 int k = ( axis + j ) % 3;
220 p1[k] = ( 1 - t ) * p0[k] + t * p1[k];
221 }
222 }
223 }
224 // if we made it to here without "break"ing out of the loop, the
225 // remaining segment is visible
226 if ( axis == 3 ) // not clipped away
227 {
228 PLFLT u0, v0, u1, v1;
229 u0 = plP_wcpcx( plP_w3wcx( p0[0], p0[1], p0[2] ) );
230 v0 = plP_wcpcy( plP_w3wcy( p0[0], p0[1], p0[2] ) );
231 u1 = plP_wcpcx( plP_w3wcx( p1[0], p1[1], p1[2] ) );
232 v1 = plP_wcpcy( plP_w3wcy( p1[0], p1[1], p1[2] ) );
233 plP_movphy( (PLINT) u0, (PLINT) v0 );
234 plP_draphy( (PLINT) u1, (PLINT) v1 );
235 }
236 }
237 return;
238 }
239 //--------------------------------------------------------------------------
240 // void plpoly3( n, x, y, z, draw, ifcc )
241 //
242 // Draws a polygon in 3 space. This differs from plline3() in that
243 // this attempts to determine if the polygon is viewable. If the back
244 // of polygon is facing the viewer, then it isn't drawn. If this
245 // isn't what you want, then use plline3 instead.
246 //
247 // n specifies the number of points. They are assumed to be in a
248 // plane, and the directionality of the plane is determined from the
249 // first three points. Additional points do not /have/ to lie on the
250 // plane defined by the first three, but if they do not, then the
251 // determiniation of visibility obviously can't be 100% accurate...
252 // So if you're 3 space polygons are too far from planar, consider
253 // breaking them into smaller polygons. "3 points define a plane" :-).
254 //
255 // For ifcc == 1, the directionality of the polygon is determined by assuming
256 // the points are laid out in counter-clockwise order.
257 //
258 // For ifcc == 0, the directionality of the polygon is determined by assuming
259 // the points are laid out in clockwise order.
260 //
261 // BUGS: If one of the first two segments is of zero length, or if
262 // they are colinear, the calculation of visibility has a 50/50 chance
263 // of being correct. Avoid such situations :-). See x18c for an
264 // example of this problem. (Search for "20.1").
265 //--------------------------------------------------------------------------
266
267 void
268 c_plpoly3( PLINT n, const PLFLT *x, const PLFLT *y, const PLFLT *z, const PLBOOL *draw, PLBOOL ifcc )
269 {
270 int i;
271 PLFLT vmin[3], vmax[3], zscale;
272 PLFLT u1, v1, u2, v2, u3, v3;
273 PLFLT c;
274
275 if ( plsc->level < 3 )
276 {
277 plabort( "plpoly3: Please set up window first" );
278 return;
279 }
280
281 if ( n < 3 )
282 {
283 plabort( "plpoly3: Must specify at least 3 points" );
284 return;
285 }
286
287 // Now figure out which side this is.
288
289 u1 = plP_wcpcx( plP_w3wcx( x[0], y[0], z[0] ) );
290 v1 = plP_wcpcy( plP_w3wcy( x[0], y[0], z[0] ) );
291
292 u2 = plP_wcpcx( plP_w3wcx( x[1], y[1], z[1] ) );
293 v2 = plP_wcpcy( plP_w3wcy( x[1], y[1], z[1] ) );
294
295 u3 = plP_wcpcx( plP_w3wcx( x[2], y[2], z[2] ) );
296 v3 = plP_wcpcy( plP_w3wcy( x[2], y[2], z[2] ) );
297
298 c = ( u1 - u2 ) * ( v3 - v2 ) - ( v1 - v2 ) * ( u3 - u2 );
299
300 if ( c * ( 1 - 2 * ABS( ifcc ) ) < 0. )
301 return;
302
303 // get the bounding box in 3d
304 plP_gdom( &vmin[0], &vmax[0], &vmin[1], &vmax[1] );
305 plP_grange( &zscale, &vmin[2], &vmax[2] );
306
307 // interate over the vertices
308 for ( i = 0; i < n - 1; i++ )
309 {
310 PLFLT p0[3], p1[3];
311 int axis;
312
313 // copy the end points of the segment to allow clipping
314 p0[0] = x[i]; p0[1] = y[i]; p0[2] = z[i];
315 p1[0] = x[i + 1]; p1[1] = y[i + 1]; p1[2] = z[i + 1];
316
317 // check against each axis of the bounding box
318 for ( axis = 0; axis < 3; axis++ )
319 {
320 if ( p0[axis] < vmin[axis] ) // first out
321 {
322 if ( p1[axis] < vmin[axis] )
323 {
324 break; // both endpoints out so quit
325 }
326 else
327 {
328 int j;
329 // interpolate to find intersection with box
330 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
331 p0[axis] = vmin[axis];
332 for ( j = 1; j < 3; j++ )
333 {
334 int k = ( axis + j ) % 3;
335 p0[k] = ( 1 - t ) * p0[k] + t * p1[k];
336 }
337 }
338 }
339 else if ( p1[axis] < vmin[axis] ) // second out
340 {
341 int j;
342 // interpolate to find intersection with box
343 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
344 p1[axis] = vmin[axis];
345 for ( j = 1; j < 3; j++ )
346 {
347 int k = ( axis + j ) % 3;
348 p1[k] = ( 1 - t ) * p0[k] + t * p1[k];
349 }
350 }
351 if ( p0[axis] > vmax[axis] ) // first out
352 {
353 if ( p1[axis] > vmax[axis] )
354 {
355 break; // both out so quit
356 }
357 else
358 {
359 int j;
360 // interpolate to find intersection with box
361 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
362 p0[axis] = vmax[axis];
363 for ( j = 1; j < 3; j++ )
364 {
365 int k = ( axis + j ) % 3;
366 p0[k] = ( 1 - t ) * p0[k] + t * p1[k];
367 }
368 }
369 }
370 else if ( p1[axis] > vmax[axis] ) // second out
371 {
372 int j;
373 // interpolate to find intersection with box
374 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] );
375 p1[axis] = vmax[axis];
376 for ( j = 1; j < 3; j++ )
377 {
378 int k = ( axis + j ) % 3;
379 p1[k] = ( 1 - t ) * p0[k] + t * p1[k];
380 }
381 }
382 }
383 // if we made it to here without "break"ing out of the loop, the
384 // remaining segment is visible
385 if ( axis == 3 && draw[i] ) // not clipped away
386 {
387 u1 = plP_wcpcx( plP_w3wcx( p0[0], p0[1], p0[2] ) );
388 v1 = plP_wcpcy( plP_w3wcy( p0[0], p0[1], p0[2] ) );
389 u2 = plP_wcpcx( plP_w3wcx( p1[0], p1[1], p1[2] ) );
390 v2 = plP_wcpcy( plP_w3wcy( p1[0], p1[1], p1[2] ) );
391 plP_movphy( (PLINT) u1, (PLINT) v1 );
392 plP_draphy( (PLINT) u2, (PLINT) v2 );
393 }
394 }
395 return;
396 }
397
398 //--------------------------------------------------------------------------
399 // void plstyl()
400 //
401 // Set up a new line style of "nms" elements, with mark and space
402 // lengths given by arrays "mark" and "space".
403 //--------------------------------------------------------------------------
404
405 void
406 c_plstyl( PLINT nms, const PLINT *mark, const PLINT *space )
407 {
408 short int i;
409 short int flag;
410
411 if ( plsc->level < 1 )
412 {
413 plabort( "plstyl: Please call plinit first" );
414 return;
415 }
416 if ( ( nms < 0 ) || ( nms > 10 ) )
417 {
418 plabort( "plstyl: Broken lines cannot have <0 or >10 elements" );
419 return;
420 }
421 flag = 1;
422 for ( i = 0; i < nms; i++ )
423 {
424 if ( ( mark[i] < 0 ) || ( space[i] < 0 ) )
425 {
426 plabort( "plstyl: Mark and space lengths must be > 0" );
427 return;
428 }
429 if ( ( mark[i] != 0 ) || ( space[i] != 0 ) )
430 {
431 flag = 0;
432 }
433 }
434 // Check for blank style
435 if ( ( nms > 0 ) && ( flag == 1 ) )
436 {
437 plabort( "plstyl: At least one mark or space must be > 0" );
438 return;
439 }
440
441 plsc->nms = nms;
442 for ( i = 0; i < nms; i++ )
443 {
444 plsc->mark[i] = mark[i];
445 plsc->space[i] = space[i];
446 }
447
448 plsc->curel = 0;
449 plsc->pendn = 1;
450 plsc->timecnt = 0;
451 plsc->alarm = nms > 0 ? mark[0] : 0;
452 }
453
454 //--------------------------------------------------------------------------
455 // void plP_movphy()
456 //
457 // Move to physical coordinates (x,y).
458 //--------------------------------------------------------------------------
459
460 void
461 plP_movphy( PLINT x, PLINT y )
462 {
463 plsc->currx = x;
464 plsc->curry = y;
465 }
466
467 //--------------------------------------------------------------------------
468 // void plP_draphy()
469 //
470 // Draw to physical coordinates (x,y).
471 //--------------------------------------------------------------------------
472
473 void
474 plP_draphy( PLINT x, PLINT y )
475 {
476 xline[0] = plsc->currx;
477 xline[1] = x;
478 yline[0] = plsc->curry;
479 yline[1] = y;
480
481 pllclp( xline, yline, 2 );
482 }
483
484 //--------------------------------------------------------------------------
485 // void plP_movwor()
486 //
487 // Move to world coordinates (x,y).
488 //--------------------------------------------------------------------------
489
490 void
491 plP_movwor( PLFLT x, PLFLT y )
492 {
493 PLFLT xt, yt;
494 TRANSFORM( x, y, &xt, &yt );
495
496 plsc->currx = plP_wcpcx( xt );
497 plsc->curry = plP_wcpcy( yt );
498 }
499
500 //--------------------------------------------------------------------------
501 // void plP_drawor()
502 //
503 // Draw to world coordinates (x,y).
504 //--------------------------------------------------------------------------
505
506 void
507 plP_drawor( PLFLT x, PLFLT y )
508 {
509 PLFLT xt, yt;
510 TRANSFORM( x, y, &xt, &yt );
511
512 xline[0] = plsc->currx;
513 xline[1] = plP_wcpcx( xt );
514 yline[0] = plsc->curry;
515 yline[1] = plP_wcpcy( yt );
516
517 pllclp( xline, yline, 2 );
518 }
519
520 //--------------------------------------------------------------------------
521 // void plP_draphy_poly()
522 //
523 // Draw polyline in physical coordinates.
524 // Need to draw buffers in increments of (PL_MAXPOLY-1) since the
525 // last point must be repeated (for solid lines).
526 //--------------------------------------------------------------------------
527
528 void
529 plP_draphy_poly( PLINT *x, PLINT *y, PLINT n )
530 {
531 PLINT i, j, ib, ilim;
532
533 for ( ib = 0; ib < n; ib += PL_MAXPOLY - 1 )
534 {
535 ilim = MIN( PL_MAXPOLY, n - ib );
536
537 for ( i = 0; i < ilim; i++ )
538 {
539 j = ib + i;
540 xline[i] = x[j];
541 yline[i] = y[j];
542 }
543 pllclp( xline, yline, ilim );
544 }
545 }
546
547 //--------------------------------------------------------------------------
548 // void plP_drawor_poly()
549 //
550 // Draw polyline in world coordinates.
551 // Need to draw buffers in increments of (PL_MAXPOLY-1) since the
552 // last point must be repeated (for solid lines).
553 //--------------------------------------------------------------------------
554
555 void
556 plP_drawor_poly( const PLFLT *x, const PLFLT *y, PLINT n )
557 {
558 PLINT i, j, ib, ilim;
559 PLFLT xt, yt;
560
561 for ( ib = 0; ib < n; ib += PL_MAXPOLY - 1 )
562 {
563 ilim = MIN( PL_MAXPOLY, n - ib );
564
565 for ( i = 0; i < ilim; i++ )
566 {
567 j = ib + i;
568 TRANSFORM( x[j], y[j], &xt, &yt );
569 xline[i] = plP_wcpcx( xt );
570 yline[i] = plP_wcpcy( yt );
571 }
572 pllclp( xline, yline, ilim );
573 }
574 }
575
576 //--------------------------------------------------------------------------
577 // void pllclp()
578 //
579 // Draws a polyline within the clip limits.
580 // Merely a front-end to plP_pllclp().
581 //--------------------------------------------------------------------------
582
583 static void
584 pllclp( PLINT *x, PLINT *y, PLINT npts )
585 {
586 plP_pllclp( x, y, npts, plsc->clpxmi, plsc->clpxma,
587 plsc->clpymi, plsc->clpyma, genlin );
588 }
589
590 //--------------------------------------------------------------------------
591 // void plP_pllclp()
592 //
593 // Draws a polyline within the clip limits.
594 //
595 // (AM)
596 // Wanted to change the type of xclp, yclp to avoid overflows!
597 // But that changes the type for the drawing routines too!
598 //--------------------------------------------------------------------------
599
600 void
601 plP_pllclp( PLINT *x, PLINT *y, PLINT npts,
602 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax,
603 void ( *draw )( short *, short *, PLINT ) )
604 {
605 PLINT x1, x2, y1, y2;
606 PLINT i, iclp = 0;
607
608 short _xclp[PL_MAXPOLY], _yclp[PL_MAXPOLY];
609 short *xclp = NULL, *yclp = NULL;
610 int drawable;
611
612 if ( npts < PL_MAXPOLY )
613 {
614 xclp = _xclp;
615 yclp = _yclp;
616 }
617 else
618 {
619 if ( ( ( xclp = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
620 ( ( yclp = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) )
621 {
622 plexit( "plP_pllclp: Insufficient memory" );
623 }
624 }
625
626 for ( i = 0; i < npts - 1; i++ )
627 {
628 x1 = x[i];
629 x2 = x[i + 1];
630 y1 = y[i];
631 y2 = y[i + 1];
632
633 drawable = ( INSIDE( x1, y1 ) && INSIDE( x2, y2 ) );
634 if ( !drawable )
635 drawable = !plP_clipline( &x1, &y1, &x2, &y2,
636 xmin, xmax, ymin, ymax );
637
638 if ( drawable )
639 {
640 // First point of polyline.
641
642 if ( iclp == 0 )
643 {
644 xclp[iclp] = (short) x1;
645 yclp[iclp] = (short) y1;
646 iclp++;
647 xclp[iclp] = (short) x2;
648 yclp[iclp] = (short) y2;
649 }
650
651 // Not first point. Check if first point of this segment matches up to
652 // previous point, and if so, add it to the current polyline buffer.
653
654 else if ( x1 == xclp[iclp] && y1 == yclp[iclp] )
655 {
656 iclp++;
657 xclp[iclp] = (short) x2;
658 yclp[iclp] = (short) y2;
659 }
660
661 // Otherwise it's time to start a new polyline
662
663 else
664 {
665 if ( iclp + 1 >= 2 )
666 ( *draw )( xclp, yclp, iclp + 1 );
667 iclp = 0;
668 xclp[iclp] = (short) x1;
669 yclp[iclp] = (short) y1;
670 iclp++;
671 xclp[iclp] = (short) x2;
672 yclp[iclp] = (short) y2;
673 }
674 }
675 }
676
677 // Handle remaining polyline
678
679 if ( iclp + 1 >= 2 )
680 ( *draw )( xclp, yclp, iclp + 1 );
681
682 plsc->currx = x[npts - 1];
683 plsc->curry = y[npts - 1];
684
685 if ( xclp != _xclp )
686 {
687 free( xclp );
688 free( yclp );
689 }
690 }
691
692 //--------------------------------------------------------------------------
693 // int plP_clipline()
694 //
695 // Get clipped endpoints
696 //--------------------------------------------------------------------------
697
698 int
699 plP_clipline( PLINT *p_x1, PLINT *p_y1, PLINT *p_x2, PLINT *p_y2,
700 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax )
701 {
702 PLINT t, dx, dy, flipx, flipy;
703 double dydx = 0, dxdy = 0;
704
705 // If both points are outside clip region with no hope of intersection,
706 // return with an error
707
708 if ( ( *p_x1 <= xmin && *p_x2 <= xmin ) ||
709 ( *p_x1 >= xmax && *p_x2 >= xmax ) ||
710 ( *p_y1 <= ymin && *p_y2 <= ymin ) ||
711 ( *p_y1 >= ymax && *p_y2 >= ymax ) )
712 return 1;
713
714 // If one of the coordinates is not finite then return with an error
715 if ( ( *p_x1 == PLINT_MIN ) || ( *p_y1 == PLINT_MIN ) ||
716 ( *p_x2 == PLINT_MIN ) || ( *p_y2 == PLINT_MIN ) )
717 return 1;
718
719 flipx = 0;
720 flipy = 0;
721
722 if ( *p_x2 < *p_x1 )
723 {
724 *p_x1 = 2 * xmin - *p_x1;
725 *p_x2 = 2 * xmin - *p_x2;
726 xmax = 2 * xmin - xmax;
727 t = xmax;
728 xmax = xmin;
729 xmin = t;
730 flipx = 1;
731 }
732
733 if ( *p_y2 < *p_y1 )
734 {
735 *p_y1 = 2 * ymin - *p_y1;
736 *p_y2 = 2 * ymin - *p_y2;
737 ymax = 2 * ymin - ymax;
738 t = ymax;
739 ymax = ymin;
740 ymin = t;
741 flipy = 1;
742 }
743
744 dx = *p_x2 - *p_x1;
745 dy = *p_y2 - *p_y1;
746
747 if ( dx != 0 && dy != 0 )
748 {
749 dydx = (double) dy / (double) dx;
750 dxdy = 1. / dydx;
751 }
752
753 if ( *p_x1 < xmin )
754 {
755 if ( dx != 0 && dy != 0 )
756 *p_y1 = *p_y1 + ROUND( ( xmin - *p_x1 ) * dydx );
757 *p_x1 = xmin;
758 }
759
760 if ( *p_y1 < ymin )
761 {
762 if ( dx != 0 && dy != 0 )
763 *p_x1 = *p_x1 + ROUND( ( ymin - *p_y1 ) * dxdy );
764 *p_y1 = ymin;
765 }
766
767 if ( *p_x1 >= xmax || *p_y1 >= ymax )
768 return 1;
769
770 if ( *p_y2 > ymax )
771 {
772 if ( dx != 0 && dy != 0 )
773 *p_x2 = *p_x2 - ROUND( ( *p_y2 - ymax ) * dxdy );
774 *p_y2 = ymax;
775 }
776
777 if ( *p_x2 > xmax )
778 {
779 if ( dx != 0 && dy != 0 )
780 *p_y2 = *p_y2 - ROUND( ( *p_x2 - xmax ) * dydx );
781 *p_x2 = xmax;
782 }
783
784 if ( flipx )
785 {
786 *p_x1 = 2 * xmax - *p_x1;
787 *p_x2 = 2 * xmax - *p_x2;
788 }
789
790 if ( flipy )
791 {
792 *p_y1 = 2 * ymax - *p_y1;
793 *p_y2 = 2 * ymax - *p_y2;
794 }
795
796 return 0;
797 }
798
799 //--------------------------------------------------------------------------
800 // void genlin()
801 //
802 // General line-drawing routine. Takes line styles into account.
803 // If only 2 points are in the polyline, it is more efficient to use
804 // plP_line() rather than plP_polyline().
805 //--------------------------------------------------------------------------
806
807 static void
808 genlin( short *x, short *y, PLINT npts )
809 {
810 // Check for solid line
811
812 if ( plsc->nms == 0 )
813 {
814 if ( npts == 2 )
815 plP_line( x, y );
816 else
817 plP_polyline( x, y, npts );
818 }
819
820 // Right now dashed lines don't use polyline capability -- this
821 // should be improved
822
823 else
824 {
825 PLINT i;
826
827 // Call escape sequence to draw dashed lines, only for drivers
828 // that have this capability
829 if ( plsc->dev_dash )
830 {
831 plsc->dev_npts = npts;
832 plsc->dev_x = x;
833 plsc->dev_y = y;
834 plP_esc( PLESC_DASH, NULL );
835 return;
836 }
837
838 for ( i = 0; i < npts - 1; i++ )
839 {
840 grdashline( x + i, y + i );
841 }
842 }
843 }
844
845 //--------------------------------------------------------------------------
846 // void grdashline()
847 //
848 // Draws a dashed line to the specified point from the previous one.
849 //--------------------------------------------------------------------------
850
851 static void
852 grdashline( short *x, short *y )
853 {
854 PLINT nx, ny, nxp, nyp, incr, temp;
855 PLINT modulo, dx, dy, i, xtmp, ytmp;
856 PLINT tstep, pix_distance, j;
857 int loop_x;
858 short xl[2], yl[2];
859 double nxstep, nystep;
860
861 // Check if pattern needs to be restarted
862
863 if ( x[0] != lastx || y[0] != lasty )
864 {
865 plsc->curel = 0;
866 plsc->pendn = 1;
867 plsc->timecnt = 0;
868 plsc->alarm = plsc->mark[0];
869 }
870
871 lastx = xtmp = x[0];
872 lasty = ytmp = y[0];
873
874 if ( x[0] == x[1] && y[0] == y[1] )
875 return;
876
877 nx = x[1] - x[0];
878 dx = ( nx > 0 ) ? 1 : -1;
879 nxp = ABS( nx );
880
881 ny = y[1] - y[0];
882 dy = ( ny > 0 ) ? 1 : -1;
883 nyp = ABS( ny );
884
885 if ( nyp > nxp )
886 {
887 modulo = nyp;
888 incr = nxp;
889 loop_x = 0;
890 }
891 else
892 {
893 modulo = nxp;
894 incr = nyp;
895 loop_x = 1;
896 }
897
898 temp = modulo / 2;
899
900 // Compute the timer step
901
902 nxstep = nxp * plsc->umx;
903 nystep = nyp * plsc->umy;
904 tstep = (PLINT) ( sqrt( nxstep * nxstep + nystep * nystep ) / modulo );
905 if ( tstep < 1 )
906 tstep = 1;
907
908 // tstep is distance per pixel moved
909
910 i = 0;
911 while ( i < modulo )
912 {
913 pix_distance = ( plsc->alarm - plsc->timecnt + tstep - 1 ) / tstep;
914 i += pix_distance;
915 if ( i > modulo )
916 pix_distance -= ( i - modulo );
917 plsc->timecnt += pix_distance * tstep;
918
919 temp += pix_distance * incr;
920 j = temp / modulo;
921 temp = temp % modulo;
922
923 if ( loop_x )
924 {
925 xtmp += pix_distance * dx;
926 ytmp += j * dy;
927 }
928 else
929 {
930 xtmp += j * dx;
931 ytmp += pix_distance * dy;
932 }
933 if ( plsc->pendn != 0 )
934 {
935 xl[0] = (short) lastx;
936 yl[0] = (short) lasty;
937 xl[1] = (short) xtmp;
938 yl[1] = (short) ytmp;
939 plP_line( xl, yl );
940 }
941
942 // Update line style variables when alarm goes off
943
944 while ( plsc->timecnt >= plsc->alarm )
945 {
946 if ( plsc->pendn != 0 )
947 {
948 plsc->pendn = 0;
949 plsc->timecnt -= plsc->alarm;
950 plsc->alarm = plsc->space[plsc->curel];
951 }
952 else
953 {
954 plsc->pendn = 1;
955 plsc->timecnt -= plsc->alarm;
956 plsc->curel++;
957 if ( plsc->curel >= plsc->nms )
958 plsc->curel = 0;
959 plsc->alarm = plsc->mark[plsc->curel];
960 }
961 }
962 lastx = xtmp;
963 lasty = ytmp;
964 }
965 }
966
967 //--------------------------------------------------------------------------
968 // interpolate_between()
969 //
970 // Returns a pointer to an array of PLFLT values which interpolate in n steps
971 // from a to b.
972 // Note:
973 // The returned array is allocated by the function and needs to be freed by
974 // the function's caller.
975 // If the return value is NULL, the allocation failed and it is up to the
976 // caller to handle the error.
977 //--------------------------------------------------------------------------
978
979 PLFLT *interpolate_between( PLINT n, PLFLT a, PLFLT b )
980 {
981 PLFLT *values;
982 PLFLT step_size;
983 int i;
984
985 if ( ( values = (PLFLT *) malloc( (size_t) n * sizeof ( PLFLT ) ) ) == NULL )
986 {
987 return NULL;
988 }
989
990 step_size = ( b - a ) / (PLFLT) ( n - 1 );
991 for ( i = 0; i < n; i++ )
992 {
993 values[i] = a + step_size * (PLFLT) i;
994 }
995
996 return values;
997 }