43 #include "access/gist.h"
44 #include "access/itup.h"
45 #include "access/skey.h"
47 #include "../postgis_config.h"
50 #include "lwgeom_pg.h"
51 #include "gserialized_gist.h"
55 # ifdef HAVE_GNU_ISFINITE
58 # define isfinite finite
68 #define LIMIT_RATIO 0.1
74 #define KOROTKOV_SPLIT 1
79 #if POSTGIS_DEBUG_LEVEL > 0
80 static int g2d_counter_leaf = 0;
81 static int g2d_counter_internal = 0;
120 #if POSTGIS_PGSQL_VERSION > 94
140 return pstrdup(
"<NULLPTR>");
143 sprintf(rv,
"BOX2DF(%.12g %.12g, %.12g %.12g)", a->xmin, a->ymin, a->xmax, a->ymax);
150 BOX2DF *c = (BOX2DF*)palloc(
sizeof(BOX2DF));
151 memcpy((
void*)c, (
void*)b,
sizeof(BOX2DF));
152 POSTGIS_DEBUGF(5,
"copied box2df (%p) to box2df (%p)", b, c);
166 a->xmin = a->xmax = a->ymin = a->ymax =
NAN;
172 if ( ! isfinite(a->xmax) )
174 if ( ! isfinite(a->ymax) )
176 if ( ! isfinite(a->ymin) )
177 a->ymin = -1*FLT_MAX;
178 if ( ! isfinite(a->xmin) )
179 a->xmin = -1*FLT_MAX;
190 if (b_union->xmin > b_new->xmin || isnan(b_union->xmin))
191 b_union->xmin = b_new->xmin;
192 if (b_union->ymin > b_new->ymin || isnan(b_union->ymin))
193 b_union->ymin = b_new->ymin;
195 if (b_union->xmax < b_new->xmax || isnan(b_union->xmax))
196 b_union->xmax = b_new->xmax;
197 if (b_union->ymax < b_new->ymax || isnan(b_union->ymax))
198 b_union->ymax = b_new->ymax;
204 #if KOROTKOV_SPLIT < 1
205 static bool box2df_intersection(
const BOX2DF *a,
const BOX2DF *b, BOX2DF *n)
209 if( a == NULL || b == NULL || n == NULL )
212 n->xmax = Min(a->xmax, b->xmax);
213 n->ymax = Min(a->ymax, b->ymax);
214 n->xmin = Max(a->xmin, b->xmin);
215 n->ymin = Max(a->ymin, b->ymin);
219 if ( (n->xmax < n->xmin) || (n->ymax < n->ymin) )
233 if ( (a->xmax <= a->xmin) || (a->ymax <= a->ymin) )
235 result = (float) 0.0;
239 result = (((double) a->xmax)-((double) a->xmin)) * (((
double) a->ymax)-((
double) a->ymin));
250 return ((a->xmax) - (a->xmin)) + ((a->ymax) - (a->ymin));
257 POSTGIS_DEBUG(5,
"entered function");
259 if ( a == NULL && b == NULL )
261 elog(ERROR,
"box2df_union_size received two null arguments");
271 result = ((double)Max(a->xmax,b->xmax) - (double)Min(a->xmin,b->xmin)) *
272 ((
double)Max(a->ymax,b->ymax) - (double)Min(a->ymin,b->ymin));
284 POSTGIS_DEBUG(5,
"entered function");
286 if ( a == NULL && b == NULL )
288 elog(ERROR,
"box2df_union_edge received two null arguments");
298 result = (Max(a->xmax,b->xmax) - Min(a->xmin,b->xmin)) +
299 (Max(a->ymax,b->ymax) - Min(a->ymin,b->ymin));
319 memset(box, 0,
sizeof(
GBOX));
340 if ( b->xmax < b->xmin )
346 if ( b->ymax < b->ymin )
360 if ( (a->xmin > b->xmax) || (b->xmin > a->xmax) ||
361 (a->ymin > b->ymax) || (b->ymin > a->ymax) )
378 if ( (a->xmin > b->xmin) || (a->xmax < b->xmax) ||
379 (a->ymin > b->ymin) || (a->ymax < b->ymax) )
396 POSTGIS_DEBUG(5,
"entered function");
410 else if ((a->xmin == b->xmin) && (a->xmax == b->xmax) && (a->ymin == b->ymin) && (a->ymax == b->ymax))
422 return a->xmax <= b->xmax;
431 return a->xmax < b->xmin;
440 return a->xmin > b->xmax;
449 return a->xmin >= b->xmin;
458 return a->ymax <= b->ymax;
467 return a->ymax < b->ymin;
476 return a->ymin > b->ymax;
485 return a->ymin >= b->ymin;
494 double a_x = (a->xmax + a->xmin) / 2.0;
495 double a_y = (a->ymax + a->ymin) / 2.0;
496 double b_x = (b->xmax + b->xmin) / 2.0;
497 double b_y = (b->ymax + b->ymin) / 2.0;
500 return sqrt((a_x - b_x) * (a_x - b_x) + (a_y - b_y) * (a_y - b_y));
503 #if POSTGIS_PGSQL_VERSION < 95
508 static double box2df_distance_node_centroid(
const BOX2DF *node,
const BOX2DF *query)
515 q.xmin = q.xmax = (query->xmin + query->xmax) / 2.0;
516 q.ymin = q.ymax = (query->ymin + query->ymax) / 2.0;
525 if ( qx >= node->xmin && qx <= node->xmax )
527 if( qy > node->ymax )
529 else if ( qy < node->ymin )
534 else if ( qy >= node->ymin && qy <= node->ymax )
536 if ( qx > node->xmax )
538 else if ( qx < node->xmin )
546 if ( qx < node->xmin && qy < node->ymin )
548 d = (node->xmin - qx) * (node->xmin - qx) +
549 (node->ymin - qy) * (node->ymin - qy);
552 else if ( qx < node->xmin && qy > node->ymax )
554 d = (node->xmin - qx) * (node->xmin - qx) +
555 (node->ymax - qy) * (node->ymax - qy);
558 else if ( qx > node->xmax && qy > node->ymax )
560 d = (node->xmax - qx) * (node->xmax - qx) +
561 (node->ymax - qy) * (node->ymax - qy);
564 else if ( qx > node->xmin && qy < node->ymin )
566 d = (node->xmax - qx) * (node->xmax - qx) +
567 (node->ymin - qy) * (node->ymin - qy);
572 elog(ERROR,
"%s: reached unreachable code", __func__);
581 static inline double pt_distance(
double ax,
double ay,
double bx,
double by)
583 return sqrt((ax - bx) * (ax - bx) + (ay - by) * (ay - by));
598 return pt_distance(a->xmax, a->ymin, b->xmin, b->ymax);
600 return pt_distance(a->xmax, a->ymax, b->xmin, b->ymin);
602 return (
double)b->xmin - (double)a->xmax;
607 return pt_distance(a->xmin, a->ymin, b->xmax, b->ymax);
609 return pt_distance(a->xmin, a->ymax, b->xmax, b->ymin);
611 return (
double)a->xmin - (double)b->xmax;
616 return pt_distance(a->xmax, a->ymin, b->xmin, b->ymax);
618 return pt_distance(a->xmin, a->ymin, b->xmax, b->ymax);
620 return (
double)a->ymin - (double)b->ymax;
625 return pt_distance(a->xmax, a->ymax, b->xmin, b->ymin);
627 return pt_distance(a->xmin, a->ymax, b->xmax, b->ymin);
629 return (
double)b->ymin - (double)a->ymax;
649 POSTGIS_DEBUG(4,
"entered function");
655 if (VARATT_IS_EXTENDED(gsdatum))
657 gpart = (
GSERIALIZED*)PG_DETOAST_DATUM_SLICE(gsdatum, 0, 8 +
sizeof(BOX2DF));
664 flags = gpart->
flags;
666 POSTGIS_DEBUGF(4,
"got flags %d", gpart->
flags);
672 POSTGIS_DEBUG(4,
"copying box out of serialization");
673 memcpy(box2df, gpart->
data,
sizeof(BOX2DF));
686 POSTGIS_DEBUG(4,
"could not calculate bbox, returning failure");
687 POSTGIS_FREE_IF_COPY_P(gpart, gsdatum);
688 POSTGIS_FREE_IF_COPY_P(g, gsdatum);
691 POSTGIS_FREE_IF_COPY_P(g, gsdatum);
695 POSTGIS_FREE_IF_COPY_P(gpart, gsdatum);
713 BOX2DF b1, b2, *br1=NULL, *br2=NULL;
714 POSTGIS_DEBUG(3,
"entered function");
719 if ( predicate(br1, br2) )
727 #if POSTGIS_PGSQL_VERSION > 94
731 BOX2DF b2, *br2=NULL;
732 POSTGIS_DEBUG(3,
"entered function");
736 if ( predicate(br1, br2) )
751 POSTGIS_DEBUG(3,
"entered function");
753 PG_RETURN_BOOL(
true);
755 PG_RETURN_BOOL(
false);
761 if (
box2df_contains((BOX2DF *)PG_GETARG_POINTER(0), (BOX2DF *)PG_GETARG_POINTER(1)))
762 PG_RETURN_BOOL(
true);
764 PG_RETURN_BOOL(
false);
770 POSTGIS_DEBUG(3,
"entered function");
772 PG_RETURN_BOOL(
true);
774 PG_RETURN_BOOL(
false);
780 if (
box2df_within((BOX2DF *)PG_GETARG_POINTER(0), (BOX2DF *)PG_GETARG_POINTER(1)))
781 PG_RETURN_BOOL(
true);
783 PG_RETURN_BOOL(
false);
789 POSTGIS_DEBUG(3,
"entered function");
791 PG_RETURN_BOOL(
true);
793 PG_RETURN_BOOL(
false);
799 if (
box2df_overlaps((BOX2DF *)PG_GETARG_POINTER(0), (BOX2DF *)PG_GETARG_POINTER(1)))
800 PG_RETURN_BOOL(
true);
802 PG_RETURN_BOOL(
false);
814 Datum gs1 = PG_GETARG_DATUM(0);
815 Datum gs2 = PG_GETARG_DATUM(1);
817 POSTGIS_DEBUG(3,
"entered function");
827 PG_RETURN_FLOAT8(FLT_MAX);
834 Datum gs1 = PG_GETARG_DATUM(0);
835 Datum gs2 = PG_GETARG_DATUM(1);
837 POSTGIS_DEBUG(3,
"entered function");
847 PG_RETURN_FLOAT8(FLT_MAX);
854 PG_RETURN_BOOL(
true);
856 PG_RETURN_BOOL(
false);
862 POSTGIS_DEBUG(3,
"entered function");
864 PG_RETURN_BOOL(
true);
866 PG_RETURN_BOOL(
false);
872 POSTGIS_DEBUG(3,
"entered function");
874 PG_RETURN_BOOL(
true);
876 PG_RETURN_BOOL(
false);
883 PG_RETURN_BOOL(
true);
885 PG_RETURN_BOOL(
false);
892 PG_RETURN_BOOL(
true);
894 PG_RETURN_BOOL(
false);
901 PG_RETURN_BOOL(
true);
903 PG_RETURN_BOOL(
false);
910 PG_RETURN_BOOL(
true);
912 PG_RETURN_BOOL(
false);
919 PG_RETURN_BOOL(
true);
921 PG_RETURN_BOOL(
false);
928 PG_RETURN_BOOL(
true);
930 PG_RETURN_BOOL(
false);
937 PG_RETURN_BOOL(
true);
939 PG_RETURN_BOOL(
false);
946 PG_RETURN_BOOL(
true);
948 PG_RETURN_BOOL(
false);
955 PG_RETURN_BOOL(
true);
957 PG_RETURN_BOOL(
false);
974 GISTENTRY *entry_in = (GISTENTRY*)PG_GETARG_POINTER(0);
975 GISTENTRY *entry_out = NULL;
979 POSTGIS_DEBUG(4,
"[GIST] 'compress' function called");
985 if ( ! entry_in->leafkey )
987 POSTGIS_DEBUG(4,
"[GIST] non-leafkey entry, returning input unaltered");
988 PG_RETURN_POINTER(entry_in);
991 POSTGIS_DEBUG(4,
"[GIST] processing leafkey input");
992 entry_out = palloc(
sizeof(GISTENTRY));
998 if ( DatumGetPointer(entry_in->key) == NULL )
1000 POSTGIS_DEBUG(4,
"[GIST] leafkey is null");
1001 gistentryinit(*entry_out, (Datum) 0, entry_in->rel,
1002 entry_in->page, entry_in->offset,
false);
1003 POSTGIS_DEBUG(4,
"[GIST] returning copy of input");
1004 PG_RETURN_POINTER(entry_out);
1014 gistentryinit(*entry_out, PointerGetDatum(
box2df_copy(&bbox_out)),
1015 entry_in->rel, entry_in->page, entry_in->offset,
false);
1017 POSTGIS_DEBUG(4,
"[GIST] empty geometry!");
1018 PG_RETURN_POINTER(entry_out);
1021 POSTGIS_DEBUGF(4,
"[GIST] got entry_in->key: %s",
box2df_to_string(&bbox_out));
1024 if ( ! isfinite(bbox_out.xmax) || ! isfinite(bbox_out.xmin) ||
1025 ! isfinite(bbox_out.ymax) || ! isfinite(bbox_out.ymin) )
1028 gistentryinit(*entry_out, PointerGetDatum(
box2df_copy(&bbox_out)),
1029 entry_in->rel, entry_in->page, entry_in->offset,
false);
1031 POSTGIS_DEBUG(4,
"[GIST] infinite geometry!");
1032 PG_RETURN_POINTER(entry_out);
1039 gistentryinit(*entry_out, PointerGetDatum(
box2df_copy(&bbox_out)),
1040 entry_in->rel, entry_in->page, entry_in->offset,
false);
1043 POSTGIS_DEBUG(4,
"[GIST] 'compress' function complete");
1044 PG_RETURN_POINTER(entry_out);
1055 POSTGIS_DEBUG(5,
"[GIST] 'decompress' function called");
1057 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
1069 POSTGIS_DEBUGF(4,
"[GIST] leaf consistent, strategy [%d], count[%i]",
1070 strategy, g2d_counter_leaf++);
1076 case RTOverlapStrategyNumber:
1079 case RTSameStrategyNumber:
1082 case RTContainsStrategyNumber:
1083 case RTOldContainsStrategyNumber:
1086 case RTContainedByStrategyNumber:
1087 case RTOldContainedByStrategyNumber:
1092 case RTAboveStrategyNumber:
1095 case RTBelowStrategyNumber:
1098 case RTRightStrategyNumber:
1101 case RTLeftStrategyNumber:
1106 case RTOverAboveStrategyNumber:
1109 case RTOverBelowStrategyNumber:
1112 case RTOverRightStrategyNumber:
1115 case RTOverLeftStrategyNumber:
1133 POSTGIS_DEBUGF(4,
"[GIST] internal consistent, strategy [%d], count[%i], query[%s], key[%s]",
1140 case RTOverlapStrategyNumber:
1143 case RTSameStrategyNumber:
1144 case RTContainsStrategyNumber:
1145 case RTOldContainsStrategyNumber:
1148 case RTContainedByStrategyNumber:
1149 case RTOldContainedByStrategyNumber:
1154 case RTAboveStrategyNumber:
1157 case RTBelowStrategyNumber:
1160 case RTRightStrategyNumber:
1163 case RTLeftStrategyNumber:
1168 case RTOverAboveStrategyNumber:
1171 case RTOverBelowStrategyNumber:
1174 case RTOverRightStrategyNumber:
1177 case RTOverLeftStrategyNumber:
1195 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1196 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1198 BOX2DF query_gbox_index;
1202 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1209 POSTGIS_DEBUG(4,
"[GIST] 'consistent' function called");
1212 if ( DatumGetPointer(PG_GETARG_DATUM(1)) == NULL )
1214 POSTGIS_DEBUG(4,
"[GIST] null query pointer (!?!), returning false");
1215 PG_RETURN_BOOL(
false);
1219 if ( DatumGetPointer(entry->key) == NULL )
1221 POSTGIS_DEBUG(4,
"[GIST] null index entry, returning false");
1222 PG_RETURN_BOOL(
false);
1228 POSTGIS_DEBUG(4,
"[GIST] null query_gbox_index!");
1229 PG_RETURN_BOOL(
false);
1233 if (GIST_LEAF(entry))
1236 (BOX2DF*)DatumGetPointer(entry->key),
1237 &query_gbox_index, strategy);
1242 (BOX2DF*)DatumGetPointer(entry->key),
1243 &query_gbox_index, strategy);
1246 PG_RETURN_BOOL(result);
1269 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1272 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1274 #if POSTGIS_PGSQL_VERSION >= 95
1275 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1278 POSTGIS_DEBUG(4,
"[GIST] 'distance' function called");
1282 if ( strategy != 13 && strategy != 14 ) {
1283 elog(ERROR,
"unrecognized strategy number: %d", strategy);
1284 PG_RETURN_FLOAT8(FLT_MAX);
1290 POSTGIS_DEBUG(4,
"[GIST] null query_gbox_index!");
1291 PG_RETURN_FLOAT8(FLT_MAX);
1295 entry_box = (BOX2DF*)DatumGetPointer(entry->key);
1297 #if POSTGIS_PGSQL_VERSION >= 95
1300 if ( strategy == 14 )
1305 else if ( strategy == 13 )
1312 if (GIST_LEAF(entry))
1317 elog(ERROR,
"%s: reached unreachable code", __func__);
1322 if ( strategy == 14 )
1329 if (GIST_LEAF(entry))
1337 distance = (double)box2df_distance_node_centroid(entry_box, &query_box);
1361 struct {
unsigned value:31, sign:1; } vbits;
1362 struct {
unsigned value:29, realm:2, sign:1; } rbits;
1366 a.rbits.value = a.vbits.value >> 2;
1367 a.rbits.realm = realm;
1379 GISTENTRY *origentry = (GISTENTRY*) PG_GETARG_POINTER(0);
1380 GISTENTRY *newentry = (GISTENTRY*) PG_GETARG_POINTER(1);
1381 float *result = (
float*) PG_GETARG_POINTER(2);
1382 BOX2DF *gbox_index_orig, *gbox_index_new;
1383 float size_union, size_orig, edge_union, edge_orig;
1385 POSTGIS_DEBUG(4,
"[GIST] 'penalty' function called");
1387 gbox_index_orig = (BOX2DF*)DatumGetPointer(origentry->key);
1388 gbox_index_new = (BOX2DF*)DatumGetPointer(newentry->key);
1391 if ( (gbox_index_orig == NULL) && (gbox_index_new == NULL) )
1393 POSTGIS_DEBUG(4,
"[GIST] both inputs NULL! returning penalty of zero");
1395 PG_RETURN_FLOAT8(*result);
1401 *result = size_union - size_orig;
1418 *result = edge_union - edge_orig;
1434 POSTGIS_DEBUGF(4,
"[GIST] 'penalty', union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result);
1436 PG_RETURN_POINTER(result);
1445 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1446 int *sizep = (
int *) PG_GETARG_POINTER(1);
1448 BOX2DF *box_cur, *box_union;
1450 POSTGIS_DEBUG(4,
"[GIST] 'union' function called");
1452 numranges = entryvec->n;
1454 box_cur = (BOX2DF*) DatumGetPointer(entryvec->vector[0].key);
1458 for ( i = 1; i < numranges; i++ )
1460 box_cur = (BOX2DF*) DatumGetPointer(entryvec->vector[i].key);
1464 *sizep =
sizeof(BOX2DF);
1466 POSTGIS_DEBUGF(4,
"[GIST] 'union', numranges(%i), pageunion %s", numranges,
box2df_to_string(box_union));
1468 PG_RETURN_POINTER(box_union);
1478 BOX2DF *b1 = (BOX2DF*)PG_GETARG_POINTER(0);
1479 BOX2DF *b2 = (BOX2DF*)PG_GETARG_POINTER(1);
1480 bool *result = (
bool*)PG_GETARG_POINTER(2);
1482 POSTGIS_DEBUG(4,
"[GIST] 'same' function called");
1486 PG_RETURN_POINTER(result);
1489 #if KOROTKOV_SPLIT > 0
1496 if (b->xmax < addon->xmax || isnan(b->xmax))
1497 b->xmax = addon->xmax;
1498 if (b->xmin > addon->xmin || isnan(b->xmin))
1499 b->xmin = addon->xmin;
1500 if (b->ymax < addon->ymax || isnan(b->ymax))
1501 b->ymax = addon->ymax;
1502 if (b->ymin > addon->ymin || isnan(b->ymin))
1503 b->ymin = addon->ymin;
1515 BOX2DF *unionL = NULL,
1519 maxoff = entryvec->n - 1;
1521 nbytes = (maxoff + 2) *
sizeof(OffsetNumber);
1522 v->spl_left = (OffsetNumber *) palloc(nbytes);
1523 v->spl_right = (OffsetNumber *) palloc(nbytes);
1524 v->spl_nleft = v->spl_nright = 0;
1526 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1528 BOX2DF *
cur = (BOX2DF *) DatumGetPointer(entryvec->vector[i].key);
1530 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
1532 v->spl_left[v->spl_nleft] = i;
1535 unionL = (BOX2DF *) palloc(
sizeof(BOX2DF));
1545 v->spl_right[v->spl_nright] = i;
1548 unionR = (BOX2DF *) palloc(
sizeof(BOX2DF));
1558 if (v->spl_ldatum_exists)
1559 adjustBox(unionL, (BOX2DF *) DatumGetPointer(v->spl_ldatum));
1560 v->spl_ldatum = BoxPGetDatum(unionL);
1562 if (v->spl_rdatum_exists)
1563 adjustBox(unionR, (BOX2DF *) DatumGetPointer(v->spl_rdatum));
1564 v->spl_rdatum = BoxPGetDatum(unionR);
1566 v->spl_ldatum_exists = v->spl_rdatum_exists =
false;
1629 else if (isnan(lower2))
1635 if (lower1 < lower2)
1637 else if (lower1 > lower2)
1661 else if (isnan(upper2))
1667 if (upper1 < upper2)
1669 else if (upper1 > upper2)
1693 float rightLower,
int minLeftCount,
1694 float leftUpper,
int maxLeftCount)
1702 POSTGIS_DEBUGF(5,
"consider split: dimNum = %d, rightLower = %f, "
1703 "minLeftCount = %d, leftUpper = %f, maxLeftCount = %d ",
1704 dimNum, rightLower, minLeftCount, leftUpper, maxLeftCount);
1712 leftCount = minLeftCount;
1716 if (maxLeftCount <= context->entriesCount / 2)
1717 leftCount = maxLeftCount;
1727 ratio = ((float4) Min(leftCount, rightCount)) /
1732 bool selectthis =
false;
1746 overlap = (leftUpper - rightLower) / range;
1751 else if (context->
dim == dimNum)
1757 if (overlap < context->overlap ||
1758 (overlap == context->
overlap && ratio > context->
ratio))
1781 (range > context->
range &&
1789 context->
first =
false;
1790 context->
ratio = ratio;
1791 context->
range = range;
1795 context->
dim = dimNum;
1796 POSTGIS_DEBUG(5,
"split selected");
1810 union_width = Max(original->xmax, new->xmax) -
1811 Min(original->xmin, new->xmin);
1812 union_height = Max(original->ymax, new->ymax) -
1813 Min(original->ymin, new->ymin);
1814 return union_width * union_height - (original->xmax - original->xmin) *
1815 (original->ymax - original->ymin);
1827 if (delta1 < delta2)
1829 else if (delta1 > delta2)
1864 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1865 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1879 POSTGIS_DEBUG(3,
"[GIST] 'picksplit' entered");
1883 maxoff = entryvec->n - 1;
1884 nentries = context.
entriesCount = maxoff - FirstOffsetNumber + 1;
1893 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1895 box = (BOX2DF *) DatumGetPointer(entryvec->vector[i].key);
1896 if (i == FirstOffsetNumber)
1908 context.
first =
true;
1909 for (dim = 0; dim < 2; dim++)
1917 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1919 box = (BOX2DF *) DatumGetPointer(entryvec->vector[i].key);
1922 intervalsLower[i - FirstOffsetNumber].
lower = box->xmin;
1923 intervalsLower[i - FirstOffsetNumber].
upper = box->xmax;
1927 intervalsLower[i - FirstOffsetNumber].
lower = box->ymin;
1928 intervalsLower[i - FirstOffsetNumber].
upper = box->ymax;
1936 memcpy(intervalsUpper, intervalsLower,
1979 rightLower = intervalsLower[i1].
lower;
1980 leftUpper = intervalsUpper[i2].
lower;
1986 while (i1 < nentries && (rightLower == intervalsLower[i1].lower ||
1987 isnan(intervalsLower[i1].lower)))
1989 leftUpper = Max(leftUpper, intervalsLower[i1].upper);
1994 rightLower = intervalsLower[i1].
lower;
2000 while (i2 < nentries && intervalsUpper[i2].upper <= leftUpper)
2015 rightLower = intervalsLower[i1].
upper;
2016 leftUpper = intervalsUpper[i2].
upper;
2022 while (i2 >= 0 && (leftUpper == intervalsUpper[i2].upper ||
2023 isnan(intervalsUpper[i2].upper)))
2025 rightLower = Min(rightLower, intervalsUpper[i2].lower);
2030 leftUpper = intervalsUpper[i2].
upper;
2036 while (i1 >= 0 && intervalsLower[i1].lower >= rightLower)
2043 rightLower, i1 + 1, leftUpper, i2 + 1);
2052 POSTGIS_DEBUG(4,
"no acceptable splits, trivial split");
2054 PG_RETURN_POINTER(v);
2065 POSTGIS_DEBUGF(4,
"split direction: %d", context.
dim);
2068 v->spl_left = (OffsetNumber *) palloc(nentries *
sizeof(OffsetNumber));
2069 v->spl_right = (OffsetNumber *) palloc(nentries *
sizeof(OffsetNumber));
2074 leftBox = palloc0(
sizeof(BOX2DF));
2075 rightBox = palloc0(
sizeof(BOX2DF));
2081 commonEntriesCount = 0;
2085 #define PLACE_LEFT(box, off) \
2087 if (v->spl_nleft > 0) \
2088 adjustBox(leftBox, box); \
2090 *leftBox = *(box); \
2091 v->spl_left[v->spl_nleft++] = off; \
2094 #define PLACE_RIGHT(box, off) \
2096 if (v->spl_nright > 0) \
2097 adjustBox(rightBox, box); \
2099 *rightBox = *(box); \
2100 v->spl_right[v->spl_nright++] = off; \
2107 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
2115 box = (BOX2DF *) DatumGetPointer(entryvec->vector[i].key);
2116 if (context.
dim == 0)
2127 if (upper <= context.
leftUpper || isnan(upper))
2130 if (lower >= context.
rightLower || isnan(lower))
2133 commonEntries[commonEntriesCount++].
index = i;
2161 if (commonEntriesCount > 0)
2173 for (i = 0; i < commonEntriesCount; i++)
2175 box = (BOX2DF *) DatumGetPointer(entryvec->vector[
2176 commonEntries[i].
index].key);
2190 for (i = 0; i < commonEntriesCount; i++)
2192 box = (BOX2DF *) DatumGetPointer(entryvec->vector[
2193 commonEntries[i].
index].key);
2199 if (v->spl_nleft + (commonEntriesCount - i) <= m)
2201 else if (v->spl_nright + (commonEntriesCount - i) <= m)
2213 v->spl_ldatum = PointerGetDatum(leftBox);
2214 v->spl_rdatum = PointerGetDatum(rightBox);
2216 POSTGIS_DEBUG(4,
"[GIST] 'picksplit' completed");
2218 PG_RETURN_POINTER(v);
2231 compare_KB(
const void* a,
const void* b)
2233 BOX2DF *abox = ((KBsort*)a)->key;
2234 BOX2DF *bbox = ((KBsort*)b)->key;
2235 float sa = (abox->xmax - abox->xmin) * (abox->ymax - abox->ymin);
2236 float sb = (bbox->xmax - bbox->xmin) * (bbox->ymax - bbox->ymin);
2238 if ( sa==sb )
return 0;
2239 return ( sa>sb ) ? 1 : -1;
2250 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
2252 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
2254 OffsetNumber *listL, *listR, *listB, *listT;
2255 BOX2DF *unionL, *unionR, *unionB, *unionT;
2256 int posL, posR, posB, posT;
2259 char direction =
' ';
2260 bool allisequal =
true;
2261 OffsetNumber maxoff;
2264 POSTGIS_DEBUG(3,
"[GIST] 'picksplit' entered");
2266 posL = posR = posB = posT = 0;
2268 maxoff = entryvec->n - 1;
2269 cur = (BOX2DF*) DatumGetPointer(entryvec->vector[FirstOffsetNumber].key);
2271 memcpy((
void *) &pageunion, (
void *)
cur,
sizeof(BOX2DF));
2274 for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i))
2276 cur = (BOX2DF *) DatumGetPointer(entryvec->vector[i].key);
2278 if ( allisequal ==
true && (
2279 pageunion.xmax !=
cur->xmax ||
2280 pageunion.ymax !=
cur->ymax ||
2281 pageunion.xmin !=
cur->xmin ||
2282 pageunion.ymin !=
cur->ymin
2286 if (pageunion.xmax <
cur->xmax)
2287 pageunion.xmax =
cur->xmax;
2288 if (pageunion.xmin >
cur->xmin)
2289 pageunion.xmin =
cur->xmin;
2290 if (pageunion.ymax <
cur->ymax)
2291 pageunion.ymax =
cur->ymax;
2292 if (pageunion.ymin >
cur->ymin)
2293 pageunion.ymin =
cur->ymin;
2298 nbytes = (maxoff + 2) *
sizeof(OffsetNumber);
2299 listL = (OffsetNumber *) palloc(nbytes);
2300 listR = (OffsetNumber *) palloc(nbytes);
2301 unionL = (BOX2DF *) palloc(
sizeof(BOX2DF));
2302 unionR = (BOX2DF *) palloc(
sizeof(BOX2DF));
2306 POSTGIS_DEBUG(4,
" AllIsEqual!");
2308 cur = (BOX2DF*) DatumGetPointer(entryvec->vector[OffsetNumberNext(FirstOffsetNumber)].key);
2311 if (memcmp((
void *)
cur, (
void *) &pageunion,
sizeof(BOX2DF)) == 0)
2313 v->spl_left = listL;
2314 v->spl_right = listR;
2315 v->spl_nleft = v->spl_nright = 0;
2316 memcpy((
void *) unionL, (
void *) &pageunion,
sizeof(BOX2DF));
2317 memcpy((
void *) unionR, (
void *) &pageunion,
sizeof(BOX2DF));
2319 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
2321 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
2323 v->spl_left[v->spl_nleft] = i;
2328 v->spl_right[v->spl_nright] = i;
2332 v->spl_ldatum = PointerGetDatum(unionL);
2333 v->spl_rdatum = PointerGetDatum(unionR);
2335 PG_RETURN_POINTER(v);
2339 listB = (OffsetNumber *) palloc(nbytes);
2340 listT = (OffsetNumber *) palloc(nbytes);
2341 unionB = (BOX2DF *) palloc(
sizeof(BOX2DF));
2342 unionT = (BOX2DF *) palloc(
sizeof(BOX2DF));
2344 #define ADDLIST( list, unionD, pos, num ) do { \
2346 if ( unionD->xmax < cur->xmax ) unionD->xmax = cur->xmax; \
2347 if ( unionD->xmin > cur->xmin ) unionD->xmin = cur->xmin; \
2348 if ( unionD->ymax < cur->ymax ) unionD->ymax = cur->ymax; \
2349 if ( unionD->ymin > cur->ymin ) unionD->ymin = cur->ymin; \
2351 memcpy( (void*)unionD, (void*) cur, sizeof( BOX2DF ) ); \
2357 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
2359 cur = (BOX2DF*) DatumGetPointer(entryvec->vector[i].key);
2361 if (
cur->xmin - pageunion.xmin < pageunion.xmax -
cur->xmax)
2362 ADDLIST(listL, unionL, posL,i);
2364 ADDLIST(listR, unionR, posR,i);
2365 if (
cur->ymin - pageunion.ymin < pageunion.ymax -
cur->ymax)
2366 ADDLIST(listB, unionB, posB,i);
2368 ADDLIST(listT, unionT, posT,i);
2377 if ( (posR==0 || posL==0) && (posT==0 || posB==0) )
2379 KBsort *arr = (KBsort*)palloc(
sizeof(KBsort) * maxoff );
2380 posL = posR = posB = posT = 0;
2381 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
2383 arr[i-1].key = (BOX2DF*) DatumGetPointer(entryvec->vector[i].key);
2386 qsort( arr, maxoff,
sizeof(KBsort), compare_KB );
2387 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
2390 if (
cur->xmin - pageunion.xmin < pageunion.xmax -
cur->xmax)
2391 ADDLIST(listL, unionL, posL,arr[i-1].pos);
2392 else if (
cur->xmin - pageunion.xmin == pageunion.xmax -
cur->xmax )
2395 ADDLIST(listR, unionR, posR,arr[i-1].pos);
2397 ADDLIST(listL, unionL, posL,arr[i-1].pos);
2400 ADDLIST(listR, unionR, posR,arr[i-1].pos);
2402 if (
cur->ymin - pageunion.ymin < pageunion.ymax -
cur->ymax)
2403 ADDLIST(listB, unionB, posB,arr[i-1].pos);
2404 else if (
cur->ymin - pageunion.ymin == pageunion.ymax -
cur->ymax )
2407 ADDLIST(listT, unionT, posT,arr[i-1].pos);
2409 ADDLIST(listB, unionB, posB,arr[i-1].pos);
2412 ADDLIST(listT, unionT, posT,arr[i-1].pos);
2418 if (Max(posL, posR) < Max(posB, posT))
2420 else if (Max(posL, posR) > Max(posB, posT))
2424 float sizeLR, sizeBT;
2425 BOX2DF interLR, interBT;
2427 if ( box2df_intersection(unionL, unionR, &interLR) ==
false )
2432 if ( box2df_intersection(unionB, unionT, &interBT) ==
false )
2437 if (sizeLR < sizeBT)
2443 POSTGIS_DEBUGF(4,
"split direction '%c'", direction);
2445 if (direction ==
'x')
2452 v->spl_left = listL;
2453 v->spl_right = listR;
2454 v->spl_nleft = posL;
2455 v->spl_nright = posR;
2456 v->spl_ldatum = PointerGetDatum(unionL);
2457 v->spl_rdatum = PointerGetDatum(unionR);
2466 v->spl_left = listB;
2467 v->spl_right = listT;
2468 v->spl_nleft = posB;
2469 v->spl_nright = posT;
2470 v->spl_ldatum = PointerGetDatum(unionB);
2471 v->spl_rdatum = PointerGetDatum(unionT);
2474 POSTGIS_DEBUG(4,
"[GIST] 'picksplit' completed");
2476 PG_RETURN_POINTER(v);
2489 ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2490 errmsg(
"function box2df_in not implemented")));
2491 PG_RETURN_POINTER(NULL);
2497 BOX2DF *box = (BOX2DF *) PG_GETARG_POINTER(0);
2499 PG_RETURN_CSTRING(result);
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and calculate one if it is not already there.
bool box2df_left(const BOX2DF *a, const BOX2DF *b)
static char * box2df_to_string(const BOX2DF *a)
void box2df_merge(BOX2DF *b_union, BOX2DF *b_new)
static void fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
static float box2df_size(const BOX2DF *a)
Datum gserialized_overbelow_2d(PG_FUNCTION_ARGS)
void box2df_set_empty(BOX2DF *a)
Datum gserialized_gist_same_2d(PG_FUNCTION_ARGS)
static float box2df_union_size(const BOX2DF *a, const BOX2DF *b)
Datum gserialized_contains_box2df_geom_2d(PG_FUNCTION_ARGS)
bool box2df_is_empty(const BOX2DF *a)
static float pack_float(const float value, const int realm)
static int gserialized_datum_predicate_2d(Datum gs1, Datum gs2, box2df_predicate predicate)
Support function.
Datum gserialized_within_2d(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(gserialized_contains_box2df_geom_2d)
Datum box2df_out(PG_FUNCTION_ARGS)
Datum gserialized_within_box2df_geom_2d(PG_FUNCTION_ARGS)
Datum gserialized_gist_penalty_2d(PG_FUNCTION_ARGS)
Datum gserialized_left_2d(PG_FUNCTION_ARGS)
Datum gserialized_contains_2d(PG_FUNCTION_ARGS)
Datum gserialized_gist_consistent_2d(PG_FUNCTION_ARGS)
static int interval_cmp_upper(const void *i1, const void *i2)
Datum gserialized_distance_box_2d(PG_FUNCTION_ARGS)
bool box2df_equals(const BOX2DF *a, const BOX2DF *b)
bool box2df_contains(const BOX2DF *a, const BOX2DF *b)
Datum gserialized_gist_union_2d(PG_FUNCTION_ARGS)
#define PLACE_RIGHT(box, off)
Datum gserialized_gist_compress_2d(PG_FUNCTION_ARGS)
Datum gserialized_distance_centroid_2d(PG_FUNCTION_ARGS)
Datum gserialized_contains_box2df_box2df_2d(PG_FUNCTION_ARGS)
static float box2df_union_edge(const BOX2DF *a, const BOX2DF *b)
Datum gserialized_overlaps_2d(PG_FUNCTION_ARGS)
Datum gserialized_overlaps_box2df_geom_2d(PG_FUNCTION_ARGS)
Datum gserialized_within_box2df_box2df_2d(PG_FUNCTION_ARGS)
bool box2df_right(const BOX2DF *a, const BOX2DF *b)
bool box2df_overlaps(const BOX2DF *a, const BOX2DF *b)
Datum gserialized_overleft_2d(PG_FUNCTION_ARGS)
void box2df_set_finite(BOX2DF *a)
static float box_penalty(BOX2DF *original, BOX2DF *new)
static bool gserialized_gist_consistent_internal_2d(BOX2DF *key, BOX2DF *query, StrategyNumber strategy)
Datum gserialized_overlaps_box2df_box2df_2d(PG_FUNCTION_ARGS)
Datum gserialized_gist_distance_2d(PG_FUNCTION_ARGS)
Datum gserialized_overright_2d(PG_FUNCTION_ARGS)
static bool box2df_within(const BOX2DF *a, const BOX2DF *b)
bool box2df_above(const BOX2DF *a, const BOX2DF *b)
Datum gserialized_right_2d(PG_FUNCTION_ARGS)
bool box2df_overbelow(const BOX2DF *a, const BOX2DF *b)
bool(* box2df_predicate)(const BOX2DF *a, const BOX2DF *b)
static double box2df_distance(const BOX2DF *a, const BOX2DF *b)
Calculate the box->box distance.
static double box2df_distance_leaf_centroid(const BOX2DF *a, const BOX2DF *b)
Calculate the centroid->centroid distance between the boxes.
Datum gserialized_below_2d(PG_FUNCTION_ARGS)
Datum gserialized_overabove_2d(PG_FUNCTION_ARGS)
static void g_box_consider_split(ConsiderSplitContext *context, int dimNum, float rightLower, int minLeftCount, float leftUpper, int maxLeftCount)
static float box2df_edge(const BOX2DF *a)
int box2df_to_gbox_p(BOX2DF *a, GBOX *box)
static int interval_cmp_lower(const void *i1, const void *i2)
bool box2df_overright(const BOX2DF *a, const BOX2DF *b)
static double pt_distance(double ax, double ay, double bx, double by)
static int common_entry_cmp(const void *i1, const void *i2)
Datum gserialized_gist_decompress_2d(PG_FUNCTION_ARGS)
int gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df)
Peak into a GSERIALIZED datum to find the bounding box.
static int box2df_from_gbox_p(GBOX *box, BOX2DF *a)
bool box2df_overabove(const BOX2DF *a, const BOX2DF *b)
Datum gserialized_gist_picksplit_2d(PG_FUNCTION_ARGS)
#define PLACE_LEFT(box, off)
void box2df_validate(BOX2DF *b)
bool box2df_below(const BOX2DF *a, const BOX2DF *b)
static bool gserialized_gist_consistent_leaf_2d(BOX2DF *key, BOX2DF *query, StrategyNumber strategy)
bool box2df_overleft(const BOX2DF *a, const BOX2DF *b)
Datum gserialized_above_2d(PG_FUNCTION_ARGS)
static int gserialized_datum_predicate_box2df_geom_2d(const BOX2DF *br1, Datum gs2, box2df_predicate predicate)
BOX2DF * box2df_copy(BOX2DF *b)
Datum gserialized_same_2d(PG_FUNCTION_ARGS)
Datum box2df_in(PG_FUNCTION_ARGS)
static void adjustBox(BOX2DF *b, BOX2DF *addon)
static float non_negative(float val)
#define FLAGS_GET_BBOX(flags)
float next_float_up(double d)
#define LW_TRUE
Return types for functions with status returns.
float next_float_down(double d)
This library is the generic geometry handling section of PostGIS.
Datum distance(PG_FUNCTION_ARGS)