예제 #1
0
/*
 *     polytoregion
 *
 *     Scan converts a polygon by returning a run-length
 *     encoding of the resultant bitmap -- the run-length
 *     encoding is in the form of an array of rectangles.
 */
Region
XPolygonRegion(
    XPoint     *Pts,		     /* the pts                 */
    int       Count,                 /* number of pts           */
    int	rule)			     /* winding rule */
{
    Region region;
    register EdgeTableEntry *pAET;   /* Active Edge Table       */
    register int y;                  /* current scanline        */
    register int iPts = 0;           /* number of pts in buffer */
    register EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
    register ScanLineList *pSLL;     /* current scanLineList    */
    register XPoint *pts;             /* output buffer           */
    EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
    EdgeTable ET;                    /* header node for ET      */
    EdgeTableEntry AET;              /* header node for AET     */
    EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
    ScanLineListBlock SLLBlock;      /* header for scanlinelist */
    int fixWAET = FALSE;
    POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
    POINTBLOCK *tmpPtBlock;
    int numFullPtBlocks = 0;

    if (! (region = XCreateRegion())) return (Region) NULL;

    /* special case a rectangle */
    pts = Pts;
    if (((Count == 4) ||
	 ((Count == 5) && (pts[4].x == pts[0].x) && (pts[4].y == pts[0].y))) &&
	(((pts[0].y == pts[1].y) &&
	  (pts[1].x == pts[2].x) &&
	  (pts[2].y == pts[3].y) &&
	  (pts[3].x == pts[0].x)) ||
	 ((pts[0].x == pts[1].x) &&
	  (pts[1].y == pts[2].y) &&
	  (pts[2].x == pts[3].x) &&
	  (pts[3].y == pts[0].y)))) {
	region->extents.x1 = min(pts[0].x, pts[2].x);
	region->extents.y1 = min(pts[0].y, pts[2].y);
	region->extents.x2 = max(pts[0].x, pts[2].x);
	region->extents.y2 = max(pts[0].y, pts[2].y);
	if ((region->extents.x1 != region->extents.x2) &&
	    (region->extents.y1 != region->extents.y2)) {
	    region->numRects = 1;
	    *(region->rects) = region->extents;
	}
	return(region);
    }

    if (Count < 2) return region;

    if (! (pETEs = Xmalloc(sizeof(EdgeTableEntry) * Count))) {
	XDestroyRegion(region);
	return (Region) NULL;
    }

    pts = FirstPtBlock.pts;
    CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
    pSLL = ET.scanlines.next;
    curPtBlock = &FirstPtBlock;

    if (rule == EvenOddRule) {
        /*
         *  for each scanline
         */
        for (y = ET.ymin; y < ET.ymax; y++) {
            /*
             *  Add a new edge to the active edge table when we
             *  get to the next edge.
             */
            if (pSLL != NULL && y == pSLL->scanline) {
                loadAET(&AET, pSLL->edgelist);
                pSLL = pSLL->next;
            }
            pPrevAET = &AET;
            pAET = AET.next;

            /*
             *  for each active edge
             */
            while (pAET) {
                pts->x = pAET->bres.minor_axis,  pts->y = y;
                pts++, iPts++;

                /*
                 *  send out the buffer
                 */
                if (iPts == NUMPTSTOBUFFER) {
                    tmpPtBlock = Xmalloc(sizeof(POINTBLOCK));
                    curPtBlock->next = tmpPtBlock;
                    curPtBlock = tmpPtBlock;
                    pts = curPtBlock->pts;
                    numFullPtBlocks++;
                    iPts = 0;
                }
                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
            }
            (void) InsertionSort(&AET);
        }
    }
    else {
        /*
         *  for each scanline
         */
        for (y = ET.ymin; y < ET.ymax; y++) {
            /*
             *  Add a new edge to the active edge table when we
             *  get to the next edge.
             */
            if (pSLL != NULL && y == pSLL->scanline) {
                loadAET(&AET, pSLL->edgelist);
                computeWAET(&AET);
                pSLL = pSLL->next;
            }
            pPrevAET = &AET;
            pAET = AET.next;
            pWETE = pAET;

            /*
             *  for each active edge
             */
            while (pAET) {
                /*
                 *  add to the buffer only those edges that
                 *  are in the Winding active edge table.
                 */
                if (pWETE == pAET) {
                    pts->x = pAET->bres.minor_axis,  pts->y = y;
                    pts++, iPts++;

                    /*
                     *  send out the buffer
                     */
                    if (iPts == NUMPTSTOBUFFER) {
                        tmpPtBlock = Xmalloc(sizeof(POINTBLOCK));
                        curPtBlock->next = tmpPtBlock;
                        curPtBlock = tmpPtBlock;
                        pts = curPtBlock->pts;
                        numFullPtBlocks++;    iPts = 0;
                    }
                    pWETE = pWETE->nextWETE;
                }
                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
            }

            /*
             *  recompute the winding active edge table if
             *  we just resorted or have exited an edge.
             */
            if (InsertionSort(&AET) || fixWAET) {
                computeWAET(&AET);
                fixWAET = FALSE;
            }
        }
    }
    FreeStorage(SLLBlock.next);
    (void) PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
	tmpPtBlock = curPtBlock->next;
	Xfree(curPtBlock);
	curPtBlock = tmpPtBlock;
    }
    Xfree(pETEs);
    return(region);
}
예제 #2
0
/*
 *           GdAllocPolyPolygonRegion
 */
MWCLIPREGION *
GdAllocPolyPolygonRegion(MWPOINT *points, int *count, int nbpolygons, int mode)
{
    MWCLIPREGION *rgn;
    EdgeTableEntry *pAET;   /* Active Edge Table       */
    int y;                  /* current scanline        */
    int iPts = 0;           /* number of pts in buffer */
    EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
    ScanLineList *pSLL;     /* current scanLineList    */
    MWPOINT *pts;           /* output buffer           */
    EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
    EdgeTable ET;                    /* header node for ET      */
    EdgeTableEntry AET;              /* header node for AET     */
    EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
    ScanLineListBlock SLLBlock;      /* header for scanlinelist */
    int fixWAET = FALSE;
    POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
    POINTBLOCK *tmpPtBlock;
    int numFullPtBlocks = 0;
    int poly, total;

    if(!(rgn = GdAllocRegion()))
        return NULL;

    /* special case a rectangle */

    if (((nbpolygons == 1) && ((*count == 4) ||
       ((*count == 5) && (points[4].x == points[0].x)
        && (points[4].y == points[0].y)))) &&
        (((points[0].y == points[1].y) &&
          (points[1].x == points[2].x) &&
          (points[2].y == points[3].y) &&
          (points[3].x == points[0].x)) ||
         ((points[0].x == points[1].x) &&
          (points[1].y == points[2].y) &&
          (points[2].x == points[3].x) &&
          (points[3].y == points[0].y))))
    {
        GdSetRectRegion( rgn,
	    MWMIN(points[0].x, points[2].x), MWMIN(points[0].y, points[2].y),
	    MWMAX(points[0].x, points[2].x), MWMAX(points[0].y, points[2].y) );
        return rgn;
    }

    for(poly = total = 0; poly < nbpolygons; poly++)
        total += count[poly];
    if (! (pETEs = malloc( sizeof(EdgeTableEntry) * total )))
    {
        GdDestroyRegion( rgn );
        return 0;
    }
    pts = FirstPtBlock.pts;
    REGION_CreateETandAET(count, nbpolygons, points, &ET, &AET,
        pETEs, &SLLBlock);
    pSLL = ET.scanlines.next;
    curPtBlock = &FirstPtBlock;

    if (mode != MWPOLY_WINDING) {
        /*
         *  for each scanline
         */
        for (y = ET.ymin; y < ET.ymax; y++) {
            /*
             *  Add a new edge to the active edge table when we
             *  get to the next edge.
             */
            if (pSLL != NULL && y == pSLL->scanline) {
                REGION_loadAET(&AET, pSLL->edgelist);
                pSLL = pSLL->next;
            }
            pPrevAET = &AET;
            pAET = AET.next;

            /*
             *  for each active edge
             */
            while (pAET) {
                pts->x = pAET->bres.minor_axis,  pts->y = y;
                pts++, iPts++;

                /*
                 *  send out the buffer
                 */
                if (iPts == NUMPTSTOBUFFER) {
                    tmpPtBlock = malloc( sizeof(POINTBLOCK));
                    if(!tmpPtBlock) {
                        return 0;
                    }
                    curPtBlock->next = tmpPtBlock;
                    curPtBlock = tmpPtBlock;
                    pts = curPtBlock->pts;
                    numFullPtBlocks++;
                    iPts = 0;
                }
                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);

            }
            REGION_InsertionSort(&AET);
        }
    }
    else {
        /*
         *  for each scanline
         */
        for (y = ET.ymin; y < ET.ymax; y++) {
            /*
             *  Add a new edge to the active edge table when we
             *  get to the next edge.
             */
            if (pSLL != NULL && y == pSLL->scanline) {
                REGION_loadAET(&AET, pSLL->edgelist);
                REGION_computeWAET(&AET);
                pSLL = pSLL->next;
            }
            pPrevAET = &AET;
            pAET = AET.next;
            pWETE = pAET;

            /*
             *  for each active edge
             */
            while (pAET) {
                /*
                 *  add to the buffer only those edges that
                 *  are in the Winding active edge table.
                 */
                if (pWETE == pAET) {
                    pts->x = pAET->bres.minor_axis,  pts->y = y;
                    pts++, iPts++;

                    /*
                     *  send out the buffer
                     */
                    if (iPts == NUMPTSTOBUFFER) {
                        tmpPtBlock = malloc( sizeof(POINTBLOCK) );
                        if(!tmpPtBlock) {
                            return 0;
                        }
                        curPtBlock->next = tmpPtBlock;
                        curPtBlock = tmpPtBlock;
                        pts = curPtBlock->pts;
                        numFullPtBlocks++;    iPts = 0;
                    }
                    pWETE = pWETE->nextWETE;
                }
                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
            }

            /*
             *  recompute the winding active edge table if
             *  we just resorted or have exited an edge.
             */
            if (REGION_InsertionSort(&AET) || fixWAET) {
                REGION_computeWAET(&AET);
                fixWAET = FALSE;
            }
        }
    }
    REGION_FreeStorage(SLLBlock.next);
    REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, rgn);
    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
        tmpPtBlock = curPtBlock->next;
        free( curPtBlock );
        curPtBlock = tmpPtBlock;
    }
    free( pETEs );
    return rgn;
}
예제 #3
0
/*
 * Written by Brian Kelleher;  Oct. 1985
 *
 * Routine to fill a polygon.  Two fill rules are supported: frWINDING and
 * frEVENODD.
 */
static Bool
miFillGeneralPoly(DrawablePtr dst, GCPtr pgc, int count, DDXPointPtr ptsIn)
{
    EdgeTableEntry *pAET;       /* the Active Edge Table   */
    int y;                      /* the current scanline    */
    int nPts = 0;               /* number of pts in buffer */
    EdgeTableEntry *pWETE;      /* Winding Edge Table      */
    ScanLineList *pSLL;         /* Current ScanLineList    */
    DDXPointPtr ptsOut;         /* ptr to output buffers   */
    int *width;
    DDXPointRec FirstPoint[NUMPTSTOBUFFER];     /* the output buffers */
    int FirstWidth[NUMPTSTOBUFFER];
    EdgeTableEntry *pPrevAET;   /* previous AET entry      */
    EdgeTable ET;               /* Edge Table header node  */
    EdgeTableEntry AET;         /* Active ET header node   */
    EdgeTableEntry *pETEs;      /* Edge Table Entries buff */
    ScanLineListBlock SLLBlock; /* header for ScanLineList */
    int fixWAET = 0;

    if (count < 3)
        return TRUE;

    if (!(pETEs = malloc(sizeof(EdgeTableEntry) * count)))
        return FALSE;
    ptsOut = FirstPoint;
    width = FirstWidth;
    if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) {
        free(pETEs);
        return FALSE;
    }
    pSLL = ET.scanlines.next;

    if (pgc->fillRule == EvenOddRule) {
        /*
         *  for each scanline
         */
        for (y = ET.ymin; y < ET.ymax; y++) {
            /*
             *  Add a new edge to the active edge table when we
             *  get to the next edge.
             */
            if (pSLL && y == pSLL->scanline) {
                miloadAET(&AET, pSLL->edgelist);
                pSLL = pSLL->next;
            }
            pPrevAET = &AET;
            pAET = AET.next;

            /*
             *  for each active edge
             */
            while (pAET) {
                ptsOut->x = pAET->bres.minor;
                ptsOut++->y = y;
                *width++ = pAET->next->bres.minor - pAET->bres.minor;
                nPts++;

                /*
                 *  send out the buffer when its full
                 */
                if (nPts == NUMPTSTOBUFFER) {
                    (*pgc->ops->FillSpans) (dst, pgc,
                                            nPts, FirstPoint, FirstWidth, 1);
                    ptsOut = FirstPoint;
                    width = FirstWidth;
                    nPts = 0;
                }
                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
            }
            miInsertionSort(&AET);
        }
    }
    else {                      /* default to WindingNumber */

        /*
         *  for each scanline
         */
        for (y = ET.ymin; y < ET.ymax; y++) {
            /*
             *  Add a new edge to the active edge table when we
             *  get to the next edge.
             */
            if (pSLL && y == pSLL->scanline) {
                miloadAET(&AET, pSLL->edgelist);
                micomputeWAET(&AET);
                pSLL = pSLL->next;
            }
            pPrevAET = &AET;
            pAET = AET.next;
            pWETE = pAET;

            /*
             *  for each active edge
             */
            while (pAET) {
                /*
                 *  if the next edge in the active edge table is
                 *  also the next edge in the winding active edge
                 *  table.
                 */
                if (pWETE == pAET) {
                    ptsOut->x = pAET->bres.minor;
                    ptsOut++->y = y;
                    *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor;
                    nPts++;

                    /*
                     *  send out the buffer
                     */
                    if (nPts == NUMPTSTOBUFFER) {
                        (*pgc->ops->FillSpans) (dst, pgc, nPts, FirstPoint,
                                                FirstWidth, 1);
                        ptsOut = FirstPoint;
                        width = FirstWidth;
                        nPts = 0;
                    }

                    pWETE = pWETE->nextWETE;
                    while (pWETE != pAET)
                        EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
                    pWETE = pWETE->nextWETE;
                }
                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
            }

            /*
             *  reevaluate the Winding active edge table if we
             *  just had to resort it or if we just exited an edge.
             */
            if (miInsertionSort(&AET) || fixWAET) {
                micomputeWAET(&AET);
                fixWAET = 0;
            }
        }
    }

    /*
     *     Get any spans that we missed by buffering
     */
    (*pgc->ops->FillSpans) (dst, pgc, nPts, FirstPoint, FirstWidth, 1);
    free(pETEs);
    miFreeStorage(SLLBlock.next);
    return TRUE;
}
예제 #4
0
/* ARGS: count = number of points, ptsIn = the points */
void
miFillGeneralPoly (miPaintedSet *paintedSet, const miGC *pGC, int count, const miPoint *ptsIn)
{
  EdgeTableEntry *pAET;		/* the Active Edge Table   */
  int y;			/* the current scanline    */
  int nPts = 0;			/* number of pts in buffer */
  EdgeTableEntry *pWETE;	/* Winding Edge Table      */
  ScanLineList *pSLL;		/* Current ScanLineList    */
  miPoint *ptsOut;		/* ptr to output buffers   */
  unsigned int *width;
  miPoint FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
  unsigned int FirstWidth[NUMPTSTOBUFFER];
  EdgeTableEntry *pPrevAET;	/* previous AET entry      */
  EdgeTable ET;			/* Edge Table header node  */
  EdgeTableEntry AET;		/* Active ET header node   */
  EdgeTableEntry *pETEs;	/* Edge Table Entries buff */
  ScanLineListBlock SLLBlock;	/* header for ScanLineList */
  bool fixWAET = false;

  if (count <= 2)
    return;

  pETEs = (EdgeTableEntry *) mi_xmalloc(sizeof(EdgeTableEntry) * count);
  ptsOut = FirstPoint;
  width = FirstWidth;
  miCreateETandAET (count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
  pSLL = ET.scanlines.next;

  if (pGC->fillRule == (int)MI_EVEN_ODD_RULE) 
    {
      /*
       *  for each scanline
       */
      for (y = ET.ymin; y < ET.ymax; y++) 
        {
	  /*
	   *  Add a new edge to the active edge table when we
	   *  get to the next edge.
	   */
	  if (pSLL && y == pSLL->scanline) 
            {
	      miloadAET(&AET, pSLL->edgelist);
	      pSLL = pSLL->next;
            }
	  pPrevAET = &AET;
	  pAET = AET.next;

	  /*
	   *  for each active edge
	   */
	  while (pAET) 
            {
	      ptsOut->x = pAET->bres.minor_axis;
	      ptsOut++->y = y;
	      *width++ = (unsigned int)(pAET->next->bres.minor_axis - pAET->bres.minor_axis);
	      nPts++;

	      /*
	       *  send out the buffer when its full
	       */
	      if (nPts == NUMPTSTOBUFFER) 
		{
		  MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[1], nPts, FirstPoint, FirstWidth)
		  ptsOut = FirstPoint;
		  width = FirstWidth;
		  nPts = 0;
                }
	      EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
            }
	  miInsertionSort(&AET);
        }
    }
  else				/* default to WindingNumber */
    {
      /*
       *  for each scanline
       */
      for (y = ET.ymin; y < ET.ymax; y++) 
        {
	  /*
	   *  Add a new edge to the active edge table when we
	   *  get to the next edge.
	   */
	  if (pSLL && y == pSLL->scanline) 
            {
	      miloadAET(&AET, pSLL->edgelist);
	      micomputeWAET(&AET);
	      pSLL = pSLL->next;
            }
	  pPrevAET = &AET;
	  pAET = AET.next;
	  pWETE = pAET;

	  /*
	   *  for each active edge
	   */
	  while (pAET) 
            {
	      /*
	       *  if the next edge in the active edge table is
	       *  also the next edge in the winding active edge
	       *  table.
	       */
	      if (pWETE == pAET) 
                {
		  ptsOut->x = pAET->bres.minor_axis;
		  ptsOut++->y = y;
		  *width++ = (unsigned int)(pAET->nextWETE->bres.minor_axis - pAET->bres.minor_axis);
		  nPts++;

		  /*
		   *  send out the buffer
		   */
		  if (nPts == NUMPTSTOBUFFER) 
                    {
		      MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[1], nPts, FirstPoint, FirstWidth)
		      ptsOut = FirstPoint;
		      width  = FirstWidth;
		      nPts = 0;
                    }

		  pWETE = pWETE->nextWETE;
		  while (pWETE != pAET)
		    EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
		  pWETE = pWETE->nextWETE;
                }
	      EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
            }

	  /*
	   *  reevaluate the Winding active edge table if we
	   *  just had to resort it or if we just exited an edge.
	   */
	  if (miInsertionSort(&AET) || fixWAET) 
            {
	      micomputeWAET(&AET);
	      fixWAET = false;
            }
        }
    }

  /*
   *     Get any spans that we missed by buffering
   */
  MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[1], nPts, FirstPoint, FirstWidth)
  free (pETEs);
  miFreeStorage(SLLBlock.next);
}