Blame gegl/buffer/gegl-region-generic.c

Packit Service 2781ba
/* $TOG: Region.c /main/31 1998/02/06 17:50:22 kaleb $ */
Packit Service 2781ba
/************************************************************************
Packit Service 2781ba
Packit Service 2781ba
   Copyright 1987, 1988, 1998  The Open Group
Packit Service 2781ba
Packit Service 2781ba
   All Rights Reserved.
Packit Service 2781ba
Packit Service 2781ba
   The above copyright notice and this permission notice shall be included in
Packit Service 2781ba
   all copies or substantial portions of the Software.
Packit Service 2781ba
Packit Service 2781ba
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service 2781ba
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service 2781ba
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit Service 2781ba
   OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit Service 2781ba
   AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service 2781ba
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit Service 2781ba
Packit Service 2781ba
   Except as contained in this notice, the name of The Open Group shall not be
Packit Service 2781ba
   used in advertising or otherwise to promote the sale, use or other dealings
Packit Service 2781ba
   in this Software without prior written authorization from The Open Group.
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
   Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
Packit Service 2781ba
Packit Service 2781ba
                        All Rights Reserved
Packit Service 2781ba
Packit Service 2781ba
   Permission to use, copy, modify, and distribute this software and its
Packit Service 2781ba
   documentation for any purpose and without fee is hereby granted,
Packit Service 2781ba
   provided that the above copyright notice appear in all copies and that
Packit Service 2781ba
   both that copyright notice and this permission notice appear in
Packit Service 2781ba
   supporting documentation, and that the name of Digital not be
Packit Service 2781ba
   used in advertising or publicity pertaining to distribution of the
Packit Service 2781ba
   software without specific, written prior permission.
Packit Service 2781ba
Packit Service 2781ba
   DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
Packit Service 2781ba
   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
Packit Service 2781ba
   DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
Packit Service 2781ba
   ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
Packit Service 2781ba
   WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
Packit Service 2781ba
   ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit Service 2781ba
   SOFTWARE.
Packit Service 2781ba
Packit Service 2781ba
************************************************************************/
Packit Service 2781ba
/* $XFree86: xc/lib/X11/Region.c,v 1.5 1999/05/09 10:50:01 dawes Exp $ */
Packit Service 2781ba
/*
Packit Service 2781ba
 * The functions in this file implement the Region abstraction, similar to one
Packit Service 2781ba
 * used in the X11 sample server. A Region is simply an area, as the name
Packit Service 2781ba
 * implies, and is implemented as a "y-x-banded" array of rectangles. To
Packit Service 2781ba
 * explain: Each Region is made up of a certain number of rectangles sorted
Packit Service 2781ba
 * by y coordinate first, and then by x coordinate.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Furthermore, the rectangles are banded such that every rectangle with a
Packit Service 2781ba
 * given upper-left y coordinate (y1) will have the same lower-right y
Packit Service 2781ba
 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
Packit Service 2781ba
 * will span the entire vertical distance of the band. This means that some
Packit Service 2781ba
 * areas that could be merged into a taller rectangle will be represented as
Packit Service 2781ba
 * several shorter rectangles to account for shorter rectangles to its left
Packit Service 2781ba
 * or right but within its "vertical scope".
Packit Service 2781ba
 *
Packit Service 2781ba
 * An added constraint on the rectangles is that they must cover as much
Packit Service 2781ba
 * horizontal area as possible. E.g. no two rectangles in a band are allowed
Packit Service 2781ba
 * to touch.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Whenever possible, bands will be merged together to cover a greater vertical
Packit Service 2781ba
 * distance (and thus reduce the number of rectangles). Two bands can be merged
Packit Service 2781ba
 * only if the bottom of one touches the top of the other and they have
Packit Service 2781ba
 * rectangles in the same places (of the same width, of course). This maintains
Packit Service 2781ba
 * the y-x-banding that's so nice to have...
Packit Service 2781ba
 */
Packit Service 2781ba
Packit Service 2781ba
#include <config.h>
Packit Service 2781ba
#include <stdlib.h>
Packit Service 2781ba
#include <string.h>
Packit Service 2781ba
Packit Service 2781ba
#include <glib.h>
Packit Service 2781ba
#include <glib-object.h>
Packit Service 2781ba
Packit Service 2781ba
#include "gegl.h"
Packit Service 2781ba
#include "gegl-region.h"
Packit Service 2781ba
#include "gegl-region-generic.h"
Packit Service 2781ba
Packit Service 2781ba
typedef void (* overlapFunc)    (GeglRegion    *pReg,
Packit Service 2781ba
                                 GeglRegionBox *r1,
Packit Service 2781ba
                                 GeglRegionBox *r1End,
Packit Service 2781ba
                                 GeglRegionBox *r2,
Packit Service 2781ba
                                 GeglRegionBox *r2End,
Packit Service 2781ba
                                 gint           y1,
Packit Service 2781ba
                                 gint           y2);
Packit Service 2781ba
typedef void (* nonOverlapFunc) (GeglRegion    *pReg,
Packit Service 2781ba
                                 GeglRegionBox *r,
Packit Service 2781ba
                                 GeglRegionBox *rEnd,
Packit Service 2781ba
                                 gint           y1,
Packit Service 2781ba
                                 gint           y2);
Packit Service 2781ba
Packit Service 2781ba
static void miRegionCopy (GeglRegion       *dstrgn,
Packit Service 2781ba
                          const GeglRegion *rgn);
Packit Service 2781ba
static void miRegionOp   (GeglRegion       *newReg,
Packit Service 2781ba
                          GeglRegion       *reg1,
Packit Service 2781ba
                          const GeglRegion *reg2,
Packit Service 2781ba
                          overlapFunc       overlapFn,
Packit Service 2781ba
                          nonOverlapFunc    nonOverlap1Fn,
Packit Service 2781ba
                          nonOverlapFunc    nonOverlap2Fn);
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_new:
Packit Service 2781ba
 *
Packit Service 2781ba
 * Creates a new empty #GeglRegion.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Returns: a new empty #GeglRegion
Packit Service 2781ba
 */
Packit Service 2781ba
GeglRegion *
Packit Service 2781ba
gegl_region_new (void)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegion *temp;
Packit Service 2781ba
Packit Service 2781ba
  temp = g_slice_new (GeglRegion);
Packit Service 2781ba
Packit Service 2781ba
  temp->numRects   = 0;
Packit Service 2781ba
  temp->rects      = &temp->extents;
Packit Service 2781ba
  temp->extents.x1 = 0;
Packit Service 2781ba
  temp->extents.y1 = 0;
Packit Service 2781ba
  temp->extents.x2 = 0;
Packit Service 2781ba
  temp->extents.y2 = 0;
Packit Service 2781ba
  temp->size       = 1;
Packit Service 2781ba
Packit Service 2781ba
  return temp;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_rectangle:
Packit Service 2781ba
 * @rectangle: a #GeglRectangle
Packit Service 2781ba
 *
Packit Service 2781ba
 * Creates a new region containing the area @rectangle.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Return value: a new region
Packit Service 2781ba
 **/
Packit Service 2781ba
GeglRegion *
Packit Service 2781ba
gegl_region_rectangle (const GeglRectangle *rectangle)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegion *temp;
Packit Service 2781ba
Packit Service 2781ba
  g_return_val_if_fail (rectangle != NULL, NULL);
Packit Service 2781ba
Packit Service 2781ba
  if (rectangle->width <= 0 || rectangle->height <= 0)
Packit Service 2781ba
    return gegl_region_new ();
Packit Service 2781ba
Packit Service 2781ba
  temp = g_slice_new (GeglRegion);
Packit Service 2781ba
Packit Service 2781ba
  temp->numRects   = 1;
Packit Service 2781ba
  temp->rects      = &temp->extents;
Packit Service 2781ba
  temp->extents.x1 = rectangle->x;
Packit Service 2781ba
  temp->extents.y1 = rectangle->y;
Packit Service 2781ba
  temp->extents.x2 = rectangle->x + rectangle->width;
Packit Service 2781ba
  temp->extents.y2 = rectangle->y + rectangle->height;
Packit Service 2781ba
  temp->size       = 1;
Packit Service 2781ba
Packit Service 2781ba
  return temp;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_copy:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Copies @region, creating an identical new region.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Return value: a new region identical to @region
Packit Service 2781ba
 **/
Packit Service 2781ba
GeglRegion *
Packit Service 2781ba
gegl_region_copy (const GeglRegion *region)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegion *temp;
Packit Service 2781ba
Packit Service 2781ba
  g_return_val_if_fail (region != NULL, NULL);
Packit Service 2781ba
Packit Service 2781ba
  temp = gegl_region_new ();
Packit Service 2781ba
Packit Service 2781ba
  miRegionCopy (temp, region);
Packit Service 2781ba
Packit Service 2781ba
  return temp;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_get_clipbox:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 * @rectangle: return location for the clipbox
Packit Service 2781ba
 *
Packit Service 2781ba
 * Obtains the smallest rectangle which includes the entire #GeglRegion.
Packit Service 2781ba
 *
Packit Service 2781ba
 */
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_get_clipbox (GeglRegion    *region,
Packit Service 2781ba
                         GeglRectangle *rectangle)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_if_fail (region != NULL);
Packit Service 2781ba
  g_return_if_fail (rectangle != NULL);
Packit Service 2781ba
Packit Service 2781ba
  rectangle->x      = region->extents.x1;
Packit Service 2781ba
  rectangle->y      = region->extents.y1;
Packit Service 2781ba
  rectangle->width  = region->extents.x2 - region->extents.x1;
Packit Service 2781ba
  rectangle->height = region->extents.y2 - region->extents.y1;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_get_rectangles:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 * @rectangles: return location for an array of rectangles
Packit Service 2781ba
 * @n_rectangles: length of returned array
Packit Service 2781ba
 *
Packit Service 2781ba
 * Obtains the area covered by the region as a list of rectangles.
Packit Service 2781ba
 * The array returned in @rectangles must be freed with g_free().
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_get_rectangles (GeglRegion     *region,
Packit Service 2781ba
                            GeglRectangle **rectangles,
Packit Service 2781ba
                            gint           *n_rectangles)
Packit Service 2781ba
{
Packit Service 2781ba
  gint i;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (region != NULL);
Packit Service 2781ba
  g_return_if_fail (rectangles != NULL);
Packit Service 2781ba
  g_return_if_fail (n_rectangles != NULL);
Packit Service 2781ba
Packit Service 2781ba
  *n_rectangles = region->numRects;
Packit Service 2781ba
  *rectangles   = g_new (GeglRectangle, region->numRects);
Packit Service 2781ba
Packit Service 2781ba
  for (i = 0; i < region->numRects; i++)
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglRegionBox rect;
Packit Service 2781ba
      rect                    = region->rects[i];
Packit Service 2781ba
      (*rectangles)[i].x      = rect.x1;
Packit Service 2781ba
      (*rectangles)[i].y      = rect.y1;
Packit Service 2781ba
      (*rectangles)[i].width  = rect.x2 - rect.x1;
Packit Service 2781ba
      (*rectangles)[i].height = rect.y2 - rect.y1;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_union_with_rect:
Packit Service 2781ba
 * @region: a #GeglRegion.
Packit Service 2781ba
 * @rect: a #GeglRectangle.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Sets the area of @region to the union of the areas of @region and
Packit Service 2781ba
 * @rect. The resulting area is the set of pixels contained in
Packit Service 2781ba
 * either @region or @rect.
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_union_with_rect (GeglRegion          *region,
Packit Service 2781ba
                             const GeglRectangle *rect)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegion tmp_region;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (region != NULL);
Packit Service 2781ba
  g_return_if_fail (rect != NULL);
Packit Service 2781ba
Packit Service 2781ba
  if (rect->width <= 0 || rect->height <= 0)
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  tmp_region.rects      = &tmp_region.extents;
Packit Service 2781ba
  tmp_region.numRects   = 1;
Packit Service 2781ba
  tmp_region.extents.x1 = rect->x;
Packit Service 2781ba
  tmp_region.extents.y1 = rect->y;
Packit Service 2781ba
  tmp_region.extents.x2 = rect->x + rect->width;
Packit Service 2781ba
  tmp_region.extents.y2 = rect->y + rect->height;
Packit Service 2781ba
  tmp_region.size       = 1;
Packit Service 2781ba
Packit Service 2781ba
  gegl_region_union (region, &tmp_region);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miSetExtents --
Packit Service 2781ba
 *	Reset the extents of a region to what they should be. Called by
Packit Service 2781ba
 *	miSubtract and miIntersect b/c they can't figure it out along the
Packit Service 2781ba
 *	way or do so easily, as miUnion can.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	None.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	The region's 'extents' structure is overwritten.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
static void
Packit Service 2781ba
miSetExtents (GeglRegion *pReg)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *pBox, *pBoxEnd, *pExtents;
Packit Service 2781ba
Packit Service 2781ba
  if (pReg->numRects == 0)
Packit Service 2781ba
    {
Packit Service 2781ba
      pReg->extents.x1 = 0;
Packit Service 2781ba
      pReg->extents.y1 = 0;
Packit Service 2781ba
      pReg->extents.x2 = 0;
Packit Service 2781ba
      pReg->extents.y2 = 0;
Packit Service 2781ba
      return;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  pExtents = &pReg->extents;
Packit Service 2781ba
  pBox     = pReg->rects;
Packit Service 2781ba
  pBoxEnd  = &pBox[pReg->numRects - 1];
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Since pBox is the first rectangle in the region, it must have the
Packit Service 2781ba
   * smallest y1 and since pBoxEnd is the last rectangle in the region,
Packit Service 2781ba
   * it must have the largest y2, because of banding. Initialize x1 and
Packit Service 2781ba
   * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
Packit Service 2781ba
   * to...
Packit Service 2781ba
   */
Packit Service 2781ba
  pExtents->x1 = pBox->x1;
Packit Service 2781ba
  pExtents->y1 = pBox->y1;
Packit Service 2781ba
  pExtents->x2 = pBoxEnd->x2;
Packit Service 2781ba
  pExtents->y2 = pBoxEnd->y2;
Packit Service 2781ba
Packit Service 2781ba
  g_assert (pExtents->y1 < pExtents->y2);
Packit Service 2781ba
  while (pBox <= pBoxEnd)
Packit Service 2781ba
    {
Packit Service 2781ba
      if (pBox->x1 < pExtents->x1)
Packit Service 2781ba
        {
Packit Service 2781ba
          pExtents->x1 = pBox->x1;
Packit Service 2781ba
        }
Packit Service 2781ba
      if (pBox->x2 > pExtents->x2)
Packit Service 2781ba
        {
Packit Service 2781ba
          pExtents->x2 = pBox->x2;
Packit Service 2781ba
        }
Packit Service 2781ba
      pBox++;
Packit Service 2781ba
    }
Packit Service 2781ba
  g_assert (pExtents->x1 < pExtents->x2);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_destroy:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Destroys a #GeglRegion.
Packit Service 2781ba
 */
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_destroy (GeglRegion *region)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_if_fail (region != NULL);
Packit Service 2781ba
Packit Service 2781ba
  if (region->rects != &region->extents)
Packit Service 2781ba
    g_free (region->rects);
Packit Service 2781ba
  g_slice_free (GeglRegion, region);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_offset:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 * @dx: the distance to move the region horizontally
Packit Service 2781ba
 * @dy: the distance to move the region vertically
Packit Service 2781ba
 *
Packit Service 2781ba
 * Moves a region the specified distance.
Packit Service 2781ba
 */
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_offset (GeglRegion *region,
Packit Service 2781ba
                    gint        x,
Packit Service 2781ba
                    gint        y)
Packit Service 2781ba
{
Packit Service 2781ba
  int            nbox;
Packit Service 2781ba
  GeglRegionBox *pbox;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (region != NULL);
Packit Service 2781ba
Packit Service 2781ba
  pbox = region->rects;
Packit Service 2781ba
  nbox = region->numRects;
Packit Service 2781ba
Packit Service 2781ba
  while (nbox--)
Packit Service 2781ba
    {
Packit Service 2781ba
      pbox->x1 += x;
Packit Service 2781ba
      pbox->x2 += x;
Packit Service 2781ba
      pbox->y1 += y;
Packit Service 2781ba
      pbox->y2 += y;
Packit Service 2781ba
      pbox++;
Packit Service 2781ba
    }
Packit Service 2781ba
  if (region->rects != &region->extents)
Packit Service 2781ba
    {
Packit Service 2781ba
      region->extents.x1 += x;
Packit Service 2781ba
      region->extents.x2 += x;
Packit Service 2781ba
      region->extents.y1 += y;
Packit Service 2781ba
      region->extents.y2 += y;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/*
Packit Service 2781ba
   Utility procedure Compress:
Packit Service 2781ba
   Replace r by the region r', where
Packit Service 2781ba
     p in r' iff (Quantifer m <= dx) (p + m in r), and
Packit Service 2781ba
     Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and
Packit Service 2781ba
     (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE.
Packit Service 2781ba
Packit Service 2781ba
   Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region
Packit Service 2781ba
   of all points p such that p and the next dx points on the same
Packit Service 2781ba
   horizontal scan line are all in r.  We do this using by noting
Packit Service 2781ba
   that p is the head of a run of length 2^i + k iff p is the head
Packit Service 2781ba
   of a run of length 2^i and p+2^i is the head of a run of length
Packit Service 2781ba
   k. Thus, the loop invariant: s contains the region corresponding
Packit Service 2781ba
   to the runs of length shift.  r contains the region corresponding
Packit Service 2781ba
   to the runs of length 1 + dxo & (shift-1), where dxo is the original
Packit Service 2781ba
   value of dx.  dx = dxo & ~(shift-1).  As parameters, s and t are
Packit Service 2781ba
   scratch regions, so that we don't have to allocate them on every
Packit Service 2781ba
   call.
Packit Service 2781ba
 */
Packit Service 2781ba
Packit Service 2781ba
#define ZOpRegion(a, b)       if (grow) gegl_region_union (a, b);\
Packit Service 2781ba
  else gegl_region_intersect (a, b)
Packit Service 2781ba
#define ZShiftRegion(a, b)    if (xdir) gegl_region_offset (a, b, 0);\
Packit Service 2781ba
  else gegl_region_offset (a, 0, b)
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
Compress (GeglRegion *r,
Packit Service 2781ba
          GeglRegion *s,
Packit Service 2781ba
          GeglRegion *t,
Packit Service 2781ba
          guint       dx,
Packit Service 2781ba
          int         xdir,
Packit Service 2781ba
          int         grow)
Packit Service 2781ba
{
Packit Service 2781ba
  guint shift = 1;
Packit Service 2781ba
Packit Service 2781ba
  miRegionCopy (s, r);
Packit Service 2781ba
  while (dx)
Packit Service 2781ba
    {
Packit Service 2781ba
      if (dx & shift)
Packit Service 2781ba
        {
Packit Service 2781ba
          ZShiftRegion (r, -(int) shift);
Packit Service 2781ba
          ZOpRegion (r, s);
Packit Service 2781ba
          dx -= shift;
Packit Service 2781ba
          if (!dx) break;
Packit Service 2781ba
        }
Packit Service 2781ba
      miRegionCopy (t, s);
Packit Service 2781ba
      ZShiftRegion (s, -(int) shift);
Packit Service 2781ba
      ZOpRegion (s, t);
Packit Service 2781ba
      shift <<= 1;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
#undef ZOpRegion
Packit Service 2781ba
#undef ZShiftRegion
Packit Service 2781ba
#undef ZCopyRegion
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_shrink:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 * @dx: the number of pixels to shrink the region horizontally
Packit Service 2781ba
 * @dy: the number of pixels to shrink the region vertically
Packit Service 2781ba
 *
Packit Service 2781ba
 * Resizes a region by the specified amount.
Packit Service 2781ba
 * Positive values shrink the region. Negative values expand it.
Packit Service 2781ba
 */
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_shrink (GeglRegion *region,
Packit Service 2781ba
                    int         dx,
Packit Service 2781ba
                    int         dy)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegion *s, *t;
Packit Service 2781ba
  int         grow;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (region != NULL);
Packit Service 2781ba
Packit Service 2781ba
  if (!dx && !dy)
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  s = gegl_region_new ();
Packit Service 2781ba
  t = gegl_region_new ();
Packit Service 2781ba
Packit Service 2781ba
  grow = (dx < 0);
Packit Service 2781ba
  if (grow)
Packit Service 2781ba
    dx = -dx;
Packit Service 2781ba
  if (dx)
Packit Service 2781ba
    Compress (region, s, t, (unsigned) 2 * dx, TRUE, grow);
Packit Service 2781ba
Packit Service 2781ba
  grow = (dy < 0);
Packit Service 2781ba
  if (grow)
Packit Service 2781ba
    dy = -dy;
Packit Service 2781ba
  if (dy)
Packit Service 2781ba
    Compress (region, s, t, (unsigned) 2 * dy, FALSE, grow);
Packit Service 2781ba
Packit Service 2781ba
  gegl_region_offset (region, dx, dy);
Packit Service 2781ba
  gegl_region_destroy (s);
Packit Service 2781ba
  gegl_region_destroy (t);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/*======================================================================
Packit Service 2781ba
 *	    Region Intersection
Packit Service 2781ba
 *====================================================================*/
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miIntersectO --
Packit Service 2781ba
 *	Handle an overlapping band for miIntersect.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	None.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	Rectangles may be added to the region.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
/* static void*/
Packit Service 2781ba
static void
Packit Service 2781ba
miIntersectO (GeglRegion    *pReg,
Packit Service 2781ba
              GeglRegionBox *r1,
Packit Service 2781ba
              GeglRegionBox *r1End,
Packit Service 2781ba
              GeglRegionBox *r2,
Packit Service 2781ba
              GeglRegionBox *r2End,
Packit Service 2781ba
              gint           y1,
Packit Service 2781ba
              gint           y2)
Packit Service 2781ba
{
Packit Service 2781ba
  int            x1;
Packit Service 2781ba
  int            x2;
Packit Service 2781ba
  GeglRegionBox *pNextRect;
Packit Service 2781ba
Packit Service 2781ba
  pNextRect = &pReg->rects[pReg->numRects];
Packit Service 2781ba
Packit Service 2781ba
  while ((r1 != r1End) && (r2 != r2End))
Packit Service 2781ba
    {
Packit Service 2781ba
      x1 = MAX (r1->x1, r2->x1);
Packit Service 2781ba
      x2 = MIN (r1->x2, r2->x2);
Packit Service 2781ba
Packit Service 2781ba
      /*
Packit Service 2781ba
       * If there's any overlap between the two rectangles, add that
Packit Service 2781ba
       * overlap to the new region.
Packit Service 2781ba
       * There's no need to check for subsumption because the only way
Packit Service 2781ba
       * such a need could arise is if some region has two rectangles
Packit Service 2781ba
       * right next to each other. Since that should never happen...
Packit Service 2781ba
       */
Packit Service 2781ba
      if (x1 < x2)
Packit Service 2781ba
        {
Packit Service 2781ba
          g_assert (y1 < y2);
Packit Service 2781ba
Packit Service 2781ba
          MEMCHECK (pReg, pNextRect, pReg->rects);
Packit Service 2781ba
          pNextRect->x1   = x1;
Packit Service 2781ba
          pNextRect->y1   = y1;
Packit Service 2781ba
          pNextRect->x2   = x2;
Packit Service 2781ba
          pNextRect->y2   = y2;
Packit Service 2781ba
          pReg->numRects += 1;
Packit Service 2781ba
          pNextRect++;
Packit Service 2781ba
          g_assert (pReg->numRects <= pReg->size);
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /*
Packit Service 2781ba
       * Need to advance the pointers. Shift the one that extends
Packit Service 2781ba
       * to the right the least, since the other still has a chance to
Packit Service 2781ba
       * overlap with that region's next rectangle, if you see what I mean.
Packit Service 2781ba
       */
Packit Service 2781ba
      if (r1->x2 < r2->x2)
Packit Service 2781ba
        {
Packit Service 2781ba
          r1++;
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (r2->x2 < r1->x2)
Packit Service 2781ba
        {
Packit Service 2781ba
          r2++;
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          r1++;
Packit Service 2781ba
          r2++;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_intersect:
Packit Service 2781ba
 * @source1: a #GeglRegion
Packit Service 2781ba
 * @source2: another #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Sets the area of @source1 to the intersection of the areas of @source1
Packit Service 2781ba
 * and @source2. The resulting area is the set of pixels contained in
Packit Service 2781ba
 * both @source1 and @source2.
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_intersect (GeglRegion       *source1,
Packit Service 2781ba
                       const GeglRegion *source2)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_if_fail (source1 != NULL);
Packit Service 2781ba
  g_return_if_fail (source2 != NULL);
Packit Service 2781ba
Packit Service 2781ba
  /* check for trivial reject */
Packit Service 2781ba
  if ((!(source1->numRects)) || (!(source2->numRects)) ||
Packit Service 2781ba
      (!EXTENTCHECK (&source1->extents, &source2->extents)))
Packit Service 2781ba
    source1->numRects = 0;
Packit Service 2781ba
  else
Packit Service 2781ba
    miRegionOp (source1, source1, source2,
Packit Service 2781ba
                miIntersectO, (nonOverlapFunc) NULL, (nonOverlapFunc) NULL);
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Can't alter source1's extents before miRegionOp depends on the
Packit Service 2781ba
   * extents of the regions being unchanged. Besides, this way there's
Packit Service 2781ba
   * no checking against rectangles that will be nuked due to
Packit Service 2781ba
   * coalescing, so we have to examine fewer rectangles.
Packit Service 2781ba
   */
Packit Service 2781ba
  miSetExtents (source1);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
miRegionCopy (GeglRegion       *dstrgn,
Packit Service 2781ba
              const GeglRegion *rgn)
Packit Service 2781ba
{
Packit Service 2781ba
  if (dstrgn != rgn) /*  don't want to copy to itself */
Packit Service 2781ba
    {
Packit Service 2781ba
      if (dstrgn->size < rgn->numRects)
Packit Service 2781ba
        {
Packit Service 2781ba
          if (dstrgn->rects != &dstrgn->extents)
Packit Service 2781ba
            g_free (dstrgn->rects);
Packit Service 2781ba
Packit Service 2781ba
          dstrgn->rects = g_new (GeglRegionBox, rgn->numRects);
Packit Service 2781ba
          dstrgn->size  = rgn->numRects;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      dstrgn->numRects = rgn->numRects;
Packit Service 2781ba
      dstrgn->extents  = rgn->extents;
Packit Service 2781ba
Packit Service 2781ba
      memcpy (dstrgn->rects, rgn->rects, rgn->numRects * sizeof (GeglRegionBox));
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/*======================================================================
Packit Service 2781ba
 *	    Generic Region Operator
Packit Service 2781ba
 *====================================================================*/
Packit Service 2781ba
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miCoalesce --
Packit Service 2781ba
 *	Attempt to merge the boxes in the current band with those in the
Packit Service 2781ba
 *	previous one. Used only by miRegionOp.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	The new index for the previous band.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	If coalescing takes place:
Packit Service 2781ba
 *	    - rectangles in the previous band will have their y2 fields
Packit Service 2781ba
 *	      altered.
Packit Service 2781ba
 *	    - pReg->numRects will be decreased.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
/* static int*/
Packit Service 2781ba
static int
Packit Service 2781ba
miCoalesce (GeglRegion *pReg,         /* Region to coalesce */
Packit Service 2781ba
            gint        prevStart,   /* Index of start of previous band */
Packit Service 2781ba
            gint        curStart)    /* Index of start of current band */
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *pPrevBox;      /* Current box in previous band */
Packit Service 2781ba
  GeglRegionBox *pCurBox;       /* Current box in current band */
Packit Service 2781ba
  GeglRegionBox *pRegEnd;       /* End of region */
Packit Service 2781ba
  int            curNumRects;   /* Number of rectangles in current
Packit Service 2781ba
                                 * band */
Packit Service 2781ba
  int            prevNumRects;  /* Number of rectangles in previous
Packit Service 2781ba
                                 * band */
Packit Service 2781ba
  int            bandY1;        /* Y1 coordinate for current band */
Packit Service 2781ba
Packit Service 2781ba
  pRegEnd = &pReg->rects[pReg->numRects];
Packit Service 2781ba
Packit Service 2781ba
  pPrevBox     = &pReg->rects[prevStart];
Packit Service 2781ba
  prevNumRects = curStart - prevStart;
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Figure out how many rectangles are in the current band. Have to do
Packit Service 2781ba
   * this because multiple bands could have been added in miRegionOp
Packit Service 2781ba
   * at the end when one region has been exhausted.
Packit Service 2781ba
   */
Packit Service 2781ba
  pCurBox = &pReg->rects[curStart];
Packit Service 2781ba
  bandY1  = pCurBox->y1;
Packit Service 2781ba
  for (curNumRects = 0;
Packit Service 2781ba
       (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
Packit Service 2781ba
       curNumRects++)
Packit Service 2781ba
    {
Packit Service 2781ba
      pCurBox++;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (pCurBox != pRegEnd)
Packit Service 2781ba
    {
Packit Service 2781ba
      /*
Packit Service 2781ba
       * If more than one band was added, we have to find the start
Packit Service 2781ba
       * of the last band added so the next coalescing job can start
Packit Service 2781ba
       * at the right place... (given when multiple bands are added,
Packit Service 2781ba
       * this may be pointless -- see above).
Packit Service 2781ba
       */
Packit Service 2781ba
      pRegEnd--;
Packit Service 2781ba
      while (pRegEnd[-1].y1 == pRegEnd->y1)
Packit Service 2781ba
        {
Packit Service 2781ba
          pRegEnd--;
Packit Service 2781ba
        }
Packit Service 2781ba
      curStart = pRegEnd - pReg->rects;
Packit Service 2781ba
      pRegEnd  = pReg->rects + pReg->numRects;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if ((curNumRects == prevNumRects) && (curNumRects != 0))
Packit Service 2781ba
    {
Packit Service 2781ba
      pCurBox -= curNumRects;
Packit Service 2781ba
      /*
Packit Service 2781ba
       * The bands may only be coalesced if the bottom of the previous
Packit Service 2781ba
       * matches the top scanline of the current.
Packit Service 2781ba
       */
Packit Service 2781ba
      if (pPrevBox->y2 == pCurBox->y1)
Packit Service 2781ba
        {
Packit Service 2781ba
          /*
Packit Service 2781ba
           * Make sure the bands have boxes in the same places. This
Packit Service 2781ba
           * assumes that boxes have been added in such a way that they
Packit Service 2781ba
           * cover the most area possible. I.e. two boxes in a band must
Packit Service 2781ba
           * have some horizontal space between them.
Packit Service 2781ba
           */
Packit Service 2781ba
          do
Packit Service 2781ba
            {
Packit Service 2781ba
              if ((pPrevBox->x1 != pCurBox->x1) ||
Packit Service 2781ba
                  (pPrevBox->x2 != pCurBox->x2))
Packit Service 2781ba
                {
Packit Service 2781ba
                  /*
Packit Service 2781ba
                   * The bands don't line up so they can't be coalesced.
Packit Service 2781ba
                   */
Packit Service 2781ba
                  return (curStart);
Packit Service 2781ba
                }
Packit Service 2781ba
              pPrevBox++;
Packit Service 2781ba
              pCurBox++;
Packit Service 2781ba
              prevNumRects -= 1;
Packit Service 2781ba
            } while (prevNumRects != 0);
Packit Service 2781ba
Packit Service 2781ba
          pReg->numRects -= curNumRects;
Packit Service 2781ba
          pCurBox        -= curNumRects;
Packit Service 2781ba
          pPrevBox       -= curNumRects;
Packit Service 2781ba
Packit Service 2781ba
          /*
Packit Service 2781ba
           * The bands may be merged, so set the bottom y of each box
Packit Service 2781ba
           * in the previous band to that of the corresponding box in
Packit Service 2781ba
           * the current band.
Packit Service 2781ba
           */
Packit Service 2781ba
          do
Packit Service 2781ba
            {
Packit Service 2781ba
              pPrevBox->y2 = pCurBox->y2;
Packit Service 2781ba
              pPrevBox++;
Packit Service 2781ba
              pCurBox++;
Packit Service 2781ba
              curNumRects -= 1;
Packit Service 2781ba
            } while (curNumRects != 0);
Packit Service 2781ba
Packit Service 2781ba
          /*
Packit Service 2781ba
           * If only one band was added to the region, we have to backup
Packit Service 2781ba
           * curStart to the start of the previous band.
Packit Service 2781ba
           *
Packit Service 2781ba
           * If more than one band was added to the region, copy the
Packit Service 2781ba
           * other bands down. The assumption here is that the other bands
Packit Service 2781ba
           * came from the same region as the current one and no further
Packit Service 2781ba
           * coalescing can be done on them since it's all been done
Packit Service 2781ba
           * already... curStart is already in the right place.
Packit Service 2781ba
           */
Packit Service 2781ba
          if (pCurBox == pRegEnd)
Packit Service 2781ba
            {
Packit Service 2781ba
              curStart = prevStart;
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              do
Packit Service 2781ba
                {
Packit Service 2781ba
                  *pPrevBox++ = *pCurBox++;
Packit Service 2781ba
                } while (pCurBox != pRegEnd);
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
  return curStart;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miRegionOp --
Packit Service 2781ba
 *	Apply an operation to two regions. Called by miUnion, miInverse,
Packit Service 2781ba
 *	miSubtract, miIntersect...
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	None.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	The new region is overwritten.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Notes:
Packit Service 2781ba
 *	The idea behind this function is to view the two regions as sets.
Packit Service 2781ba
 *	Together they cover a rectangle of area that this function divides
Packit Service 2781ba
 *	into horizontal bands where points are covered only by one region
Packit Service 2781ba
 *	or by both. For the first case, the nonOverlapFunc is called with
Packit Service 2781ba
 *	each the band and the band's upper and lower extents. For the
Packit Service 2781ba
 *	second, the overlapFunc is called to process the entire band. It
Packit Service 2781ba
 *	is responsible for clipping the rectangles in the band, though
Packit Service 2781ba
 *	this function provides the boundaries.
Packit Service 2781ba
 *	At the end of each band, the new region is coalesced, if possible,
Packit Service 2781ba
 *	to reduce the number of rectangles in the region.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
/* static void*/
Packit Service 2781ba
static void
Packit Service 2781ba
miRegionOp (GeglRegion       *newReg,
Packit Service 2781ba
            GeglRegion       *reg1,
Packit Service 2781ba
            const GeglRegion *reg2,
Packit Service 2781ba
            overlapFunc       overlapFn,        /* Function to call for over-
Packit Service 2781ba
                                                 * lapping bands */
Packit Service 2781ba
            nonOverlapFunc    nonOverlap1Fn,    /* Function to call for non-
Packit Service 2781ba
                                                 * overlapping bands in region
Packit Service 2781ba
                                                 * 1 */
Packit Service 2781ba
            nonOverlapFunc    nonOverlap2Fn)    /* Function to call for non-
Packit Service 2781ba
                                                 * overlapping bands in region
Packit Service 2781ba
                                                 * 2 */
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *r1;                    /* Pointer into first region */
Packit Service 2781ba
  GeglRegionBox *r2;                    /* Pointer into 2d region */
Packit Service 2781ba
  GeglRegionBox *r1End;                 /* End of 1st region */
Packit Service 2781ba
  GeglRegionBox *r2End;                 /* End of 2d region */
Packit Service 2781ba
  int            ybot;                  /* Bottom of intersection */
Packit Service 2781ba
  int            ytop;                  /* Top of intersection */
Packit Service 2781ba
  GeglRegionBox *oldRects;              /* Old rects for newReg */
Packit Service 2781ba
  int            prevBand;              /* Index of start of
Packit Service 2781ba
                                         * previous band in newReg */
Packit Service 2781ba
  int            curBand;               /* Index of start of current
Packit Service 2781ba
                                         * band in newReg */
Packit Service 2781ba
  GeglRegionBox *r1BandEnd;             /* End of current band in r1 */
Packit Service 2781ba
  GeglRegionBox *r2BandEnd;             /* End of current band in r2 */
Packit Service 2781ba
  int            top;                   /* Top of non-overlapping
Packit Service 2781ba
                                         * band */
Packit Service 2781ba
  int            bot;                   /* Bottom of non-overlapping
Packit Service 2781ba
                                         * band */
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Initialization:
Packit Service 2781ba
   *	set r1, r2, r1End and r2End appropriately, preserve the important
Packit Service 2781ba
   * parts of the destination region until the end in case it's one of
Packit Service 2781ba
   * the two source regions, then mark the "new" region empty, allocating
Packit Service 2781ba
   * another array of rectangles for it to use.
Packit Service 2781ba
   */
Packit Service 2781ba
  r1    = reg1->rects;
Packit Service 2781ba
  r2    = reg2->rects;
Packit Service 2781ba
  r1End = r1 + reg1->numRects;
Packit Service 2781ba
  r2End = r2 + reg2->numRects;
Packit Service 2781ba
Packit Service 2781ba
  oldRects = newReg->rects;
Packit Service 2781ba
Packit Service 2781ba
  EMPTY_REGION (newReg);
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Allocate a reasonable number of rectangles for the new region. The idea
Packit Service 2781ba
   * is to allocate enough so the individual functions don't need to
Packit Service 2781ba
   * reallocate and copy the array, which is time consuming, yet we don't
Packit Service 2781ba
   * have to worry about using too much memory. I hope to be able to
Packit Service 2781ba
   * nuke the Xrealloc() at the end of this function eventually.
Packit Service 2781ba
   */
Packit Service 2781ba
  newReg->size  = MAX (reg1->numRects, reg2->numRects) * 2;
Packit Service 2781ba
  newReg->rects = g_new (GeglRegionBox, newReg->size);
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Initialize ybot and ytop.
Packit Service 2781ba
   * In the upcoming loop, ybot and ytop serve different functions depending
Packit Service 2781ba
   * on whether the band being handled is an overlapping or non-overlapping
Packit Service 2781ba
   * band.
Packit Service 2781ba
   * 	In the case of a non-overlapping band (only one of the regions
Packit Service 2781ba
   * has points in the band), ybot is the bottom of the most recent
Packit Service 2781ba
   * intersection and thus clips the top of the rectangles in that band.
Packit Service 2781ba
   * ytop is the top of the next intersection between the two regions and
Packit Service 2781ba
   * serves to clip the bottom of the rectangles in the current band.
Packit Service 2781ba
   *	For an overlapping band (where the two regions intersect), ytop clips
Packit Service 2781ba
   * the top of the rectangles of both regions and ybot clips the bottoms.
Packit Service 2781ba
   */
Packit Service 2781ba
  if (reg1->extents.y1 < reg2->extents.y1)
Packit Service 2781ba
    ybot = reg1->extents.y1;
Packit Service 2781ba
  else
Packit Service 2781ba
    ybot = reg2->extents.y1;
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * prevBand serves to mark the start of the previous band so rectangles
Packit Service 2781ba
   * can be coalesced into larger rectangles. qv. miCoalesce, above.
Packit Service 2781ba
   * In the beginning, there is no previous band, so prevBand == curBand
Packit Service 2781ba
   * (curBand is set later on, of course, but the first band will always
Packit Service 2781ba
   * start at index 0). prevBand and curBand must be indices because of
Packit Service 2781ba
   * the possible expansion, and resultant moving, of the new region's
Packit Service 2781ba
   * array of rectangles.
Packit Service 2781ba
   */
Packit Service 2781ba
  prevBand = 0;
Packit Service 2781ba
Packit Service 2781ba
  do
Packit Service 2781ba
    {
Packit Service 2781ba
      curBand = newReg->numRects;
Packit Service 2781ba
Packit Service 2781ba
      /*
Packit Service 2781ba
       * This algorithm proceeds one source-band (as opposed to a
Packit Service 2781ba
       * destination band, which is determined by where the two regions
Packit Service 2781ba
       * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
Packit Service 2781ba
       * rectangle after the last one in the current band for their
Packit Service 2781ba
       * respective regions.
Packit Service 2781ba
       */
Packit Service 2781ba
      r1BandEnd = r1;
Packit Service 2781ba
      while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
Packit Service 2781ba
        {
Packit Service 2781ba
          r1BandEnd++;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      r2BandEnd = r2;
Packit Service 2781ba
      while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
Packit Service 2781ba
        {
Packit Service 2781ba
          r2BandEnd++;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /*
Packit Service 2781ba
       * First handle the band that doesn't intersect, if any.
Packit Service 2781ba
       *
Packit Service 2781ba
       * Note that attention is restricted to one band in the
Packit Service 2781ba
       * non-intersecting region at once, so if a region has n
Packit Service 2781ba
       * bands between the current position and the next place it overlaps
Packit Service 2781ba
       * the other, this entire loop will be passed through n times.
Packit Service 2781ba
       */
Packit Service 2781ba
      if (r1->y1 < r2->y1)
Packit Service 2781ba
        {
Packit Service 2781ba
          top = MAX (r1->y1, ybot);
Packit Service 2781ba
          bot = MIN (r1->y2, r2->y1);
Packit Service 2781ba
Packit Service 2781ba
          if ((top != bot) && (nonOverlap1Fn != (void (*)())NULL))
Packit Service 2781ba
            {
Packit Service 2781ba
              (*nonOverlap1Fn)(newReg, r1, r1BandEnd, top, bot);
Packit Service 2781ba
            }
Packit Service 2781ba
Packit Service 2781ba
          ytop = r2->y1;
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (r2->y1 < r1->y1)
Packit Service 2781ba
        {
Packit Service 2781ba
          top = MAX (r2->y1, ybot);
Packit Service 2781ba
          bot = MIN (r2->y2, r1->y1);
Packit Service 2781ba
Packit Service 2781ba
          if ((top != bot) && (nonOverlap2Fn != (void (*)())NULL))
Packit Service 2781ba
            {
Packit Service 2781ba
              (*nonOverlap2Fn)(newReg, r2, r2BandEnd, top, bot);
Packit Service 2781ba
            }
Packit Service 2781ba
Packit Service 2781ba
          ytop = r1->y1;
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          ytop = r1->y1;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /*
Packit Service 2781ba
       * If any rectangles got added to the region, try and coalesce them
Packit Service 2781ba
       * with rectangles from the previous band. Note we could just do
Packit Service 2781ba
       * this test in miCoalesce, but some machines incur a not
Packit Service 2781ba
       * inconsiderable cost for function calls, so...
Packit Service 2781ba
       */
Packit Service 2781ba
      if (newReg->numRects != curBand)
Packit Service 2781ba
        {
Packit Service 2781ba
          prevBand = miCoalesce (newReg, prevBand, curBand);
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /*
Packit Service 2781ba
       * Now see if we've hit an intersecting band. The two bands only
Packit Service 2781ba
       * intersect if ybot > ytop
Packit Service 2781ba
       */
Packit Service 2781ba
      ybot    = MIN (r1->y2, r2->y2);
Packit Service 2781ba
      curBand = newReg->numRects;
Packit Service 2781ba
      if (ybot > ytop)
Packit Service 2781ba
        {
Packit Service 2781ba
          (*overlapFn)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      if (newReg->numRects != curBand)
Packit Service 2781ba
        {
Packit Service 2781ba
          prevBand = miCoalesce (newReg, prevBand, curBand);
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /*
Packit Service 2781ba
       * If we've finished with a band (y2 == ybot) we skip forward
Packit Service 2781ba
       * in the region to the next band.
Packit Service 2781ba
       */
Packit Service 2781ba
      if (r1->y2 == ybot)
Packit Service 2781ba
        {
Packit Service 2781ba
          r1 = r1BandEnd;
Packit Service 2781ba
        }
Packit Service 2781ba
      if (r2->y2 == ybot)
Packit Service 2781ba
        {
Packit Service 2781ba
          r2 = r2BandEnd;
Packit Service 2781ba
        }
Packit Service 2781ba
    } while ((r1 != r1End) && (r2 != r2End));
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Deal with whichever region still has rectangles left.
Packit Service 2781ba
   */
Packit Service 2781ba
  curBand = newReg->numRects;
Packit Service 2781ba
  if (r1 != r1End)
Packit Service 2781ba
    {
Packit Service 2781ba
      if (nonOverlap1Fn != (nonOverlapFunc) NULL)
Packit Service 2781ba
        {
Packit Service 2781ba
          do
Packit Service 2781ba
            {
Packit Service 2781ba
              r1BandEnd = r1;
Packit Service 2781ba
              while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
Packit Service 2781ba
                {
Packit Service 2781ba
                  r1BandEnd++;
Packit Service 2781ba
                }
Packit Service 2781ba
              (*nonOverlap1Fn)(newReg, r1, r1BandEnd,
Packit Service 2781ba
                               MAX (r1->y1, ybot), r1->y2);
Packit Service 2781ba
              r1 = r1BandEnd;
Packit Service 2781ba
            } while (r1 != r1End);
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
  else if ((r2 != r2End) && (nonOverlap2Fn != (nonOverlapFunc) NULL))
Packit Service 2781ba
    {
Packit Service 2781ba
      do
Packit Service 2781ba
        {
Packit Service 2781ba
          r2BandEnd = r2;
Packit Service 2781ba
          while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
Packit Service 2781ba
            {
Packit Service 2781ba
              r2BandEnd++;
Packit Service 2781ba
            }
Packit Service 2781ba
          (*nonOverlap2Fn)(newReg, r2, r2BandEnd,
Packit Service 2781ba
                           MAX (r2->y1, ybot), r2->y2);
Packit Service 2781ba
          r2 = r2BandEnd;
Packit Service 2781ba
        } while (r2 != r2End);
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (newReg->numRects != curBand)
Packit Service 2781ba
    {
Packit Service 2781ba
      (void) miCoalesce (newReg, prevBand, curBand);
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * A bit of cleanup. To keep regions from growing without bound,
Packit Service 2781ba
   * we shrink the array of rectangles to match the new number of
Packit Service 2781ba
   * rectangles in the region. This never goes to 0, however...
Packit Service 2781ba
   *
Packit Service 2781ba
   * Only do this stuff if the number of rectangles allocated is more than
Packit Service 2781ba
   * twice the number of rectangles in the region (a simple optimization...).
Packit Service 2781ba
   */
Packit Service 2781ba
  if (newReg->numRects < (newReg->size >> 1))
Packit Service 2781ba
    {
Packit Service 2781ba
      if (REGION_NOT_EMPTY (newReg))
Packit Service 2781ba
        {
Packit Service 2781ba
          newReg->size  = newReg->numRects;
Packit Service 2781ba
          newReg->rects = g_renew (GeglRegionBox, newReg->rects, newReg->size);
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          /*
Packit Service 2781ba
           * No point in doing the extra work involved in an Xrealloc if
Packit Service 2781ba
           * the region is empty
Packit Service 2781ba
           */
Packit Service 2781ba
          newReg->size = 1;
Packit Service 2781ba
          g_free (newReg->rects);
Packit Service 2781ba
          newReg->rects = &newReg->extents;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (oldRects != &newReg->extents)
Packit Service 2781ba
    g_free (oldRects);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/*======================================================================
Packit Service 2781ba
 *	    Region Union
Packit Service 2781ba
 *====================================================================*/
Packit Service 2781ba
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miUnionNonO --
Packit Service 2781ba
 *	Handle a non-overlapping band for the union operation. Just
Packit Service 2781ba
 *	Adds the rectangles into the region. Doesn't have to check for
Packit Service 2781ba
 *	subsumption or anything.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	None.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	pReg->numRects is incremented and the final rectangles overwritten
Packit Service 2781ba
 *	with the rectangles we're passed.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
static void
Packit Service 2781ba
miUnionNonO (GeglRegion    *pReg,
Packit Service 2781ba
             GeglRegionBox *r,
Packit Service 2781ba
             GeglRegionBox *rEnd,
Packit Service 2781ba
             gint           y1,
Packit Service 2781ba
             gint           y2)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *pNextRect;
Packit Service 2781ba
Packit Service 2781ba
  pNextRect = &pReg->rects[pReg->numRects];
Packit Service 2781ba
Packit Service 2781ba
  g_assert (y1 < y2);
Packit Service 2781ba
Packit Service 2781ba
  while (r != rEnd)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_assert (r->x1 < r->x2);
Packit Service 2781ba
      MEMCHECK (pReg, pNextRect, pReg->rects);
Packit Service 2781ba
      pNextRect->x1   = r->x1;
Packit Service 2781ba
      pNextRect->y1   = y1;
Packit Service 2781ba
      pNextRect->x2   = r->x2;
Packit Service 2781ba
      pNextRect->y2   = y2;
Packit Service 2781ba
      pReg->numRects += 1;
Packit Service 2781ba
      pNextRect++;
Packit Service 2781ba
Packit Service 2781ba
      g_assert (pReg->numRects <= pReg->size);
Packit Service 2781ba
      r++;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miUnionO --
Packit Service 2781ba
 *	Handle an overlapping band for the union operation. Picks the
Packit Service 2781ba
 *	left-most rectangle each time and merges it into the region.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	None.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	Rectangles are overwritten in pReg->rects and pReg->numRects will
Packit Service 2781ba
 *	be changed.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
Packit Service 2781ba
/* static void*/
Packit Service 2781ba
static void
Packit Service 2781ba
miUnionO (GeglRegion    *pReg,
Packit Service 2781ba
          GeglRegionBox *r1,
Packit Service 2781ba
          GeglRegionBox *r1End,
Packit Service 2781ba
          GeglRegionBox *r2,
Packit Service 2781ba
          GeglRegionBox *r2End,
Packit Service 2781ba
          gint           y1,
Packit Service 2781ba
          gint           y2)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *pNextRect;
Packit Service 2781ba
Packit Service 2781ba
  pNextRect = &pReg->rects[pReg->numRects];
Packit Service 2781ba
Packit Service 2781ba
#define MERGERECT(r)                                    \
Packit Service 2781ba
  if ((pReg->numRects != 0) && \
Packit Service 2781ba
      (pNextRect[-1].y1 == y1) && \
Packit Service 2781ba
      (pNextRect[-1].y2 == y2) && \
Packit Service 2781ba
      (pNextRect[-1].x2 >= r->x1)) \
Packit Service 2781ba
    { \
Packit Service 2781ba
      if (pNextRect[-1].x2 < r->x2) \
Packit Service 2781ba
        { \
Packit Service 2781ba
          pNextRect[-1].x2 = r->x2;                   \
Packit Service 2781ba
          g_assert (pNextRect[-1].x1 < pNextRect[-1].x2);        \
Packit Service 2781ba
        }                                             \
Packit Service 2781ba
    }                                                 \
Packit Service 2781ba
  else                                                \
Packit Service 2781ba
    { \
Packit Service 2781ba
      MEMCHECK (pReg, pNextRect, pReg->rects);         \
Packit Service 2781ba
      pNextRect->y1   = y1;                             \
Packit Service 2781ba
      pNextRect->y2   = y2;                             \
Packit Service 2781ba
      pNextRect->x1   = r->x1;                          \
Packit Service 2781ba
      pNextRect->x2   = r->x2;                          \
Packit Service 2781ba
      pReg->numRects += 1;                            \
Packit Service 2781ba
      pNextRect      += 1;                                 \
Packit Service 2781ba
    }                                                 \
Packit Service 2781ba
  g_assert (pReg->numRects <= pReg->size);                       \
Packit Service 2781ba
  r++;
Packit Service 2781ba
Packit Service 2781ba
  g_assert (y1 < y2);
Packit Service 2781ba
  while ((r1 != r1End) && (r2 != r2End))
Packit Service 2781ba
    {
Packit Service 2781ba
      if (r1->x1 < r2->x1)
Packit Service 2781ba
        {
Packit Service 2781ba
          MERGERECT (r1);
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          MERGERECT (r2);
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (r1 != r1End)
Packit Service 2781ba
    {
Packit Service 2781ba
      do
Packit Service 2781ba
        {
Packit Service 2781ba
          MERGERECT (r1);
Packit Service 2781ba
        } while (r1 != r1End);
Packit Service 2781ba
    }
Packit Service 2781ba
  else while (r2 != r2End)
Packit Service 2781ba
      {
Packit Service 2781ba
        MERGERECT (r2);
Packit Service 2781ba
      }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_union:
Packit Service 2781ba
 * @source1:  a #GeglRegion
Packit Service 2781ba
 * @source2: a #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Sets the area of @source1 to the union of the areas of @source1 and
Packit Service 2781ba
 * @source2. The resulting area is the set of pixels contained in
Packit Service 2781ba
 * either @source1 or @source2.
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_union (GeglRegion       *source1,
Packit Service 2781ba
                   const GeglRegion *source2)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_if_fail (source1 != NULL);
Packit Service 2781ba
  g_return_if_fail (source2 != NULL);
Packit Service 2781ba
Packit Service 2781ba
  /*  checks all the simple cases */
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * source1 and source2 are the same or source2 is empty
Packit Service 2781ba
   */
Packit Service 2781ba
  if ((source1 == source2) || (!(source2->numRects)))
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * source1 is empty
Packit Service 2781ba
   */
Packit Service 2781ba
  if (!(source1->numRects))
Packit Service 2781ba
    {
Packit Service 2781ba
      miRegionCopy (source1, source2);
Packit Service 2781ba
      return;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * source1 completely subsumes source2
Packit Service 2781ba
   */
Packit Service 2781ba
  if ((source1->numRects == 1) &&
Packit Service 2781ba
      (source1->extents.x1 <= source2->extents.x1) &&
Packit Service 2781ba
      (source1->extents.y1 <= source2->extents.y1) &&
Packit Service 2781ba
      (source1->extents.x2 >= source2->extents.x2) &&
Packit Service 2781ba
      (source1->extents.y2 >= source2->extents.y2))
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * source2 completely subsumes source1
Packit Service 2781ba
   */
Packit Service 2781ba
  if ((source2->numRects == 1) &&
Packit Service 2781ba
      (source2->extents.x1 <= source1->extents.x1) &&
Packit Service 2781ba
      (source2->extents.y1 <= source1->extents.y1) &&
Packit Service 2781ba
      (source2->extents.x2 >= source1->extents.x2) &&
Packit Service 2781ba
      (source2->extents.y2 >= source1->extents.y2))
Packit Service 2781ba
    {
Packit Service 2781ba
      miRegionCopy (source1, source2);
Packit Service 2781ba
      return;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  miRegionOp (source1, source1, source2, miUnionO,
Packit Service 2781ba
              miUnionNonO, miUnionNonO);
Packit Service 2781ba
Packit Service 2781ba
  source1->extents.x1 = MIN (source1->extents.x1, source2->extents.x1);
Packit Service 2781ba
  source1->extents.y1 = MIN (source1->extents.y1, source2->extents.y1);
Packit Service 2781ba
  source1->extents.x2 = MAX (source1->extents.x2, source2->extents.x2);
Packit Service 2781ba
  source1->extents.y2 = MAX (source1->extents.y2, source2->extents.y2);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/*======================================================================
Packit Service 2781ba
 * 	    	  Region Subtraction
Packit Service 2781ba
 *====================================================================*/
Packit Service 2781ba
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miSubtractNonO --
Packit Service 2781ba
 *	Deal with non-overlapping band for subtraction. Any parts from
Packit Service 2781ba
 *	region 2 we discard. Anything from region 1 we add to the region.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	None.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	pReg may be affected.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
/* static void*/
Packit Service 2781ba
static void
Packit Service 2781ba
miSubtractNonO1 (GeglRegion    *pReg,
Packit Service 2781ba
                 GeglRegionBox *r,
Packit Service 2781ba
                 GeglRegionBox *rEnd,
Packit Service 2781ba
                 gint           y1,
Packit Service 2781ba
                 gint           y2)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *pNextRect;
Packit Service 2781ba
Packit Service 2781ba
  pNextRect = &pReg->rects[pReg->numRects];
Packit Service 2781ba
Packit Service 2781ba
  g_assert (y1 < y2);
Packit Service 2781ba
Packit Service 2781ba
  while (r != rEnd)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_assert (r->x1 < r->x2);
Packit Service 2781ba
      MEMCHECK (pReg, pNextRect, pReg->rects);
Packit Service 2781ba
      pNextRect->x1   = r->x1;
Packit Service 2781ba
      pNextRect->y1   = y1;
Packit Service 2781ba
      pNextRect->x2   = r->x2;
Packit Service 2781ba
      pNextRect->y2   = y2;
Packit Service 2781ba
      pReg->numRects += 1;
Packit Service 2781ba
      pNextRect++;
Packit Service 2781ba
Packit Service 2781ba
      g_assert (pReg->numRects <= pReg->size);
Packit Service 2781ba
Packit Service 2781ba
      r++;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/*-
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 * miSubtractO --
Packit Service 2781ba
 *	Overlapping band subtraction. x1 is the left-most point not yet
Packit Service 2781ba
 *	checked.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Results:
Packit Service 2781ba
 *	None.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Side Effects:
Packit Service 2781ba
 *	pReg may have rectangles added to it.
Packit Service 2781ba
 *
Packit Service 2781ba
 *-----------------------------------------------------------------------
Packit Service 2781ba
 */
Packit Service 2781ba
/* static void*/
Packit Service 2781ba
static void
Packit Service 2781ba
miSubtractO (GeglRegion    *pReg,
Packit Service 2781ba
             GeglRegionBox *r1,
Packit Service 2781ba
             GeglRegionBox *r1End,
Packit Service 2781ba
             GeglRegionBox *r2,
Packit Service 2781ba
             GeglRegionBox *r2End,
Packit Service 2781ba
             gint           y1,
Packit Service 2781ba
             gint           y2)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *pNextRect;
Packit Service 2781ba
  int            x1;
Packit Service 2781ba
Packit Service 2781ba
  x1 = r1->x1;
Packit Service 2781ba
Packit Service 2781ba
  g_assert (y1 < y2);
Packit Service 2781ba
  pNextRect = &pReg->rects[pReg->numRects];
Packit Service 2781ba
Packit Service 2781ba
  while ((r1 != r1End) && (r2 != r2End))
Packit Service 2781ba
    {
Packit Service 2781ba
      if (r2->x2 <= x1)
Packit Service 2781ba
        {
Packit Service 2781ba
          /*
Packit Service 2781ba
           * Subtrahend missed the boat: go to next subtrahend.
Packit Service 2781ba
           */
Packit Service 2781ba
          r2++;
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (r2->x1 <= x1)
Packit Service 2781ba
        {
Packit Service 2781ba
          /*
Packit Service 2781ba
           * Subtrahend preceeds minuend: nuke left edge of minuend.
Packit Service 2781ba
           */
Packit Service 2781ba
          x1 = r2->x2;
Packit Service 2781ba
          if (x1 >= r1->x2)
Packit Service 2781ba
            {
Packit Service 2781ba
              /*
Packit Service 2781ba
               * Minuend completely covered: advance to next minuend and
Packit Service 2781ba
               * reset left fence to edge of new minuend.
Packit Service 2781ba
               */
Packit Service 2781ba
              r1++;
Packit Service 2781ba
              if (r1 != r1End)
Packit Service 2781ba
                x1 = r1->x1;
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              /*
Packit Service 2781ba
               * Subtrahend now used up since it doesn't extend beyond
Packit Service 2781ba
               * minuend
Packit Service 2781ba
               */
Packit Service 2781ba
              r2++;
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (r2->x1 < r1->x2)
Packit Service 2781ba
        {
Packit Service 2781ba
          /*
Packit Service 2781ba
           * Left part of subtrahend covers part of minuend: add uncovered
Packit Service 2781ba
           * part of minuend to region and skip to next subtrahend.
Packit Service 2781ba
           */
Packit Service 2781ba
          g_assert (x1 < r2->x1);
Packit Service 2781ba
          MEMCHECK (pReg, pNextRect, pReg->rects);
Packit Service 2781ba
          pNextRect->x1   = x1;
Packit Service 2781ba
          pNextRect->y1   = y1;
Packit Service 2781ba
          pNextRect->x2   = r2->x1;
Packit Service 2781ba
          pNextRect->y2   = y2;
Packit Service 2781ba
          pReg->numRects += 1;
Packit Service 2781ba
          pNextRect++;
Packit Service 2781ba
Packit Service 2781ba
          g_assert (pReg->numRects <= pReg->size);
Packit Service 2781ba
Packit Service 2781ba
          x1 = r2->x2;
Packit Service 2781ba
          if (x1 >= r1->x2)
Packit Service 2781ba
            {
Packit Service 2781ba
              /*
Packit Service 2781ba
               * Minuend used up: advance to new...
Packit Service 2781ba
               */
Packit Service 2781ba
              r1++;
Packit Service 2781ba
              if (r1 != r1End)
Packit Service 2781ba
                x1 = r1->x1;
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              /*
Packit Service 2781ba
               * Subtrahend used up
Packit Service 2781ba
               */
Packit Service 2781ba
              r2++;
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          /*
Packit Service 2781ba
           * Minuend used up: add any remaining piece before advancing.
Packit Service 2781ba
           */
Packit Service 2781ba
          if (r1->x2 > x1)
Packit Service 2781ba
            {
Packit Service 2781ba
              MEMCHECK (pReg, pNextRect, pReg->rects);
Packit Service 2781ba
              pNextRect->x1   = x1;
Packit Service 2781ba
              pNextRect->y1   = y1;
Packit Service 2781ba
              pNextRect->x2   = r1->x2;
Packit Service 2781ba
              pNextRect->y2   = y2;
Packit Service 2781ba
              pReg->numRects += 1;
Packit Service 2781ba
              pNextRect++;
Packit Service 2781ba
              g_assert (pReg->numRects <= pReg->size);
Packit Service 2781ba
            }
Packit Service 2781ba
          r1++;
Packit Service 2781ba
          if (r1 != r1End)
Packit Service 2781ba
            x1 = r1->x1;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Add remaining minuend rectangles to region.
Packit Service 2781ba
   */
Packit Service 2781ba
  while (r1 != r1End)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_assert (x1 < r1->x2);
Packit Service 2781ba
      MEMCHECK (pReg, pNextRect, pReg->rects);
Packit Service 2781ba
      pNextRect->x1   = x1;
Packit Service 2781ba
      pNextRect->y1   = y1;
Packit Service 2781ba
      pNextRect->x2   = r1->x2;
Packit Service 2781ba
      pNextRect->y2   = y2;
Packit Service 2781ba
      pReg->numRects += 1;
Packit Service 2781ba
      pNextRect++;
Packit Service 2781ba
Packit Service 2781ba
      g_assert (pReg->numRects <= pReg->size);
Packit Service 2781ba
Packit Service 2781ba
      r1++;
Packit Service 2781ba
      if (r1 != r1End)
Packit Service 2781ba
        {
Packit Service 2781ba
          x1 = r1->x1;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_subtract:
Packit Service 2781ba
 * @source1: a #GeglRegion
Packit Service 2781ba
 * @source2: another #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Subtracts the area of @source2 from the area @source1. The resulting
Packit Service 2781ba
 * area is the set of pixels contained in @source1 but not in @source2.
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_subtract (GeglRegion       *source1,
Packit Service 2781ba
                      const GeglRegion *source2)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_if_fail (source1 != NULL);
Packit Service 2781ba
  g_return_if_fail (source2 != NULL);
Packit Service 2781ba
Packit Service 2781ba
  /* check for trivial reject */
Packit Service 2781ba
  if ((!(source1->numRects)) || (!(source2->numRects)) ||
Packit Service 2781ba
      (!EXTENTCHECK (&source1->extents, &source2->extents)))
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  miRegionOp (source1, source1, source2, miSubtractO,
Packit Service 2781ba
              miSubtractNonO1, (nonOverlapFunc) NULL);
Packit Service 2781ba
Packit Service 2781ba
  /*
Packit Service 2781ba
   * Can't alter source1's extents before we call miRegionOp because miRegionOp
Packit Service 2781ba
   * depends on the extents of those regions being the unaltered. Besides, this
Packit Service 2781ba
   * way there's no checking against rectangles that will be nuked
Packit Service 2781ba
   * due to coalescing, so we have to examine fewer rectangles.
Packit Service 2781ba
   */
Packit Service 2781ba
  miSetExtents (source1);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_xor:
Packit Service 2781ba
 * @source1: a #GeglRegion
Packit Service 2781ba
 * @source2: another #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Sets the area of @source1 to the exclusive-OR of the areas of @source1
Packit Service 2781ba
 * and @source2. The resulting area is the set of pixels contained in one
Packit Service 2781ba
 * or the other of the two sources but not in both.
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_xor (GeglRegion       *source1,
Packit Service 2781ba
                 const GeglRegion *source2)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegion *trb;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (source1 != NULL);
Packit Service 2781ba
  g_return_if_fail (source2 != NULL);
Packit Service 2781ba
Packit Service 2781ba
  trb = gegl_region_copy (source2);
Packit Service 2781ba
Packit Service 2781ba
  gegl_region_subtract (trb, source1);
Packit Service 2781ba
  gegl_region_subtract (source1, source2);
Packit Service 2781ba
Packit Service 2781ba
  gegl_region_union (source1, trb);
Packit Service 2781ba
Packit Service 2781ba
  gegl_region_destroy (trb);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_empty:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Finds out if the #GeglRegion is empty.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Returns: %TRUE if @region is empty.
Packit Service 2781ba
 */
Packit Service 2781ba
gboolean
Packit Service 2781ba
gegl_region_empty (const GeglRegion *region)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_val_if_fail (region != NULL, FALSE);
Packit Service 2781ba
Packit Service 2781ba
  if (region->numRects == 0)
Packit Service 2781ba
    return TRUE;
Packit Service 2781ba
  else
Packit Service 2781ba
    return FALSE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_equal:
Packit Service 2781ba
 * @region1: a #GeglRegion
Packit Service 2781ba
 * @region2: a #GeglRegion
Packit Service 2781ba
 *
Packit Service 2781ba
 * Finds out if the two regions are the same.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Returns: %TRUE if @region1 and @region2 are equal.
Packit Service 2781ba
 */
Packit Service 2781ba
gboolean
Packit Service 2781ba
gegl_region_equal (const GeglRegion *region1,
Packit Service 2781ba
                   const GeglRegion *region2)
Packit Service 2781ba
{
Packit Service 2781ba
  int i;
Packit Service 2781ba
Packit Service 2781ba
  g_return_val_if_fail (region1 != NULL, FALSE);
Packit Service 2781ba
  g_return_val_if_fail (region2 != NULL, FALSE);
Packit Service 2781ba
Packit Service 2781ba
  if (region1->numRects != region2->numRects) return FALSE;
Packit Service 2781ba
  else if (region1->numRects == 0) return TRUE;
Packit Service 2781ba
  else if (region1->extents.x1 != region2->extents.x1) return FALSE;
Packit Service 2781ba
  else if (region1->extents.x2 != region2->extents.x2) return FALSE;
Packit Service 2781ba
  else if (region1->extents.y1 != region2->extents.y1) return FALSE;
Packit Service 2781ba
  else if (region1->extents.y2 != region2->extents.y2) return FALSE;
Packit Service 2781ba
  else
Packit Service 2781ba
    for (i = 0; i < region1->numRects; i++)
Packit Service 2781ba
      {
Packit Service 2781ba
        if (region1->rects[i].x1 != region2->rects[i].x1) return FALSE;
Packit Service 2781ba
        else if (region1->rects[i].x2 != region2->rects[i].x2) return FALSE;
Packit Service 2781ba
        else if (region1->rects[i].y1 != region2->rects[i].y1) return FALSE;
Packit Service 2781ba
        else if (region1->rects[i].y2 != region2->rects[i].y2) return FALSE;
Packit Service 2781ba
      }
Packit Service 2781ba
  return TRUE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_point_in:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 * @x: the x coordinate of a point
Packit Service 2781ba
 * @y: the y coordinate of a point
Packit Service 2781ba
 *
Packit Service 2781ba
 * Finds out if a point is in a region.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Returns: %TRUE if the point is in @region.
Packit Service 2781ba
 */
Packit Service 2781ba
gboolean
Packit Service 2781ba
gegl_region_point_in (const GeglRegion *region,
Packit Service 2781ba
                      gint              x,
Packit Service 2781ba
                      gint              y)
Packit Service 2781ba
{
Packit Service 2781ba
  int i;
Packit Service 2781ba
Packit Service 2781ba
  g_return_val_if_fail (region != NULL, FALSE);
Packit Service 2781ba
Packit Service 2781ba
  if (region->numRects == 0)
Packit Service 2781ba
    return FALSE;
Packit Service 2781ba
  if (!INBOX (region->extents, x, y))
Packit Service 2781ba
    return FALSE;
Packit Service 2781ba
  for (i = 0; i < region->numRects; i++)
Packit Service 2781ba
    {
Packit Service 2781ba
      if (INBOX (region->rects[i], x, y))
Packit Service 2781ba
        return TRUE;
Packit Service 2781ba
    }
Packit Service 2781ba
  return FALSE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_rect_in:
Packit Service 2781ba
 * @region: a #GeglRegion.
Packit Service 2781ba
 * @rectangle: a #GeglRectangle.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Tests whether a rectangle is within a region.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Returns: %GEGL_OVERLAP_RECTANGLE_IN, %GEGL_OVERLAP_RECTANGLE_OUT, or
Packit Service 2781ba
 *   %GEGL_OVERLAP_RECTANGLE_PART, depending on whether the rectangle is inside,
Packit Service 2781ba
 *   outside, or partly inside the #GeglRegion, respectively.
Packit Service 2781ba
 */
Packit Service 2781ba
GeglOverlapType
Packit Service 2781ba
gegl_region_rect_in (const GeglRegion    *region,
Packit Service 2781ba
                     const GeglRectangle *rectangle)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRegionBox *pbox;
Packit Service 2781ba
  GeglRegionBox *pboxEnd;
Packit Service 2781ba
  GeglRegionBox  rect;
Packit Service 2781ba
  GeglRegionBox *prect = ▭
Packit Service 2781ba
  gboolean       partIn, partOut;
Packit Service 2781ba
  gint           rx, ry;
Packit Service 2781ba
Packit Service 2781ba
  g_return_val_if_fail (region != NULL, GEGL_OVERLAP_RECTANGLE_OUT);
Packit Service 2781ba
  g_return_val_if_fail (rectangle != NULL, GEGL_OVERLAP_RECTANGLE_OUT);
Packit Service 2781ba
Packit Service 2781ba
  rx = rectangle->x;
Packit Service 2781ba
  ry = rectangle->y;
Packit Service 2781ba
Packit Service 2781ba
  prect->x1 = rx;
Packit Service 2781ba
  prect->y1 = ry;
Packit Service 2781ba
  prect->x2 = rx + rectangle->width;
Packit Service 2781ba
  prect->y2 = ry + rectangle->height;
Packit Service 2781ba
Packit Service 2781ba
  /* this is (just) a useful optimization */
Packit Service 2781ba
  if ((region->numRects == 0) || !EXTENTCHECK (&region->extents, prect))
Packit Service 2781ba
    return GEGL_OVERLAP_RECTANGLE_OUT;
Packit Service 2781ba
Packit Service 2781ba
  partOut = FALSE;
Packit Service 2781ba
  partIn  = FALSE;
Packit Service 2781ba
Packit Service 2781ba
  /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
Packit Service 2781ba
  for (pbox = region->rects, pboxEnd = pbox + region->numRects;
Packit Service 2781ba
       pbox < pboxEnd;
Packit Service 2781ba
       pbox++)
Packit Service 2781ba
    {
Packit Service 2781ba
      if (pbox->y2 <= ry)
Packit Service 2781ba
        continue;/* getting up to speed or skipping remainder of band */
Packit Service 2781ba
Packit Service 2781ba
      if (pbox->y1 > ry)
Packit Service 2781ba
        {
Packit Service 2781ba
          partOut = TRUE;       /* missed part of rectangle above */
Packit Service 2781ba
          if (partIn || (pbox->y1 >= prect->y2))
Packit Service 2781ba
            break;
Packit Service 2781ba
          ry = pbox->y1;        /* x guaranteed to be == prect->x1 */
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      if (pbox->x2 <= rx)
Packit Service 2781ba
        continue;/* not far enough over yet */
Packit Service 2781ba
Packit Service 2781ba
      if (pbox->x1 > rx)
Packit Service 2781ba
        {
Packit Service 2781ba
          partOut = TRUE;       /* missed part of rectangle to left */
Packit Service 2781ba
          if (partIn)
Packit Service 2781ba
            break;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      if (pbox->x1 < prect->x2)
Packit Service 2781ba
        {
Packit Service 2781ba
          partIn = TRUE;        /* definitely overlap */
Packit Service 2781ba
          if (partOut)
Packit Service 2781ba
            break;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      if (pbox->x2 >= prect->x2)
Packit Service 2781ba
        {
Packit Service 2781ba
          ry = pbox->y2;        /* finished with this band */
Packit Service 2781ba
          if (ry >= prect->y2)
Packit Service 2781ba
            break;
Packit Service 2781ba
          rx = prect->x1;       /* reset x out to left again */
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          /*
Packit Service 2781ba
           * Because boxes in a band are maximal width, if the first box
Packit Service 2781ba
           * to overlap the rectangle doesn't completely cover it in that
Packit Service 2781ba
           * band, the rectangle must be partially out, since some of it
Packit Service 2781ba
           * will be uncovered in that band. partIn will have been set true
Packit Service 2781ba
           * by now...
Packit Service 2781ba
           */
Packit Service 2781ba
          break;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  return (partIn ?
Packit Service 2781ba
          ((ry < prect->y2) ?
Packit Service 2781ba
           GEGL_OVERLAP_RECTANGLE_PART : GEGL_OVERLAP_RECTANGLE_IN) :
Packit Service 2781ba
          GEGL_OVERLAP_RECTANGLE_OUT);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_region_unsorted_spans_intersect_foreach (GeglRegion  *region,
Packit Service 2781ba
                                              GeglSpan    *spans,
Packit Service 2781ba
                                              int          n_spans,
Packit Service 2781ba
                                              GeglSpanFunc function,
Packit Service 2781ba
                                              gpointer     data)
Packit Service 2781ba
{
Packit Service 2781ba
  gint           i, left, right, y;
Packit Service 2781ba
  gint           clipped_left, clipped_right;
Packit Service 2781ba
  GeglRegionBox *pbox;
Packit Service 2781ba
  GeglRegionBox *pboxEnd;
Packit Service 2781ba
  GeglSpan       out_span;
Packit Service 2781ba
Packit Service 2781ba
  if (!region->numRects)
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  for (i = 0; i < n_spans; i++)
Packit Service 2781ba
    {
Packit Service 2781ba
      y     = spans[i].y;
Packit Service 2781ba
      left  = spans[i].x;
Packit Service 2781ba
      right = left + spans[i].width; /* right is not in the span! */
Packit Service 2781ba
Packit Service 2781ba
      if (!((region->extents.y1 <= y) &&
Packit Service 2781ba
            (region->extents.y2 > y) &&
Packit Service 2781ba
            (region->extents.x1 < right) &&
Packit Service 2781ba
            (region->extents.x2 > left)))
Packit Service 2781ba
        continue;
Packit Service 2781ba
Packit Service 2781ba
      /* can stop when we passed y */
Packit Service 2781ba
      for (pbox = region->rects, pboxEnd = pbox + region->numRects;
Packit Service 2781ba
           pbox < pboxEnd;
Packit Service 2781ba
           pbox++)
Packit Service 2781ba
        {
Packit Service 2781ba
          if (pbox->y2 <= y)
Packit Service 2781ba
            continue;/* Not quite there yet */
Packit Service 2781ba
Packit Service 2781ba
          if (pbox->y1 > y)
Packit Service 2781ba
            break;/* passed the spanline */
Packit Service 2781ba
Packit Service 2781ba
          if ((right > pbox->x1) && (left < pbox->x2))
Packit Service 2781ba
            {
Packit Service 2781ba
              clipped_left  = MAX (left, pbox->x1);
Packit Service 2781ba
              clipped_right = MIN (right, pbox->x2);
Packit Service 2781ba
Packit Service 2781ba
              out_span.y     = y;
Packit Service 2781ba
              out_span.x     = clipped_left;
Packit Service 2781ba
              out_span.width = clipped_right - clipped_left;
Packit Service 2781ba
              (*function)(&out_span, data);
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_region_spans_intersect_foreach:
Packit Service 2781ba
 * @region: a #GeglRegion
Packit Service 2781ba
 * @spans: an array of #GeglSpans
Packit Service 2781ba
 * @n_spans: the length of @spans
Packit Service 2781ba
 * @sorted: %TRUE if @spans is sorted wrt. the y coordinate
Packit Service 2781ba
 * @function: function to call on each span in the intersection
Packit Service 2781ba
 * @data: data to pass to @function
Packit Service 2781ba
 *
Packit Service 2781ba
 * Calls a function on each span in the intersection of @region and @spans.
Packit Service 2781ba
 */
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_spans_intersect_foreach (GeglRegion  *region,
Packit Service 2781ba
                                     GeglSpan    *spans,
Packit Service 2781ba
                                     int          n_spans,
Packit Service 2781ba
                                     gboolean     sorted,
Packit Service 2781ba
                                     GeglSpanFunc function,
Packit Service 2781ba
                                     gpointer     data)
Packit Service 2781ba
{
Packit Service 2781ba
  gint           left, right, y;
Packit Service 2781ba
  gint           clipped_left, clipped_right;
Packit Service 2781ba
  GeglRegionBox *pbox;
Packit Service 2781ba
  GeglRegionBox *pboxEnd;
Packit Service 2781ba
  GeglSpan      *span, *tmpspan;
Packit Service 2781ba
  GeglSpan      *end_span;
Packit Service 2781ba
  GeglSpan       out_span;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (region != NULL);
Packit Service 2781ba
  g_return_if_fail (spans != NULL);
Packit Service 2781ba
Packit Service 2781ba
  if (!sorted)
Packit Service 2781ba
    {
Packit Service 2781ba
      gegl_region_unsorted_spans_intersect_foreach (region,
Packit Service 2781ba
                                                    spans,
Packit Service 2781ba
                                                    n_spans,
Packit Service 2781ba
                                                    function,
Packit Service 2781ba
                                                    data);
Packit Service 2781ba
      return;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if ((!region->numRects) || (n_spans == 0))
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  /* The main method here is to step along the
Packit Service 2781ba
   * sorted rectangles and spans in lock step, and
Packit Service 2781ba
   * clipping the spans that are in the current
Packit Service 2781ba
   * rectangle before going on to the next rectangle.
Packit Service 2781ba
   */
Packit Service 2781ba
Packit Service 2781ba
  span     = spans;
Packit Service 2781ba
  end_span = spans + n_spans;
Packit Service 2781ba
  pbox     = region->rects;
Packit Service 2781ba
  pboxEnd  = pbox + region->numRects;
Packit Service 2781ba
  while (pbox < pboxEnd)
Packit Service 2781ba
    {
Packit Service 2781ba
      while ((pbox->y2 < span->y) || (span->y < pbox->y1))
Packit Service 2781ba
        {
Packit Service 2781ba
          /* Skip any rectangles that are above the current span */
Packit Service 2781ba
          if (pbox->y2 < span->y)
Packit Service 2781ba
            {
Packit Service 2781ba
              pbox++;
Packit Service 2781ba
              if (pbox == pboxEnd)
Packit Service 2781ba
                return;
Packit Service 2781ba
            }
Packit Service 2781ba
          /* Skip any spans that are above the current rectangle */
Packit Service 2781ba
          if (span->y < pbox->y1)
Packit Service 2781ba
            {
Packit Service 2781ba
              span++;
Packit Service 2781ba
              if (span == end_span)
Packit Service 2781ba
                return;
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /* Ok, we got at least one span that might intersect this rectangle. */
Packit Service 2781ba
      tmpspan = span;
Packit Service 2781ba
      while ((tmpspan < end_span) &&
Packit Service 2781ba
             (tmpspan->y < pbox->y2))
Packit Service 2781ba
        {
Packit Service 2781ba
          y     = tmpspan->y;
Packit Service 2781ba
          left  = tmpspan->x;
Packit Service 2781ba
          right = left + tmpspan->width; /* right is not in the span! */
Packit Service 2781ba
Packit Service 2781ba
          if ((right > pbox->x1) && (left < pbox->x2))
Packit Service 2781ba
            {
Packit Service 2781ba
              clipped_left  = MAX (left, pbox->x1);
Packit Service 2781ba
              clipped_right = MIN (right, pbox->x2);
Packit Service 2781ba
Packit Service 2781ba
              out_span.y     = y;
Packit Service 2781ba
              out_span.x     = clipped_left;
Packit Service 2781ba
              out_span.width = clipped_right - clipped_left;
Packit Service 2781ba
              (*function)(&out_span, data);
Packit Service 2781ba
            }
Packit Service 2781ba
Packit Service 2781ba
          tmpspan++;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /* Finished this rectangle.
Packit Service 2781ba
       * The spans could still intersect the next one
Packit Service 2781ba
       */
Packit Service 2781ba
      pbox++;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
void
Packit Service 2781ba
gegl_region_dump (GeglRegion *region)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRectangle *rectangles   = NULL;
Packit Service 2781ba
  gint           n_rectangles = 0;
Packit Service 2781ba
  gint           i;
Packit Service 2781ba
Packit Service 2781ba
  gegl_region_get_rectangles (region, &rectangles, &n_rectangles);
Packit Service 2781ba
Packit Service 2781ba
  g_print ("GeglRegion %p:\n", region);
Packit Service 2781ba
  for (i = 0; i < n_rectangles; i++)
Packit Service 2781ba
    g_print ("  { %d, %d, %dx%d },\n",
Packit Service 2781ba
             rectangles[i].x,
Packit Service 2781ba
             rectangles[i].y,
Packit Service 2781ba
             rectangles[i].width,
Packit Service 2781ba
             rectangles[i].height);
Packit Service 2781ba
Packit Service 2781ba
  g_free (rectangles);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
#define __GEGL_REGION_GENERIC_C__