Back to index

plt-scheme  4.2.1
plfill.c
Go to the documentation of this file.
00001 /* $Id: plfill.c,v 1.2 2005/03/17 21:39:21 eli Exp $
00002 
00003        Polygon pattern fill.
00004 */
00005 
00006 #include "plplotP.h"
00007 
00008 #define DTOR            0.0174533
00009 #define BINC            50
00010 
00011 struct point {
00012     PLINT x, y;
00013 };
00014 static PLINT bufferleng, buffersize, *buffer;
00015 
00016 /* Static function prototypes */
00017 /* INDENT OFF */
00018 
00019 static int   compar  (const void *, const void *);
00020 static void  addcoord       (PLINT, PLINT);
00021 static void  tran    (PLINT *, PLINT *, PLFLT, PLFLT);
00022 static void  buildlist      (PLINT, PLINT, PLINT, PLINT, PLINT, PLINT, PLINT);
00023 
00024 /* INDENT ON */
00025 
00026 /*----------------------------------------------------------------------*\
00027  * void plfill()
00028  *
00029  * Pattern fills the polygon bounded by the input points.
00030  * If hardware fill is used, a maximum of PL_MAXPOLY-1 vertices is allowed.
00031  * The final point is explicitly added if it doesn't match up to the first,
00032  * to prevent clipping problems.
00033 \*----------------------------------------------------------------------*/
00034 
00035 MZ_DLLEXPORT
00036 void
00037 c_plfill(PLINT n, PLFLT *x, PLFLT *y)
00038 {
00039     PLINT xpoly[PL_MAXPOLY], ypoly[PL_MAXPOLY];
00040     PLINT i;
00041 
00042     if (plsc->level < 3) {
00043        plabort("plfill: Please set up window first");
00044        return;
00045     }
00046     if (n < 3) {
00047        plabort("plfill: Not enough points in object");
00048        return;
00049     }
00050     if (n > PL_MAXPOLY-1) {
00051        plwarn("plfill: too many points in polygon");
00052        n = PL_MAXPOLY;
00053     }
00054     for (i = 0; i < n; i++) {
00055        xpoly[i] = plP_wcpcx(x[i]);
00056        ypoly[i] = plP_wcpcy(y[i]);
00057     }
00058 
00059     if (x[0] != x[n-1] || y[0] != y[n-1]) {
00060        n++;
00061        xpoly[n-1] = plP_wcpcx(x[0]);
00062        ypoly[n-1] = plP_wcpcy(y[0]);
00063     }
00064 
00065     plP_plfclp(xpoly, ypoly, n, plsc->clpxmi, plsc->clpxma,
00066               plsc->clpymi, plsc->clpyma, plP_fill);
00067 }
00068 
00069 /*----------------------------------------------------------------------*\
00070  * void plfill3()
00071  *
00072  * Pattern fills the polygon in 3d bounded by the input points.
00073  * If hardware fill is used, a maximum of PL_MAXPOLY-1 vertices is allowed.
00074  * The final point is explicitly added if it doesn't match up to the first,
00075  * to prevent clipping problems.
00076 \*----------------------------------------------------------------------*/
00077 
00078 void
00079 c_plfill3(PLINT n, PLFLT *x, PLFLT *y, PLFLT *z)
00080 {
00081     PLFLT tx[PL_MAXPOLY], ty[PL_MAXPOLY], tz[PL_MAXPOLY];
00082     PLFLT *V[3];
00083     PLINT xpoly[PL_MAXPOLY], ypoly[PL_MAXPOLY];
00084     PLINT i;
00085     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00086 
00087     if (plsc->level < 3) {
00088        plabort("plfill3: Please set up window first");
00089        return;
00090     }
00091     if (n < 3) {
00092        plabort("plfill3: Not enough points in object");
00093        return;
00094     }
00095     if (n > PL_MAXPOLY-1) {
00096        plwarn("plfill3: too many points in polygon");
00097        n = PL_MAXPOLY;
00098     }
00099 
00100     plP_gdom(&xmin, &xmax, &ymin, &ymax);
00101     plP_grange(&zscale, &zmin, &zmax);
00102     
00103     /* copy the vertices so we can clip without corrupting the input */
00104     for( i=0; i < n; i++ ) {
00105       tx[i] = x[i]; ty[i] = y[i]; tz[i] = z[i];
00106     }
00107     if (tx[0] != tx[n-1] || ty[0] != ty[n-1] || tz[0] != tz[n-1]) {
00108       tx[n] = tx[0]; ty[n] = ty[0]; tz[n] = tz[0];
00109       n++;
00110     }
00111     V[0] = tx; V[1] = ty; V[2] = tz;
00112     n = plP_clip_poly(n, V, 0,  1, -xmin);
00113     n = plP_clip_poly(n, V, 0, -1,  xmax);
00114     n = plP_clip_poly(n, V, 1,  1, -ymin);
00115     n = plP_clip_poly(n, V, 1, -1,  ymax);
00116     n = plP_clip_poly(n, V, 2,  1, -zmin);
00117     n = plP_clip_poly(n, V, 2, -1,  zmax);
00118     for( i=0; i < n; i++ ) {
00119        xpoly[i] = plP_wcpcx(plP_w3wcx( tx[i], ty[i], tz[i] ));
00120        ypoly[i] = plP_wcpcy(plP_w3wcy( tx[i], ty[i], tz[i] ));
00121        }
00122 
00123 /* AWI: in the past we have used
00124  *  plP_fill(xpoly, ypoly, n);
00125  * here, but our educated guess is this fill should be done via the clipping
00126  * interface instead as below.
00127  * No example tests this code so one of our users will end up inadvertently
00128  * testing this for us. 
00129  *
00130  * jc: I have checked, and both versions does give the same result, i.e., clipping
00131  * to the window boundaries. The reason is that the above plP_clip_poly() does
00132  * the clipping. To check this, is enough to diminish the x/y/z min/max arguments in
00133  * plw3d() in x08c. But let's keep it, although 10% slower...
00134  */
00135     plP_plfclp(xpoly, ypoly, n, plsc->clpxmi, plsc->clpxma,
00136            plsc->clpymi, plsc->clpyma, plP_fill);
00137 }
00138 
00139 /*----------------------------------------------------------------------*\
00140  * void plfill_soft()
00141  *
00142  * Pattern fills in software the polygon bounded by the input points.
00143 \*----------------------------------------------------------------------*/
00144 
00145 void
00146 plfill_soft(short *x, short *y, PLINT n)
00147 {
00148     PLINT i, j;
00149     PLINT xp1, yp1, xp2, yp2, xp3, yp3;
00150     PLINT k, dinc;
00151     PLFLT ci, si;
00152     double temp;
00153 
00154     buffersize = 2 * BINC;
00155     buffer = (PLINT *) malloc((size_t) buffersize * sizeof(PLINT));
00156     if ( ! buffer) {
00157        plabort("plfill: Out of memory");
00158        return;
00159     }
00160 
00161 /* Loop over sets of lines in pattern */
00162 
00163     for (k = 0; k < plsc->nps; k++) {
00164        bufferleng = 0;
00165 
00166         temp = DTOR * plsc->inclin[k] * 0.1;
00167         si = sin(temp) * plsc->ypmm;
00168         ci = cos(temp) * plsc->xpmm;
00169 
00170        /* normalize: 1 = si*si + ci*ci */
00171 
00172         temp = sqrt((double) (si*si + ci*ci));
00173        si /= temp;
00174        ci /= temp;
00175 
00176        dinc = plsc->delta[k] * SSQR(plsc->ypmm * ABS(ci),
00177                                  plsc->xpmm * ABS(si)) / 1000.;
00178 
00179        if (dinc < 0) dinc = -dinc;
00180        if (dinc == 0) dinc = 1;
00181 
00182        xp1 = x[n-2];
00183        yp1 = y[n-2];
00184        tran(&xp1, &yp1, (PLFLT) ci, (PLFLT) si);
00185 
00186        xp2 = x[n-1];
00187        yp2 = y[n-1];
00188        tran(&xp2, &yp2, (PLFLT) ci, (PLFLT) si);
00189 
00190 /* Loop over points in polygon */
00191 
00192        for (i = 0; i < n; i++) {
00193            xp3 = x[i];
00194            yp3 = y[i];
00195            tran(&xp3, &yp3, (PLFLT) ci, (PLFLT) si);
00196            buildlist(xp1, yp1, xp2, yp2, xp3, yp3, dinc);
00197            xp1 = xp2;
00198            yp1 = yp2;
00199            xp2 = xp3;
00200            yp2 = yp3;
00201        }
00202 
00203 /* Sort list by y then x */
00204 
00205        qsort((void *) buffer, (size_t) bufferleng / 2,
00206              (size_t) sizeof(struct point), compar);
00207 
00208 /* OK, now do the hatching */
00209 
00210        i = 0;
00211 
00212        while (i < bufferleng) {
00213            xp1 = buffer[i];
00214            yp1 = buffer[i + 1];
00215            i += 2;
00216            xp2 = xp1;
00217            yp2 = yp1;
00218            tran(&xp1, &yp1, (PLFLT) ci, (PLFLT) (-si));
00219            plP_movphy(xp1, yp1);
00220            xp1 = buffer[i];
00221            yp1 = buffer[i + 1];
00222            i += 2;
00223            if (yp2 != yp1) {
00224               fprintf(stderr, "plfill: oh oh we are lost\n");
00225               for (j = 0; j < bufferleng; j+=2) {
00226                   fprintf(stderr, "plfill: %d %d\n",
00227                          (int) buffer[j], (int) buffer[j+1]);
00228               }
00229               continue;     /* Uh oh we're lost */
00230            }
00231            tran(&xp1, &yp1, (PLFLT) ci, (PLFLT) (-si));
00232            plP_draphy(xp1, yp1);
00233        }
00234     }
00235     free((void *) buffer);
00236 }
00237 
00238 /*----------------------------------------------------------------------*\
00239  * Utility functions
00240 \*----------------------------------------------------------------------*/
00241 
00242 static void
00243 tran(PLINT *a, PLINT *b, PLFLT c, PLFLT d)
00244 {
00245     PLINT ta, tb;
00246 
00247     ta = *a;
00248     tb = *b;
00249 
00250     *a = floor((double) (ta * c + tb * d + 0.5));
00251     *b = floor((double) (tb * c - ta * d + 0.5));
00252 }
00253 
00254 static void
00255 buildlist(PLINT xp1, PLINT yp1, PLINT xp2, PLINT yp2, PLINT xp3, PLINT yp3,
00256          PLINT dinc)
00257 {
00258     PLINT min_y, max_y;
00259     PLINT dx, dy, cstep, nstep, ploty, plotx;
00260 
00261     dx = xp2 - xp1;
00262     dy = yp2 - yp1;
00263 
00264     if (dy == 0) {
00265        if (yp2 > yp3 && ((yp2 % dinc) == 0)) 
00266            addcoord(xp2, yp2);
00267        return;
00268     }
00269 
00270     if (dy > 0) {
00271        cstep = 1;
00272        min_y = yp1;
00273        max_y = yp2;
00274     }
00275     else {
00276        cstep = -1;
00277        min_y = yp2;
00278        max_y = yp1;
00279     }
00280 
00281     nstep = (yp3 > yp2 ? 1 : -1);
00282     if (yp3 == yp2) nstep = 0;
00283 
00284     /* Build coordinate list */
00285 
00286     ploty = (min_y / dinc) * dinc;
00287     if (ploty < min_y) ploty += dinc;
00288 
00289     for (; ploty <= max_y; ploty += dinc) {
00290        if (ploty == yp1) continue;
00291        if (ploty == yp2) {
00292            if (cstep == -nstep) continue;
00293            if (yp2 == yp3 && yp1 > yp2) continue;
00294        }
00295        plotx = xp1 + floor(((double) (ploty - yp1) * dx) / dy + 0.5);
00296        addcoord(plotx, ploty);
00297     }
00298 }
00299 
00300 static void
00301 addcoord(PLINT xp1, PLINT yp1)
00302 {
00303     PLINT *temp;
00304 
00305     if (bufferleng + 2 > buffersize) {
00306        buffersize += 2 * BINC;
00307        temp = (PLINT *) realloc((void *) buffer,
00308                              (size_t) buffersize * sizeof(PLINT));
00309        if (!temp) {
00310            free((void *) buffer);
00311            plexit("plfill: Out of memory!");
00312        }
00313        buffer = temp;
00314     }
00315 
00316     buffer[bufferleng++] = xp1;
00317     buffer[bufferleng++] = yp1;
00318 }
00319 
00320 static int
00321 compar(const void *pnum1, const void *pnum2)
00322 {
00323     const struct point *pnt1, *pnt2;
00324 
00325     pnt1 = (const struct point *) pnum1;
00326     pnt2 = (const struct point *) pnum2;
00327 
00328     if (pnt1->y < pnt2->y)
00329        return -1;
00330     else if (pnt1->y > pnt2->y)
00331        return 1;
00332 
00333     /* Only reach here if y coords are equal, so sort by x */
00334 
00335     if (pnt1->x < pnt2->x)
00336        return -1;
00337     else if (pnt1->x > pnt2->x)
00338        return 1;
00339 
00340     return 0;
00341 }