00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "postgres.h"
00010
00011 #include <float.h>
00012 #include <math.h>
00013
00014 #include "access/gist.h"
00015 #include "access/skey.h"
00016 #include "utils/array.h"
00017 #include "utils/builtins.h"
00018
00019 #include "cubedata.h"
00020
00021 PG_MODULE_MAGIC;
00022
00023
00024
00025
00026 #define ARRPTR(x) ( (double *) ARR_DATA_PTR(x) )
00027 #define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
00028
00029 extern int cube_yyparse();
00030 extern void cube_yyerror(const char *message);
00031 extern void cube_scanner_init(const char *str);
00032 extern void cube_scanner_finish(void);
00033
00034
00035
00036
00037 PG_FUNCTION_INFO_V1(cube_in);
00038 PG_FUNCTION_INFO_V1(cube_a_f8_f8);
00039 PG_FUNCTION_INFO_V1(cube_a_f8);
00040 PG_FUNCTION_INFO_V1(cube_out);
00041 PG_FUNCTION_INFO_V1(cube_f8);
00042 PG_FUNCTION_INFO_V1(cube_f8_f8);
00043 PG_FUNCTION_INFO_V1(cube_c_f8);
00044 PG_FUNCTION_INFO_V1(cube_c_f8_f8);
00045 PG_FUNCTION_INFO_V1(cube_dim);
00046 PG_FUNCTION_INFO_V1(cube_ll_coord);
00047 PG_FUNCTION_INFO_V1(cube_ur_coord);
00048 PG_FUNCTION_INFO_V1(cube_subset);
00049
00050 Datum cube_in(PG_FUNCTION_ARGS);
00051 Datum cube_a_f8_f8(PG_FUNCTION_ARGS);
00052 Datum cube_a_f8(PG_FUNCTION_ARGS);
00053 Datum cube_out(PG_FUNCTION_ARGS);
00054 Datum cube_f8(PG_FUNCTION_ARGS);
00055 Datum cube_f8_f8(PG_FUNCTION_ARGS);
00056 Datum cube_c_f8(PG_FUNCTION_ARGS);
00057 Datum cube_c_f8_f8(PG_FUNCTION_ARGS);
00058 Datum cube_dim(PG_FUNCTION_ARGS);
00059 Datum cube_ll_coord(PG_FUNCTION_ARGS);
00060 Datum cube_ur_coord(PG_FUNCTION_ARGS);
00061 Datum cube_subset(PG_FUNCTION_ARGS);
00062
00063
00064
00065
00066
00067 PG_FUNCTION_INFO_V1(g_cube_consistent);
00068 PG_FUNCTION_INFO_V1(g_cube_compress);
00069 PG_FUNCTION_INFO_V1(g_cube_decompress);
00070 PG_FUNCTION_INFO_V1(g_cube_penalty);
00071 PG_FUNCTION_INFO_V1(g_cube_picksplit);
00072 PG_FUNCTION_INFO_V1(g_cube_union);
00073 PG_FUNCTION_INFO_V1(g_cube_same);
00074
00075 Datum g_cube_consistent(PG_FUNCTION_ARGS);
00076 Datum g_cube_compress(PG_FUNCTION_ARGS);
00077 Datum g_cube_decompress(PG_FUNCTION_ARGS);
00078 Datum g_cube_penalty(PG_FUNCTION_ARGS);
00079 Datum g_cube_picksplit(PG_FUNCTION_ARGS);
00080 Datum g_cube_union(PG_FUNCTION_ARGS);
00081 Datum g_cube_same(PG_FUNCTION_ARGS);
00082
00083
00084
00085
00086 PG_FUNCTION_INFO_V1(cube_eq);
00087 PG_FUNCTION_INFO_V1(cube_ne);
00088 PG_FUNCTION_INFO_V1(cube_lt);
00089 PG_FUNCTION_INFO_V1(cube_gt);
00090 PG_FUNCTION_INFO_V1(cube_le);
00091 PG_FUNCTION_INFO_V1(cube_ge);
00092 PG_FUNCTION_INFO_V1(cube_cmp);
00093
00094 Datum cube_eq(PG_FUNCTION_ARGS);
00095 Datum cube_ne(PG_FUNCTION_ARGS);
00096 Datum cube_lt(PG_FUNCTION_ARGS);
00097 Datum cube_gt(PG_FUNCTION_ARGS);
00098 Datum cube_le(PG_FUNCTION_ARGS);
00099 Datum cube_ge(PG_FUNCTION_ARGS);
00100 Datum cube_cmp(PG_FUNCTION_ARGS);
00101
00102
00103
00104
00105
00106 PG_FUNCTION_INFO_V1(cube_contains);
00107 PG_FUNCTION_INFO_V1(cube_contained);
00108 PG_FUNCTION_INFO_V1(cube_overlap);
00109 PG_FUNCTION_INFO_V1(cube_union);
00110 PG_FUNCTION_INFO_V1(cube_inter);
00111 PG_FUNCTION_INFO_V1(cube_size);
00112
00113 Datum cube_contains(PG_FUNCTION_ARGS);
00114 Datum cube_contained(PG_FUNCTION_ARGS);
00115 Datum cube_overlap(PG_FUNCTION_ARGS);
00116 Datum cube_union(PG_FUNCTION_ARGS);
00117 Datum cube_inter(PG_FUNCTION_ARGS);
00118 Datum cube_size(PG_FUNCTION_ARGS);
00119
00120
00121
00122
00123 PG_FUNCTION_INFO_V1(cube_distance);
00124 PG_FUNCTION_INFO_V1(cube_is_point);
00125 PG_FUNCTION_INFO_V1(cube_enlarge);
00126
00127 Datum cube_distance(PG_FUNCTION_ARGS);
00128 Datum cube_is_point(PG_FUNCTION_ARGS);
00129 Datum cube_enlarge(PG_FUNCTION_ARGS);
00130
00131
00132
00133
00134 int32 cube_cmp_v0(NDBOX *a, NDBOX *b);
00135 bool cube_contains_v0(NDBOX *a, NDBOX *b);
00136 bool cube_overlap_v0(NDBOX *a, NDBOX *b);
00137 NDBOX *cube_union_v0(NDBOX *a, NDBOX *b);
00138 void rt_cube_size(NDBOX *a, double *sz);
00139 NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
00140 bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
00141 bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
00142
00143
00144
00145
00146 static double distance_1D(double a1, double a2, double b1, double b2);
00147
00148
00149
00150
00151
00152
00153
00154
00155 Datum
00156 cube_in(PG_FUNCTION_ARGS)
00157 {
00158 char *str = PG_GETARG_CSTRING(0);
00159 void *result;
00160
00161 cube_scanner_init(str);
00162
00163 if (cube_yyparse(&result) != 0)
00164 cube_yyerror("bogus input");
00165
00166 cube_scanner_finish();
00167
00168 PG_RETURN_NDBOX(result);
00169 }
00170
00171
00172
00173
00174
00175 Datum
00176 cube_a_f8_f8(PG_FUNCTION_ARGS)
00177 {
00178 ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0);
00179 ArrayType *ll = PG_GETARG_ARRAYTYPE_P(1);
00180 NDBOX *result;
00181 int i;
00182 int dim;
00183 int size;
00184 double *dur,
00185 *dll;
00186
00187 if (array_contains_nulls(ur) || array_contains_nulls(ll))
00188 ereport(ERROR,
00189 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
00190 errmsg("cannot work with arrays containing NULLs")));
00191
00192 dim = ARRNELEMS(ur);
00193 if (ARRNELEMS(ll) != dim)
00194 ereport(ERROR,
00195 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
00196 errmsg("UR and LL arrays must be of same length")));
00197
00198 dur = ARRPTR(ur);
00199 dll = ARRPTR(ll);
00200
00201 size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
00202 result = (NDBOX *) palloc0(size);
00203 SET_VARSIZE(result, size);
00204 result->dim = dim;
00205
00206 for (i = 0; i < dim; i++)
00207 {
00208 result->x[i] = dur[i];
00209 result->x[i + dim] = dll[i];
00210 }
00211
00212 PG_RETURN_NDBOX(result);
00213 }
00214
00215
00216
00217
00218 Datum
00219 cube_a_f8(PG_FUNCTION_ARGS)
00220 {
00221 ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0);
00222 NDBOX *result;
00223 int i;
00224 int dim;
00225 int size;
00226 double *dur;
00227
00228 if (array_contains_nulls(ur))
00229 ereport(ERROR,
00230 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
00231 errmsg("cannot work with arrays containing NULLs")));
00232
00233 dim = ARRNELEMS(ur);
00234
00235 dur = ARRPTR(ur);
00236
00237 size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
00238 result = (NDBOX *) palloc0(size);
00239 SET_VARSIZE(result, size);
00240 result->dim = dim;
00241
00242 for (i = 0; i < dim; i++)
00243 {
00244 result->x[i] = dur[i];
00245 result->x[i + dim] = dur[i];
00246 }
00247
00248 PG_RETURN_NDBOX(result);
00249 }
00250
00251 Datum
00252 cube_subset(PG_FUNCTION_ARGS)
00253 {
00254 NDBOX *c = PG_GETARG_NDBOX(0);
00255 ArrayType *idx = PG_GETARG_ARRAYTYPE_P(1);
00256 NDBOX *result;
00257 int size,
00258 dim,
00259 i;
00260 int *dx;
00261
00262 if (array_contains_nulls(idx))
00263 ereport(ERROR,
00264 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
00265 errmsg("cannot work with arrays containing NULLs")));
00266
00267 dx = (int32 *) ARR_DATA_PTR(idx);
00268
00269 dim = ARRNELEMS(idx);
00270 size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
00271 result = (NDBOX *) palloc0(size);
00272 SET_VARSIZE(result, size);
00273 result->dim = dim;
00274
00275 for (i = 0; i < dim; i++)
00276 {
00277 if ((dx[i] <= 0) || (dx[i] > c->dim))
00278 {
00279 pfree(result);
00280 ereport(ERROR,
00281 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
00282 errmsg("Index out of bounds")));
00283 }
00284 result->x[i] = c->x[dx[i] - 1];
00285 result->x[i + dim] = c->x[dx[i] + c->dim - 1];
00286 }
00287
00288 PG_FREE_IF_COPY(c, 0);
00289 PG_RETURN_NDBOX(result);
00290 }
00291
00292 Datum
00293 cube_out(PG_FUNCTION_ARGS)
00294 {
00295 NDBOX *cube = PG_GETARG_NDBOX(0);
00296 StringInfoData buf;
00297 int dim = cube->dim;
00298 bool equal = true;
00299 int i;
00300 int ndig;
00301
00302 initStringInfo(&buf);
00303
00304
00305
00306
00307 ndig = DBL_DIG + extra_float_digits;
00308 if (ndig < 1)
00309 ndig = 1;
00310
00311
00312
00313
00314
00315 appendStringInfoChar(&buf, '(');
00316 for (i = 0; i < dim; i++)
00317 {
00318 if (i > 0)
00319 appendStringInfo(&buf, ", ");
00320 appendStringInfo(&buf, "%.*g", ndig, cube->x[i]);
00321 if (cube->x[i] != cube->x[i + dim])
00322 equal = false;
00323 }
00324 appendStringInfoChar(&buf, ')');
00325
00326 if (!equal)
00327 {
00328 appendStringInfo(&buf, ",(");
00329 for (i = 0; i < dim; i++)
00330 {
00331 if (i > 0)
00332 appendStringInfo(&buf, ", ");
00333 appendStringInfo(&buf, "%.*g", ndig, cube->x[i + dim]);
00334 }
00335 appendStringInfoChar(&buf, ')');
00336 }
00337
00338 PG_FREE_IF_COPY(cube, 0);
00339 PG_RETURN_CSTRING(buf.data);
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 Datum
00354 g_cube_consistent(PG_FUNCTION_ARGS)
00355 {
00356 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00357 NDBOX *query = PG_GETARG_NDBOX(1);
00358 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
00359
00360
00361 bool *recheck = (bool *) PG_GETARG_POINTER(4);
00362 bool res;
00363
00364
00365 *recheck = false;
00366
00367
00368
00369
00370
00371 if (GIST_LEAF(entry))
00372 res = g_cube_leaf_consistent(DatumGetNDBOX(entry->key),
00373 query, strategy);
00374 else
00375 res = g_cube_internal_consistent(DatumGetNDBOX(entry->key),
00376 query, strategy);
00377
00378 PG_FREE_IF_COPY(query, 1);
00379 PG_RETURN_BOOL(res);
00380 }
00381
00382
00383
00384
00385
00386
00387 Datum
00388 g_cube_union(PG_FUNCTION_ARGS)
00389 {
00390 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
00391 int *sizep = (int *) PG_GETARG_POINTER(1);
00392 NDBOX *out = (NDBOX *) NULL;
00393 NDBOX *tmp;
00394 int i;
00395
00396
00397
00398
00399 tmp = DatumGetNDBOX(entryvec->vector[0].key);
00400
00401
00402
00403
00404 *sizep = VARSIZE(tmp);
00405
00406 for (i = 1; i < entryvec->n; i++)
00407 {
00408 out = g_cube_binary_union(tmp,
00409 DatumGetNDBOX(entryvec->vector[i].key),
00410 sizep);
00411 tmp = out;
00412 }
00413
00414 PG_RETURN_POINTER(out);
00415 }
00416
00417
00418
00419
00420
00421
00422 Datum
00423 g_cube_compress(PG_FUNCTION_ARGS)
00424 {
00425 PG_RETURN_DATUM(PG_GETARG_DATUM(0));
00426 }
00427
00428 Datum
00429 g_cube_decompress(PG_FUNCTION_ARGS)
00430 {
00431 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00432 NDBOX *key = DatumGetNDBOX(PG_DETOAST_DATUM(entry->key));
00433
00434 if (key != DatumGetNDBOX(entry->key))
00435 {
00436 GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
00437
00438 gistentryinit(*retval, PointerGetDatum(key),
00439 entry->rel, entry->page,
00440 entry->offset, FALSE);
00441 PG_RETURN_POINTER(retval);
00442 }
00443 PG_RETURN_POINTER(entry);
00444 }
00445
00446
00447
00448
00449
00450
00451 Datum
00452 g_cube_penalty(PG_FUNCTION_ARGS)
00453 {
00454 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
00455 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
00456 float *result = (float *) PG_GETARG_POINTER(2);
00457 NDBOX *ud;
00458 double tmp1,
00459 tmp2;
00460
00461 ud = cube_union_v0(DatumGetNDBOX(origentry->key),
00462 DatumGetNDBOX(newentry->key));
00463 rt_cube_size(ud, &tmp1);
00464 rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2);
00465 *result = (float) (tmp1 - tmp2);
00466
00467
00468
00469
00470 PG_RETURN_FLOAT8(*result);
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 Datum
00480 g_cube_picksplit(PG_FUNCTION_ARGS)
00481 {
00482 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
00483 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
00484 OffsetNumber i,
00485 j;
00486 NDBOX *datum_alpha,
00487 *datum_beta;
00488 NDBOX *datum_l,
00489 *datum_r;
00490 NDBOX *union_d,
00491 *union_dl,
00492 *union_dr;
00493 NDBOX *inter_d;
00494 bool firsttime;
00495 double size_alpha,
00496 size_beta,
00497 size_union,
00498 size_inter;
00499 double size_waste,
00500 waste;
00501 double size_l,
00502 size_r;
00503 int nbytes;
00504 OffsetNumber seed_1 = 1,
00505 seed_2 = 2;
00506 OffsetNumber *left,
00507 *right;
00508 OffsetNumber maxoff;
00509
00510
00511
00512
00513 maxoff = entryvec->n - 2;
00514 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
00515 v->spl_left = (OffsetNumber *) palloc(nbytes);
00516 v->spl_right = (OffsetNumber *) palloc(nbytes);
00517
00518 firsttime = true;
00519 waste = 0.0;
00520
00521 for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
00522 {
00523 datum_alpha = DatumGetNDBOX(entryvec->vector[i].key);
00524 for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
00525 {
00526 datum_beta = DatumGetNDBOX(entryvec->vector[j].key);
00527
00528
00529
00530 union_d = cube_union_v0(datum_alpha, datum_beta);
00531 rt_cube_size(union_d, &size_union);
00532 inter_d = DatumGetNDBOX(DirectFunctionCall2(cube_inter,
00533 entryvec->vector[i].key, entryvec->vector[j].key));
00534 rt_cube_size(inter_d, &size_inter);
00535 size_waste = size_union - size_inter;
00536
00537
00538
00539
00540
00541 if (size_waste > waste || firsttime)
00542 {
00543 waste = size_waste;
00544 seed_1 = i;
00545 seed_2 = j;
00546 firsttime = false;
00547 }
00548 }
00549 }
00550
00551 left = v->spl_left;
00552 v->spl_nleft = 0;
00553 right = v->spl_right;
00554 v->spl_nright = 0;
00555
00556 datum_alpha = DatumGetNDBOX(entryvec->vector[seed_1].key);
00557 datum_l = cube_union_v0(datum_alpha, datum_alpha);
00558 rt_cube_size(datum_l, &size_l);
00559 datum_beta = DatumGetNDBOX(entryvec->vector[seed_2].key);
00560 datum_r = cube_union_v0(datum_beta, datum_beta);
00561 rt_cube_size(datum_r, &size_r);
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 maxoff = OffsetNumberNext(maxoff);
00576 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
00577 {
00578
00579
00580
00581
00582
00583
00584 if (i == seed_1)
00585 {
00586 *left++ = i;
00587 v->spl_nleft++;
00588 continue;
00589 }
00590 else if (i == seed_2)
00591 {
00592 *right++ = i;
00593 v->spl_nright++;
00594 continue;
00595 }
00596
00597
00598 datum_alpha = DatumGetNDBOX(entryvec->vector[i].key);
00599 union_dl = cube_union_v0(datum_l, datum_alpha);
00600 union_dr = cube_union_v0(datum_r, datum_alpha);
00601 rt_cube_size(union_dl, &size_alpha);
00602 rt_cube_size(union_dr, &size_beta);
00603
00604
00605 if (size_alpha - size_l < size_beta - size_r)
00606 {
00607 datum_l = union_dl;
00608 size_l = size_alpha;
00609 *left++ = i;
00610 v->spl_nleft++;
00611 }
00612 else
00613 {
00614 datum_r = union_dr;
00615 size_r = size_beta;
00616 *right++ = i;
00617 v->spl_nright++;
00618 }
00619 }
00620 *left = *right = FirstOffsetNumber;
00621
00622 v->spl_ldatum = PointerGetDatum(datum_l);
00623 v->spl_rdatum = PointerGetDatum(datum_r);
00624
00625 PG_RETURN_POINTER(v);
00626 }
00627
00628
00629
00630
00631 Datum
00632 g_cube_same(PG_FUNCTION_ARGS)
00633 {
00634 NDBOX *b1 = PG_GETARG_NDBOX(0);
00635 NDBOX *b2 = PG_GETARG_NDBOX(1);
00636 bool *result = (bool *) PG_GETARG_POINTER(2);
00637
00638 if (cube_cmp_v0(b1, b2) == 0)
00639 *result = TRUE;
00640 else
00641 *result = FALSE;
00642
00643
00644
00645
00646 PG_RETURN_NDBOX(result);
00647 }
00648
00649
00650
00651
00652 bool
00653 g_cube_leaf_consistent(NDBOX *key,
00654 NDBOX *query,
00655 StrategyNumber strategy)
00656 {
00657 bool retval;
00658
00659
00660
00661
00662 switch (strategy)
00663 {
00664 case RTOverlapStrategyNumber:
00665 retval = (bool) cube_overlap_v0(key, query);
00666 break;
00667 case RTSameStrategyNumber:
00668 retval = (bool) (cube_cmp_v0(key, query) == 0);
00669 break;
00670 case RTContainsStrategyNumber:
00671 case RTOldContainsStrategyNumber:
00672 retval = (bool) cube_contains_v0(key, query);
00673 break;
00674 case RTContainedByStrategyNumber:
00675 case RTOldContainedByStrategyNumber:
00676 retval = (bool) cube_contains_v0(query, key);
00677 break;
00678 default:
00679 retval = FALSE;
00680 }
00681 return (retval);
00682 }
00683
00684 bool
00685 g_cube_internal_consistent(NDBOX *key,
00686 NDBOX *query,
00687 StrategyNumber strategy)
00688 {
00689 bool retval;
00690
00691
00692
00693
00694 switch (strategy)
00695 {
00696 case RTOverlapStrategyNumber:
00697 retval = (bool) cube_overlap_v0(key, query);
00698 break;
00699 case RTSameStrategyNumber:
00700 case RTContainsStrategyNumber:
00701 case RTOldContainsStrategyNumber:
00702 retval = (bool) cube_contains_v0(key, query);
00703 break;
00704 case RTContainedByStrategyNumber:
00705 case RTOldContainedByStrategyNumber:
00706 retval = (bool) cube_overlap_v0(key, query);
00707 break;
00708 default:
00709 retval = FALSE;
00710 }
00711 return (retval);
00712 }
00713
00714 NDBOX *
00715 g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
00716 {
00717 NDBOX *retval;
00718
00719 retval = cube_union_v0(r1, r2);
00720 *sizep = VARSIZE(retval);
00721
00722 return (retval);
00723 }
00724
00725
00726
00727 NDBOX *
00728 cube_union_v0(NDBOX *a, NDBOX *b)
00729 {
00730 int i;
00731 NDBOX *result;
00732
00733 if (a->dim >= b->dim)
00734 {
00735 result = palloc0(VARSIZE(a));
00736 SET_VARSIZE(result, VARSIZE(a));
00737 result->dim = a->dim;
00738 }
00739 else
00740 {
00741 result = palloc0(VARSIZE(b));
00742 SET_VARSIZE(result, VARSIZE(b));
00743 result->dim = b->dim;
00744 }
00745
00746
00747 if (a->dim < b->dim)
00748 {
00749 NDBOX *tmp = b;
00750
00751 b = a;
00752 a = tmp;
00753 }
00754
00755
00756
00757
00758
00759 for (i = 0; i < b->dim; i++)
00760 {
00761 result->x[i] = Min(b->x[i], b->x[i + b->dim]);
00762 result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
00763 }
00764 for (i = b->dim; i < a->dim; i++)
00765 {
00766 result->x[i] = 0;
00767 result->x[i + a->dim] = 0;
00768 }
00769
00770
00771 for (i = 0; i < a->dim; i++)
00772 {
00773 result->x[i] =
00774 Min(Min(a->x[i], a->x[i + a->dim]), result->x[i]);
00775 result->x[i + a->dim] = Max(Max(a->x[i],
00776 a->x[i + a->dim]), result->x[i + a->dim]);
00777 }
00778
00779 return (result);
00780 }
00781
00782 Datum
00783 cube_union(PG_FUNCTION_ARGS)
00784 {
00785 NDBOX *a = PG_GETARG_NDBOX(0);
00786 NDBOX *b = PG_GETARG_NDBOX(1);
00787 NDBOX *res;
00788
00789 res = cube_union_v0(a, b);
00790
00791 PG_FREE_IF_COPY(a, 0);
00792 PG_FREE_IF_COPY(b, 1);
00793 PG_RETURN_NDBOX(res);
00794 }
00795
00796
00797 Datum
00798 cube_inter(PG_FUNCTION_ARGS)
00799 {
00800 NDBOX *a = PG_GETARG_NDBOX(0);
00801 NDBOX *b = PG_GETARG_NDBOX(1);
00802 NDBOX *result;
00803 bool swapped = false;
00804 int i;
00805
00806 if (a->dim >= b->dim)
00807 {
00808 result = palloc0(VARSIZE(a));
00809 SET_VARSIZE(result, VARSIZE(a));
00810 result->dim = a->dim;
00811 }
00812 else
00813 {
00814 result = palloc0(VARSIZE(b));
00815 SET_VARSIZE(result, VARSIZE(b));
00816 result->dim = b->dim;
00817 }
00818
00819
00820 if (a->dim < b->dim)
00821 {
00822 NDBOX *tmp = b;
00823
00824 b = a;
00825 a = tmp;
00826 swapped = true;
00827 }
00828
00829
00830
00831
00832
00833 for (i = 0; i < b->dim; i++)
00834 {
00835 result->x[i] = Min(b->x[i], b->x[i + b->dim]);
00836 result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
00837 }
00838 for (i = b->dim; i < a->dim; i++)
00839 {
00840 result->x[i] = 0;
00841 result->x[i + a->dim] = 0;
00842 }
00843
00844
00845 for (i = 0; i < a->dim; i++)
00846 {
00847 result->x[i] =
00848 Max(Min(a->x[i], a->x[i + a->dim]), result->x[i]);
00849 result->x[i + a->dim] = Min(Max(a->x[i],
00850 a->x[i + a->dim]), result->x[i + a->dim]);
00851 }
00852
00853 if (swapped)
00854 {
00855 PG_FREE_IF_COPY(b, 0);
00856 PG_FREE_IF_COPY(a, 1);
00857 }
00858 else
00859 {
00860 PG_FREE_IF_COPY(a, 0);
00861 PG_FREE_IF_COPY(b, 1);
00862 }
00863
00864
00865
00866
00867 PG_RETURN_NDBOX(result);
00868 }
00869
00870
00871 Datum
00872 cube_size(PG_FUNCTION_ARGS)
00873 {
00874 NDBOX *a = PG_GETARG_NDBOX(0);
00875 double result;
00876 int i,
00877 j;
00878
00879 result = 1.0;
00880 for (i = 0, j = a->dim; i < a->dim; i++, j++)
00881 result = result * Abs((a->x[j] - a->x[i]));
00882
00883 PG_FREE_IF_COPY(a, 0);
00884 PG_RETURN_FLOAT8(result);
00885 }
00886
00887 void
00888 rt_cube_size(NDBOX *a, double *size)
00889 {
00890 int i,
00891 j;
00892
00893 if (a == (NDBOX *) NULL)
00894 *size = 0.0;
00895 else
00896 {
00897 *size = 1.0;
00898 for (i = 0, j = a->dim; i < a->dim; i++, j++)
00899 *size = (*size) * Abs((a->x[j] - a->x[i]));
00900 }
00901 return;
00902 }
00903
00904
00905
00906 int32
00907 cube_cmp_v0(NDBOX *a, NDBOX *b)
00908 {
00909 int i;
00910 int dim;
00911
00912 dim = Min(a->dim, b->dim);
00913
00914
00915 for (i = 0; i < dim; i++)
00916 {
00917 if (Min(a->x[i], a->x[a->dim + i]) >
00918 Min(b->x[i], b->x[b->dim + i]))
00919 return 1;
00920 if (Min(a->x[i], a->x[a->dim + i]) <
00921 Min(b->x[i], b->x[b->dim + i]))
00922 return -1;
00923 }
00924 for (i = 0; i < dim; i++)
00925 {
00926 if (Max(a->x[i], a->x[a->dim + i]) >
00927 Max(b->x[i], b->x[b->dim + i]))
00928 return 1;
00929 if (Max(a->x[i], a->x[a->dim + i]) <
00930 Max(b->x[i], b->x[b->dim + i]))
00931 return -1;
00932 }
00933
00934
00935 if (a->dim > b->dim)
00936 {
00937 for (i = dim; i < a->dim; i++)
00938 {
00939 if (Min(a->x[i], a->x[a->dim + i]) > 0)
00940 return 1;
00941 if (Min(a->x[i], a->x[a->dim + i]) < 0)
00942 return -1;
00943 }
00944 for (i = dim; i < a->dim; i++)
00945 {
00946 if (Max(a->x[i], a->x[a->dim + i]) > 0)
00947 return 1;
00948 if (Max(a->x[i], a->x[a->dim + i]) < 0)
00949 return -1;
00950 }
00951
00952
00953
00954
00955
00956 return 1;
00957 }
00958 if (a->dim < b->dim)
00959 {
00960 for (i = dim; i < b->dim; i++)
00961 {
00962 if (Min(b->x[i], b->x[b->dim + i]) > 0)
00963 return -1;
00964 if (Min(b->x[i], b->x[b->dim + i]) < 0)
00965 return 1;
00966 }
00967 for (i = dim; i < b->dim; i++)
00968 {
00969 if (Max(b->x[i], b->x[b->dim + i]) > 0)
00970 return -1;
00971 if (Max(b->x[i], b->x[b->dim + i]) < 0)
00972 return 1;
00973 }
00974
00975
00976
00977
00978
00979 return -1;
00980 }
00981
00982
00983 return 0;
00984 }
00985
00986 Datum
00987 cube_cmp(PG_FUNCTION_ARGS)
00988 {
00989 NDBOX *a = PG_GETARG_NDBOX(0),
00990 *b = PG_GETARG_NDBOX(1);
00991 int32 res;
00992
00993 res = cube_cmp_v0(a, b);
00994
00995 PG_FREE_IF_COPY(a, 0);
00996 PG_FREE_IF_COPY(b, 1);
00997 PG_RETURN_INT32(res);
00998 }
00999
01000
01001 Datum
01002 cube_eq(PG_FUNCTION_ARGS)
01003 {
01004 NDBOX *a = PG_GETARG_NDBOX(0),
01005 *b = PG_GETARG_NDBOX(1);
01006 int32 res;
01007
01008 res = cube_cmp_v0(a, b);
01009
01010 PG_FREE_IF_COPY(a, 0);
01011 PG_FREE_IF_COPY(b, 1);
01012 PG_RETURN_BOOL(res == 0);
01013 }
01014
01015
01016 Datum
01017 cube_ne(PG_FUNCTION_ARGS)
01018 {
01019 NDBOX *a = PG_GETARG_NDBOX(0),
01020 *b = PG_GETARG_NDBOX(1);
01021 int32 res;
01022
01023 res = cube_cmp_v0(a, b);
01024
01025 PG_FREE_IF_COPY(a, 0);
01026 PG_FREE_IF_COPY(b, 1);
01027 PG_RETURN_BOOL(res != 0);
01028 }
01029
01030
01031 Datum
01032 cube_lt(PG_FUNCTION_ARGS)
01033 {
01034 NDBOX *a = PG_GETARG_NDBOX(0),
01035 *b = PG_GETARG_NDBOX(1);
01036 int32 res;
01037
01038 res = cube_cmp_v0(a, b);
01039
01040 PG_FREE_IF_COPY(a, 0);
01041 PG_FREE_IF_COPY(b, 1);
01042 PG_RETURN_BOOL(res < 0);
01043 }
01044
01045
01046 Datum
01047 cube_gt(PG_FUNCTION_ARGS)
01048 {
01049 NDBOX *a = PG_GETARG_NDBOX(0),
01050 *b = PG_GETARG_NDBOX(1);
01051 int32 res;
01052
01053 res = cube_cmp_v0(a, b);
01054
01055 PG_FREE_IF_COPY(a, 0);
01056 PG_FREE_IF_COPY(b, 1);
01057 PG_RETURN_BOOL(res > 0);
01058 }
01059
01060
01061 Datum
01062 cube_le(PG_FUNCTION_ARGS)
01063 {
01064 NDBOX *a = PG_GETARG_NDBOX(0),
01065 *b = PG_GETARG_NDBOX(1);
01066 int32 res;
01067
01068 res = cube_cmp_v0(a, b);
01069
01070 PG_FREE_IF_COPY(a, 0);
01071 PG_FREE_IF_COPY(b, 1);
01072 PG_RETURN_BOOL(res <= 0);
01073 }
01074
01075
01076 Datum
01077 cube_ge(PG_FUNCTION_ARGS)
01078 {
01079 NDBOX *a = PG_GETARG_NDBOX(0),
01080 *b = PG_GETARG_NDBOX(1);
01081 int32 res;
01082
01083 res = cube_cmp_v0(a, b);
01084
01085 PG_FREE_IF_COPY(a, 0);
01086 PG_FREE_IF_COPY(b, 1);
01087 PG_RETURN_BOOL(res >= 0);
01088 }
01089
01090
01091
01092
01093 bool
01094 cube_contains_v0(NDBOX *a, NDBOX *b)
01095 {
01096 int i;
01097
01098 if ((a == NULL) || (b == NULL))
01099 return (FALSE);
01100
01101 if (a->dim < b->dim)
01102 {
01103
01104
01105
01106
01107
01108 for (i = a->dim; i < b->dim; i++)
01109 {
01110 if (b->x[i] != 0)
01111 return (FALSE);
01112 if (b->x[i + b->dim] != 0)
01113 return (FALSE);
01114 }
01115 }
01116
01117
01118 for (i = 0; i < Min(a->dim, b->dim); i++)
01119 {
01120 if (Min(a->x[i], a->x[a->dim + i]) >
01121 Min(b->x[i], b->x[b->dim + i]))
01122 return (FALSE);
01123 if (Max(a->x[i], a->x[a->dim + i]) <
01124 Max(b->x[i], b->x[b->dim + i]))
01125 return (FALSE);
01126 }
01127
01128 return (TRUE);
01129 }
01130
01131 Datum
01132 cube_contains(PG_FUNCTION_ARGS)
01133 {
01134 NDBOX *a = PG_GETARG_NDBOX(0),
01135 *b = PG_GETARG_NDBOX(1);
01136 bool res;
01137
01138 res = cube_contains_v0(a, b);
01139
01140 PG_FREE_IF_COPY(a, 0);
01141 PG_FREE_IF_COPY(b, 1);
01142 PG_RETURN_BOOL(res);
01143 }
01144
01145
01146
01147 Datum
01148 cube_contained(PG_FUNCTION_ARGS)
01149 {
01150 NDBOX *a = PG_GETARG_NDBOX(0),
01151 *b = PG_GETARG_NDBOX(1);
01152 bool res;
01153
01154 res = cube_contains_v0(b, a);
01155
01156 PG_FREE_IF_COPY(a, 0);
01157 PG_FREE_IF_COPY(b, 1);
01158 PG_RETURN_BOOL(res);
01159 }
01160
01161
01162
01163 bool
01164 cube_overlap_v0(NDBOX *a, NDBOX *b)
01165 {
01166 int i;
01167
01168
01169
01170
01171
01172 if ((a == NULL) || (b == NULL))
01173 return (FALSE);
01174
01175
01176 if (a->dim < b->dim)
01177 {
01178 NDBOX *tmp = b;
01179
01180 b = a;
01181 a = tmp;
01182 }
01183
01184
01185 for (i = 0; i < b->dim; i++)
01186 {
01187 if (Min(a->x[i], a->x[a->dim + i]) >
01188 Max(b->x[i], b->x[b->dim + i]))
01189 return (FALSE);
01190 if (Max(a->x[i], a->x[a->dim + i]) <
01191 Min(b->x[i], b->x[b->dim + i]))
01192 return (FALSE);
01193 }
01194
01195
01196 for (i = b->dim; i < a->dim; i++)
01197 {
01198 if (Min(a->x[i], a->x[a->dim + i]) > 0)
01199 return (FALSE);
01200 if (Max(a->x[i], a->x[a->dim + i]) < 0)
01201 return (FALSE);
01202 }
01203
01204 return (TRUE);
01205 }
01206
01207
01208 Datum
01209 cube_overlap(PG_FUNCTION_ARGS)
01210 {
01211 NDBOX *a = PG_GETARG_NDBOX(0),
01212 *b = PG_GETARG_NDBOX(1);
01213 bool res;
01214
01215 res = cube_overlap_v0(a, b);
01216
01217 PG_FREE_IF_COPY(a, 0);
01218 PG_FREE_IF_COPY(b, 1);
01219 PG_RETURN_BOOL(res);
01220 }
01221
01222
01223
01224
01225
01226
01227
01228 Datum
01229 cube_distance(PG_FUNCTION_ARGS)
01230 {
01231 NDBOX *a = PG_GETARG_NDBOX(0),
01232 *b = PG_GETARG_NDBOX(1);
01233 bool swapped = false;
01234 double d,
01235 distance;
01236 int i;
01237
01238
01239 if (a->dim < b->dim)
01240 {
01241 NDBOX *tmp = b;
01242
01243 b = a;
01244 a = tmp;
01245 swapped = true;
01246 }
01247
01248 distance = 0.0;
01249
01250 for (i = 0; i < b->dim; i++)
01251 {
01252 d = distance_1D(a->x[i], a->x[i + a->dim], b->x[i], b->x[i + b->dim]);
01253 distance += d * d;
01254 }
01255
01256
01257 for (i = b->dim; i < a->dim; i++)
01258 {
01259 d = distance_1D(a->x[i], a->x[i + a->dim], 0.0, 0.0);
01260 distance += d * d;
01261 }
01262
01263 if (swapped)
01264 {
01265 PG_FREE_IF_COPY(b, 0);
01266 PG_FREE_IF_COPY(a, 1);
01267 }
01268 else
01269 {
01270 PG_FREE_IF_COPY(a, 0);
01271 PG_FREE_IF_COPY(b, 1);
01272 }
01273
01274 PG_RETURN_FLOAT8(sqrt(distance));
01275 }
01276
01277 static double
01278 distance_1D(double a1, double a2, double b1, double b2)
01279 {
01280
01281 if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
01282 return (Min(b1, b2) - Max(a1, a2));
01283
01284
01285 if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
01286 return (Min(a1, a2) - Max(b1, b2));
01287
01288
01289 return (0.0);
01290 }
01291
01292
01293 Datum
01294 cube_is_point(PG_FUNCTION_ARGS)
01295 {
01296 NDBOX *a = PG_GETARG_NDBOX(0);
01297 int i,
01298 j;
01299
01300 for (i = 0, j = a->dim; i < a->dim; i++, j++)
01301 {
01302 if (a->x[i] != a->x[j])
01303 PG_RETURN_BOOL(FALSE);
01304 }
01305
01306 PG_FREE_IF_COPY(a, 0);
01307 PG_RETURN_BOOL(TRUE);
01308 }
01309
01310
01311 Datum
01312 cube_dim(PG_FUNCTION_ARGS)
01313 {
01314 NDBOX *c = PG_GETARG_NDBOX(0);
01315 int dim = c->dim;
01316
01317 PG_FREE_IF_COPY(c, 0);
01318 PG_RETURN_INT32(dim);
01319 }
01320
01321
01322 Datum
01323 cube_ll_coord(PG_FUNCTION_ARGS)
01324 {
01325 NDBOX *c = PG_GETARG_NDBOX(0);
01326 int n = PG_GETARG_INT16(1);
01327 double result;
01328
01329 if (c->dim >= n && n > 0)
01330 result = Min(c->x[n - 1], c->x[c->dim + n - 1]);
01331 else
01332 result = 0;
01333
01334 PG_FREE_IF_COPY(c, 0);
01335 PG_RETURN_FLOAT8(result);
01336 }
01337
01338
01339 Datum
01340 cube_ur_coord(PG_FUNCTION_ARGS)
01341 {
01342 NDBOX *c = PG_GETARG_NDBOX(0);
01343 int n = PG_GETARG_INT16(1);
01344 double result;
01345
01346 if (c->dim >= n && n > 0)
01347 result = Max(c->x[n - 1], c->x[c->dim + n - 1]);
01348 else
01349 result = 0;
01350
01351 PG_FREE_IF_COPY(c, 0);
01352 PG_RETURN_FLOAT8(result);
01353 }
01354
01355
01356 Datum
01357 cube_enlarge(PG_FUNCTION_ARGS)
01358 {
01359 NDBOX *a = PG_GETARG_NDBOX(0);
01360 double r = PG_GETARG_FLOAT8(1);
01361 int32 n = PG_GETARG_INT32(2);
01362 NDBOX *result;
01363 int dim = 0;
01364 int size;
01365 int i,
01366 j,
01367 k;
01368
01369 if (n > CUBE_MAX_DIM)
01370 n = CUBE_MAX_DIM;
01371 if (r > 0 && n > 0)
01372 dim = n;
01373 if (a->dim > dim)
01374 dim = a->dim;
01375 size = offsetof(NDBOX, x[0]) +sizeof(double) * dim * 2;
01376 result = (NDBOX *) palloc0(size);
01377 SET_VARSIZE(result, size);
01378 result->dim = dim;
01379 for (i = 0, j = dim, k = a->dim; i < a->dim; i++, j++, k++)
01380 {
01381 if (a->x[i] >= a->x[k])
01382 {
01383 result->x[i] = a->x[k] - r;
01384 result->x[j] = a->x[i] + r;
01385 }
01386 else
01387 {
01388 result->x[i] = a->x[i] - r;
01389 result->x[j] = a->x[k] + r;
01390 }
01391 if (result->x[i] > result->x[j])
01392 {
01393 result->x[i] = (result->x[i] + result->x[j]) / 2;
01394 result->x[j] = result->x[i];
01395 }
01396 }
01397
01398 for (; i < dim; i++, j++)
01399 {
01400 result->x[i] = -r;
01401 result->x[j] = r;
01402 }
01403
01404 PG_FREE_IF_COPY(a, 0);
01405 PG_RETURN_NDBOX(result);
01406 }
01407
01408
01409 Datum
01410 cube_f8(PG_FUNCTION_ARGS)
01411 {
01412 double x = PG_GETARG_FLOAT8(0);
01413 NDBOX *result;
01414 int size;
01415
01416 size = offsetof(NDBOX, x[0]) +sizeof(double) * 2;
01417 result = (NDBOX *) palloc0(size);
01418 SET_VARSIZE(result, size);
01419 result->dim = 1;
01420 result->x[0] = result->x[1] = x;
01421
01422 PG_RETURN_NDBOX(result);
01423 }
01424
01425
01426 Datum
01427 cube_f8_f8(PG_FUNCTION_ARGS)
01428 {
01429 double x0 = PG_GETARG_FLOAT8(0);
01430 double x1 = PG_GETARG_FLOAT8(1);
01431 NDBOX *result;
01432 int size;
01433
01434 size = offsetof(NDBOX, x[0]) +sizeof(double) * 2;
01435 result = (NDBOX *) palloc0(size);
01436 SET_VARSIZE(result, size);
01437 result->dim = 1;
01438 result->x[0] = x0;
01439 result->x[1] = x1;
01440
01441 PG_RETURN_NDBOX(result);
01442 }
01443
01444
01445
01446 Datum
01447 cube_c_f8(PG_FUNCTION_ARGS)
01448 {
01449 NDBOX *c = PG_GETARG_NDBOX(0);
01450 double x = PG_GETARG_FLOAT8(1);
01451 NDBOX *result;
01452 int size;
01453 int i;
01454
01455 size = offsetof(NDBOX, x[0]) +sizeof(double) * (c->dim + 1) *2;
01456 result = (NDBOX *) palloc0(size);
01457 SET_VARSIZE(result, size);
01458 result->dim = c->dim + 1;
01459 for (i = 0; i < c->dim; i++)
01460 {
01461 result->x[i] = c->x[i];
01462 result->x[result->dim + i] = c->x[c->dim + i];
01463 }
01464 result->x[result->dim - 1] = x;
01465 result->x[2 * result->dim - 1] = x;
01466
01467 PG_FREE_IF_COPY(c, 0);
01468 PG_RETURN_NDBOX(result);
01469 }
01470
01471
01472 Datum
01473 cube_c_f8_f8(PG_FUNCTION_ARGS)
01474 {
01475 NDBOX *c = PG_GETARG_NDBOX(0);
01476 double x1 = PG_GETARG_FLOAT8(1);
01477 double x2 = PG_GETARG_FLOAT8(2);
01478 NDBOX *result;
01479 int size;
01480 int i;
01481
01482 size = offsetof(NDBOX, x[0]) +sizeof(double) * (c->dim + 1) *2;
01483 result = (NDBOX *) palloc0(size);
01484 SET_VARSIZE(result, size);
01485 result->dim = c->dim + 1;
01486 for (i = 0; i < c->dim; i++)
01487 {
01488 result->x[i] = c->x[i];
01489 result->x[result->dim + i] = c->x[c->dim + i];
01490 }
01491 result->x[result->dim - 1] = x1;
01492 result->x[2 * result->dim - 1] = x2;
01493
01494 PG_FREE_IF_COPY(c, 0);
01495 PG_RETURN_NDBOX(result);
01496 }