GRASS 8 Programmer's Manual 8.6.0dev(2026)-8843f13794
Loading...
Searching...
No Matches
split.c
Go to the documentation of this file.
1/***********************************************************************
2 * MODULE: R-Tree library
3 *
4 * AUTHOR(S): Antonin Guttman - original code
5 * Daniel Green (green@superliminal.com) - major clean-up
6 * and implementation of bounding spheres
7 * Markus Metz - file-based and memory-based R*-tree
8 *
9 * PURPOSE: Multidimensional index
10 *
11 * SPDX-FileCopyrightText: 2001 GRASS Development Team
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 *
14 ***********************************************************************/
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <assert.h>
19#include <float.h>
20/* remove after debug */
21#include <grass/gis.h>
22#include "index.h"
23#include "card.h"
24#include "split.h"
25
26#ifndef DBL_MAX
27#define DBL_MAX 1.797693E308 /* DBL_MAX approximation */
28#endif
29
30/*----------------------------------------------------------------------
31| Load branch buffer with branches from full node plus the extra branch.
32----------------------------------------------------------------------*/
33static void RTreeGetBranches(struct RTree_Node *n, struct RTree_Branch *b,
35{
36 int i, maxkids = 0;
37
38 if ((n)->level > 0) {
39 maxkids = t->nodecard;
40 /* load the branch buffer */
41 for (i = 0; i < maxkids; i++) {
42 assert(t->valid_child(
43 &(n->branch[i].child))); /* n should have every entry full */
44 RTreeCopyBranch(&(t->BranchBuf[i]), &(n->branch[i]), t);
45 }
46 }
47 else {
48 maxkids = t->leafcard;
49 /* load the branch buffer */
50 for (i = 0; i < maxkids; i++) {
51 assert(n->branch[i].child.id); /* n should have every entry full */
52 RTreeCopyBranch(&(t->BranchBuf[i]), &(n->branch[i]), t);
53 }
54 }
55
56 RTreeCopyBranch(&(t->BranchBuf[maxkids]), b, t);
57 t->BranchCount = maxkids + 1;
58
59 if (METHOD == 0) { /* quadratic split */
60 /* calculate rect containing all in the set */
61 RTreeCopyRect(&(t->orect), &(t->BranchBuf[0].rect), t);
62 for (i = 1; i < maxkids + 1; i++) {
63 RTreeExpandRect(&(t->orect), &(t->BranchBuf[i].rect), t);
64 }
66 }
67
68 RTreeInitNode(t, n, NODETYPE(n->level, t->fd));
69}
70
71/*----------------------------------------------------------------------
72| Put a branch in one of the groups.
73----------------------------------------------------------------------*/
74static void RTreeClassify(int i, int group, struct RTree_PartitionVars *p,
75 struct RTree *t)
76{
77 assert(!p->taken[i]);
78
79 p->partition[i] = group;
80 p->taken[i] = TRUE;
81
82 if (METHOD == 0) {
83 if (p->count[group] == 0)
84 RTreeCopyRect(&(p->cover[group]), &(t->BranchBuf[i].rect), t);
85 else
86 RTreeExpandRect(&(p->cover[group]), &(t->BranchBuf[i].rect), t);
87 p->area[group] = RTreeRectSphericalVolume(&(p->cover[group]), t);
88 }
89 p->count[group]++;
90}
91
92/***************************************************
93 * *
94 * Toni Guttman's quadratic splitting method *
95 * *
96 ***************************************************/
97
98/*----------------------------------------------------------------------
99| Pick two rects from set to be the first elements of the two groups.
100| Pick the two that waste the most area if covered by a single
101| rectangle.
102----------------------------------------------------------------------*/
103static void RTreePickSeeds(struct RTree_PartitionVars *p,
105{
106 int i, j, seed0 = 0, seed1 = 0;
107 RectReal worst, waste, area[MAXCARD + 1];
108
109 for (i = 0; i < p->total; i++)
110 area[i] = RTreeRectSphericalVolume(&(t->BranchBuf[i]).rect, t);
111
112 worst = -CoverSplitArea - 1;
113 for (i = 0; i < p->total - 1; i++) {
114 for (j = i + 1; j < p->total; j++) {
115
116 RTreeCombineRect(&(t->BranchBuf[i].rect), &(t->BranchBuf[j].rect),
117 &(t->orect), t);
118 waste =
119 RTreeRectSphericalVolume(&(t->orect), t) - area[i] - area[j];
120 if (waste > worst) {
121 worst = waste;
122 seed0 = i;
123 seed1 = j;
124 }
125 }
126 }
127 RTreeClassify(seed0, 0, p, t);
128 RTreeClassify(seed1, 1, p, t);
129}
130
131/*----------------------------------------------------------------------
132| Copy branches from the buffer into two nodes according to the
133| partition.
134----------------------------------------------------------------------*/
135static void RTreeLoadNodes(struct RTree_Node *n, struct RTree_Node *q,
136 struct RTree_PartitionVars *p, struct RTree *t)
137{
138 int i;
139
140 for (i = 0; i < p->total; i++) {
141 assert(p->partition[i] == 0 || p->partition[i] == 1);
142 if (p->partition[i] == 0)
143 RTreeAddBranch(&(t->BranchBuf[i]), n, NULL, NULL, NULL, NULL, t);
144 else if (p->partition[i] == 1)
145 RTreeAddBranch(&(t->BranchBuf[i]), q, NULL, NULL, NULL, NULL, t);
146 }
147}
148
149/*----------------------------------------------------------------------
150| Initialize a PartitionVars structure.
151----------------------------------------------------------------------*/
152void RTreeInitPVars(struct RTree_PartitionVars *p, int maxrects, int minfill,
153 struct RTree *t)
154{
155 int i;
156
157 p->count[0] = p->count[1] = 0;
158 if (METHOD == 0) {
159 RTreeNullRect(&(p->cover[0]), t);
160 RTreeNullRect(&(p->cover[1]), t);
161 p->area[0] = p->area[1] = (RectReal)0;
162 }
163 p->total = maxrects;
164 p->minfill = minfill;
165 for (i = 0; i < maxrects; i++) {
166 p->taken[i] = FALSE;
167 p->partition[i] = -1;
168 }
169}
170
171#ifdef DEBUG
172
173/*----------------------------------------------------------------------
174| Print out data for a partition from PartitionVars struct.
175| Unused, for debugging only
176----------------------------------------------------------------------*/
177static void RTreePrintPVars(struct RTree_PartitionVars *p, struct RTree *t,
179{
180 int i;
181
182 fprintf(stdout, "\npartition:\n");
183 for (i = 0; i < p->total; i++) {
184 fprintf(stdout, "%3d\t", i);
185 }
186 fprintf(stdout, "\n");
187 for (i = 0; i < p->total; i++) {
188 if (p->taken[i])
189 fprintf(stdout, " t\t");
190 else
191 fprintf(stdout, "\t");
192 }
193 fprintf(stdout, "\n");
194 for (i = 0; i < p->total; i++) {
195 fprintf(stdout, "%3d\t", p->partition[i]);
196 }
197 fprintf(stdout, "\n");
198
199 fprintf(stdout, "count[0] = %d area = %f\n", p->count[0], p->area[0]);
200 fprintf(stdout, "count[1] = %d area = %f\n", p->count[1], p->area[1]);
201 if (p->area[0] + p->area[1] > 0) {
202 fprintf(stdout, "total area = %f effectiveness = %3.2f\n",
203 p->area[0] + p->area[1],
204 (float)CoverSplitArea / (p->area[0] + p->area[1]));
205 }
206 fprintf(stdout, "cover[0]:\n");
207 RTreePrintRect(&p->cover[0], 0, t);
208
209 fprintf(stdout, "cover[1]:\n");
210 RTreePrintRect(&p->cover[1], 0, t);
211}
212#endif /* DEBUG */
213
214/*----------------------------------------------------------------------
215| Method #0 for choosing a partition: this is Toni Guttman's quadratic
216| split
217|
218| As the seeds for the two groups, pick the two rects that would waste
219| the most area if covered by a single rectangle, i.e. evidently the
220| worst pair to have in the same group. Of the remaining, one at a time
221| is chosen to be put in one of the two groups. The one chosen is the
222| one with the greatest difference in area expansion depending on which
223| group - the rect most strongly attracted to one group and repelled
224| from the other. If one group gets too full (more would force other
225| group to violate min fill requirement) then other group gets the rest.
226| These last are the ones that can go in either group most easily.
227----------------------------------------------------------------------*/
228static void RTreeMethodZero(struct RTree_PartitionVars *p, int minfill,
230{
231 int i;
233 int group, chosen = 0, betterGroup = 0;
234 struct RTree_Rect *r, *rect_0, *rect_1;
235
236 RTreeInitPVars(p, t->BranchCount, minfill, t);
237 RTreePickSeeds(p, CoverSplitArea, t);
238
239 rect_0 = &(t->rect_0);
240 rect_1 = &(t->rect_1);
241
242 while (p->count[0] + p->count[1] < p->total &&
243 p->count[0] < p->total - p->minfill &&
244 p->count[1] < p->total - p->minfill) {
245 biggestDiff = (RectReal)-1.;
246 for (i = 0; i < p->total; i++) {
247 if (!p->taken[i]) {
249
250 r = &(t->BranchBuf[i].rect);
251 RTreeCombineRect(r, &(p->cover[0]), rect_0, t);
252 RTreeCombineRect(r, &(p->cover[1]), rect_1, t);
255 diff = growth1 - growth0;
256 if (diff >= 0)
257 group = 0;
258 else {
259 group = 1;
260 diff = -diff;
261 }
262
263 if (diff > biggestDiff) {
265 chosen = i;
266 betterGroup = group;
267 }
268 else if (diff == biggestDiff &&
269 p->count[group] < p->count[betterGroup]) {
270 chosen = i;
271 betterGroup = group;
272 }
273 }
274 }
275 RTreeClassify(chosen, betterGroup, p, t);
276 }
277
278 /* if one group too full, put remaining rects in the other */
279 if (p->count[0] + p->count[1] < p->total) {
280 if (p->count[0] >= p->total - p->minfill)
281 group = 1;
282 else
283 group = 0;
284 for (i = 0; i < p->total; i++) {
285 if (!p->taken[i])
286 RTreeClassify(i, group, p, t);
287 }
288 }
289
290 assert(p->count[0] + p->count[1] == p->total);
291 assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill);
292}
293
294/**********************************************************************
295 * *
296 * Norbert Beckmann's R*-tree splitting method *
297 * *
298 **********************************************************************/
299
300/*----------------------------------------------------------------------
301| swap branches
302----------------------------------------------------------------------*/
303static void RTreeSwapBranches(struct RTree_Branch *a, struct RTree_Branch *b,
304 struct RTree *t)
305{
306 RTreeCopyBranch(&(t->c), a, t);
307 RTreeCopyBranch(a, b, t);
308 RTreeCopyBranch(b, &(t->c), t);
309}
310
311/*----------------------------------------------------------------------
312| compare branches for given rectangle side
313| return 1 if a > b
314| return 0 if a == b
315| return -1 if a < b
316----------------------------------------------------------------------*/
317static int RTreeCompareBranches(struct RTree_Branch *a, struct RTree_Branch *b,
318 int side)
319{
320 if (a->rect.boundary[side] < b->rect.boundary[side])
321 return -1;
322
323 return (a->rect.boundary[side] > b->rect.boundary[side]);
324}
325
326/*----------------------------------------------------------------------
327| check if BranchBuf is sorted along given axis (dimension)
328----------------------------------------------------------------------*/
329static int RTreeBranchBufIsSorted(int first, int last, int side,
330 struct RTree *t)
331{
332 int i;
333
334 for (i = first; i < last; i++) {
335 if (RTreeCompareBranches(&(t->BranchBuf[i]), &(t->BranchBuf[i + 1]),
336 side) == 1)
337 return 0;
338 }
339
340 return 1;
341}
342
343/*----------------------------------------------------------------------
344| partition BranchBuf for quicksort along given axis (dimension)
345----------------------------------------------------------------------*/
346static int RTreePartitionBranchBuf(int first, int last, int side,
347 struct RTree *t)
348{
349 int pivot, mid = ((first + last) >> 1);
350 int larger, smaller;
351
352 if (last - first == 1) { /* only two items in list */
353 if (RTreeCompareBranches(&(t->BranchBuf[first]), &(t->BranchBuf[last]),
354 side) == 1) {
355 RTreeSwapBranches(&(t->BranchBuf[first]), &(t->BranchBuf[last]), t);
356 }
357 return last;
358 }
359
360 /* larger of two */
361 larger = pivot = mid;
362 smaller = first;
363 if (RTreeCompareBranches(&(t->BranchBuf[first]), &(t->BranchBuf[mid]),
364 side) == 1) {
365 larger = pivot = first;
366 smaller = mid;
367 }
368
369 if (RTreeCompareBranches(&(t->BranchBuf[larger]), &(t->BranchBuf[last]),
370 side) == 1) {
371 /* larger is largest, get the larger of smaller and last */
372 pivot = last;
373 if (RTreeCompareBranches(&(t->BranchBuf[smaller]),
374 &(t->BranchBuf[last]), side) == 1) {
375 pivot = smaller;
376 }
377 }
378
379 if (pivot != last) {
380 RTreeSwapBranches(&(t->BranchBuf[pivot]), &(t->BranchBuf[last]), t);
381 }
382
383 pivot = first;
384
385 while (first < last) {
386 if (RTreeCompareBranches(&(t->BranchBuf[first]), &(t->BranchBuf[last]),
387 side) != 1) {
388 if (pivot != first) {
389 RTreeSwapBranches(&(t->BranchBuf[pivot]),
390 &(t->BranchBuf[first]), t);
391 }
392 pivot++;
393 }
394 ++first;
395 }
396
397 if (pivot != last) {
398 RTreeSwapBranches(&(t->BranchBuf[pivot]), &(t->BranchBuf[last]), t);
399 }
400
401 return pivot;
402}
403
404/*----------------------------------------------------------------------
405| quicksort BranchBuf along given side
406----------------------------------------------------------------------*/
407static void RTreeQuicksortBranchBuf(int side, struct RTree *t)
408{
409 int pivot, first, last;
410 int s_first[MAXCARD + 1], s_last[MAXCARD + 1], stacksize;
411
412 s_first[0] = 0;
413 s_last[0] = t->BranchCount - 1;
414
415 stacksize = 1;
416
417 /* use stack */
418 while (stacksize) {
419 stacksize--;
420 first = s_first[stacksize];
421 last = s_last[stacksize];
422 if (first < last) {
423 if (!RTreeBranchBufIsSorted(first, last, side, t)) {
424
425 pivot = RTreePartitionBranchBuf(first, last, side, t);
426
427 s_first[stacksize] = first;
428 s_last[stacksize] = pivot - 1;
429 stacksize++;
430
431 s_first[stacksize] = pivot + 1;
432 s_last[stacksize] = last;
433 stacksize++;
434 }
435 }
436 }
437}
438
439/*----------------------------------------------------------------------
440| Method #1 for choosing a partition: this is the R*-tree method
441|
442| Pick the axis with the smallest margin increase (keep rectangles
443| square).
444| Along the chosen split axis, choose the distribution with the minimum
445| overlap-value. Resolve ties by choosing the distribution with the
446| minimum area-value.
447| If one group gets too full (more would force other group to violate min
448| fill requirement) then other group gets the rest.
449| These last are the ones that can go in either group most easily.
450----------------------------------------------------------------------*/
451static void RTreeMethodOne(struct RTree_PartitionVars *p, int minfill,
452 int maxkids, struct RTree *t)
453{
454 int i, j, k, l, s;
455 int axis = 0, best_axis = 0, side = 0;
457 struct RTree_Rect *r1, *r2;
458 struct RTree_Rect *rect_0, *rect_1, *orect, *upperrect;
459 int minfill1 = minfill - 1;
460 RectReal overlap, vol, smallest_overlap = -1, smallest_vol = -1;
461
462 static int *best_cut = NULL, *best_side = NULL;
463 static int one_init = 0;
464
465 if (!one_init) {
466 best_cut = (int *)malloc(MAXLEVEL * sizeof(int));
467 best_side = (int *)malloc(MAXLEVEL * sizeof(int));
468 one_init = 1;
469 }
470
471 rect_0 = &(t->rect_0);
472 rect_1 = &(t->rect_1);
473 orect = &(t->orect);
474 upperrect = &(t->upperrect);
475
476 RTreeInitPVars(p, t->BranchCount, minfill, t);
477 RTreeInitRect(orect, t);
478
479 margin = DBL_MAX;
480
481 /* choose split axis */
482 /* For each dimension, sort rectangles first by lower boundary then
483 * by upper boundary. Get the smallest margin. */
484 for (i = 0; i < t->ndims; i++) {
485 axis = i;
486 best_cut[i] = 0;
487 best_side[i] = 0;
488
491
492 /* first upper then lower bounds for each axis */
493 s = 1;
494 do {
495 RTreeQuicksortBranchBuf(i + s * t->ndims_alloc, t);
496
497 side = s;
498
499 RTreeCopyRect(rect_0, &(t->BranchBuf[0].rect), t);
500 RTreeCopyRect(upperrect, &(t->BranchBuf[maxkids].rect), t);
501
502 for (j = 1; j < minfill1; j++) {
503 r1 = &(t->BranchBuf[j].rect);
505 r2 = &(t->BranchBuf[maxkids - j].rect);
507 }
508 r2 = &(t->BranchBuf[maxkids - minfill1].rect);
510
511 /* check distributions for this axis, adhere the minimum node fill
512 */
513 for (j = minfill1; j < t->BranchCount - minfill; j++) {
514
515 r1 = &(t->BranchBuf[j].rect);
517
519 for (k = j + 1; k < t->BranchCount - minfill; k++) {
520 r2 = &(t->BranchBuf[k].rect);
522 }
523
524 /* the margin is the sum of the lengths of the edges of a
525 * rectangle */
526 margin =
528
529 /* remember best axis */
530 if (margin <= smallest_margin) {
532 best_axis = i;
533 }
534
535 /* remember best distribution for this axis */
536
537 /* overlap size */
538 overlap = 1;
539
540 for (k = 0; k < t->ndims; k++) {
541 /* no overlap */
542 if (rect_0->boundary[k] >
543 rect_1->boundary[k + t->ndims_alloc] ||
544 rect_0->boundary[k + t->ndims_alloc] <
545 rect_1->boundary[k]) {
546 overlap = 0;
547 break;
548 }
549 /* get overlap */
550 else {
551 if (rect_0->boundary[k] > rect_1->boundary[k])
552 orect->boundary[k] = rect_0->boundary[k];
553 else
554 orect->boundary[k] = rect_1->boundary[k];
555
556 l = k + t->ndims_alloc;
557 if (rect_0->boundary[l] < rect_1->boundary[l])
558 orect->boundary[l] = rect_0->boundary[l];
559 else
560 orect->boundary[l] = rect_1->boundary[l];
561 }
562 }
563 if (overlap)
564 overlap = RTreeRectVolume(orect, t);
565
567
568 /* get best cut for this axis */
569 if (overlap <= smallest_overlap) {
570 smallest_overlap = overlap;
572 best_cut[i] = j;
573 best_side[i] = s;
574 }
575 else if (overlap == smallest_overlap) {
576 /* resolve ties by minimum volume */
577 if (vol <= smallest_vol) {
579 best_cut[i] = j;
580 best_side[i] = s;
581 }
582 }
583 } /* end of distribution check */
584 } while (s--); /* end of side check */
585 } /* end of axis check */
586
587 /* Use best distribution to classify branches */
588 if (best_axis != axis || best_side[best_axis] != side)
589 RTreeQuicksortBranchBuf(
590 best_axis + best_side[best_axis] * t->ndims_alloc, t);
591
593
594 for (i = 0; i < best_cut[best_axis]; i++)
595 RTreeClassify(i, 0, p, t);
596
597 for (i = best_cut[best_axis]; i < t->BranchCount; i++)
598 RTreeClassify(i, 1, p, t);
599
600 assert(p->count[0] + p->count[1] == p->total);
601 assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill);
602}
603
604/*----------------------------------------------------------------------
605| Split a node.
606| Divides the nodes branches and the extra one between two nodes.
607| Old node is one of the new ones, and one really new one is created.
608| May use quadratic split or R*-tree split.
609----------------------------------------------------------------------*/
610void RTreeSplitNode(struct RTree_Node *n, struct RTree_Branch *b,
611 struct RTree_Node *nn, struct RTree *t)
612{
613 struct RTree_PartitionVars *p;
615 int level;
616
617 /* load all the branches into a buffer, initialize old node */
618 level = n->level;
619 RTreeGetBranches(n, b, &CoverSplitArea, t);
620
621 /* find partition */
622 p = &(t->p);
623
624 if (METHOD == 1) /* R* split */
625 RTreeMethodOne(&(t->p), MINFILL(level, t), MAXKIDS(level, t), t);
626 else
627 RTreeMethodZero(&(t->p), MINFILL(level, t), CoverSplitArea, t);
628
629 /*
630 * put branches from buffer into 2 nodes
631 * according to chosen partition
632 */
633 (nn)->level = n->level = level;
634 RTreeLoadNodes(n, nn, p, t);
635 assert(n->count + nn->count == p->total);
636}
#define MAXKIDS(level, t)
Definition card.h:24
#define MINFILL(level, t)
Definition card.h:25
#define NULL
Definition ccmath.h:32
#define TRUE
Definition gis.h:75
#define FALSE
Definition gis.h:79
int RTreeAddBranch(struct RTree_Branch *, struct RTree_Node *, struct RTree_Node **, struct RTree_ListBranch **, struct RTree_Rect *, char *, struct RTree *)
Definition node.c:540
RectReal RTreeRectSphericalVolume(struct RTree_Rect *, struct RTree *)
Definition rect.c:429
void RTreeNullRect(struct RTree_Rect *, struct RTree *)
Definition rect.c:222
#define NODETYPE(l, fd)
Definition index.h:28
void RTreeCopyBranch(struct RTree_Branch *, struct RTree_Branch *, struct RTree *)
Definition node.c:121
RectReal RTreeRectVolume(struct RTree_Rect *, struct RTree *)
Definition rect.c:320
RectReal RTreeRectMargin(struct RTree_Rect *, struct RTree *)
Definition rect.c:480
void RTreeCombineRect(struct RTree_Rect *, struct RTree_Rect *, struct RTree_Rect *, struct RTree *)
Definition rect.c:497
int RTreeExpandRect(struct RTree_Rect *, struct RTree_Rect *, struct RTree *)
Definition rect.c:533
void RTreeInitRect(struct RTree_Rect *, struct RTree *)
Initialize a rectangle to have all 0 coordinates.
Definition rect.c:106
#define RTreeCopyRect(r1, r2, t)
Definition index.h:97
#define assert(condition)
Definition lz4.c:291
void RTreeInitNode(struct RTree *t, struct RTree_Node *n, int type)
Definition node.c:59
double b
Definition r_raster.c:37
double l
Definition r_raster.c:37
double t
Definition r_raster.c:37
double r
Definition r_raster.c:37
void RTreePrintRect(struct RTree_Rect *R, int depth, struct RTree *t)
Definition rect.c:301
#define MAXCARD
Definition rtree.h:41
double RectReal
Definition rtree.h:23
void RTreeInitPVars(struct RTree_PartitionVars *p, int maxrects, int minfill, struct RTree *t)
Definition split.c:152
void RTreeSplitNode(struct RTree_Node *n, struct RTree_Branch *b, struct RTree_Node *nn, struct RTree *t)
Definition split.c:610
#define DBL_MAX
Definition split.c:27
#define METHOD
Definition split.h:21
void * malloc(unsigned)
struct RTree_Rect rect
Definition rtree.h:65
int count
Definition rtree.h:71
int level
Definition rtree.h:72
struct RTree_Branch * branch
Definition rtree.h:73
int taken[9+1]
Definition rtree.h:114
RectReal area[2]
Definition rtree.h:117
struct RTree_Rect cover[2]
Definition rtree.h:116
int partition[9+1]
Definition rtree.h:112
RectReal * boundary
Definition rtree.h:52
Definition rtree.h:120
#define MAXLEVEL
Maximum verbosity level.
Definition verbose.c:28