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