Esempio n. 1
0
ICEILTEMPDECL
#endif

/*
 *        Written by Todd Newman; April. 1987.
 *
 *        Fill a convex polygon.  If the given polygon
 *        is not convex, then the result is undefined.
 *        The algorithm is to order the edges from smallest
 *        y to largest by partitioning the array into a left
 *        edge list and a right edge list.  The algorithm used
 *        to traverse each edge is digital differencing analyzer
 *        line algorithm with y as the major axis. There's some funny linear
 *        interpolation involved because of the subpixel postioning.
 * 
 * count:               number of points
 * ptsIn:               the points
 * xTrans, yTrans:      Translate each point by this
 * xFtrans, yFtrans:    translate before conversion
 *                      by this amount.  This provides
 *                      a mechanism to match rounding
 *                      errors with any shape that must
 *                      meet the polygon exactly.
 */
void miFillSppPoly (PDC pdc, int count, SppPointPtr ptsIn, int xTrans, int yTrans, double xFtrans, double yFtrans)
{
    double          xl = 0, xr = 0, /* x vals of left and right edges */
                    ml = 0,         /* left edge slope */
                    mr = 0,         /* right edge slope */
                    dy,             /* delta y */
                    i;              /* loop counter */
    int             y,              /* current scanline */
                    j,
                    imin,           /* index of vertex with smallest y */
                    ymin,           /* y-extents of polygon */
                    ymax,
                    *Marked;        /* set if this vertex has been used */
    register int    left, right,    /* indices to first endpoints */
                    nextleft,
                    nextright;      /* indices to second endpoints */
    Span            *ptsOut, *FirstPoint;   /* output buffer */

    imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax);

    y = ymax - ymin + 1;
    if ((count < 3) || (y <= 0))
        return;

    ptsOut = FirstPoint = (Span*)ALLOCATE_LOCAL(sizeof(Span) * y);
    Marked = (int *) ALLOCATE_LOCAL(sizeof(int) * count);

    if(!ptsOut || !Marked)
    {
        if (Marked) DEALLOCATE_LOCAL(Marked);
        if (ptsOut) DEALLOCATE_LOCAL(ptsOut);
        return;
    }

    for(j = 0; j < count; j++)
        Marked[j] = 0;
    nextleft = nextright = imin;
    Marked[imin] = -1;
    y = ICEIL(ptsIn[nextleft].y + yFtrans);

    /*
     *  loop through all edges of the polygon
     */
    do
    {
        /* add a left edge if we need to */
        if ((y > (ptsIn[nextleft].y + yFtrans) ||
              ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) &&
             Marked[nextleft] != 1)
        {
            Marked[nextleft]++;
            left = nextleft++;

            /* find the next edge, considering the end conditions */
            if (nextleft >= count)
                nextleft = 0;

            /* now compute the starting point and slope */
            dy = ptsIn[nextleft].y - ptsIn[left].y;
            if (dy != 0.0)
            { 
                ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy;
                dy = y - (ptsIn[left].y + yFtrans);
                xl = (ptsIn[left].x + xFtrans) + ml * MAX(dy, 0); 
            }
        }

        /* add a right edge if we need to */
        if ((y > ptsIn[nextright].y + yFtrans) ||
              (ISEQUAL(y, ptsIn[nextright].y + yFtrans)
              && Marked[nextright] != 1))
        {
            Marked[nextright]++;
            right = nextright--;

            /* find the next edge, considering the end conditions */
            if (nextright < 0)
                nextright = count - 1;

            /* now compute the starting point and slope */
            dy = ptsIn[nextright].y - ptsIn[right].y;
            if (dy != 0.0) 
            { 
                mr = (ptsIn[nextright].x - ptsIn[right].x) / dy;
                dy = y - (ptsIn[right].y + yFtrans); 
                xr = (ptsIn[right].x + xFtrans) + mr * MAX(dy, 0);
            }
        }


        /*
         *  generate scans to fill while we still have
         *  a right edge as well as a left edge.
         */
        i = (MIN(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y;

        if (i < EPSILON)
        {
            if(Marked[nextleft] && Marked[nextright])
            {
                /* Arrgh, we're trapped! (no more points) 
                 * Out, we've got to get out of here before this decadence saps
                 * our will completely! */
                break;
            }
            continue;
        }
        else
        {
                j = (int) i;
                if(!j)
                    j++;
        }
        while (j > 0) 
        {
            int cxl, cxr;

            ptsOut->y = (y) + yTrans;

            cxl = ICEIL(xl);
            cxr = ICEIL(xr);
            /* reverse the edges if necessary */
            if (xl < xr) 
            {
              ptsOut->width = cxr - cxl;
              (ptsOut++)->x = cxl + xTrans;
            }
            else 
            {
              ptsOut->width = cxl - cxr;
              (ptsOut++)->x = cxr + xTrans;
            }
            y++;

            /* increment down the edges */
            xl += ml;
            xr += mr;
            j--;
        }
    }  while (y <= ymax);

    /* Finally, fill the spans we've collected */
    _dc_fill_spans (pdc, FirstPoint, ptsOut-FirstPoint, FALSE);
    DEALLOCATE_LOCAL(Marked);
    DEALLOCATE_LOCAL(FirstPoint);
}
Esempio n. 2
0
/*
 *	Written by Todd Newman; April. 1987.
 *
 *	Fill a convex polygon.  If the given polygon
 *	is not convex, then the result is undefined.
 *	The algorithm is to order the edges from smallest
 *	y to largest by partitioning the array into a left
 *	edge list and a right edge list.  The algorithm used
 *	to traverse each edge is digital differencing analyzer
 *	line algorithm with y as the major axis. There's some funny linear
 *	interpolation involved because of the subpixel postioning.
 */
void
miFillSppPoly(DrawablePtr dst, GCPtr pgc, int count,    /* number of points */
              SppPointPtr ptsIn,        /* the points */
              int xTrans, int yTrans,   /* Translate each point by this */
              double xFtrans, double yFtrans    /* translate before conversion
                                                   by this amount.  This provides
                                                   a mechanism to match rounding
                                                   errors with any shape that must
                                                   meet the polygon exactly.
                                                 */
    )
{
    double xl = 0.0, xr = 0.0,  /* x vals of left and right edges */
        ml = 0.0,               /* left edge slope */
        mr = 0.0,               /* right edge slope */
        dy,                     /* delta y */
        i;                      /* loop counter */
    int y,                      /* current scanline */
     j, imin,                   /* index of vertex with smallest y */
     ymin,                      /* y-extents of polygon */
     ymax, *width, *FirstWidth, /* output buffer */
    *Marked;                    /* set if this vertex has been used */
    int left, right,            /* indices to first endpoints */
     nextleft, nextright;       /* indices to second endpoints */
    DDXPointPtr ptsOut, FirstPoint;     /* output buffer */

    if (pgc->miTranslate) {
        xTrans += dst->x;
        yTrans += dst->y;
    }

    imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax);

    y = ymax - ymin + 1;
    if ((count < 3) || (y <= 0))
        return;
    ptsOut = FirstPoint = malloc(sizeof(DDXPointRec) * y);
    width = FirstWidth = malloc(sizeof(int) * y);
    Marked = malloc(sizeof(int) * count);

    if (!ptsOut || !width || !Marked) {
        free(Marked);
        free(width);
        free(ptsOut);
        return;
    }

    for (j = 0; j < count; j++)
        Marked[j] = 0;
    nextleft = nextright = imin;
    Marked[imin] = -1;
    y = ICEIL(ptsIn[nextleft].y + yFtrans);

    /*
     *  loop through all edges of the polygon
     */
    do {
        /* add a left edge if we need to */
        if ((y > (ptsIn[nextleft].y + yFtrans) ||
             ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) &&
            Marked[nextleft] != 1) {
            Marked[nextleft]++;
            left = nextleft++;

            /* find the next edge, considering the end conditions */
            if (nextleft >= count)
                nextleft = 0;

            /* now compute the starting point and slope */
            dy = ptsIn[nextleft].y - ptsIn[left].y;
            if (dy != 0.0) {
                ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy;
                dy = y - (ptsIn[left].y + yFtrans);
                xl = (ptsIn[left].x + xFtrans) + ml * max(dy, 0);
            }
        }

        /* add a right edge if we need to */
        if ((y > ptsIn[nextright].y + yFtrans) ||
            (ISEQUAL(y, ptsIn[nextright].y + yFtrans)
             && Marked[nextright] != 1)) {
            Marked[nextright]++;
            right = nextright--;

            /* find the next edge, considering the end conditions */
            if (nextright < 0)
                nextright = count - 1;

            /* now compute the starting point and slope */
            dy = ptsIn[nextright].y - ptsIn[right].y;
            if (dy != 0.0) {
                mr = (ptsIn[nextright].x - ptsIn[right].x) / dy;
                dy = y - (ptsIn[right].y + yFtrans);
                xr = (ptsIn[right].x + xFtrans) + mr * max(dy, 0);
            }
        }

        /*
         *  generate scans to fill while we still have
         *  a right edge as well as a left edge.
         */
        i = (min(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y;

        if (i < EPSILON) {
            if (Marked[nextleft] && Marked[nextright]) {
                /* Arrgh, we're trapped! (no more points) 
                 * Out, we've got to get out of here before this decadence saps
                 * our will completely! */
                break;
            }
            continue;
        }
        else {
            j = (int) i;
            if (!j)
                j++;
        }
        while (j > 0) {
            int cxl, cxr;

            ptsOut->y = (y) + yTrans;

            cxl = ICEIL(xl);
            cxr = ICEIL(xr);
            /* reverse the edges if necessary */
            if (xl < xr) {
                *(width++) = cxr - cxl;
                (ptsOut++)->x = cxl + xTrans;
            }
            else {
                *(width++) = cxl - cxr;
                (ptsOut++)->x = cxr + xTrans;
            }
            y++;

            /* increment down the edges */
            xl += ml;
            xr += mr;
            j--;
        }
    } while (y <= ymax);

    /* Finally, fill the spans we've collected */
    (*pgc->ops->FillSpans) (dst, pgc,
                            ptsOut - FirstPoint, FirstPoint, FirstWidth, 1);
    free(Marked);
    free(FirstWidth);
    free(FirstPoint);
}