• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

plline.c

Go to the documentation of this file.
00001 // $Id: plline.c 11682 2011-03-31 02:55:49Z airwin $
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, const PLFLT *x, const 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, const PLFLT *x, const PLFLT *y, const 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, const PLFLT *x, const PLFLT *y, const PLFLT *z, const 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, const PLINT *mark, const 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( const PLFLT *x, const 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 }

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1