Back to index

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