PLplot  5.10.0
plline.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines