cube.c 25.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/******************************************************************************
  This file contains routines that can be bound to a Postgres backend and
  called by the backend in the process of processing queries.  The calling
  format for these routines is dictated by Postgres architecture.
******************************************************************************/

#include "postgres.h"

#include <math.h>

#include "access/gist.h"
#include "access/rtree.h"
13
#include "lib/stringinfo.h"
14 15 16 17
#include "utils/builtins.h"

#include "cubedata.h"

B
Bruce Momjian 已提交
18
extern int	cube_yyparse();
19 20 21
extern void cube_yyerror(const char *message);
extern void cube_scanner_init(const char *str);
extern void cube_scanner_finish(void);
22 23 24 25

/*
** Input/Output routines
*/
B
Bruce Momjian 已提交
26
NDBOX	   *cube_in(char *str);
27
NDBOX	   *cube(text *str);
B
Bruce Momjian 已提交
28
char	   *cube_out(NDBOX * cube);
B
Bruce Momjian 已提交
29 30 31 32 33
NDBOX	   *cube_f8(double *);
NDBOX	   *cube_f8_f8(double *, double *);
NDBOX	   *cube_c_f8(NDBOX *, double *);
NDBOX	   *cube_c_f8_f8(NDBOX *, double *, double *);
int4		cube_dim(NDBOX * a);
34 35
double	   *cube_ll_coord(NDBOX * a, int4 n);
double	   *cube_ur_coord(NDBOX * a, int4 n);
36 37


B
Bruce Momjian 已提交
38
/*
39 40
** GiST support methods
*/
B
Bruce Momjian 已提交
41 42 43 44
bool		g_cube_consistent(GISTENTRY *entry, NDBOX * query, StrategyNumber strategy);
GISTENTRY  *g_cube_compress(GISTENTRY *entry);
GISTENTRY  *g_cube_decompress(GISTENTRY *entry);
float	   *g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result);
45
GIST_SPLITVEC *g_cube_picksplit(GistEntryVector *entryvec, GIST_SPLITVEC *v);
B
Bruce Momjian 已提交
46 47
bool		g_cube_leaf_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy);
bool		g_cube_internal_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy);
48
NDBOX	   *g_cube_union(GistEntryVector *entryvec, int *sizep);
B
Bruce Momjian 已提交
49 50
NDBOX	   *g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep);
bool	   *g_cube_same(NDBOX * b1, NDBOX * b2, bool *result);
51

52 53 54 55 56 57 58 59 60 61 62
/*
** B-tree support functions
*/
bool		cube_eq(NDBOX * a, NDBOX * b);
bool		cube_ne(NDBOX * a, NDBOX * b);
bool		cube_lt(NDBOX * a, NDBOX * b);
bool		cube_gt(NDBOX * a, NDBOX * b);
bool		cube_le(NDBOX * a, NDBOX * b);
bool		cube_ge(NDBOX * a, NDBOX * b);
int32		cube_cmp(NDBOX * a, NDBOX * b);

63
/*
64
** R-tree support functions
65
*/
B
Bruce Momjian 已提交
66 67 68 69 70
bool		cube_contains(NDBOX * a, NDBOX * b);
bool		cube_contained(NDBOX * a, NDBOX * b);
bool		cube_overlap(NDBOX * a, NDBOX * b);
NDBOX	   *cube_union(NDBOX * a, NDBOX * b);
NDBOX	   *cube_inter(NDBOX * a, NDBOX * b);
71 72
double	   *cube_size(NDBOX * a);
void		rt_cube_size(NDBOX * a, double *sz);
73 74 75 76

/*
** These make no sense for this type, but R-tree wants them
*/
B
Bruce Momjian 已提交
77 78 79 80
bool		cube_over_left(NDBOX * a, NDBOX * b);
bool		cube_over_right(NDBOX * a, NDBOX * b);
bool		cube_left(NDBOX * a, NDBOX * b);
bool		cube_right(NDBOX * a, NDBOX * b);
81 82 83 84

/*
** miscellaneous
*/
B
Bruce Momjian 已提交
85 86
bool		cube_lt(NDBOX * a, NDBOX * b);
bool		cube_gt(NDBOX * a, NDBOX * b);
87
double	   *cube_distance(NDBOX * a, NDBOX * b);
B
Bruce Momjian 已提交
88
bool		cube_is_point(NDBOX * a);
89
NDBOX	   *cube_enlarge(NDBOX * a, double *r, int4 n);
90

91

B
Bruce Momjian 已提交
92
/*
93 94
** Auxiliary funxtions
*/
95
static double distance_1D(double a1, double a2, double b1, double b2);
96 97 98 99 100 101 102 103 104 105 106


/*****************************************************************************
 * Input/Output functions
 *****************************************************************************/

/* NdBox = [(lowerleft),(upperright)] */
/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
NDBOX *
cube_in(char *str)
{
B
Bruce Momjian 已提交
107
	void	   *result;
108

109
	cube_scanner_init(str);
110

B
Bruce Momjian 已提交
111
	if (cube_yyparse(&result) != 0)
112 113 114
		cube_yyerror("bogus input");

	cube_scanner_finish();
115

B
Bruce Momjian 已提交
116
	return ((NDBOX *) result);
117 118
}

119 120 121 122 123 124
/* Allow conversion from text to cube to allow input of computed strings */
/* There may be issues with toasted data here. I don't know enough to be sure.*/
NDBOX *
cube(text *str)
{
	return cube_in(DatumGetCString(DirectFunctionCall1(textout,
B
Bruce Momjian 已提交
125
												 PointerGetDatum(str))));
126 127
}

128
char *
B
Bruce Momjian 已提交
129
cube_out(NDBOX * cube)
130
{
131 132
	StringInfoData buf;
	bool		equal = true;
B
Bruce Momjian 已提交
133 134
	int			dim = cube->dim;
	int			i;
B
Bruce Momjian 已提交
135
	int			ndig;
B
Bruce Momjian 已提交
136

137
	initStringInfo(&buf);
B
Bruce Momjian 已提交
138

139 140 141 142
	/*
	 * Get the number of digits to display.
	 */
	ndig = DBL_DIG + extra_float_digits;
B
Bruce Momjian 已提交
143 144
	if (ndig < 1)
		ndig = 1;
145

B
Bruce Momjian 已提交
146 147
	/*
	 * while printing the first (LL) corner, check if it is equal to the
148
	 * second one
B
Bruce Momjian 已提交
149
	 */
150
	appendStringInfoChar(&buf, '(');
B
Bruce Momjian 已提交
151 152
	for (i = 0; i < dim; i++)
	{
153 154
		if (i > 0)
			appendStringInfo(&buf, ", ");
155
		appendStringInfo(&buf, "%.*g", ndig, cube->x[i]);
B
Bruce Momjian 已提交
156
		if (cube->x[i] != cube->x[i + dim])
157
			equal = false;
B
Bruce Momjian 已提交
158
	}
159
	appendStringInfoChar(&buf, ')');
B
Bruce Momjian 已提交
160 161 162

	if (!equal)
	{
163 164
		appendStringInfo(&buf, ",(");
		for (i = 0; i < dim; i++)
B
Bruce Momjian 已提交
165
		{
166 167
			if (i > 0)
				appendStringInfo(&buf, ", ");
168
			appendStringInfo(&buf, "%.*g", ndig, cube->x[i + dim]);
B
Bruce Momjian 已提交
169
		}
170
		appendStringInfoChar(&buf, ')');
B
Bruce Momjian 已提交
171 172
	}

173
	return buf.data;
174 175 176 177
}


/*****************************************************************************
B
Bruce Momjian 已提交
178
 *						   GiST functions
179 180 181 182 183 184 185 186
 *****************************************************************************/

/*
** The GiST Consistent method for boxes
** Should return false if for all data items x below entry,
** the predicate x op query == FALSE, where op is the oper
** corresponding to strategy in the pg_amop table.
*/
B
Bruce Momjian 已提交
187
bool
188
g_cube_consistent(GISTENTRY *entry,
B
Bruce Momjian 已提交
189 190
				  NDBOX * query,
				  StrategyNumber strategy)
191
{
B
Bruce Momjian 已提交
192
	/*
193
	 * if entry is not leaf, use g_cube_internal_consistent, else use
B
Bruce Momjian 已提交
194 195 196
	 * g_cube_leaf_consistent
	 */
	if (GIST_LEAF(entry))
197 198
		return g_cube_leaf_consistent((NDBOX *) DatumGetPointer(entry->key),
									  query, strategy);
B
Bruce Momjian 已提交
199
	else
200 201
		return g_cube_internal_consistent((NDBOX *) DatumGetPointer(entry->key),
										  query, strategy);
202 203 204 205 206 207 208 209
}


/*
** The GiST Union method for boxes
** returns the minimal bounding box that encloses all the entries in entryvec
*/
NDBOX *
210
g_cube_union(GistEntryVector *entryvec, int *sizep)
211
{
212
	int			i;
B
Bruce Momjian 已提交
213 214 215 216 217 218
	NDBOX	   *out = (NDBOX *) NULL;
	NDBOX	   *tmp;

	/*
	 * fprintf(stderr, "union\n");
	 */
219
	tmp = (NDBOX *) DatumGetPointer(entryvec->vector[0].key);
B
Bruce Momjian 已提交
220 221 222 223 224 225

	/*
	 * sizep = sizeof(NDBOX); -- NDBOX has variable size
	 */
	*sizep = tmp->size;

226
	for (i = 1; i < entryvec->n; i++)
B
Bruce Momjian 已提交
227 228
	{
		out = g_cube_binary_union(tmp, (NDBOX *)
B
Bruce Momjian 已提交
229
								DatumGetPointer(entryvec->vector[i].key),
B
Bruce Momjian 已提交
230 231 232 233 234 235 236
								  sizep);
		if (i > 1)
			pfree(tmp);
		tmp = out;
	}

	return (out);
237 238 239 240 241 242
}

/*
** GiST Compress and Decompress methods for boxes
** do not do anything.
*/
243
GISTENTRY *
244 245
g_cube_compress(GISTENTRY *entry)
{
B
Bruce Momjian 已提交
246
	return (entry);
247 248
}

249
GISTENTRY *
250 251
g_cube_decompress(GISTENTRY *entry)
{
B
Bruce Momjian 已提交
252
	return (entry);
253 254 255 256 257 258 259 260 261
}

/*
** The GiST Penalty method for boxes
** As in the R-tree paper, we use change in area as our penalty metric
*/
float *
g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
{
262
	NDBOX	   *ud;
263
	double		tmp1,
B
Bruce Momjian 已提交
264 265
				tmp2;

266 267 268 269
	ud = cube_union((NDBOX *) DatumGetPointer(origentry->key),
					(NDBOX *) DatumGetPointer(newentry->key));
	rt_cube_size(ud, &tmp1);
	rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2);
270
	*result = (float) (tmp1 - tmp2);
271
	pfree(ud);
B
Bruce Momjian 已提交
272 273 274 275 276

	/*
	 * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
	 */
	return (result);
277 278 279 280 281 282
}



/*
** The GiST PickSplit method for boxes
B
Bruce Momjian 已提交
283
** We use Guttman's poly time split algorithm
284 285
*/
GIST_SPLITVEC *
286
g_cube_picksplit(GistEntryVector *entryvec,
B
Bruce Momjian 已提交
287
				 GIST_SPLITVEC *v)
288
{
B
Bruce Momjian 已提交
289 290 291 292 293 294 295 296 297 298 299
	OffsetNumber i,
				j;
	NDBOX	   *datum_alpha,
			   *datum_beta;
	NDBOX	   *datum_l,
			   *datum_r;
	NDBOX	   *union_d,
			   *union_dl,
			   *union_dr;
	NDBOX	   *inter_d;
	bool		firsttime;
300
	double		size_alpha,
B
Bruce Momjian 已提交
301 302 303
				size_beta,
				size_union,
				size_inter;
304
	double		size_waste,
B
Bruce Momjian 已提交
305
				waste;
306
	double		size_l,
B
Bruce Momjian 已提交
307 308 309 310 311 312 313 314
				size_r;
	int			nbytes;
	OffsetNumber seed_1 = 0,
				seed_2 = 0;
	OffsetNumber *left,
			   *right;
	OffsetNumber maxoff;

315
	/*
B
Bruce Momjian 已提交
316
	 * fprintf(stderr, "picksplit\n");
317
	 */
318
	maxoff = entryvec->n - 2;
B
Bruce Momjian 已提交
319 320 321 322 323 324 325 326 327
	nbytes = (maxoff + 2) * sizeof(OffsetNumber);
	v->spl_left = (OffsetNumber *) palloc(nbytes);
	v->spl_right = (OffsetNumber *) palloc(nbytes);

	firsttime = true;
	waste = 0.0;

	for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
	{
328
		datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[i].key);
B
Bruce Momjian 已提交
329 330
		for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
		{
331
			datum_beta = (NDBOX *) DatumGetPointer(entryvec->vector[j].key);
B
Bruce Momjian 已提交
332 333 334

			/* compute the wasted space by unioning these guys */
			/* size_waste = size_union - size_inter; */
335
			union_d = cube_union(datum_alpha, datum_beta);
B
Bruce Momjian 已提交
336
			rt_cube_size(union_d, &size_union);
337
			inter_d = cube_inter(datum_alpha, datum_beta);
B
Bruce Momjian 已提交
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
			rt_cube_size(inter_d, &size_inter);
			size_waste = size_union - size_inter;

			pfree(union_d);

			if (inter_d != (NDBOX *) NULL)
				pfree(inter_d);

			/*
			 * are these a more promising split than what we've already
			 * seen?
			 */

			if (size_waste > waste || firsttime)
			{
				waste = size_waste;
				seed_1 = i;
				seed_2 = j;
				firsttime = false;
			}
		}
359
	}
B
Bruce Momjian 已提交
360 361 362 363 364 365

	left = v->spl_left;
	v->spl_nleft = 0;
	right = v->spl_right;
	v->spl_nright = 0;

366
	datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[seed_1].key);
367 368
	datum_l = cube_union(datum_alpha, datum_alpha);
	rt_cube_size(datum_l, &size_l);
369
	datum_beta = (NDBOX *) DatumGetPointer(entryvec->vector[seed_2].key);
370 371
	datum_r = cube_union(datum_beta, datum_beta);
	rt_cube_size(datum_r, &size_r);
B
Bruce Momjian 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407

	/*
	 * Now split up the regions between the two seeds.	An important
	 * property of this split algorithm is that the split vector v has the
	 * indices of items to be split in order in its left and right
	 * vectors.  We exploit this property by doing a merge in the code
	 * that actually splits the page.
	 *
	 * For efficiency, we also place the new index tuple in this loop. This
	 * is handled at the very end, when we have placed all the existing
	 * tuples and i == maxoff + 1.
	 */

	maxoff = OffsetNumberNext(maxoff);
	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
	{
		/*
		 * If we've already decided where to place this item, just put it
		 * on the right list.  Otherwise, we need to figure out which page
		 * needs the least enlargement in order to store the item.
		 */

		if (i == seed_1)
		{
			*left++ = i;
			v->spl_nleft++;
			continue;
		}
		else if (i == seed_2)
		{
			*right++ = i;
			v->spl_nright++;
			continue;
		}

		/* okay, which page needs least enlargement? */
408
		datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[i].key);
409 410 411 412
		union_dl = cube_union(datum_l, datum_alpha);
		union_dr = cube_union(datum_r, datum_alpha);
		rt_cube_size(union_dl, &size_alpha);
		rt_cube_size(union_dr, &size_beta);
B
Bruce Momjian 已提交
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

		/* pick which page to add it to */
		if (size_alpha - size_l < size_beta - size_r)
		{
			pfree(datum_l);
			pfree(union_dr);
			datum_l = union_dl;
			size_l = size_alpha;
			*left++ = i;
			v->spl_nleft++;
		}
		else
		{
			pfree(datum_r);
			pfree(union_dl);
			datum_r = union_dr;
			size_r = size_alpha;
			*right++ = i;
			v->spl_nright++;
		}
433
	}
B
Bruce Momjian 已提交
434
	*left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
435

436 437
	v->spl_ldatum = PointerGetDatum(datum_l);
	v->spl_rdatum = PointerGetDatum(datum_r);
B
Bruce Momjian 已提交
438 439

	return v;
440 441 442 443 444 445
}

/*
** Equality method
*/
bool *
B
Bruce Momjian 已提交
446
g_cube_same(NDBOX * b1, NDBOX * b2, bool *result)
447
{
448
	if (cube_eq(b1, b2))
B
Bruce Momjian 已提交
449 450 451 452 453 454 455 456
		*result = TRUE;
	else
		*result = FALSE;

	/*
	 * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" ));
	 */
	return (result);
457 458
}

B
Bruce Momjian 已提交
459
/*
460 461
** SUPPORT ROUTINES
*/
B
Bruce Momjian 已提交
462 463 464 465
bool
g_cube_leaf_consistent(NDBOX * key,
					   NDBOX * query,
					   StrategyNumber strategy)
466
{
B
Bruce Momjian 已提交
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
	bool		retval;

	/*
	 * fprintf(stderr, "leaf_consistent, %d\n", strategy);
	 */
	switch (strategy)
	{
		case RTLeftStrategyNumber:
			retval = (bool) cube_left(key, query);
			break;
		case RTOverLeftStrategyNumber:
			retval = (bool) cube_over_left(key, query);
			break;
		case RTOverlapStrategyNumber:
			retval = (bool) cube_overlap(key, query);
			break;
		case RTOverRightStrategyNumber:
			retval = (bool) cube_over_right(key, query);
			break;
		case RTRightStrategyNumber:
			retval = (bool) cube_right(key, query);
			break;
		case RTSameStrategyNumber:
490
			retval = (bool) cube_eq(key, query);
B
Bruce Momjian 已提交
491 492 493 494 495 496 497 498 499 500 501
			break;
		case RTContainsStrategyNumber:
			retval = (bool) cube_contains(key, query);
			break;
		case RTContainedByStrategyNumber:
			retval = (bool) cube_contained(key, query);
			break;
		default:
			retval = FALSE;
	}
	return (retval);
502 503
}

B
Bruce Momjian 已提交
504 505 506 507
bool
g_cube_internal_consistent(NDBOX * key,
						   NDBOX * query,
						   StrategyNumber strategy)
508
{
B
Bruce Momjian 已提交
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
	bool		retval;

	/*
	 * fprintf(stderr, "internal_consistent, %d\n", strategy);
	 */
	switch (strategy)
	{
		case RTLeftStrategyNumber:
		case RTOverLeftStrategyNumber:
			retval = (bool) cube_over_left(key, query);
			break;
		case RTOverlapStrategyNumber:
			retval = (bool) cube_overlap(key, query);
			break;
		case RTOverRightStrategyNumber:
		case RTRightStrategyNumber:
			retval = (bool) cube_right(key, query);
			break;
		case RTSameStrategyNumber:
		case RTContainsStrategyNumber:
			retval = (bool) cube_contains(key, query);
			break;
		case RTContainedByStrategyNumber:
			retval = (bool) cube_overlap(key, query);
			break;
		default:
			retval = FALSE;
	}
	return (retval);
538 539 540
}

NDBOX *
B
Bruce Momjian 已提交
541
g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep)
542
{
B
Bruce Momjian 已提交
543
	NDBOX	   *retval;
544

B
Bruce Momjian 已提交
545 546
	retval = cube_union(r1, r2);
	*sizep = retval->size;
547

B
Bruce Momjian 已提交
548
	return (retval);
549 550 551 552
}


/* cube_union */
B
Bruce Momjian 已提交
553
NDBOX *
554
cube_union(NDBOX * a, NDBOX * b)
555
{
B
Bruce Momjian 已提交
556 557 558 559 560 561
	int			i;
	NDBOX	   *result;

	if (a->dim >= b->dim)
	{
		result = palloc(a->size);
B
Bruce Momjian 已提交
562
		memset(result, 0, a->size);
B
Bruce Momjian 已提交
563 564 565 566 567 568
		result->size = a->size;
		result->dim = a->dim;
	}
	else
	{
		result = palloc(b->size);
B
Bruce Momjian 已提交
569
		memset(result, 0, b->size);
B
Bruce Momjian 已提交
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
		result->size = b->size;
		result->dim = b->dim;
	}

	/* swap the box pointers if needed */
	if (a->dim < b->dim)
	{
		NDBOX	   *tmp = b;

		b = a;
		a = tmp;
	}

	/*
	 * use the potentially smaller of the two boxes (b) to fill in the
	 * result, padding absent dimensions with zeroes
	 */
	for (i = 0; i < b->dim; i++)
	{
589 590
		result->x[i] = Min(b->x[i], b->x[i + b->dim]);
		result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
B
Bruce Momjian 已提交
591 592 593 594 595 596 597 598 599
	}
	for (i = b->dim; i < a->dim; i++)
	{
		result->x[i] = 0;
		result->x[i + a->dim] = 0;
	}

	/* compute the union */
	for (i = 0; i < a->dim; i++)
B
Bruce Momjian 已提交
600
	{
601
		result->x[i] =
602 603
			Min(Min(a->x[i], a->x[i + a->dim]), result->x[i]);
		result->x[i + a->dim] = Max(Max(a->x[i],
B
Bruce Momjian 已提交
604 605
							   a->x[i + a->dim]), result->x[i + a->dim]);
	}
B
Bruce Momjian 已提交
606 607

	return (result);
608 609 610
}

/* cube_inter */
B
Bruce Momjian 已提交
611
NDBOX *
612
cube_inter(NDBOX * a, NDBOX * b)
613
{
B
Bruce Momjian 已提交
614 615 616 617 618 619
	int			i;
	NDBOX	   *result;

	if (a->dim >= b->dim)
	{
		result = palloc(a->size);
B
Bruce Momjian 已提交
620
		memset(result, 0, a->size);
B
Bruce Momjian 已提交
621 622 623 624 625 626
		result->size = a->size;
		result->dim = a->dim;
	}
	else
	{
		result = palloc(b->size);
B
Bruce Momjian 已提交
627
		memset(result, 0, b->size);
B
Bruce Momjian 已提交
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
		result->size = b->size;
		result->dim = b->dim;
	}

	/* swap the box pointers if needed */
	if (a->dim < b->dim)
	{
		NDBOX	   *tmp = b;

		b = a;
		a = tmp;
	}

	/*
	 * use the potentially	smaller of the two boxes (b) to fill in the
	 * result, padding absent dimensions with zeroes
	 */
	for (i = 0; i < b->dim; i++)
	{
647 648
		result->x[i] = Min(b->x[i], b->x[i + b->dim]);
		result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
B
Bruce Momjian 已提交
649 650 651 652 653 654 655 656 657
	}
	for (i = b->dim; i < a->dim; i++)
	{
		result->x[i] = 0;
		result->x[i + a->dim] = 0;
	}

	/* compute the intersection */
	for (i = 0; i < a->dim; i++)
B
Bruce Momjian 已提交
658
	{
659
		result->x[i] =
660 661
			Max(Min(a->x[i], a->x[i + a->dim]), result->x[i]);
		result->x[i + a->dim] = Min(Max(a->x[i],
B
Bruce Momjian 已提交
662 663
							   a->x[i + a->dim]), result->x[i + a->dim]);
	}
B
Bruce Momjian 已提交
664 665 666 667 668 669

	/*
	 * Is it OK to return a non-null intersection for non-overlapping
	 * boxes?
	 */
	return (result);
670 671 672
}

/* cube_size */
673
double *
B
Bruce Momjian 已提交
674
cube_size(NDBOX * a)
675
{
B
Bruce Momjian 已提交
676 677
	int			i,
				j;
678
	double	   *result;
B
Bruce Momjian 已提交
679

680
	result = (double *) palloc(sizeof(double));
B
Bruce Momjian 已提交
681 682 683

	*result = 1.0;
	for (i = 0, j = a->dim; i < a->dim; i++, j++)
684
		*result = (*result) * Abs((a->x[j] - a->x[i]));
B
Bruce Momjian 已提交
685 686

	return (result);
687 688 689
}

void
690
rt_cube_size(NDBOX * a, double *size)
691
{
B
Bruce Momjian 已提交
692 693 694 695 696 697 698 699 700
	int			i,
				j;

	if (a == (NDBOX *) NULL)
		*size = 0.0;
	else
	{
		*size = 1.0;
		for (i = 0, j = a->dim; i < a->dim; i++, j++)
701
			*size = (*size) * Abs((a->x[j] - a->x[i]));
B
Bruce Momjian 已提交
702 703
	}
	return;
704 705 706 707 708 709 710
}

/* The following four methods compare the projections of the boxes
   onto the 0-th coordinate axis. These methods are useless for dimensions
   larger than 2, but it seems that R-tree requires all its strategies
   map to real functions that return something */

B
Bruce Momjian 已提交
711 712 713
/*	is the right edge of (a) located to the left of
	the right edge of (b)? */
bool
714
cube_over_left(NDBOX * a, NDBOX * b)
715
{
716
	if ((a == NULL) || (b == NULL))
B
Bruce Momjian 已提交
717
		return (FALSE);
718

719 720
	return (Min(a->x[a->dim - 1], a->x[2 * a->dim - 1]) <=
			Min(b->x[b->dim - 1], b->x[2 * b->dim - 1]) &&
B
Bruce Momjian 已提交
721
			!cube_left(a, b) && !cube_right(a, b));
722 723
}

B
Bruce Momjian 已提交
724 725 726
/*	is the left edge of (a) located to the right of
	the left edge of (b)? */
bool
727
cube_over_right(NDBOX * a, NDBOX * b)
728
{
729
	if ((a == NULL) || (b == NULL))
B
Bruce Momjian 已提交
730
		return (FALSE);
731

732 733
	return (Min(a->x[a->dim - 1], a->x[2 * a->dim - 1]) >=
			Min(b->x[b->dim - 1], b->x[2 * b->dim - 1]) &&
B
Bruce Momjian 已提交
734
			!cube_left(a, b) && !cube_right(a, b));
735 736 737 738 739
}


/* return 'true' if the projection of 'a' is
   entirely on the left of the projection of 'b' */
B
Bruce Momjian 已提交
740
bool
741
cube_left(NDBOX * a, NDBOX * b)
742
{
743
	if ((a == NULL) || (b == NULL))
B
Bruce Momjian 已提交
744
		return (FALSE);
745

746 747
	return (Min(a->x[a->dim - 1], a->x[2 * a->dim - 1]) <
			Min(b->x[0], b->x[b->dim]));
748 749 750 751
}

/* return 'true' if the projection of 'a' is
   entirely on the right  of the projection of 'b' */
B
Bruce Momjian 已提交
752
bool
753
cube_right(NDBOX * a, NDBOX * b)
754
{
755
	if ((a == NULL) || (b == NULL))
B
Bruce Momjian 已提交
756
		return (FALSE);
757

758 759
	return (Min(a->x[0], a->x[a->dim]) >
			Min(b->x[b->dim - 1], b->x[2 * b->dim - 1]));
760 761 762
}

/* make up a metric in which one box will be 'lower' than the other
763
   -- this can be useful for sorting and to determine uniqueness */
764 765
int32
cube_cmp(NDBOX * a, NDBOX * b)
766
{
B
Bruce Momjian 已提交
767 768 769
	int			i;
	int			dim;

770
	dim = Min(a->dim, b->dim);
B
Bruce Momjian 已提交
771 772 773 774

	/* compare the common dimensions */
	for (i = 0; i < dim; i++)
	{
775 776
		if (Min(a->x[i], a->x[a->dim + i]) >
			Min(b->x[i], b->x[b->dim + i]))
777
			return 1;
778 779
		if (Min(a->x[i], a->x[a->dim + i]) <
			Min(b->x[i], b->x[b->dim + i]))
780
			return -1;
B
Bruce Momjian 已提交
781 782 783
	}
	for (i = 0; i < dim; i++)
	{
784 785
		if (Max(a->x[i], a->x[a->dim + i]) >
			Max(b->x[i], b->x[b->dim + i]))
786
			return 1;
787 788
		if (Max(a->x[i], a->x[a->dim + i]) <
			Max(b->x[i], b->x[b->dim + i]))
789
			return -1;
B
Bruce Momjian 已提交
790 791 792 793 794 795 796
	}

	/* compare extra dimensions to zero */
	if (a->dim > b->dim)
	{
		for (i = dim; i < a->dim; i++)
		{
797
			if (Min(a->x[i], a->x[a->dim + i]) > 0)
798
				return 1;
799
			if (Min(a->x[i], a->x[a->dim + i]) < 0)
800
				return -1;
B
Bruce Momjian 已提交
801
		}
802
		for (i = dim; i < a->dim; i++)
B
Bruce Momjian 已提交
803
		{
804
			if (Max(a->x[i], a->x[a->dim + i]) > 0)
805
				return 1;
806
			if (Max(a->x[i], a->x[a->dim + i]) < 0)
807
				return -1;
B
Bruce Momjian 已提交
808
		}
B
Bruce Momjian 已提交
809 810 811 812 813

		/*
		 * if all common dimensions are equal, the cube with more
		 * dimensions wins
		 */
814
		return 1;
B
Bruce Momjian 已提交
815 816 817 818 819
	}
	if (a->dim < b->dim)
	{
		for (i = dim; i < b->dim; i++)
		{
820
			if (Min(b->x[i], b->x[b->dim + i]) > 0)
821
				return -1;
822
			if (Min(b->x[i], b->x[b->dim + i]) < 0)
823
				return 1;
B
Bruce Momjian 已提交
824
		}
825
		for (i = dim; i < b->dim; i++)
B
Bruce Momjian 已提交
826
		{
827
			if (Max(b->x[i], b->x[b->dim + i]) > 0)
828
				return -1;
829
			if (Max(b->x[i], b->x[b->dim + i]) < 0)
830
				return 1;
B
Bruce Momjian 已提交
831
		}
B
Bruce Momjian 已提交
832 833 834 835 836

		/*
		 * if all common dimensions are equal, the cube with more
		 * dimensions wins
		 */
837
		return -1;
B
Bruce Momjian 已提交
838 839
	}

840 841
	/* They're really equal */
	return 0;
842 843 844
}


B
Bruce Momjian 已提交
845
bool
846
cube_eq(NDBOX * a, NDBOX * b)
847
{
848
	return (cube_cmp(a, b) == 0);
849 850
}

B
Bruce Momjian 已提交
851
bool
852
cube_ne(NDBOX * a, NDBOX * b)
853
{
854 855
	return (cube_cmp(a, b) != 0);
}
B
Bruce Momjian 已提交
856

857 858 859 860 861
bool
cube_lt(NDBOX * a, NDBOX * b)
{
	return (cube_cmp(a, b) < 0);
}
B
Bruce Momjian 已提交
862

863 864 865 866 867
bool
cube_gt(NDBOX * a, NDBOX * b)
{
	return (cube_cmp(a, b) > 0);
}
B
Bruce Momjian 已提交
868

869 870 871 872
bool
cube_le(NDBOX * a, NDBOX * b)
{
	return (cube_cmp(a, b) <= 0);
873 874
}

B
Bruce Momjian 已提交
875
bool
876
cube_ge(NDBOX * a, NDBOX * b)
877
{
878
	return (cube_cmp(a, b) >= 0);
879 880 881 882 883
}


/* Contains */
/* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
B
Bruce Momjian 已提交
884
bool
885
cube_contains(NDBOX * a, NDBOX * b)
886
{
B
Bruce Momjian 已提交
887 888
	int			i;

889
	if ((a == NULL) || (b == NULL))
B
Bruce Momjian 已提交
890 891 892 893 894 895
		return (FALSE);

	if (a->dim < b->dim)
	{
		/*
		 * the further comparisons will make sense if the excess
B
Bruce Momjian 已提交
896 897 898
		 * dimensions of (b) were zeroes Since both UL and UR coordinates
		 * must be zero, we can check them all without worrying about
		 * which is which.
B
Bruce Momjian 已提交
899 900 901 902 903 904 905 906 907 908 909
		 */
		for (i = a->dim; i < b->dim; i++)
		{
			if (b->x[i] != 0)
				return (FALSE);
			if (b->x[i + b->dim] != 0)
				return (FALSE);
		}
	}

	/* Can't care less about the excess dimensions of (a), if any */
910
	for (i = 0; i < Min(a->dim, b->dim); i++)
B
Bruce Momjian 已提交
911
	{
912 913
		if (Min(a->x[i], a->x[a->dim + i]) >
			Min(b->x[i], b->x[b->dim + i]))
B
Bruce Momjian 已提交
914
			return (FALSE);
915 916
		if (Max(a->x[i], a->x[a->dim + i]) <
			Max(b->x[i], b->x[b->dim + i]))
B
Bruce Momjian 已提交
917 918 919 920
			return (FALSE);
	}

	return (TRUE);
921 922 923 924
}

/* Contained */
/* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
B
Bruce Momjian 已提交
925 926
bool
cube_contained(NDBOX * a, NDBOX * b)
927
{
B
Bruce Momjian 已提交
928 929 930 931
	if (cube_contains(b, a) == TRUE)
		return (TRUE);
	else
		return (FALSE);
932 933 934 935
}

/* Overlap */
/* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
B
Bruce Momjian 已提交
936
bool
937
cube_overlap(NDBOX * a, NDBOX * b)
938
{
B
Bruce Momjian 已提交
939 940 941 942 943 944
	int			i;

	/*
	 * This *very bad* error was found in the source: if ( (a==NULL) ||
	 * (b=NULL) ) return(FALSE);
	 */
945
	if ((a == NULL) || (b == NULL))
B
Bruce Momjian 已提交
946 947 948 949 950 951 952 953 954 955 956 957 958 959
		return (FALSE);

	/* swap the box pointers if needed */
	if (a->dim < b->dim)
	{
		NDBOX	   *tmp = b;

		b = a;
		a = tmp;
	}

	/* compare within the dimensions of (b) */
	for (i = 0; i < b->dim; i++)
	{
960 961
		if (Min(a->x[i], a->x[a->dim + i]) >
			Max(b->x[i], b->x[b->dim + i]))
B
Bruce Momjian 已提交
962
			return (FALSE);
963 964
		if (Max(a->x[i], a->x[a->dim + i]) <
			Min(b->x[i], b->x[b->dim + i]))
B
Bruce Momjian 已提交
965 966 967 968 969 970
			return (FALSE);
	}

	/* compare to zero those dimensions in (a) absent in (b) */
	for (i = b->dim; i < a->dim; i++)
	{
971
		if (Min(a->x[i], a->x[a->dim + i]) > 0)
B
Bruce Momjian 已提交
972
			return (FALSE);
973
		if (Max(a->x[i], a->x[a->dim + i]) < 0)
B
Bruce Momjian 已提交
974 975 976 977
			return (FALSE);
	}

	return (TRUE);
978 979 980 981 982
}


/* Distance */
/* The distance is computed as a per axis sum of the squared distances
B
Bruce Momjian 已提交
983 984
   between 1D projections of the boxes onto Cartesian axes. Assuming zero
   distance between overlapping projections, this metric coincides with the
985
   "common sense" geometric distance */
986
double *
B
Bruce Momjian 已提交
987
cube_distance(NDBOX * a, NDBOX * b)
988
{
B
Bruce Momjian 已提交
989 990 991
	int			i;
	double		d,
				distance;
992
	double	   *result;
B
Bruce Momjian 已提交
993

994
	result = (double *) palloc(sizeof(double));
B
Bruce Momjian 已提交
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

	/* swap the box pointers if needed */
	if (a->dim < b->dim)
	{
		NDBOX	   *tmp = b;

		b = a;
		a = tmp;
	}

	distance = 0.0;
	/* compute within the dimensions of (b) */
	for (i = 0; i < b->dim; i++)
	{
		d = distance_1D(a->x[i], a->x[i + a->dim], b->x[i], b->x[i + b->dim]);
		distance += d * d;
	}

	/* compute distance to zero for those dimensions in (a) absent in (b) */
	for (i = b->dim; i < a->dim; i++)
	{
		d = distance_1D(a->x[i], a->x[i + a->dim], 0.0, 0.0);
		distance += d * d;
	}

1020
	*result = (double) sqrt(distance);
B
Bruce Momjian 已提交
1021 1022

	return (result);
1023 1024
}

1025 1026
static double
distance_1D(double a1, double a2, double b1, double b2)
1027
{
B
Bruce Momjian 已提交
1028 1029
	/* interval (a) is entirely on the left of (b) */
	if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
1030
		return (Min(b1, b2) - Max(a1, a2));
B
Bruce Momjian 已提交
1031 1032 1033

	/* interval (a) is entirely on the right of (b) */
	if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
1034
		return (Min(a1, a2) - Max(b1, b2));
B
Bruce Momjian 已提交
1035 1036 1037

	/* the rest are all sorts of intersections */
	return (0.0);
1038 1039
}

1040 1041 1042
/* Test if a box is also a point */
bool
cube_is_point(NDBOX * a)
1043
{
B
Bruce Momjian 已提交
1044 1045 1046
	int			i,
				j;

1047
	for (i = 0, j = a->dim; i < a->dim; i++, j++)
B
Bruce Momjian 已提交
1048 1049 1050 1051
	{
		if (a->x[i] != a->x[j])
			return FALSE;
	}
B
Bruce Momjian 已提交
1052

B
Bruce Momjian 已提交
1053
	return TRUE;
1054
}
B
Bruce Momjian 已提交
1055

1056
/* Return dimensions in use in the data structure */
1057
int4
1058 1059
cube_dim(NDBOX * a)
{
B
Bruce Momjian 已提交
1060 1061
	/* Other things will break before unsigned int doesn't fit. */
	return a->dim;
1062
}
B
Bruce Momjian 已提交
1063

1064 1065
/* Return a specific normalized LL coordinate */
double *
1066
cube_ll_coord(NDBOX * a, int4 n)
1067
{
B
Bruce Momjian 已提交
1068 1069
	double	   *result;

1070
	result = (double *) palloc(sizeof(double));
B
Bruce Momjian 已提交
1071 1072
	*result = 0;
	if (a->dim >= n && n > 0)
1073
		*result = Min(a->x[n - 1], a->x[a->dim + n - 1]);
B
Bruce Momjian 已提交
1074
	return result;
1075 1076 1077 1078
}

/* Return a specific normalized UR coordinate */
double *
1079
cube_ur_coord(NDBOX * a, int4 n)
1080
{
B
Bruce Momjian 已提交
1081 1082
	double	   *result;

1083
	result = (double *) palloc(sizeof(double));
B
Bruce Momjian 已提交
1084 1085
	*result = 0;
	if (a->dim >= n && n > 0)
1086
		*result = Max(a->x[n - 1], a->x[a->dim + n - 1]);
B
Bruce Momjian 已提交
1087
	return result;
1088 1089 1090 1091
}

/* Increase or decrease box size by a radius in at least n dimensions. */
NDBOX *
1092
cube_enlarge(NDBOX * a, double *r, int4 n)
1093
{
B
Bruce Momjian 已提交
1094 1095 1096 1097
	NDBOX	   *result;
	int			dim = 0;
	int			size;
	int			i,
1098 1099
				j,
				k;
B
Bruce Momjian 已提交
1100

B
Bruce Momjian 已提交
1101 1102
	if (n > CUBE_MAX_DIM)
		n = CUBE_MAX_DIM;
B
Bruce Momjian 已提交
1103 1104 1105 1106 1107 1108 1109 1110 1111
	if (*r > 0 && n > 0)
		dim = n;
	if (a->dim > dim)
		dim = a->dim;
	size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2;
	result = (NDBOX *) palloc(size);
	memset(result, 0, size);
	result->size = size;
	result->dim = dim;
1112
	for (i = 0, j = dim, k = a->dim; i < a->dim; i++, j++, k++)
B
Bruce Momjian 已提交
1113
	{
1114
		if (a->x[i] >= a->x[k])
B
Bruce Momjian 已提交
1115
		{
1116
			result->x[i] = a->x[k] - *r;
B
Bruce Momjian 已提交
1117 1118 1119 1120 1121
			result->x[j] = a->x[i] + *r;
		}
		else
		{
			result->x[i] = a->x[i] - *r;
1122
			result->x[j] = a->x[k] + *r;
B
Bruce Momjian 已提交
1123 1124 1125 1126 1127 1128 1129 1130
		}
		if (result->x[i] > result->x[j])
		{
			result->x[i] = (result->x[i] + result->x[j]) / 2;
			result->x[j] = result->x[i];
		}
	}
	/* dim > a->dim only if r > 0 */
1131
	for (; i < dim; i++, j++)
B
Bruce Momjian 已提交
1132 1133 1134 1135 1136
	{
		result->x[i] = -*r;
		result->x[j] = *r;
	}
	return result;
1137
}
1138 1139 1140 1141 1142 1143

/* Create a one dimensional box with identical upper and lower coordinates */
NDBOX *
cube_f8(double *x1)
{
	NDBOX	   *result;
B
Bruce Momjian 已提交
1144 1145
	int			size;

1146 1147 1148 1149 1150
	size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
	result = (NDBOX *) palloc(size);
	memset(result, 0, size);
	result->size = size;
	result->dim = 1;
B
Bruce Momjian 已提交
1151 1152
	result->x[0] = *x1;
	result->x[1] = *x1;
1153 1154 1155 1156 1157 1158 1159 1160
	return result;
}

/* Create a one dimensional box */
NDBOX *
cube_f8_f8(double *x1, double *x2)
{
	NDBOX	   *result;
B
Bruce Momjian 已提交
1161 1162
	int			size;

1163 1164 1165 1166 1167
	size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
	result = (NDBOX *) palloc(size);
	memset(result, 0, size);
	result->size = size;
	result->dim = 1;
B
Bruce Momjian 已提交
1168 1169
	result->x[0] = *x1;
	result->x[1] = *x2;
1170 1171 1172 1173 1174 1175
	return result;
}

/* Add a dimension to an existing cube with the same values for the new
   coordinate */
NDBOX *
B
Bruce Momjian 已提交
1176
cube_c_f8(NDBOX * c, double *x1)
1177 1178
{
	NDBOX	   *result;
B
Bruce Momjian 已提交
1179 1180 1181 1182
	int			size;
	int			i;

	size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
1183 1184 1185 1186
	result = (NDBOX *) palloc(size);
	memset(result, 0, size);
	result->size = size;
	result->dim = c->dim + 1;
B
Bruce Momjian 已提交
1187 1188 1189 1190 1191 1192 1193
	for (i = 0; i < c->dim; i++)
	{
		result->x[i] = c->x[i];
		result->x[result->dim + i] = c->x[c->dim + i];
	}
	result->x[result->dim - 1] = *x1;
	result->x[2 * result->dim - 1] = *x1;
1194 1195 1196 1197 1198
	return result;
}

/* Add a dimension to an existing cube */
NDBOX *
B
Bruce Momjian 已提交
1199
cube_c_f8_f8(NDBOX * c, double *x1, double *x2)
1200 1201
{
	NDBOX	   *result;
B
Bruce Momjian 已提交
1202 1203 1204 1205
	int			size;
	int			i;

	size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
1206 1207 1208 1209
	result = (NDBOX *) palloc(size);
	memset(result, 0, size);
	result->size = size;
	result->dim = c->dim + 1;
B
Bruce Momjian 已提交
1210 1211 1212 1213 1214 1215 1216
	for (i = 0; i < c->dim; i++)
	{
		result->x[i] = c->x[i];
		result->x[result->dim + i] = c->x[c->dim + i];
	}
	result->x[result->dim - 1] = *x1;
	result->x[2 * result->dim - 1] = *x2;
1217 1218
	return result;
}