PLplot 5.9.6
plline.c
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 }
 All Data Structures Files Functions