diff options
Diffstat (limited to 'contrib/cube/cube.c')
-rw-r--r-- | contrib/cube/cube.c | 1174 |
1 files changed, 0 insertions, 1174 deletions
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c deleted file mode 100644 index c97e86d3b40..00000000000 --- a/contrib/cube/cube.c +++ /dev/null @@ -1,1174 +0,0 @@ -/****************************************************************************** - 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" -#include "utils/elog.h" -#include "utils/palloc.h" -#include "utils/builtins.h" - -#include "cubedata.h" - -#define max(a,b) ((a) > (b) ? (a) : (b)) -#define min(a,b) ((a) <= (b) ? (a) : (b)) -#define abs(a) ((a) < (0) ? (-a) : (a)) - -extern void set_parse_buffer(char *str); -extern int cube_yyparse(); - -/* -** Input/Output routines -*/ -NDBOX *cube_in(char *str); -char *cube_out(NDBOX * cube); - - -/* -** GiST support methods -*/ -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); -GIST_SPLITVEC *g_cube_picksplit(bytea *entryvec, GIST_SPLITVEC *v); -bool g_cube_leaf_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy); -bool g_cube_internal_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy); -NDBOX *g_cube_union(bytea *entryvec, int *sizep); -NDBOX *g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep); -bool *g_cube_same(NDBOX * b1, NDBOX * b2, bool *result); - -/* -** R-tree support functions -*/ -bool cube_same(NDBOX * a, NDBOX * b); -bool cube_different(NDBOX * a, NDBOX * b); -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); -float *cube_size(NDBOX * a); -void rt_cube_size(NDBOX * a, float *sz); - -/* -** These make no sense for this type, but R-tree wants them -*/ -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); - -/* -** miscellaneous -*/ -bool cube_lt(NDBOX * a, NDBOX * b); -bool cube_gt(NDBOX * a, NDBOX * b); -float *cube_distance(NDBOX * a, NDBOX * b); - -/* -** Auxiliary funxtions -*/ -static float distance_1D(float a1, float a2, float b1, float b2); -static NDBOX *swap_corners(NDBOX * a); - - -/***************************************************************************** - * Input/Output functions - *****************************************************************************/ - -/* NdBox = [(lowerleft),(upperright)] */ -/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ -NDBOX * -cube_in(char *str) -{ - void *result; - - set_parse_buffer(str); - - if (cube_yyparse(&result) != 0) - return NULL; - - return ((NDBOX *) result); -} - -/* - * You might have noticed a slight inconsistency between the following - * declaration and the SQL definition: - * CREATE FUNCTION cube_out(opaque) RETURNS opaque ... - * The reason is that the argument pass into cube_out is really just a - * pointer. POSTGRES thinks all output functions are: - * char *out_func(char *); - */ -char * -cube_out(NDBOX * cube) -{ - char *result; - char *p; - int equal = 1; - int dim = cube->dim; - int i; - - if (cube == NULL) - return (NULL); - - p = result = (char *) palloc(100); - - /* - * while printing the first (LL) corner, check if it is equal to the - * scond one - */ - p += sprintf(p, "("); - for (i = 0; i < dim; i++) - { - p += sprintf(p, "%g", cube->x[i]); - p += sprintf(p, ", "); - if (cube->x[i] != cube->x[i + dim]) - equal = 0; - } - p -= 2; /* get rid of the last ", " */ - p += sprintf(p, ")"); - - if (!equal) - { - p += sprintf(p, ",("); - for (i = dim; i < dim * 2; i++) - { - p += sprintf(p, "%g", cube->x[i]); - p += sprintf(p, ", "); - } - p -= 2; - p += sprintf(p, ")"); - } - - return (result); -} - - -/***************************************************************************** - * GiST functions - *****************************************************************************/ - -/* -** 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. -*/ -bool -g_cube_consistent(GISTENTRY *entry, - NDBOX * query, - StrategyNumber strategy) -{ - /* - * if entry is not leaf, use g_cube_internal_consistent, else use - * g_cube_leaf_consistent - */ - if (GIST_LEAF(entry)) - return g_cube_leaf_consistent((NDBOX *) DatumGetPointer(entry->key), - query, strategy); - else - return g_cube_internal_consistent((NDBOX *) DatumGetPointer(entry->key), - query, strategy); -} - - -/* -** The GiST Union method for boxes -** returns the minimal bounding box that encloses all the entries in entryvec -*/ -NDBOX * -g_cube_union(bytea *entryvec, int *sizep) -{ - int numranges, - i; - NDBOX *out = (NDBOX *) NULL; - NDBOX *tmp; - - /* - * fprintf(stderr, "union\n"); - */ - numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); - tmp = (NDBOX *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[0]).key); - - /* - * sizep = sizeof(NDBOX); -- NDBOX has variable size - */ - *sizep = tmp->size; - - for (i = 1; i < numranges; i++) - { - out = g_cube_binary_union(tmp, (NDBOX *) - DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i]).key), - sizep); - if (i > 1) - pfree(tmp); - tmp = out; - } - - return (out); -} - -/* -** GiST Compress and Decompress methods for boxes -** do not do anything. -*/ -GISTENTRY * -g_cube_compress(GISTENTRY *entry) -{ - return (entry); -} - -GISTENTRY * -g_cube_decompress(GISTENTRY *entry) -{ - return (entry); -} - -/* -** 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) -{ - NDBOX *ud; - float tmp1, - tmp2; - - ud = cube_union((NDBOX *) DatumGetPointer(origentry->key), - (NDBOX *) DatumGetPointer(newentry->key)); - rt_cube_size(ud, &tmp1); - rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2); - *result = tmp1 - tmp2; - pfree(ud); - - /* - * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); - */ - return (result); -} - - - -/* -** The GiST PickSplit method for boxes -** We use Guttman's poly time split algorithm -*/ -GIST_SPLITVEC * -g_cube_picksplit(bytea *entryvec, - GIST_SPLITVEC *v) -{ - 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; - float size_alpha, - size_beta, - size_union, - size_inter; - float size_waste, - waste; - float size_l, - size_r; - int nbytes; - OffsetNumber seed_1 = 0, - seed_2 = 0; - OffsetNumber *left, - *right; - OffsetNumber maxoff; - - /* - * fprintf(stderr, "picksplit\n"); - */ - maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 2; - 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)) - { - datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[i].key); - for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) - { - datum_beta = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[j].key); - - /* compute the wasted space by unioning these guys */ - /* size_waste = size_union - size_inter; */ - union_d = cube_union(datum_alpha, datum_beta); - rt_cube_size(union_d, &size_union); - inter_d = cube_inter(datum_alpha, datum_beta); - 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; - } - } - } - - left = v->spl_left; - v->spl_nleft = 0; - right = v->spl_right; - v->spl_nright = 0; - - datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[seed_1].key); - datum_l = cube_union(datum_alpha, datum_alpha); - rt_cube_size(datum_l, &size_l); - datum_beta = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[seed_2].key); - datum_r = cube_union(datum_beta, datum_beta); - rt_cube_size(datum_r, &size_r); - - /* - * 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? */ - datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[i].key); - 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); - - /* 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++; - } - } - *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ - - v->spl_ldatum = PointerGetDatum(datum_l); - v->spl_rdatum = PointerGetDatum(datum_r); - - return v; -} - -/* -** Equality method -*/ -bool * -g_cube_same(NDBOX * b1, NDBOX * b2, bool *result) -{ - if (cube_same(b1, b2)) - *result = TRUE; - else - *result = FALSE; - - /* - * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" )); - */ - return (result); -} - -/* -** SUPPORT ROUTINES -*/ -bool -g_cube_leaf_consistent(NDBOX * key, - NDBOX * query, - StrategyNumber strategy) -{ - 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: - retval = (bool) cube_same(key, query); - break; - case RTContainsStrategyNumber: - retval = (bool) cube_contains(key, query); - break; - case RTContainedByStrategyNumber: - retval = (bool) cube_contained(key, query); - break; - default: - retval = FALSE; - } - return (retval); -} - -bool -g_cube_internal_consistent(NDBOX * key, - NDBOX * query, - StrategyNumber strategy) -{ - 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); -} - -NDBOX * -g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep) -{ - NDBOX *retval; - - retval = cube_union(r1, r2); - *sizep = retval->size; - - return (retval); -} - - -/* cube_union */ -NDBOX * -cube_union(NDBOX * box_a, NDBOX * box_b) -{ - int i; - NDBOX *result; - NDBOX *a = swap_corners(box_a); - NDBOX *b = swap_corners(box_b); - - if (a->dim >= b->dim) - { - result = palloc(a->size); - result->size = a->size; - result->dim = a->dim; - } - else - { - result = palloc(b->size); - 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++) - { - result->x[i] = b->x[i]; - result->x[i + a->dim] = b->x[i + b->dim]; - } - 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++) - result->x[i] = min(a->x[i], result->x[i]); - for (i = a->dim; i < a->dim * 2; i++) - result->x[i] = max(a->x[i], result->x[i]); - - pfree(a); - pfree(b); - - return (result); -} - -/* cube_inter */ -NDBOX * -cube_inter(NDBOX * box_a, NDBOX * box_b) -{ - int i; - NDBOX *result; - NDBOX *a = swap_corners(box_a); - NDBOX *b = swap_corners(box_b); - - if (a->dim >= b->dim) - { - result = palloc(a->size); - result->size = a->size; - result->dim = a->dim; - } - else - { - result = palloc(b->size); - 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++) - { - result->x[i] = b->x[i]; - result->x[i + a->dim] = b->x[i + b->dim]; - } - 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++) - result->x[i] = max(a->x[i], result->x[i]); - for (i = a->dim; i < a->dim * 2; i++) - result->x[i] = min(a->x[i], result->x[i]); - - pfree(a); - pfree(b); - - /* - * Is it OK to return a non-null intersection for non-overlapping - * boxes? - */ - return (result); -} - -/* cube_size */ -float * -cube_size(NDBOX * a) -{ - int i, - j; - float *result; - - result = (float *) palloc(sizeof(float)); - - *result = 1.0; - for (i = 0, j = a->dim; i < a->dim; i++, j++) - *result = (*result) * abs((a->x[j] - a->x[i])); - - return (result); -} - -void -rt_cube_size(NDBOX * a, float *size) -{ - 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++) - *size = (*size) * abs((a->x[j] - a->x[i])); - } - return; -} - -/* 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 */ - -/* is the right edge of (a) located to the left of - the right edge of (b)? */ -bool -cube_over_left(NDBOX * box_a, NDBOX * box_b) -{ - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - - return (a->x[a->dim - 1] <= b->x[b->dim - 1] && !cube_left(a, b) && !cube_right(a, b)); -} - -/* is the left edge of (a) located to the right of - the left edge of (b)? */ -bool -cube_over_right(NDBOX * box_a, NDBOX * box_b) -{ - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - - return (a->x[a->dim - 1] >= b->x[b->dim - 1] && !cube_left(a, b) && !cube_right(a, b)); -} - - -/* return 'true' if the projection of 'a' is - entirely on the left of the projection of 'b' */ -bool -cube_left(NDBOX * box_a, NDBOX * box_b) -{ - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - - return (a->x[a->dim - 1] < b->x[0]); -} - -/* return 'true' if the projection of 'a' is - entirely on the right of the projection of 'b' */ -bool -cube_right(NDBOX * box_a, NDBOX * box_b) -{ - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - - return (a->x[0] > b->x[b->dim - 1]); -} - -/* make up a metric in which one box will be 'lower' than the other - -- this can be useful for srting and to determine uniqueness */ -bool -cube_lt(NDBOX * box_a, NDBOX * box_b) -{ - int i; - int dim; - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - dim = min(a->dim, b->dim); - - /* - * if all common dimensions are equal, the cube with more dimensions - * wins - */ - if (cube_same(a, b)) - { - if (a->dim < b->dim) - return (TRUE); - else - return (FALSE); - } - - /* compare the common dimensions */ - for (i = 0; i < dim; i++) - { - if (a->x[i] > b->x[i]) - return (FALSE); - if (a->x[i] < b->x[i]) - return (TRUE); - } - for (i = 0; i < dim; i++) - { - if (a->x[i + a->dim] > b->x[i + b->dim]) - return (FALSE); - if (a->x[i + a->dim] < b->x[i + b->dim]) - return (TRUE); - } - - /* compare extra dimensions to zero */ - if (a->dim > b->dim) - { - for (i = dim; i < a->dim; i++) - { - if (a->x[i] > 0) - return (FALSE); - if (a->x[i] < 0) - return (TRUE); - } - for (i = 0; i < dim; i++) - { - if (a->x[i + a->dim] > 0) - return (FALSE); - if (a->x[i + a->dim] < 0) - return (TRUE); - } - } - if (a->dim < b->dim) - { - for (i = dim; i < b->dim; i++) - { - if (b->x[i] > 0) - return (TRUE); - if (b->x[i] < 0) - return (FALSE); - } - for (i = 0; i < dim; i++) - { - if (b->x[i + b->dim] > 0) - return (TRUE); - if (b->x[i + b->dim] < 0) - return (FALSE); - } - } - - return (FALSE); -} - - -bool -cube_gt(NDBOX * box_a, NDBOX * box_b) -{ - int i; - int dim; - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - dim = min(a->dim, b->dim); - - /* - * if all common dimensions are equal, the cube with more dimensions - * wins - */ - if (cube_same(a, b)) - { - if (a->dim > b->dim) - return (TRUE); - else - return (FALSE); - } - - /* compare the common dimensions */ - for (i = 0; i < dim; i++) - { - if (a->x[i] < b->x[i]) - return (FALSE); - if (a->x[i] > b->x[i]) - return (TRUE); - } - for (i = 0; i < dim; i++) - { - if (a->x[i + a->dim] < b->x[i + b->dim]) - return (FALSE); - if (a->x[i + a->dim] > b->x[i + b->dim]) - return (TRUE); - } - - - /* compare extra dimensions to zero */ - if (a->dim > b->dim) - { - for (i = dim; i < a->dim; i++) - { - if (a->x[i] < 0) - return (FALSE); - if (a->x[i] > 0) - return (TRUE); - } - for (i = 0; i < dim; i++) - { - if (a->x[i + a->dim] < 0) - return (FALSE); - if (a->x[i + a->dim] > 0) - return (TRUE); - } - } - if (a->dim < b->dim) - { - for (i = dim; i < b->dim; i++) - { - if (b->x[i] < 0) - return (TRUE); - if (b->x[i] > 0) - return (FALSE); - } - for (i = 0; i < dim; i++) - { - if (b->x[i + b->dim] < 0) - return (TRUE); - if (b->x[i + b->dim] > 0) - return (FALSE); - } - } - - return (FALSE); -} - - -/* Equal */ -bool -cube_same(NDBOX * box_a, NDBOX * box_b) -{ - int i; - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - - /* swap the box pointers if necessary */ - if (a->dim < b->dim) - { - NDBOX *tmp = b; - - b = a; - a = tmp; - } - - for (i = 0; i < b->dim; i++) - { - if (a->x[i] != b->x[i]) - return (FALSE); - if (a->x[i + a->dim] != b->x[i + b->dim]) - return (FALSE); - } - - /* - * all dimensions of (b) are compared to those of (a); instead of - * those in (a) absent in (b), compare (a) to zero - */ - for (i = b->dim; i < a->dim; i++) - { - if (a->x[i] != 0) - return (FALSE); - if (a->x[i + a->dim] != 0) - return (FALSE); - } - - pfree(a); - pfree(b); - - return (TRUE); -} - -/* Different */ -bool -cube_different(NDBOX * box_a, NDBOX * box_b) -{ - return (!cube_same(box_a, box_b)); -} - - -/* Contains */ -/* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */ -bool -cube_contains(NDBOX * box_a, NDBOX * box_b) -{ - int i; - NDBOX *a; - NDBOX *b; - - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - - if (a->dim < b->dim) - { - /* - * the further comparisons will make sense if the excess - * dimensions of (b) were zeroes - */ - 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 */ - for (i = 0; i < min(a->dim, b->dim); i++) - { - if (a->x[i] > b->x[i]) - return (FALSE); - if (a->x[i + a->dim] < b->x[i + b->dim]) - return (FALSE); - } - - pfree(a); - pfree(b); - - return (TRUE); -} - -/* Contained */ -/* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */ -bool -cube_contained(NDBOX * a, NDBOX * b) -{ - if (cube_contains(b, a) == TRUE) - return (TRUE); - else - return (FALSE); -} - -/* Overlap */ -/* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */ -bool -cube_overlap(NDBOX * box_a, NDBOX * box_b) -{ - int i; - NDBOX *a; - NDBOX *b; - - /* - * This *very bad* error was found in the source: if ( (a==NULL) || - * (b=NULL) ) return(FALSE); - */ - if ((box_a == NULL) || (box_b == NULL)) - return (FALSE); - - a = swap_corners(box_a); - b = swap_corners(box_b); - - /* 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++) - { - if (a->x[i] > b->x[i + b->dim]) - return (FALSE); - if (a->x[i + a->dim] < b->x[i]) - return (FALSE); - } - - /* compare to zero those dimensions in (a) absent in (b) */ - for (i = b->dim; i < a->dim; i++) - { - if (a->x[i] > 0) - return (FALSE); - if (a->x[i + a->dim] < 0) - return (FALSE); - } - - pfree(a); - pfree(b); - - return (TRUE); -} - - -/* Distance */ -/* The distance is computed as a per axis sum of the squared distances - between 1D projections of the boxes onto Cartesian axes. Assuming zero - distance between overlapping projections, this metric coincides with the - "common sense" geometric distance */ -float * -cube_distance(NDBOX * a, NDBOX * b) -{ - int i; - double d, - distance; - float *result; - - result = (float *) palloc(sizeof(float)); - - /* 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; - } - - *result = (float) sqrt(distance); - - return (result); -} - -static float -distance_1D(float a1, float a2, float b1, float b2) -{ - /* interval (a) is entirely on the left of (b) */ - if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2)) - return (min(b1, b2) - max(a1, a2)); - - /* interval (a) is entirely on the right of (b) */ - if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2)) - return (min(a1, a2) - max(b1, b2)); - - /* the rest are all sorts of intersections */ - return (0.0); -} - -/* normalize the box's co-ordinates by placing min(xLL,xUR) to LL - and max(xLL,xUR) to UR -*/ -static NDBOX * -swap_corners(NDBOX * a) -{ - int i, - j; - NDBOX *result; - - result = palloc(a->size); - result->size = a->size; - result->dim = a->dim; - - for (i = 0, j = a->dim; i < a->dim; i++, j++) - { - result->x[i] = min(a->x[i], a->x[j]); - result->x[j] = max(a->x[i], a->x[j]); - } - - return (result); -} |