PLplot 5.9.6
|
00001 /* $Id$ 00002 * 00003 * Routines dealing with line generation. 00004 * 00005 * Copyright (C) 2004 Maurice LeBrun 00006 * 00007 * This file is part of PLplot. 00008 * 00009 * PLplot is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU Library General Public License as published 00011 * by the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * PLplot is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU Library General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Library General Public License 00020 * along with PLplot; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 */ 00024 00025 #include "plplotP.h" 00026 00027 #define INSIDE( ix, iy ) ( BETW( ix, xmin, xmax ) && BETW( iy, ymin, ymax ) ) 00028 00029 static PLINT xline[PL_MAXPOLY], yline[PL_MAXPOLY]; 00030 00031 static PLINT lastx = PL_UNDEFINED, lasty = PL_UNDEFINED; 00032 00033 /* Function prototypes */ 00034 00035 /* Draws a polyline within the clip limits. */ 00036 00037 static void 00038 pllclp( PLINT *x, PLINT *y, PLINT npts ); 00039 00040 /* General line-drawing routine. Takes line styles into account. */ 00041 00042 static void 00043 genlin( short *x, short *y, PLINT npts ); 00044 00045 /* Draws a dashed line to the specified point from the previous one. */ 00046 00047 static void 00048 grdashline( short *x, short *y ); 00049 00050 /* Determines if a point is inside a polygon or not */ 00051 00052 /* Interpolate between two points in n steps */ 00053 00054 static PLFLT * 00055 interpolate_between( int n, PLFLT a, PLFLT b ); 00056 00057 /*----------------------------------------------------------------------*\ 00058 * void pljoin() 00059 * 00060 * Draws a line segment from (x1, y1) to (x2, y2). 00061 \*----------------------------------------------------------------------*/ 00062 00063 void 00064 c_pljoin( PLFLT x1, PLFLT y1, PLFLT x2, PLFLT y2 ) 00065 { 00066 plP_movwor( x1, y1 ); 00067 plP_drawor( x2, y2 ); 00068 } 00069 00070 /*----------------------------------------------------------------------*\ 00071 * void plline() 00072 * 00073 * Draws line segments connecting a series of points. 00074 \*----------------------------------------------------------------------*/ 00075 00076 void 00077 c_plline( PLINT n, PLFLT *x, PLFLT *y ) 00078 { 00079 if ( plsc->level < 3 ) 00080 { 00081 plabort( "plline: Please set up window first" ); 00082 return; 00083 } 00084 plP_drawor_poly( x, y, n ); 00085 } 00086 00087 /*----------------------------------------------------------------------*\ 00088 * void plpath() 00089 * 00090 * Draws a line segment from (x1, y1) to (x2, y2). If a coordinate 00091 * transform is defined then break the line up in to n pieces to approximate 00092 * the path. Otherwise it simply calls pljoin(). 00093 \*----------------------------------------------------------------------*/ 00094 00095 void 00096 c_plpath( PLINT n, PLFLT x1, PLFLT y1, PLFLT x2, PLFLT y2 ) 00097 { 00098 PLFLT *xs, *ys; 00099 00100 if ( plsc->coordinate_transform == NULL ) 00101 { 00102 /* No transform, so fall back on pljoin for a normal straight line */ 00103 pljoin( x1, y1, x2, y2 ); 00104 } 00105 else 00106 { 00107 /* Approximate the path in transformed space with a sequence of line 00108 * segments. */ 00109 xs = interpolate_between( n, x1, x2 ); 00110 ys = interpolate_between( n, y1, y2 ); 00111 if ( xs == NULL || ys == NULL ) 00112 { 00113 plexit( "c_plpath: Insufficient memory" ); 00114 return; 00115 } 00116 plline( n, xs, ys ); 00117 /* plP_interpolate allocates memory, so we have to free it here. */ 00118 free( xs ); 00119 free( ys ); 00120 } 00121 } 00122 00123 /*----------------------------------------------------------------------*\ 00124 * void plline3(n, x, y, z) 00125 * 00126 * Draws a line in 3 space. You must first set up the viewport, the 00127 * 2d viewing window (in world coordinates), and the 3d normalized 00128 * coordinate box. See x18c.c for more info. 00129 * 00130 * This version adds clipping against the 3d bounding box specified in plw3d 00131 \*----------------------------------------------------------------------*/ 00132 void 00133 c_plline3( PLINT n, PLFLT *x, PLFLT *y, PLFLT *z ) 00134 { 00135 int i; 00136 PLFLT vmin[3], vmax[3], zscale; 00137 00138 if ( plsc->level < 3 ) 00139 { 00140 plabort( "plline3: Please set up window first" ); 00141 return; 00142 } 00143 00144 /* get the bounding box in 3d */ 00145 plP_gdom( &vmin[0], &vmax[0], &vmin[1], &vmax[1] ); 00146 plP_grange( &zscale, &vmin[2], &vmax[2] ); 00147 00148 /* interate over the vertices */ 00149 for ( i = 0; i < n - 1; i++ ) 00150 { 00151 PLFLT p0[3], p1[3]; 00152 int axis; 00153 00154 /* copy the end points of the segment to allow clipping */ 00155 p0[0] = x[i]; p0[1] = y[i]; p0[2] = z[i]; 00156 p1[0] = x[i + 1]; p1[1] = y[i + 1]; p1[2] = z[i + 1]; 00157 00158 /* check against each axis of the bounding box */ 00159 for ( axis = 0; axis < 3; axis++ ) 00160 { 00161 if ( p0[axis] < vmin[axis] ) /* first out */ 00162 { 00163 if ( p1[axis] < vmin[axis] ) 00164 { 00165 break; /* both endpoints out so quit */ 00166 } 00167 else 00168 { 00169 int j; 00170 /* interpolate to find intersection with box */ 00171 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00172 p0[axis] = vmin[axis]; 00173 for ( j = 1; j < 3; j++ ) 00174 { 00175 int k = ( axis + j ) % 3; 00176 p0[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00177 } 00178 } 00179 } 00180 else if ( p1[axis] < vmin[axis] ) /* second out */ 00181 { 00182 int j; 00183 /* interpolate to find intersection with box */ 00184 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00185 p1[axis] = vmin[axis]; 00186 for ( j = 1; j < 3; j++ ) 00187 { 00188 int k = ( axis + j ) % 3; 00189 p1[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00190 } 00191 } 00192 if ( p0[axis] > vmax[axis] ) /* first out */ 00193 { 00194 if ( p1[axis] > vmax[axis] ) 00195 { 00196 break; /* both out so quit */ 00197 } 00198 else 00199 { 00200 int j; 00201 /* interpolate to find intersection with box */ 00202 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00203 p0[axis] = vmax[axis]; 00204 for ( j = 1; j < 3; j++ ) 00205 { 00206 int k = ( axis + j ) % 3; 00207 p0[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00208 } 00209 } 00210 } 00211 else if ( p1[axis] > vmax[axis] ) /* second out */ 00212 { 00213 int j; 00214 /* interpolate to find intersection with box */ 00215 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00216 p1[axis] = vmax[axis]; 00217 for ( j = 1; j < 3; j++ ) 00218 { 00219 int k = ( axis + j ) % 3; 00220 p1[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00221 } 00222 } 00223 } 00224 /* if we made it to here without "break"ing out of the loop, the 00225 * remaining segment is visible */ 00226 if ( axis == 3 ) /* not clipped away */ 00227 { 00228 PLFLT u0, v0, u1, v1; 00229 u0 = plP_wcpcx( plP_w3wcx( p0[0], p0[1], p0[2] ) ); 00230 v0 = plP_wcpcy( plP_w3wcy( p0[0], p0[1], p0[2] ) ); 00231 u1 = plP_wcpcx( plP_w3wcx( p1[0], p1[1], p1[2] ) ); 00232 v1 = plP_wcpcy( plP_w3wcy( p1[0], p1[1], p1[2] ) ); 00233 plP_movphy( (PLINT) u0, (PLINT) v0 ); 00234 plP_draphy( (PLINT) u1, (PLINT) v1 ); 00235 } 00236 } 00237 return; 00238 } 00239 /*----------------------------------------------------------------------*\ 00240 * void plpoly3( n, x, y, z, draw, ifcc ) 00241 * 00242 * Draws a polygon in 3 space. This differs from plline3() in that 00243 * this attempts to determine if the polygon is viewable. If the back 00244 * of polygon is facing the viewer, then it isn't drawn. If this 00245 * isn't what you want, then use plline3 instead. 00246 * 00247 * n specifies the number of points. They are assumed to be in a 00248 * plane, and the directionality of the plane is determined from the 00249 * first three points. Additional points do not /have/ to lie on the 00250 * plane defined by the first three, but if they do not, then the 00251 * determiniation of visibility obviously can't be 100% accurate... 00252 * So if you're 3 space polygons are too far from planar, consider 00253 * breaking them into smaller polygons. "3 points define a plane" :-). 00254 * 00255 * For ifcc == 1, the directionality of the polygon is determined by assuming 00256 * the points are laid out in counter-clockwise order. 00257 * 00258 * For ifcc == 0, the directionality of the polygon is determined by assuming 00259 * the points are laid out in clockwise order. 00260 * 00261 * BUGS: If one of the first two segments is of zero length, or if 00262 * they are colinear, the calculation of visibility has a 50/50 chance 00263 * of being correct. Avoid such situations :-). See x18c for an 00264 * example of this problem. (Search for "20.1"). 00265 \*----------------------------------------------------------------------*/ 00266 00267 void 00268 c_plpoly3( PLINT n, PLFLT *x, PLFLT *y, PLFLT *z, PLBOOL *draw, PLBOOL ifcc ) 00269 { 00270 int i; 00271 PLFLT vmin[3], vmax[3], zscale; 00272 PLFLT u1, v1, u2, v2, u3, v3; 00273 PLFLT c; 00274 00275 if ( plsc->level < 3 ) 00276 { 00277 plabort( "plpoly3: Please set up window first" ); 00278 return; 00279 } 00280 00281 if ( n < 3 ) 00282 { 00283 plabort( "plpoly3: Must specify at least 3 points" ); 00284 return; 00285 } 00286 00287 /* Now figure out which side this is. */ 00288 00289 u1 = plP_wcpcx( plP_w3wcx( x[0], y[0], z[0] ) ); 00290 v1 = plP_wcpcy( plP_w3wcy( x[0], y[0], z[0] ) ); 00291 00292 u2 = plP_wcpcx( plP_w3wcx( x[1], y[1], z[1] ) ); 00293 v2 = plP_wcpcy( plP_w3wcy( x[1], y[1], z[1] ) ); 00294 00295 u3 = plP_wcpcx( plP_w3wcx( x[2], y[2], z[2] ) ); 00296 v3 = plP_wcpcy( plP_w3wcy( x[2], y[2], z[2] ) ); 00297 00298 c = ( u1 - u2 ) * ( v3 - v2 ) - ( v1 - v2 ) * ( u3 - u2 ); 00299 00300 if ( c * ( 1 - 2 * ABS( ifcc ) ) < 0. ) 00301 return; 00302 00303 /* get the bounding box in 3d */ 00304 plP_gdom( &vmin[0], &vmax[0], &vmin[1], &vmax[1] ); 00305 plP_grange( &zscale, &vmin[2], &vmax[2] ); 00306 00307 /* interate over the vertices */ 00308 for ( i = 0; i < n - 1; i++ ) 00309 { 00310 PLFLT p0[3], p1[3]; 00311 int axis; 00312 00313 /* copy the end points of the segment to allow clipping */ 00314 p0[0] = x[i]; p0[1] = y[i]; p0[2] = z[i]; 00315 p1[0] = x[i + 1]; p1[1] = y[i + 1]; p1[2] = z[i + 1]; 00316 00317 /* check against each axis of the bounding box */ 00318 for ( axis = 0; axis < 3; axis++ ) 00319 { 00320 if ( p0[axis] < vmin[axis] ) /* first out */ 00321 { 00322 if ( p1[axis] < vmin[axis] ) 00323 { 00324 break; /* both endpoints out so quit */ 00325 } 00326 else 00327 { 00328 int j; 00329 /* interpolate to find intersection with box */ 00330 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00331 p0[axis] = vmin[axis]; 00332 for ( j = 1; j < 3; j++ ) 00333 { 00334 int k = ( axis + j ) % 3; 00335 p0[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00336 } 00337 } 00338 } 00339 else if ( p1[axis] < vmin[axis] ) /* second out */ 00340 { 00341 int j; 00342 /* interpolate to find intersection with box */ 00343 PLFLT t = ( vmin[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00344 p1[axis] = vmin[axis]; 00345 for ( j = 1; j < 3; j++ ) 00346 { 00347 int k = ( axis + j ) % 3; 00348 p1[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00349 } 00350 } 00351 if ( p0[axis] > vmax[axis] ) /* first out */ 00352 { 00353 if ( p1[axis] > vmax[axis] ) 00354 { 00355 break; /* both out so quit */ 00356 } 00357 else 00358 { 00359 int j; 00360 /* interpolate to find intersection with box */ 00361 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00362 p0[axis] = vmax[axis]; 00363 for ( j = 1; j < 3; j++ ) 00364 { 00365 int k = ( axis + j ) % 3; 00366 p0[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00367 } 00368 } 00369 } 00370 else if ( p1[axis] > vmax[axis] ) /* second out */ 00371 { 00372 int j; 00373 /* interpolate to find intersection with box */ 00374 PLFLT t = ( vmax[axis] - p0[axis] ) / ( p1[axis] - p0[axis] ); 00375 p1[axis] = vmax[axis]; 00376 for ( j = 1; j < 3; j++ ) 00377 { 00378 int k = ( axis + j ) % 3; 00379 p1[k] = ( 1 - t ) * p0[k] + t * p1[k]; 00380 } 00381 } 00382 } 00383 /* if we made it to here without "break"ing out of the loop, the 00384 * remaining segment is visible */ 00385 if ( axis == 3 && draw[i] ) /* not clipped away */ 00386 { 00387 PLFLT u0, v0, u1, v1; 00388 u0 = plP_wcpcx( plP_w3wcx( p0[0], p0[1], p0[2] ) ); 00389 v0 = plP_wcpcy( plP_w3wcy( p0[0], p0[1], p0[2] ) ); 00390 u1 = plP_wcpcx( plP_w3wcx( p1[0], p1[1], p1[2] ) ); 00391 v1 = plP_wcpcy( plP_w3wcy( p1[0], p1[1], p1[2] ) ); 00392 plP_movphy( (PLINT) u0, (PLINT) v0 ); 00393 plP_draphy( (PLINT) u1, (PLINT) v1 ); 00394 } 00395 } 00396 return; 00397 } 00398 00399 /*----------------------------------------------------------------------*\ 00400 * void plstyl() 00401 * 00402 * Set up a new line style of "nms" elements, with mark and space 00403 * lengths given by arrays "mark" and "space". 00404 \*----------------------------------------------------------------------*/ 00405 00406 void 00407 c_plstyl( PLINT nms, PLINT *mark, PLINT *space ) 00408 { 00409 short int i; 00410 short int flag; 00411 00412 if ( plsc->level < 1 ) 00413 { 00414 plabort( "plstyl: Please call plinit first" ); 00415 return; 00416 } 00417 if ( ( nms < 0 ) || ( nms > 10 ) ) 00418 { 00419 plabort( "plstyl: Broken lines cannot have <0 or >10 elements" ); 00420 return; 00421 } 00422 flag = 1; 00423 for ( i = 0; i < nms; i++ ) 00424 { 00425 if ( ( mark[i] < 0 ) || ( space[i] < 0 ) ) 00426 { 00427 plabort( "plstyl: Mark and space lengths must be > 0" ); 00428 return; 00429 } 00430 if ( ( mark[i] != 0 ) || ( space[i] != 0 ) ) 00431 { 00432 flag = 0; 00433 } 00434 } 00435 /* Check for blank style */ 00436 if ( ( nms > 0 ) && ( flag == 1 ) ) 00437 { 00438 plabort( "plstyl: At least one mark or space must be > 0" ); 00439 return; 00440 } 00441 00442 plsc->nms = nms; 00443 for ( i = 0; i < nms; i++ ) 00444 { 00445 plsc->mark[i] = mark[i]; 00446 plsc->space[i] = space[i]; 00447 } 00448 00449 plsc->curel = 0; 00450 plsc->pendn = 1; 00451 plsc->timecnt = 0; 00452 plsc->alarm = nms > 0 ? mark[0] : 0; 00453 } 00454 00455 /*----------------------------------------------------------------------*\ 00456 * void plP_movphy() 00457 * 00458 * Move to physical coordinates (x,y). 00459 \*----------------------------------------------------------------------*/ 00460 00461 void 00462 plP_movphy( PLINT x, PLINT y ) 00463 { 00464 plsc->currx = x; 00465 plsc->curry = y; 00466 } 00467 00468 /*----------------------------------------------------------------------*\ 00469 * void plP_draphy() 00470 * 00471 * Draw to physical coordinates (x,y). 00472 \*----------------------------------------------------------------------*/ 00473 00474 void 00475 plP_draphy( PLINT x, PLINT y ) 00476 { 00477 xline[0] = plsc->currx; 00478 xline[1] = x; 00479 yline[0] = plsc->curry; 00480 yline[1] = y; 00481 00482 pllclp( xline, yline, 2 ); 00483 } 00484 00485 /*----------------------------------------------------------------------*\ 00486 * void plP_movwor() 00487 * 00488 * Move to world coordinates (x,y). 00489 \*----------------------------------------------------------------------*/ 00490 00491 void 00492 plP_movwor( PLFLT x, PLFLT y ) 00493 { 00494 PLFLT xt, yt; 00495 TRANSFORM( x, y, &xt, &yt ); 00496 00497 plsc->currx = plP_wcpcx( xt ); 00498 plsc->curry = plP_wcpcy( yt ); 00499 } 00500 00501 /*----------------------------------------------------------------------*\ 00502 * void plP_drawor() 00503 * 00504 * Draw to world coordinates (x,y). 00505 \*----------------------------------------------------------------------*/ 00506 00507 void 00508 plP_drawor( PLFLT x, PLFLT y ) 00509 { 00510 PLFLT xt, yt; 00511 TRANSFORM( x, y, &xt, &yt ); 00512 00513 xline[0] = plsc->currx; 00514 xline[1] = plP_wcpcx( xt ); 00515 yline[0] = plsc->curry; 00516 yline[1] = plP_wcpcy( yt ); 00517 00518 pllclp( xline, yline, 2 ); 00519 } 00520 00521 /*----------------------------------------------------------------------*\ 00522 * void plP_draphy_poly() 00523 * 00524 * Draw polyline in physical coordinates. 00525 * Need to draw buffers in increments of (PL_MAXPOLY-1) since the 00526 * last point must be repeated (for solid lines). 00527 \*----------------------------------------------------------------------*/ 00528 00529 void 00530 plP_draphy_poly( PLINT *x, PLINT *y, PLINT n ) 00531 { 00532 PLINT i, j, ib, ilim; 00533 00534 for ( ib = 0; ib < n; ib += PL_MAXPOLY - 1 ) 00535 { 00536 ilim = MIN( PL_MAXPOLY, n - ib ); 00537 00538 for ( i = 0; i < ilim; i++ ) 00539 { 00540 j = ib + i; 00541 xline[i] = x[j]; 00542 yline[i] = y[j]; 00543 } 00544 pllclp( xline, yline, ilim ); 00545 } 00546 } 00547 00548 /*----------------------------------------------------------------------*\ 00549 * void plP_drawor_poly() 00550 * 00551 * Draw polyline in world coordinates. 00552 * Need to draw buffers in increments of (PL_MAXPOLY-1) since the 00553 * last point must be repeated (for solid lines). 00554 \*----------------------------------------------------------------------*/ 00555 00556 void 00557 plP_drawor_poly( PLFLT *x, PLFLT *y, PLINT n ) 00558 { 00559 PLINT i, j, ib, ilim; 00560 PLFLT xt, yt; 00561 00562 for ( ib = 0; ib < n; ib += PL_MAXPOLY - 1 ) 00563 { 00564 ilim = MIN( PL_MAXPOLY, n - ib ); 00565 00566 for ( i = 0; i < ilim; i++ ) 00567 { 00568 j = ib + i; 00569 TRANSFORM( x[j], y[j], &xt, &yt ); 00570 xline[i] = plP_wcpcx( xt ); 00571 yline[i] = plP_wcpcy( yt ); 00572 } 00573 pllclp( xline, yline, ilim ); 00574 } 00575 } 00576 00577 /*----------------------------------------------------------------------*\ 00578 * void pllclp() 00579 * 00580 * Draws a polyline within the clip limits. 00581 * Merely a front-end to plP_pllclp(). 00582 \*----------------------------------------------------------------------*/ 00583 00584 static void 00585 pllclp( PLINT *x, PLINT *y, PLINT npts ) 00586 { 00587 plP_pllclp( x, y, npts, plsc->clpxmi, plsc->clpxma, 00588 plsc->clpymi, plsc->clpyma, genlin ); 00589 } 00590 00591 /*----------------------------------------------------------------------*\ 00592 * void plP_pllclp() 00593 * 00594 * Draws a polyline within the clip limits. 00595 * 00596 * (AM) 00597 * Wanted to change the type of xclp, yclp to avoid overflows! 00598 * But that changes the type for the drawing routines too! 00599 \*----------------------------------------------------------------------*/ 00600 00601 void 00602 plP_pllclp( PLINT *x, PLINT *y, PLINT npts, 00603 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax, 00604 void ( *draw )( short *, short *, PLINT ) ) 00605 { 00606 PLINT x1, x2, y1, y2; 00607 PLINT i, iclp = 0; 00608 00609 short _xclp[PL_MAXPOLY], _yclp[PL_MAXPOLY]; 00610 short *xclp, *yclp; 00611 int drawable; 00612 00613 if ( npts < PL_MAXPOLY ) 00614 { 00615 xclp = _xclp; 00616 yclp = _yclp; 00617 } 00618 else 00619 { 00620 if ( ( ( xclp = (short *) malloc( npts * sizeof ( short ) ) ) == NULL ) || 00621 ( ( yclp = (short *) malloc( npts * sizeof ( short ) ) ) == NULL ) ) 00622 { 00623 plexit( "plP_pllclp: Insufficient memory" ); 00624 } 00625 } 00626 00627 for ( i = 0; i < npts - 1; i++ ) 00628 { 00629 x1 = x[i]; 00630 x2 = x[i + 1]; 00631 y1 = y[i]; 00632 y2 = y[i + 1]; 00633 00634 drawable = ( INSIDE( x1, y1 ) && INSIDE( x2, y2 ) ); 00635 if ( !drawable ) 00636 drawable = !plP_clipline( &x1, &y1, &x2, &y2, 00637 xmin, xmax, ymin, ymax ); 00638 00639 if ( drawable ) 00640 { 00641 /* First point of polyline. */ 00642 00643 if ( iclp == 0 ) 00644 { 00645 xclp[iclp] = x1; 00646 yclp[iclp] = y1; 00647 iclp++; 00648 xclp[iclp] = x2; 00649 yclp[iclp] = y2; 00650 } 00651 00652 /* Not first point. Check if first point of this segment matches up to 00653 * previous point, and if so, add it to the current polyline buffer. */ 00654 00655 else if ( x1 == xclp[iclp] && y1 == yclp[iclp] ) 00656 { 00657 iclp++; 00658 xclp[iclp] = x2; 00659 yclp[iclp] = y2; 00660 } 00661 00662 /* Otherwise it's time to start a new polyline */ 00663 00664 else 00665 { 00666 if ( iclp + 1 >= 2 ) 00667 ( *draw )( xclp, yclp, iclp + 1 ); 00668 iclp = 0; 00669 xclp[iclp] = x1; 00670 yclp[iclp] = y1; 00671 iclp++; 00672 xclp[iclp] = x2; 00673 yclp[iclp] = y2; 00674 } 00675 } 00676 } 00677 00678 /* Handle remaining polyline */ 00679 00680 if ( iclp + 1 >= 2 ) 00681 ( *draw )( xclp, yclp, iclp + 1 ); 00682 00683 plsc->currx = x[npts - 1]; 00684 plsc->curry = y[npts - 1]; 00685 00686 if ( xclp != _xclp ) 00687 { 00688 free( xclp ); 00689 free( yclp ); 00690 } 00691 } 00692 00693 /*----------------------------------------------------------------------*\ 00694 * int plP_clipline() 00695 * 00696 * Get clipped endpoints 00697 \*----------------------------------------------------------------------*/ 00698 00699 int 00700 plP_clipline( PLINT *p_x1, PLINT *p_y1, PLINT *p_x2, PLINT *p_y2, 00701 PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax ) 00702 { 00703 PLINT t, dx, dy, flipx, flipy; 00704 double dydx = 0, dxdy = 0; 00705 00706 /* If both points are outside clip region with no hope of intersection, 00707 * return with an error */ 00708 00709 if ( ( *p_x1 <= xmin && *p_x2 <= xmin ) || 00710 ( *p_x1 >= xmax && *p_x2 >= xmax ) || 00711 ( *p_y1 <= ymin && *p_y2 <= ymin ) || 00712 ( *p_y1 >= ymax && *p_y2 >= ymax ) ) 00713 return 1; 00714 00715 /* If one of the coordinates is not finite then return with an error */ 00716 if ( ( *p_x1 == PLINT_MIN ) || ( *p_y1 == PLINT_MIN ) || 00717 ( *p_x2 == PLINT_MIN ) || ( *p_y2 == PLINT_MIN ) ) 00718 return 1; 00719 00720 flipx = 0; 00721 flipy = 0; 00722 00723 if ( *p_x2 < *p_x1 ) 00724 { 00725 *p_x1 = 2 * xmin - *p_x1; 00726 *p_x2 = 2 * xmin - *p_x2; 00727 xmax = 2 * xmin - xmax; 00728 t = xmax; 00729 xmax = xmin; 00730 xmin = t; 00731 flipx = 1; 00732 } 00733 00734 if ( *p_y2 < *p_y1 ) 00735 { 00736 *p_y1 = 2 * ymin - *p_y1; 00737 *p_y2 = 2 * ymin - *p_y2; 00738 ymax = 2 * ymin - ymax; 00739 t = ymax; 00740 ymax = ymin; 00741 ymin = t; 00742 flipy = 1; 00743 } 00744 00745 dx = *p_x2 - *p_x1; 00746 dy = *p_y2 - *p_y1; 00747 00748 if ( dx != 0 && dy != 0 ) 00749 { 00750 dydx = (double) dy / (double) dx; 00751 dxdy = 1. / dydx; 00752 } 00753 00754 if ( *p_x1 < xmin ) 00755 { 00756 if ( dx != 0 && dy != 0 ) 00757 *p_y1 = *p_y1 + ROUND( ( xmin - *p_x1 ) * dydx ); 00758 *p_x1 = xmin; 00759 } 00760 00761 if ( *p_y1 < ymin ) 00762 { 00763 if ( dx != 0 && dy != 0 ) 00764 *p_x1 = *p_x1 + ROUND( ( ymin - *p_y1 ) * dxdy ); 00765 *p_y1 = ymin; 00766 } 00767 00768 if ( *p_x1 >= xmax || *p_y1 >= ymax ) 00769 return 1; 00770 00771 if ( *p_y2 > ymax ) 00772 { 00773 if ( dx != 0 && dy != 0 ) 00774 *p_x2 = *p_x2 - ROUND( ( *p_y2 - ymax ) * dxdy ); 00775 *p_y2 = ymax; 00776 } 00777 00778 if ( *p_x2 > xmax ) 00779 { 00780 if ( dx != 0 && dy != 0 ) 00781 *p_y2 = *p_y2 - ROUND( ( *p_x2 - xmax ) * dydx ); 00782 *p_x2 = xmax; 00783 } 00784 00785 if ( flipx ) 00786 { 00787 *p_x1 = 2 * xmax - *p_x1; 00788 *p_x2 = 2 * xmax - *p_x2; 00789 } 00790 00791 if ( flipy ) 00792 { 00793 *p_y1 = 2 * ymax - *p_y1; 00794 *p_y2 = 2 * ymax - *p_y2; 00795 } 00796 00797 return 0; 00798 } 00799 00800 /*----------------------------------------------------------------------*\ 00801 * void genlin() 00802 * 00803 * General line-drawing routine. Takes line styles into account. 00804 * If only 2 points are in the polyline, it is more efficient to use 00805 * plP_line() rather than plP_polyline(). 00806 \*----------------------------------------------------------------------*/ 00807 00808 static void 00809 genlin( short *x, short *y, PLINT npts ) 00810 { 00811 /* Check for solid line */ 00812 00813 if ( plsc->nms == 0 ) 00814 { 00815 if ( npts == 2 ) 00816 plP_line( x, y ); 00817 else 00818 plP_polyline( x, y, npts ); 00819 } 00820 00821 /* Right now dashed lines don't use polyline capability -- this 00822 * should be improved */ 00823 00824 else 00825 { 00826 PLINT i; 00827 00828 /* Call escape sequence to draw dashed lines, only for drivers 00829 * that have this capability */ 00830 if ( plsc->dev_dash ) 00831 { 00832 plsc->dev_npts = npts; 00833 plsc->dev_x = x; 00834 plsc->dev_y = y; 00835 plP_esc( PLESC_DASH, NULL ); 00836 return; 00837 } 00838 00839 for ( i = 0; i < npts - 1; i++ ) 00840 { 00841 grdashline( x + i, y + i ); 00842 } 00843 } 00844 } 00845 00846 /*----------------------------------------------------------------------*\ 00847 * void grdashline() 00848 * 00849 * Draws a dashed line to the specified point from the previous one. 00850 \*----------------------------------------------------------------------*/ 00851 00852 static void 00853 grdashline( short *x, short *y ) 00854 { 00855 PLINT nx, ny, nxp, nyp, incr, temp; 00856 PLINT modulo, dx, dy, i, xtmp, ytmp; 00857 PLINT tstep, pix_distance, j; 00858 int loop_x; 00859 short xl[2], yl[2]; 00860 double nxstep, nystep; 00861 00862 /* Check if pattern needs to be restarted */ 00863 00864 if ( x[0] != lastx || y[0] != lasty ) 00865 { 00866 plsc->curel = 0; 00867 plsc->pendn = 1; 00868 plsc->timecnt = 0; 00869 plsc->alarm = plsc->mark[0]; 00870 } 00871 00872 lastx = xtmp = x[0]; 00873 lasty = ytmp = y[0]; 00874 00875 if ( x[0] == x[1] && y[0] == y[1] ) 00876 return; 00877 00878 nx = x[1] - x[0]; 00879 dx = ( nx > 0 ) ? 1 : -1; 00880 nxp = ABS( nx ); 00881 00882 ny = y[1] - y[0]; 00883 dy = ( ny > 0 ) ? 1 : -1; 00884 nyp = ABS( ny ); 00885 00886 if ( nyp > nxp ) 00887 { 00888 modulo = nyp; 00889 incr = nxp; 00890 loop_x = 0; 00891 } 00892 else 00893 { 00894 modulo = nxp; 00895 incr = nyp; 00896 loop_x = 1; 00897 } 00898 00899 temp = modulo / 2; 00900 00901 /* Compute the timer step */ 00902 00903 nxstep = nxp * plsc->umx; 00904 nystep = nyp * plsc->umy; 00905 tstep = (PLINT) ( sqrt( nxstep * nxstep + nystep * nystep ) / modulo ); 00906 if ( tstep < 1 ) 00907 tstep = 1; 00908 00909 /* tstep is distance per pixel moved */ 00910 00911 i = 0; 00912 while ( i < modulo ) 00913 { 00914 pix_distance = ( plsc->alarm - plsc->timecnt + tstep - 1 ) / tstep; 00915 i += pix_distance; 00916 if ( i > modulo ) 00917 pix_distance -= ( i - modulo ); 00918 plsc->timecnt += pix_distance * tstep; 00919 00920 temp += pix_distance * incr; 00921 j = temp / modulo; 00922 temp = temp % modulo; 00923 00924 if ( loop_x ) 00925 { 00926 xtmp += pix_distance * dx; 00927 ytmp += j * dy; 00928 } 00929 else 00930 { 00931 xtmp += j * dx; 00932 ytmp += pix_distance * dy; 00933 } 00934 if ( plsc->pendn != 0 ) 00935 { 00936 xl[0] = lastx; 00937 yl[0] = lasty; 00938 xl[1] = xtmp; 00939 yl[1] = ytmp; 00940 plP_line( xl, yl ); 00941 } 00942 00943 /* Update line style variables when alarm goes off */ 00944 00945 while ( plsc->timecnt >= plsc->alarm ) 00946 { 00947 if ( plsc->pendn != 0 ) 00948 { 00949 plsc->pendn = 0; 00950 plsc->timecnt -= plsc->alarm; 00951 plsc->alarm = plsc->space[plsc->curel]; 00952 } 00953 else 00954 { 00955 plsc->pendn = 1; 00956 plsc->timecnt -= plsc->alarm; 00957 plsc->curel++; 00958 if ( plsc->curel >= plsc->nms ) 00959 plsc->curel = 0; 00960 plsc->alarm = plsc->mark[plsc->curel]; 00961 } 00962 } 00963 lastx = xtmp; 00964 lasty = ytmp; 00965 } 00966 } 00967 00968 /*----------------------------------------------------------------------*\ 00969 * interpolate_between() 00970 * 00971 * Returns a pointer to an array of PLFLT values which interpolate in n steps 00972 * from a to b. 00973 * Note: 00974 * The returned array is allocated by the function and needs to be freed by 00975 * the function's caller. 00976 * If the return value is NULL, the allocation failed and it is up to the 00977 * caller to handle the error. 00978 \*----------------------------------------------------------------------*/ 00979 00980 PLFLT *interpolate_between( PLINT n, PLFLT a, PLFLT b ) 00981 { 00982 PLFLT *values; 00983 PLFLT step_size; 00984 int i; 00985 00986 if ( ( values = (PLFLT *) malloc( n * sizeof ( PLFLT ) ) ) == NULL ) 00987 { 00988 return NULL; 00989 } 00990 00991 step_size = ( b - a ) / (PLFLT) ( n - 1 ); 00992 for ( i = 0; i < n; i++ ) 00993 { 00994 values[i] = a + step_size * (PLFLT) i; 00995 } 00996 00997 return values; 00998 }