Esempio n. 1
0
/*
 * SP-GiST choose function
 */
Datum
spg_box_quad_choose(PG_FUNCTION_ARGS)
{
	spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
	spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
	BOX		   *centroid = DatumGetBoxP(in->prefixDatum),
			   *box = DatumGetBoxP(in->datum);

	out->resultType = spgMatchNode;
	out->result.matchNode.restDatum = BoxPGetDatum(box);

	/* nodeN will be set by core, when allTheSame. */
	if (!in->allTheSame)
		out->result.matchNode.nodeN = getQuadrant(centroid, box);

	PG_RETURN_VOID();
}
Esempio n. 2
0
SegmentPoint*
GenericEllipse::makeSegmentPoint(
    const Point2D& p,
    const GenericShapeElement* parent2) const
{
    float t2;

    if (parent2->containsPoint(p, t2))
    {
        const GenericArc* parent = getQuadrant(p);
        return new SegmentPoint(p, parent->getT(p), parent, t2, parent2);
    }
    else
    {
        parent2->containsPoint(p, t2);
        throw error::ConsistencyError(
            "GenericEllipse::makeSegmentPoint: Point is not part of parent2");
    }
}
void mapQuadTreeAbstraction::addNodes(graph *g)
{
	node_iterator ni = abstractions.back()->getNodeIter();
	for (node *next = abstractions.back()->nodeIterNext(ni); next;
			 next = abstractions.back()->nodeIterNext(ni))
	{
		// if it isn't abstracted, do a bfs according to the quadrant and abstract these nodes together
		if (next->getLabelL(kParent) == -1)
		{
			node *parent;
			g->addNode(parent = new node("??"));
			parent->setLabelL(kAbstractionLevel, next->getLabelL(kAbstractionLevel)+1); // level in abstraction tree
			parent->setLabelL(kNumAbstractedNodes, 0); // number of abstracted nodes
			parent->setLabelL(kParent, -1); // parent of this node in abstraction hierarchy
			parent->setLabelF(kXCoordinate, kUnknownPosition);
			parent->setLabelL(kNodeBlocked, 0);
			abstractionBFS(next, parent, getQuadrant(next));
		}
	}
}
Esempio n. 4
0
int main () {

	double x, y;
	int quadrant;
	char againResponse;
	int exitApp = 0;

	while (exitApp == 0) {

		printf("Enter X coordinate: ");
		scanf("%lf", &x);
		printf("Enter Y coordinate: ");
		scanf("%lf", &y);

		quadrant = getQuadrant(x, y);

		if (quadrant == -1) {
			printf("The point (%lf, %lf) lies on the x-axis\n", x, y);
		} else if (quadrant == -2) {
			printf("The point (%lf, %lf) lies on the y-axis\n", x, y);
		} else if (quadrant == -3) {
			printf("The point (%lf, %lf) is at the origin\n", x, y);
		} else {
			printf("Coordinate (%lf, %lf) is in quadrant %d\n", x, y, quadrant);
		}

		printf("Enter another coordinate? (y/n): ");
		scanf(" %c", &againResponse);

		if (againResponse == 'n') {
			printf("Goodbye\n");
			exitApp = 1;
		} else if (againResponse != 'y') {
			printf("Response not reognised. Exiting application.\n");
			exitApp = 1;
		}

	}
	return 0;

}
Esempio n. 5
0
Datum
spg_quad_inner_consistent(PG_FUNCTION_ARGS)
{
	spgInnerConsistentIn	*in = (spgInnerConsistentIn*)PG_GETARG_POINTER(0);
	spgInnerConsistentOut	*out = (spgInnerConsistentOut*)PG_GETARG_POINTER(1);
	Point					*query,
							*centroid;

	query = DatumGetPointP(in->query);
	Assert(in->hasPrefix);
	centroid = DatumGetPointP(in->prefixDatum);


	out->levelAdd = 0;

	out->nodeNumbers = palloc(sizeof(int));
	out->nNodes = 1;
	out->nodeNumbers[0] = getQuadrant(centroid, query) - 1;

	PG_RETURN_VOID();
}
Esempio n. 6
0
NameTableTile Background::getTile(int x, int y, int nametable)
{
	// Get true X,Y
	if (mirrorPositions[mirrorType][nametable][0])
	{
		x += 32;
	}
	if (mirrorPositions[mirrorType][nametable][1])
	{
		y += 30;
	}
	if (x > 64)
		int test = 0;
	// If this new X,Y is out of bounds, make it wrap around back from the top-left
	x %= mirrorSizes[mirrorType][0];
	y %= mirrorSizes[mirrorType][1];
	// Find which quadrant this ultimately falls into
	int quadrant = getQuadrant(x, y);
	// Reset X&Y to local quadrant coordinates
	x %= 32;
	y %= 30;
	return quadrants[mirrorLayouts[mirrorType][quadrant]].tiles[(y * 32) + x];
}
Esempio n. 7
0
Datum
spg_quad_inner_consistent(PG_FUNCTION_ARGS)
{
	spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
	spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
	Point	   *query,
			   *centroid;
	BOX		   *boxQuery;

	query = DatumGetPointP(in->query);
	Assert(in->hasPrefix);
	centroid = DatumGetPointP(in->prefixDatum);

	if (in->allTheSame)
	{
		/* Report that all nodes should be visited */
		int		i;

		out->nNodes = in->nNodes;
		out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
		for (i = 0; i < in->nNodes; i++)
			out->nodeNumbers[i] = i;
		PG_RETURN_VOID();
	}

	Assert(in->nNodes == 4);
	out->nodeNumbers = (int *) palloc(sizeof(int) * 4);

	switch (in->strategy)
	{
		case RTLeftStrategyNumber:
			setNodes(out, SPTEST(point_left, centroid, query), 3, 4);
			break;
		case RTRightStrategyNumber:
			setNodes(out, SPTEST(point_right, centroid, query), 1, 2);
			break;
		case RTSameStrategyNumber:
			out->nNodes = 1;
			out->nodeNumbers[0] = getQuadrant(centroid, query) - 1;
			break;
		case RTBelowStrategyNumber:
			setNodes(out, SPTEST(point_below, centroid, query), 2, 3);
			break;
		case RTAboveStrategyNumber:
			setNodes(out, SPTEST(point_above, centroid, query), 1, 4);
			break;
		case RTContainedByStrategyNumber:

			/*
			 * For this operator, the query is a box not a point.  We cheat to
			 * the extent of assuming that DatumGetPointP won't do anything
			 * that would be bad for a pointer-to-box.
			 */
			boxQuery = DatumGetBoxP(in->query);

			if (DatumGetBool(DirectFunctionCall2(box_contain_pt,
												 PointerGetDatum(boxQuery),
												 PointerGetDatum(centroid))))
			{
				/* centroid is in box, so descend to all quadrants */
				setNodes(out, true, 0, 0);
			}
			else
			{
				/* identify quadrant(s) containing all corners of box */
				Point		p;
				int			i,
							r = 0;

				p = boxQuery->low;
				r |= 1 << (getQuadrant(centroid, &p) - 1);

				p.y = boxQuery->high.y;
				r |= 1 << (getQuadrant(centroid, &p) - 1);

				p = boxQuery->high;
				r |= 1 << (getQuadrant(centroid, &p) - 1);

				p.x = boxQuery->low.x;
				r |= 1 << (getQuadrant(centroid, &p) - 1);

				/* we must descend into those quadrant(s) */
				out->nNodes = 0;
				for (i = 0; i < 4; i++)
				{
					if (r & (1 << i))
					{
						out->nodeNumbers[out->nNodes] = i;
						out->nNodes++;
					}
				}
			}
			break;
		default:
			elog(ERROR, "unrecognized strategy number: %d", in->strategy);
			break;
	}

	PG_RETURN_VOID();
}
Esempio n. 8
0
Datum
spgist_geom_inner_consistent(PG_FUNCTION_ARGS)
{
	spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
	spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
        BOX2DF *centroidbox_p;
	int which;
	int i;
   
	if (in->allTheSame)
	{
		/* Report that all nodes should be visited */
		out->nNodes = in->nNodes;
		out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
		for (i = 0; i < in->nNodes; i++)
			out->nodeNumbers[i] = i;
		PG_RETURN_VOID();
	}

	Assert(in->hasPrefix);

        centroidbox_p = (BOX2DF *)in->prefixDatum;

	Assert(in->nNodes == 4);

	/* "which" is a bitmask of quadrants that satisfy all constraints */
	which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);

	for (i = 0; i < in->nkeys; i++)
	{
                BOX2DF box;
                BOX2DF *box_p = &box;
                gserialized_datum_get_box2df_p(in->scankeys[i].sk_argument, box_p);

		switch (in->scankeys[i].sk_strategy)
		{
			case RTLeftStrategyNumber:
                                if (box2df_left(box_p, centroidbox_p))
                                        which &= (1 << 3) | (1 << 4);
				break;
			case RTRightStrategyNumber:
                                if (box2df_right(box_p, centroidbox_p))
					which &= (1 << 1) | (1 << 2);
				break;
			/* case RTSameStrategyNumber: */
			/* 	which &= (1 << getQuadrant(centroidbox_p, box_p)); */
			/* 	break; */
			case RTBelowStrategyNumber:
                                if (box2df_below(centroidbox_p, box_p))
					which &= (1 << 2) | (1 << 3);
				break;
			case RTAboveStrategyNumber:
                                if (box2df_above(centroidbox_p, box_p))
					which &= (1 << 1) | (1 << 4);
				break;
			case RTContainedByStrategyNumber:

                                if (box2df_contains(box_p, centroidbox_p))
				{
					/* centroid is in box, so all quadrants are OK */
				}
				else
				{
					/* identify quadrant(s) containing all corners of box */
					POINT2D	p;
                                        BOX2DF b;
                                        BOX2DF *b_p = &b;
					int r = 0;

                                        b_p->xmin = b_p->xmax = box_p->xmin;
                                        b_p->ymin = b_p->ymax = box_p->ymin;

					r |= 1 << getQuadrant(centroidbox_p, b_p);

                                        b_p->xmin = b_p->xmax = box_p->xmax;
                                        b_p->ymin = b_p->ymax = box_p->ymin;

					r |= 1 << getQuadrant(centroidbox_p, b_p);

                                        b_p->xmin = b_p->xmax = box_p->xmax;
                                        b_p->ymin = b_p->ymax = box_p->ymax;

					r |= 1 << getQuadrant(centroidbox_p, b_p);

                                        b_p->xmin = b_p->xmax = box_p->xmin;
                                        b_p->ymin = b_p->ymax = box_p->ymax;

					r |= 1 << getQuadrant(centroidbox_p, b_p);

					which &= r;
				}
				break;
			default:
				elog(ERROR, "unrecognized strategy number: %d",
					 in->scankeys[i].sk_strategy);
				break;
		}

		if (which == 0)
			break;				/* no need to consider remaining conditions */
	}

	/* We must descend into the quadrant(s) identified by which */
	out->nodeNumbers = (int *) palloc(sizeof(int) * 4);
	out->nNodes = 0;
	for (i = 1; i <= 4; i++)
	{
		if (which & (1 << i))
			out->nodeNumbers[out->nNodes++] = i - 1;
	}

	PG_RETURN_VOID();
}
Esempio n. 9
0
/*
 * SP-GiST pick-split function
 *
 * It splits a list of boxes into quadrants by choosing a central 4D
 * point as the median of the coordinates of the boxes.
 */
Datum
spg_box_quad_picksplit(PG_FUNCTION_ARGS)
{
	spgPickSplitIn	*in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
	spgPickSplitOut	*out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
	BOX		   *centroid;
	int			median,
				i;
	double	   *lowXs = palloc(sizeof(double) * in->nTuples);
	double	   *highXs = palloc(sizeof(double) * in->nTuples);
	double	   *lowYs = palloc(sizeof(double) * in->nTuples);
	double	   *highYs = palloc(sizeof(double) * in->nTuples);

	/* Calculate median of all 4D coordinates */
	for (i = 0; i < in->nTuples; i++)
	{
		BOX  *box = DatumGetBoxP(in->datums[i]);

		lowXs[i] = box->low.x;
		highXs[i] = box->high.x;
		lowYs[i] = box->low.y;
		highYs[i] = box->high.y;
	}

	qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
	qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
	qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
	qsort(highYs, in->nTuples, sizeof(double), compareDoubles);

	median = in->nTuples / 2;

	centroid = palloc(sizeof(BOX));

	centroid->low.x = lowXs[median];
	centroid->high.x = highXs[median];
	centroid->low.y = lowYs[median];
	centroid->high.y = highYs[median];

	/* Fill the output */
	out->hasPrefix = true;
	out->prefixDatum = BoxPGetDatum(centroid);

	out->nNodes = 16;
	out->nodeLabels = NULL;		/* We don't need node labels. */

	out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
	out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);

	/*
	 * Assign ranges to corresponding nodes according to quadrants
	 * relative to the "centroid" range
	 */
	for (i = 0; i < in->nTuples; i++)
	{
		BOX  *box = DatumGetBoxP(in->datums[i]);
		uint8 quadrant = getQuadrant(centroid, box);

		out->leafTupleDatums[i] = BoxPGetDatum(box);
		out->mapTuplesToNodes[i] = quadrant;
	}

	PG_RETURN_VOID();
}
Esempio n. 10
0
void setStencil(Geometry *geometry, int mu, int k, enum direction wind)
{
  register int l, m, n;

  int     l0, m0, k0, countXZ, countYZ, count, Nvalid;
  bool_t *valid;
  double  rx, ry, rz, frac1, frac2, muz, dz, longfracx, longfracy,
          svalid;
  Stencil *st;
  Longchar *lc;
  Intersect *vis;
  
  /* --- Fill interpolation stencil:

         Determine largest grid coordinate with x1_grid < x1_intersect 
         and x2_grid < x2_intersect, then fill stencil with addresses 
         of interpolation points surrounding the point of intersection.
     --                                                -------------- */

  if (wind == UPWIND) {
    st = &geometry->stencil_uw[mu][k];
    dz = geometry->z[k - 1] - geometry->z[k];
  } else {
    st = &geometry->stencil_dw[mu][k];
    dz = geometry->z[k] - geometry->z[k + 1];
  }
  muz = sqrt(1.0 - (SQ(geometry->mux[mu]) + SQ(geometry->muy[mu])));
  rx  = geometry->mux[mu] / geometry->dx;
  ry  = geometry->muy[mu] / geometry->dy;
  rz  = muz / dz;

  /* --- Calculate quadrant ray point to --            -------------- */
  
  st->quadrant = getQuadrant(geometry->mux[mu], geometry->muy[mu], wind);

  /* --- Determine which is the nearest plane in direction of ray - - */

  st->plane = getIntersect(rx, ry, rz);

  /* --- Determine fractions and distance between gridpoint and
         point where ray intersects nearest plane --   -------------- */

  calcFrac(&frac1, &frac2, rx, ry, rz, st->plane, wind);
  st->ds = calcDistance(frac1, frac2, st->plane,
			geometry->dx, geometry->dy, dz);

  switch (st->plane){
  case XY:
    st->zbase[0] = (wind == UPWIND) ?  k - 1  :  k + 1;

    l0 = floor(frac1);
    frac1 -= l0;

    m0 = floor(frac2);
    frac2 -= m0;

    switch (input.interpolate_3D) {
    case LINEAR_3D:
      st->xbase[0] = l0;
      st->xbase[1] = l0 + 1;
      st->xkernel[0] = 1.0 - frac1;
      st->xkernel[1] = frac1;

      st->ybase[0] = m0;
      st->ybase[1] = m0 + 1;
      st->ykernel[0] = 1.0 - frac2;
      st->ykernel[1] = frac2;
      break;

    case BICUBIC_3D:
      for (l = 0;  l < NCC;  l++) st->xbase[l] = l0 - 1 + l;
      cc_kernel(frac1, st->xkernel);

      for (m = 0;  m < NCC;  m++) st->ybase[m] = m0 - 1 + m;
      cc_kernel(frac2, st->ykernel);
    }
    break;

  case XZ:
    st->ybase[0] = (st->quadrant == 1 || st->quadrant == 2) ?  1  :  -1;

    l0 = floor(frac1);
    frac1 -= l0;

    if (frac2 < 0.0) {
      k0 = k + 1;
      frac2 += 1.0;
    } else
      k0 = k;

    st->xbase[0] = l0;
    st->xbase[1] = l0 + 1;
    st->xkernel[0] = 1.0 - frac1;
    st->xkernel[1] = frac1;

    st->zbase[0] = k0;
    st->zbase[1] = k0 - 1;
    st->zkernel[0] = 1.0 - frac2;
    st->zkernel[1] = frac2;
    break;

  case YZ:
    st->xbase[0] = (st->quadrant == 1 || st->quadrant == 4) ?  1  :  -1;

    m0 = floor(frac1);
    frac1 -= m0;

    if (frac2 < 0.0) {
      k0 = k + 1;
      frac2 += 1.0;
    } else
      k0 = k;

    st->ybase[0] = m0;
    st->ybase[1] = m0 + 1;
    st->ykernel[0] = 1.0 - frac1;
    st->ykernel[1] = frac1;

    st->zbase[0] = k0;
    st->zbase[1] = k0 - 1;
    st->zkernel[0] = 1.0 - frac2;
    st->zkernel[1] = frac2;
  }

  st->longchar = NULL;

  /* --- If XZ or YZ plane is hit first, fill long characteristic  
         structures --                                 -------------- */

  if (st->plane == YZ || st->plane == XZ) {
    if (wind == UPWIND) {
      longfracx = rx / rz;
      longfracy = ry / rz;
    } else {
      longfracx = -rx / rz;
      longfracy = -ry / rz;
    }
    /* --- Determine number of crossings of YZ and XZ planes,
           respectively, before XY plane is crossed -- -------------- */

    countYZ = (int) floor(fabs(longfracx));
    countXZ = (int) floor(fabs(longfracy));

    /* --- Tabulate the vertical intersects --         -------------- */

    vis = (Intersect *) malloc((countYZ + countXZ) * sizeof(Intersect));

    count = 0;
    for (l = 0;  l < countYZ;  l++) {
      vis[count].plane = YZ;
      vis[count].s     = ((l+1) * geometry->dx) / fabs(geometry->mux[mu]);
      vis[count].x     = geometry->mux[mu] * vis[count].s;
      vis[count].y     = geometry->muy[mu] * vis[count].s;
      vis[count].z     = muz * vis[count].s;
      count++;
    }
    for (m = 0;  m < countXZ;  m++) {
      vis[count].plane = XZ;
      vis[count].s     = ((m+1) * geometry->dy) / fabs(geometry->muy[mu]);
      vis[count].x     = geometry->mux[mu] * vis[count].s;
      vis[count].y     = geometry->muy[mu] * vis[count].s;
      vis[count].z     = muz * vis[count].s;
      count++;
    }
    /* --- Sort the intersections according to distance s from the
           point of origin --                          -------------- */

    qsort(vis, count, sizeof(Intersect), sascend);

    /* --- Determine if any of the intersections appear too close to
           one another, for instance when they occur on an intersection
           between YZ and XZ planes --                 -------------- */

    Nvalid = count;
    valid  = (bool_t *) malloc(Nvalid * sizeof(bool_t));
    valid[0] = TRUE;
    for (n = 1;  n < count;  n++) {
      if ((vis[n].s - vis[n-1].s) <
	  MIN_FRAC * MIN(geometry->dx, geometry->dy)) {
	valid[n] = FALSE;
	Nvalid--;
      } else
	valid[n] = TRUE;
    }

    st->longchar = (Longchar *) malloc(sizeof(Longchar));
    lc = st->longchar;
    lc->Nst = Nvalid + 1;
    lc->stencil = (Stencil *) malloc(lc->Nst * sizeof(Stencil));

    /* --- The first stencil to be stored is the intersection with
           the horizontal XY plane, ds is the distance to the first
           valid vertical intersection --              -------------- */

    lc->stencil[0].plane = XY;
    n = count;
    do {
      n--;
      lc->stencil[0].ds = dz / muz - vis[n].s;
    } while (!valid[n]);
    svalid = vis[n].s;

    l0 = floor(longfracx);
    frac1 = longfracx - l0;
    m0 = floor(longfracy);
    frac2 = longfracy - m0;

    switch (input.interpolate_3D) {
    case LINEAR_3D:
      lc->stencil[0].xbase[0] = l0;
      lc->stencil[0].xbase[1] = l0 + 1;
      lc->stencil[0].xkernel[0] = 1.0 - frac1;
      lc->stencil[0].xkernel[1] = frac1;

      lc->stencil[0].ybase[0] = m0;
      lc->stencil[0].ybase[1] = m0 + 1;
      lc->stencil[0].ykernel[0] = 1.0 - frac2;
      lc->stencil[0].ykernel[1] = frac2;

      break;
    case BICUBIC_3D:
      for (l = 0;  l < NCC;  l++) lc->stencil[0].xbase[l] = l0 - 1 + l;
      cc_kernel(frac1, lc->stencil[0].xkernel);

      for (m = 0;  m < NCC;  m++) lc->stencil[0].ybase[m] = m0 - 1 + m;
      cc_kernel(frac2, lc->stencil[0].ykernel);
    }
    lc->stencil[0].zbase[0] = (wind == UPWIND) ?  k - 1  :  k + 1;

    count = 1;
    for (n = (countXZ + countYZ)-1;  n >= 0;  n--) {
      if (valid[n]) {
	lc->stencil[count].plane = vis[n].plane;
	if (count == Nvalid)
	  lc->stencil[count].ds = svalid;
	else {
	  lc->stencil[count].ds = svalid - vis[n-1].s;
	  svalid = vis[n-1].s;
	}

	switch (vis[n].plane) {
        case XZ:
          l0 = floor(vis[n].x / geometry->dx);
          lc->stencil[count].xbase[0] = l0;
          lc->stencil[count].xbase[1] = l0 + 1;
          frac1 = vis[n].x / geometry->dx - l0;
          lc->stencil[count].xkernel[0] = 1.0 - frac1;
	  lc->stencil[count].xkernel[1] = frac1;

          lc->stencil[count].ybase[0] =
	    (int) round(vis[n].y / geometry->dy);
	  break;

        case YZ:
          lc->stencil[count].xbase[0] =
	    (int) round(vis[n].x / geometry->dx);

          m0 = floor(vis[n].y / geometry->dy);
          lc->stencil[count].ybase[0] = m0;
          lc->stencil[count].ybase[1] = m0 + 1;
          frac1 = vis[n].y / geometry->dy - m0;
          lc->stencil[count].ykernel[0] = 1.0 - frac1;
	  lc->stencil[count].ykernel[1] = frac1;
	}

	if (wind == UPWIND) {
	  lc->stencil[count].zbase[0] = k;
	  lc->stencil[count].zbase[1] = k - 1;
	  frac2 = vis[n].z / dz;
	} else {
	  lc->stencil[count].zbase[0] = k + 1;
	  lc->stencil[count].zbase[1] = k;
	  frac2 = 1.0 - vis[n].z / dz;
	}
	lc->stencil[count].zkernel[0] = 1.0 - frac2;
	lc->stencil[count].zkernel[1] = frac2;

	count++;
      }
    }
    /* --- Free temporary arrays --                    -------------- */

    free(vis);
    free(valid);

    /* --- Store total number of long characteristics to be used - -- */

    if (st->plane == YZ)
      geometry->Nlongchar += geometry->Ny;
    else
      geometry->Nlongchar += geometry->Nx;

  }
}
Esempio n. 11
0
/*
 * SP-GiST consistent function for inner nodes: check which nodes are
 * consistent with given set of queries.
 */
Datum
spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
{
	spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
	spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
	int			which;
	int			i;

	if (in->allTheSame)
	{
		/* Report that all nodes should be visited */
		out->nNodes = in->nNodes;
		out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
		for (i = 0; i < in->nNodes; i++)
			out->nodeNumbers[i] = i;
		PG_RETURN_VOID();
	}

	if (!in->hasPrefix)
	{
		/*
		 * No centroid on this inner node. Such a node has two child nodes,
		 * the first for empty ranges, and the second for non-empty ones.
		 */
		Assert(in->nNodes == 2);

		/*
		 * Nth bit of which variable means that (N - 1)th node should be
		 * visited. Initially all bits are set. Bits of nodes which should be
		 * skipped will be unset.
		 */
		which = (1 << 1) | (1 << 2);
		for (i = 0; i < in->nkeys; i++)
		{
			StrategyNumber strategy = in->scankeys[i].sk_strategy;
			bool		empty;

			/*
			 * The only strategy when second argument of operator is not range
			 * is RANGESTRAT_CONTAINS_ELEM.
			 */
			if (strategy != RANGESTRAT_CONTAINS_ELEM)
				empty = RangeIsEmpty(
							 DatumGetRangeType(in->scankeys[i].sk_argument));
			else
				empty = false;

			switch (strategy)
			{
				case RANGESTRAT_BEFORE:
				case RANGESTRAT_OVERLEFT:
				case RANGESTRAT_OVERLAPS:
				case RANGESTRAT_OVERRIGHT:
				case RANGESTRAT_AFTER:
					/* These strategies return false if any argument is empty */
					if (empty)
						which = 0;
					else
						which &= (1 << 2);
					break;

				case RANGESTRAT_CONTAINS:
					/*
					 * All ranges contain an empty range. Only non-empty ranges
					 * can contain a non-empty range.
					 */
					if (!empty)
						which &= (1 << 2);
					break;

				case RANGESTRAT_CONTAINED_BY:
					/*
					 * Only an empty range is contained by an empty range. Both
					 * empty and non-empty ranges can be contained by a
					 * non-empty range.
					 */
					if (empty)
						which &= (1 << 1);
					break;

				case RANGESTRAT_CONTAINS_ELEM:
					which &= (1 << 2);
					break;

				case RANGESTRAT_EQ:
					if (empty)
						which &= (1 << 1);
					else
						which &= (1 << 2);
					break;

				default:
					elog(ERROR, "unrecognized range strategy: %d", strategy);
					break;
			}
			if (which == 0)
				break;			/* no need to consider remaining conditions */
		}
	}
	else
	{
		RangeBound	centroidLower,
					centroidUpper;
		bool		centroidEmpty;
		TypeCacheEntry *typcache;
		RangeType  *centroid;

		/* This node has a centroid. Fetch it. */
		centroid = DatumGetRangeType(in->prefixDatum);
		typcache = range_get_typcache(fcinfo,
							   RangeTypeGetOid(DatumGetRangeType(centroid)));
		range_deserialize(typcache, centroid, &centroidLower, &centroidUpper,
						  &centroidEmpty);

		Assert(in->nNodes == 4 || in->nNodes == 5);

		/*
		 * Nth bit of which variable means that (N - 1)th node (Nth quadrant)
		 * should be visited. Initially all bits are set. Bits of nodes which
		 * can be skipped will be unset.
		 */
		which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);

		for (i = 0; i < in->nkeys; i++)
		{
			StrategyNumber strategy;
			RangeBound	lower,
						upper;
			bool		empty;
			RangeType  *range = NULL;
			/* Restrictions on range bounds according to scan strategy */
			RangeBound *minLower = NULL,
					   *maxLower = NULL,
					   *minUpper = NULL,
					   *maxUpper = NULL;
			/* Are the restrictions on range bounds inclusive? */
			bool		inclusive = true;
			bool		strictEmpty = true;

			strategy = in->scankeys[i].sk_strategy;

			/*
			 * RANGESTRAT_CONTAINS_ELEM is just like RANGESTRAT_CONTAINS, but
			 * the argument is a single element. Expand the single element to
			 * a range containing only the element, and treat it like
			 * RANGESTRAT_CONTAINS.
			 */
			if (strategy == RANGESTRAT_CONTAINS_ELEM)
			{
				lower.inclusive = true;
				lower.infinite = false;
				lower.lower = true;
				lower.val = in->scankeys[i].sk_argument;

				upper.inclusive = true;
				upper.infinite = false;
				upper.lower = false;
				upper.val = in->scankeys[i].sk_argument;

				empty = false;

				strategy = RANGESTRAT_CONTAINS;
			}
			else
			{
				range = DatumGetRangeType(in->scankeys[i].sk_argument);
				range_deserialize(typcache, range, &lower, &upper, &empty);
			}

			/*
			 * Most strategies are handled by forming a bounding box from the
			 * search key, defined by a minLower, maxLower, minUpper, maxUpper.
			 * Some modify 'which' directly, to specify exactly which quadrants
			 * need to be visited.
			 *
			 * For most strategies, nothing matches an empty search key, and
			 * an empty range never matches a non-empty key. If a strategy
			 * does not behave like that wrt. empty ranges, set strictEmpty to
			 * false.
			 */
			switch (strategy)
			{
				case RANGESTRAT_BEFORE:
					/*
					 * Range A is before range B if upper bound of A is lower
					 * than lower bound of B.
					 */
					maxUpper = &lower;
					inclusive = false;
					break;

				case RANGESTRAT_OVERLEFT:
					/*
					 * Range A is overleft to range B if upper bound of A is
					 * less or equal to upper bound of B.
					 */
					maxUpper = &upper;
					break;

				case RANGESTRAT_OVERLAPS:
					/*
					 * Non-empty ranges overlap, if lower bound of each range
					 * is lower or equal to upper bound of the other range.
					 */
					maxLower = &upper;
					minUpper = &lower;
					break;

				case RANGESTRAT_OVERRIGHT:
					/*
					 * Range A is overright to range B if lower bound of A is
					 * greater or equal to lower bound of B.
					 */
					minLower = &lower;
					break;

				case RANGESTRAT_AFTER:
					/*
					 * Range A is after range B if lower bound of A is greater
					 * than upper bound of B.
					 */
					minLower = &upper;
					inclusive = false;
					break;

				case RANGESTRAT_CONTAINS:
					/*
					 * Non-empty range A contains non-empty range B if lower
					 * bound of A is lower or equal to lower bound of range B
					 * and upper bound of range A is greater or equal to upper
					 * bound of range A.
					 *
					 * All non-empty ranges contain an empty range.
					 */
					strictEmpty = false;
					if (!empty)
					{
						which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
						maxLower = &lower;
						minUpper = &upper;
					}
					break;

				case RANGESTRAT_CONTAINED_BY:
					/* The opposite of contains. */
					strictEmpty = false;
					if (empty)
					{
						/* An empty range is only contained by an empty range */
						which &= (1 << 5);
					}
					else
					{
						minLower = &lower;
						maxUpper = &upper;
					}
					break;

				case RANGESTRAT_EQ:
					/*
					 * Equal range can be only in the same quadrant where
					 * argument would be placed to.
					 */
					strictEmpty = false;
					which &= (1 << getQuadrant(typcache, centroid, range));
					break;

				default:
					elog(ERROR, "unrecognized range strategy: %d", strategy);
					break;
			}

			if (strictEmpty)
			{
				if (empty)
				{
					/* Scan key is empty, no branches are satisfying */
					which = 0;
					break;
				}
				else
				{
					/* Shouldn't visit tree branch with empty ranges */
					which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
				}
			}

			/*
			 * Using the bounding box, see which quadrants we have to descend
			 * into.
			 */
			if (minLower)
			{
				/*
				 * If the centroid's lower bound is less than or equal to
				 * the minimum lower bound, anything in the 3rd and 4th
				 * quadrants will have an even smaller lower bound, and thus
				 * can't match.
				 */
				if (range_cmp_bounds(typcache, &centroidLower, minLower) <= 0)
					which &= (1 << 1) | (1 << 2) | (1 << 5);
			}
			if (maxLower)
			{
				/*
				 * If the centroid's lower bound is greater than the maximum
				 * lower bound, anything in the 1st and 2nd quadrants will
				 * also have a greater than or equal lower bound, and thus
				 * can't match. If the centroid's lower bound is equal to
				 * the maximum lower bound, we can still exclude the 1st and
				 * 2nd quadrants if we're looking for a value strictly greater
				 * than the maximum.
				 */
				int			cmp;

				cmp = range_cmp_bounds(typcache, &centroidLower, maxLower);
				if (cmp > 0 || (!inclusive && cmp == 0))
					which &= (1 << 3) | (1 << 4) | (1 << 5);
			}
			if (minUpper)
			{
				/*
				 * If the centroid's upper bound is less than or equal to
				 * the minimum upper bound, anything in the 2nd and 3rd
				 * quadrants will have an even smaller upper bound, and thus
				 * can't match.
				 */
				if (range_cmp_bounds(typcache, &centroidUpper, minUpper) <= 0)
					which &= (1 << 1) | (1 << 4) | (1 << 5);
			}
			if (maxUpper)
			{
				/*
				 * If the centroid's upper bound is greater than the maximum
				 * upper bound, anything in the 1st and 4th quadrants will
				 * also have a greater than or equal upper bound, and thus
				 * can't match. If the centroid's upper bound is equal to
				 * the maximum upper bound, we can still exclude the 1st and
				 * 4th quadrants if we're looking for a value strictly greater
				 * than the maximum.
				 */
				int			cmp;

				cmp = range_cmp_bounds(typcache, &centroidUpper, maxUpper);
				if (cmp > 0 || (!inclusive && cmp == 0))
					which &= (1 << 2) | (1 << 3) | (1 << 5);
			}

			if (which == 0)
				break;			/* no need to consider remaining conditions */
		}
	}

	/* We must descend into the quadrant(s) identified by 'which' */
	out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
	out->nNodes = 0;
	for (i = 1; i <= in->nNodes; i++)
	{
		if (which & (1 << i))
			out->nodeNumbers[out->nNodes++] = i - 1;
	}

	PG_RETURN_VOID();
}
Esempio n. 12
0
/*
 * Picksplit SP-GiST function: split ranges into nodes. Select "centroid"
 * range and distribute ranges according to quadrants.
 */
Datum
spg_range_quad_picksplit(PG_FUNCTION_ARGS)
{
	spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
	spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
	int			i;
	int			j;
	int			nonEmptyCount;
	RangeType  *centroid;
	bool		empty;
	TypeCacheEntry *typcache;

	/* Use the median values of lower and upper bounds as the centroid range */
	RangeBound *lowerBounds,
			   *upperBounds;

	typcache = range_get_typcache(fcinfo,
						  RangeTypeGetOid(DatumGetRangeType(in->datums[0])));

	/* Allocate memory for bounds */
	lowerBounds = palloc(sizeof(RangeBound) * in->nTuples);
	upperBounds = palloc(sizeof(RangeBound) * in->nTuples);
	j = 0;

	/* Deserialize bounds of ranges, count non-empty ranges */
	for (i = 0; i < in->nTuples; i++)
	{
		range_deserialize(typcache, DatumGetRangeType(in->datums[i]),
						  &lowerBounds[j], &upperBounds[j], &empty);
		if (!empty)
			j++;
	}
	nonEmptyCount = j;

	/*
	 * All the ranges are empty. The best we can do is to construct an inner
	 * node with no centroid, and put all ranges into node 0. If non-empty
	 * ranges are added later, they will be routed to node 1.
	 */
	if (nonEmptyCount == 0)
	{
		out->nNodes = 2;
		out->hasPrefix = false;
		/* Prefix is empty */
		out->prefixDatum = PointerGetDatum(NULL);
		out->nodeLabels = NULL;

		out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
		out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);

		/* Place all ranges into node 0 */
		for (i = 0; i < in->nTuples; i++)
		{
			RangeType  *range = DatumGetRangeType(in->datums[i]);

			out->leafTupleDatums[i] = RangeTypeGetDatum(range);
			out->mapTuplesToNodes[i] = 0;
		}
		PG_RETURN_VOID();
	}

	/* Sort range bounds in order to find medians */
	qsort_arg(lowerBounds, nonEmptyCount, sizeof(RangeBound),
			  bound_cmp, typcache);
	qsort_arg(upperBounds, nonEmptyCount, sizeof(RangeBound),
			  bound_cmp, typcache);

	/* Construct "centroid" range from medians of lower and upper bounds */
	centroid = range_serialize(typcache, &lowerBounds[nonEmptyCount / 2],
							   &upperBounds[nonEmptyCount / 2], false);
	out->hasPrefix = true;
	out->prefixDatum = RangeTypeGetDatum(centroid);

	/* Create node for empty ranges only if it is a root node */
	out->nNodes = (in->level == 0) ? 5 : 4;
	out->nodeLabels = NULL;		/* we don't need node labels */

	out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
	out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);

	/*
	 * Assign ranges to corresponding nodes according to quadrants relative to
	 * "centroid" range.
	 */
	for (i = 0; i < in->nTuples; i++)
	{
		RangeType  *range = DatumGetRangeType(in->datums[i]);
		int16		quadrant = getQuadrant(typcache, centroid, range);

		out->leafTupleDatums[i] = RangeTypeGetDatum(range);
		out->mapTuplesToNodes[i] = quadrant - 1;
	}

	PG_RETURN_VOID();
}