⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winrgn.c

📁 MinGUI 可视化程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
         * this may be pointless -- see above).
         */
        temp = region->tail;
        while (temp->prev->rc.top == temp->rc.top) {
            temp = temp->prev;
        }
        newStart = temp;
    }

    if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
        pCurRect = curStart;
        /*
         * The bands may only be coalesced if the bottom of the previous
         * matches the top scanline of the current.
         */
        if (pPrevRect->rc.bottom == pCurRect->rc.top) {
            /*
             * Make sure the bands have rects in the same places. This
             * assumes that rects have been added in such a way that they
             * cover the most area possible. I.e. two rects in a band must
             * have some horizontal space between them.
             */
            do {
                if ((pPrevRect->rc.left != pCurRect->rc.left) ||
                    (pPrevRect->rc.right != pCurRect->rc.right))
                {
                    /*
                     * The bands don't line up so they can't be coalesced.
                     */
                    return newStart;
                }
                pPrevRect = pPrevRect->next;
                pCurRect = pCurRect->next;
            } while (--prevNumRects);

            /*
             * If only one band was added to the region, we have to backup
             * newStart to the start of the previous band.
             */
            if (pCurRect == NULL) {
                newStart = prevStart;
            }

            /*
             * The bands may be merged, so set the bottom of each rect
             * in the previous band to that of the corresponding rect in
             * the current band.
             */
            /*
             * free the clipping rects merged.
             */
            pCurRect = curStart;
            pPrevRect = prevStart;
            do {
                pPrevRect->rc.bottom = pCurRect->rc.bottom;
                pPrevRect = pPrevRect->next;

                if (pCurRect->next)
                    pCurRect->next->prev = pCurRect->prev;
                else
                    region->tail = pCurRect->prev;
                if (pCurRect->prev)
                    pCurRect->prev->next = pCurRect->next;
                else
                    region->head = pCurRect->next;

                temp = pCurRect->next;
                FreeClipRect (region->heap, pCurRect);
                pCurRect = temp;
            } while (--curNumRects);
         }
    }
    return (newStart);
}

/***********************************************************************
 *           REGION_RegionOp
 *
 *      Apply an operation to two regions. Called by Union,
 *      Xor, Subtract, Intersect...
 *
 * Results:
 *      None.
 *
 * Side Effects:
 *      The new region is overwritten.
 *
 * Notes:
 *      The idea behind this function is to view the two regions as sets.
 *      Together they cover a rectangle of area that this function divides
 *      into horizontal bands where points are covered only by one region
 *      or by both. For the first case, the nonOverlapFunc is called with
 *      each the band and the band's upper and lower rcBound. For the
 *      second, the overlapFunc is called to process the entire band. It
 *      is responsible for clipping the rectangles in the band, though
 *      this function provides the boundaries.
 *      At the end of each band, the new region is coalesced, if possible,
 *      to reduce the number of rectangles in the region.
 *
 */
static void
REGION_RegionOp(
            TREGION *newReg, /* Place to store result */
            const TREGION *reg1,   /* First region in operation */
            const TREGION *reg2,   /* 2nd region in operation */
            voidProcp1 overlapFunc,     /* Function to call for over-lapping bands */
            voidProcp2 nonOverlap1Func, /* Function to call for non-overlapping bands in region 1 */
            voidProcp2 nonOverlap2Func  /* Function to call for non-overlapping bands in region 2 */
) { TREGION my_dst;
    TREGION* pdst;
    const TClipRect  *r1;                 /* Pointer into first region */
    const TClipRect  *r2;                 /* Pointer into 2d region */
    const TClipRect  *r1BandEnd;          /* End of current band in r1 */
    const TClipRect  *r2BandEnd;          /* End of current band in r2 */
    int ybot;                           /* Bottom of intersection */
    int ytop;                           /* Top of intersection */
    TClipRect * prevBand;                 /* start of previous band in newReg */
    TClipRect * curBand;                  /* start of current band in newReg */
    int top;                            /* Top of non-overlapping band */
    int bot;                            /* Bottom of non-overlapping band */
    
    /*
     * Initialization:
     *  set r1, r2, r1End and r2End appropriately, preserve the important
     * parts of the destination region until the end in case it's one of
     * the two source regions, then mark the "new" region empty, allocating
     * another array of rectangles for it to use.
     */
    r1 = reg1->head;
    r2 = reg2->head;


    if (newReg == reg1 || newReg == reg2) {
        InitRegion (&my_dst, newReg->heap);
        pdst = &my_dst;
    }
    else
	{   if(newReg->head) ClearRegion (newReg);
        pdst = newReg;
    }
     /*
     * Initialize ybot and ytop.
     * In the upcoming loop, ybot and ytop serve different functions depending
     * on whether the band being handled is an overlapping or non-overlapping
     * band.
     *  In the case of a non-overlapping band (only one of the regions
     * has points in the band), ybot is the bottom of the most recent
     * intersection and thus clips the top of the rectangles in that band.
     * ytop is the top of the next intersection between the two regions and
     * serves to clip the bottom of the rectangles in the current band.
     *  For an overlapping band (where the two regions intersect), ytop clips
     * the top of the rectangles of both regions and ybot clips the bottoms.
     */
    if (reg1->rcBound.top < reg2->rcBound.top)
        ybot = reg1->rcBound.top;
    else
        ybot = reg2->rcBound.top;
    
    /*
     * prevBand serves to mark the start of the previous band so rectangles
     * can be coalesced into larger rectangles. qv. miCoalesce, above.
     * In the beginning, there is no previous band, so prevBand == curBand
     * (curBand is set later on, of course, but the first band will always
     * start at index 0). prevBand and curBand must be indices because of
     * the possible expansion, and resultant moving, of the new region's
     * array of rectangles.
     */
    prevBand = pdst->head;
    
    do {
        curBand = pdst->tail;

        /*
         * This algorithm proceeds one source-band (as opposed to a
         * destination band, which is determined by where the two regions
         * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
         * rectangle after the last one in the current band for their
         * respective regions.
         */
        r1BandEnd = r1;
        while (r1BandEnd && (r1BandEnd->rc.top == r1->rc.top))
            r1BandEnd = r1BandEnd->next;
        
        r2BandEnd = r2;
        while (r2BandEnd && (r2BandEnd->rc.top == r2->rc.top))
            r2BandEnd = r2BandEnd->next;
        
        /*
         * First handle the band that doesn't intersect, if any.
         *
         * Note that attention is restricted to one band in the
         * non-intersecting region at once, so if a region has n
         * bands between the current position and the next place it overlaps
         * the other, this entire loop will be passed through n times.
         */
        if (r1->rc.top < r2->rc.top) {
            top = max (r1->rc.top, ybot);
            bot = min (r1->rc.bottom, r2->rc.top);

            if ((top != bot) && (nonOverlap1Func != NULL))
                (* nonOverlap1Func) (pdst, r1, r1BandEnd, top, bot);

            ytop = r2->rc.top;
        }
        else if (r2->rc.top < r1->rc.top) {
            top = max (r2->rc.top, ybot);
            bot = min (r2->rc.bottom, r1->rc.top);

            if ((top != bot) && (nonOverlap2Func != NULL))
                (* nonOverlap2Func) (pdst, r2, r2BandEnd, top, bot);

            ytop = r1->rc.top;
        }
        else {
            ytop = r1->rc.top;
        }

        /*
         * If any rectangles got added to the region, try and coalesce them
         * with rectangles from the previous band. Note we could just do
         * this test in miCoalesce, but some machines incur a not
         * inconsiderable cost for function calls, so...
         */
        if (pdst->tail != curBand) {
            prevBand = REGION_Coalesce (pdst, prevBand, curBand);
        }

        /*
         * Now see if we've hit an intersecting band. The two bands only
         * intersect if ybot > ytop
         */
        ybot = min (r1->rc.bottom, r2->rc.bottom);
        curBand = pdst->tail;
        if (ybot > ytop)
            (* overlapFunc) (pdst, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
        
        if (pdst->tail != curBand)
            prevBand = REGION_Coalesce (pdst, prevBand, curBand);

        /*
         * If we've finished with a band (bottom == ybot) we skip forward
         * in the region to the next band.
         */
        if (r1->rc.bottom == ybot)
            r1 = r1BandEnd;
        if (r2->rc.bottom == ybot)
            r2 = r2BandEnd;
    } while (r1 && r2);

    /*
     * Deal with whichever region still has rectangles left.
     */
    curBand = pdst->tail;
    if (r1) {
        if (nonOverlap1Func != NULL) {
            do {
                r1BandEnd = r1;
                while ((r1BandEnd) && (r1BandEnd->rc.top == r1->rc.top)) {
                    r1BandEnd = r1BandEnd->next;
                }
                (* nonOverlap1Func) (pdst, r1, r1BandEnd,
                                     max (r1->rc.top, ybot), r1->rc.bottom);
                r1 = r1BandEnd;
            } while (r1);
        }
    }
    else if ((r2) && (nonOverlap2Func != NULL))
    {
        do {
            r2BandEnd = r2;
            while ((r2BandEnd) && (r2BandEnd->rc.top == r2->rc.top)) {
                 r2BandEnd = r2BandEnd->next;
            }
            (* nonOverlap2Func) (pdst, r2, r2BandEnd,
                                max (r2->rc.top, ybot), r2->rc.bottom);
            r2 = r2BandEnd;
        } while (r2);
    }

    if (pdst->tail != curBand)
        (void) REGION_Coalesce (pdst, prevBand, curBand);

     if (pdst != newReg)
	 { ClearRegion (newReg);
       *newReg = my_dst;
     }
}

/***********************************************************************
 *          Region Intersection
 ***********************************************************************/


/***********************************************************************
 *             REGION_IntersectO
 *
 * Handle an overlapping band for REGION_Intersect.
 *
 * Results:
 *      None.
 *
 * Side Effects:
 *      Rectangles may be added to the region.
 *
 */
static void REGION_IntersectO (TREGION *region, const TClipRect  *r1, const TClipRect  *r1End,
                        const TClipRect  *r2, const TClipRect  *r2End, int top, int bottom)

{
    int       left, right;
    TClipRect   *newcliprect;

    while ((r1 != r1End) && (r2 != r2End))
    {
        left  = max (r1->rc.left, r2->rc.left);
        right = min (r1->rc.right, r2->rc.right);

        /*
         * If there's any overlap between the two rectangles, add that
         * overlap to the new region.
         * There's no need to check for subsumption because the only way
         * such a need could arise is if some region has two rectangles
         * right next to each other. Since that should never happen...
         */
        if (left < right) {
            NEWCLIPRECT (region, newcliprect);

            newcliprect->rc.left = left;
            newcliprect->rc.top = top;
            newcliprect->rc.right = right;
            newcliprect->rc.bottom = bottom;
        }

        /*
         * Need to advance the pointers. Shift the one that extends
         * to the right the least, since the other still has a chance to
         * overlap with that region's next rectangle, if you see what I mean.
         */
        if (r1->rc.right < r2->rc.right) {
            r1 = r1->next;
        }
        else if (r2->rc.right < r1->rc.right) {
            r2 = r2->next;
        }
        else {
            r1 = r1->next;
            r2 = r2->next;
        }
    }
}

/***********************************************************************
 *             Region Union
 ***********************************************************************/

/***********************************************************************
 *             REGION_UnionNonO
 *
 *      Handle a non-overlapping band for the union operation. Just
 *      Adds the rectangles into the region. Doesn't have to check for
 *      subsumption or anything.
 *
 * Results:
 *      None.
 *
 * Side Effects:
 *      region->numRects is incremented and the final rectangles overwritten
 *      with the rectangles we're passed.
 *
 */
static void REGION_UnionNonO (TREGION *region, const TClipRect  *r, const TClipRect  *rEnd, int top, int bottom)
{
    TClipRect  *newcliprect;

    while (r != rEnd) {
        NEWCLIPRECT (region, newcliprect);
        newcliprect->rc.left = r->rc.left;
        newcliprect->rc.top = top;
        newcliprect->rc.right = r->rc.right;
        newcliprect->rc.bottom = bottom;

        r = r->next;
    }
}

/***********************************************************************
 *             REGION_UnionO
 *
 *      Handle an overlapping band for the union operation. Picks the
 *      left-most rectangle each time and merges it into the region.
 *
 * Results:
 *      None.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -