GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
split_q.c
Go to the documentation of this file.
1 
2 /****************************************************************************
3 * MODULE: R-Tree library
4 *
5 * AUTHOR(S): Antonin Guttman - original code
6 * Daniel Green (green@superliminal.com) - major clean-up
7 * and implementation of bounding spheres
8 *
9 * PURPOSE: Multidimensional index
10 *
11 * COPYRIGHT: (C) 2001 by the GRASS Development Team
12 *
13 * This program is free software under the GNU General Public
14 * License (>=v2). Read the file COPYING that comes with GRASS
15 * for details.
16 *****************************************************************************/
17 
18 #include <stdio.h>
19 #include "assert.h"
20 #include "index.h"
21 #include "card.h"
22 #include "split_q.h"
23 
24 struct Branch BranchBuf[MAXCARD + 1];
28 
29 /* variables for finding a partition */
31 
32 /*-----------------------------------------------------------------------------
33 | Load branch buffer with branches from full node plus the extra branch.
34 -----------------------------------------------------------------------------*/
35 static void RTreeGetBranches(struct Node *n, struct Branch *b)
36 {
37  int i;
38 
39  assert(n);
40  assert(b);
41 
42  /* load the branch buffer */
43  for (i = 0; i < MAXKIDS(n); i++) {
44  assert(n->branch[i].child); /* n should have every entry full */
45  BranchBuf[i] = n->branch[i];
46  }
47  BranchBuf[MAXKIDS(n)] = *b;
48  BranchCount = MAXKIDS(n) + 1;
49 
50  /* calculate rect containing all in the set */
52  for (i = 1; i < MAXKIDS(n) + 1; i++) {
54  }
56 
57  RTreeInitNode(n);
58 }
59 
60 
61 
62 
63 /*-----------------------------------------------------------------------------
64 | Put a branch in one of the groups.
65 -----------------------------------------------------------------------------*/
66 static void RTreeClassify(int i, int group, struct PartitionVars *p)
67 {
68  assert(p);
69  assert(!p->taken[i]);
70 
71  p->partition[i] = group;
72  p->taken[i] = TRUE;
73 
74  if (p->count[group] == 0)
75  p->cover[group] = BranchBuf[i].rect;
76  else
77  p->cover[group] =
78  RTreeCombineRect(&BranchBuf[i].rect, &p->cover[group]);
79  p->area[group] = RTreeRectSphericalVolume(&p->cover[group]);
80  p->count[group]++;
81 }
82 
83 
84 
85 
86 /*-----------------------------------------------------------------------------
87 | Pick two rects from set to be the first elements of the two groups.
88 | Pick the two that waste the most area if covered by a single rectangle.
89 -----------------------------------------------------------------------------*/
90 static void RTreePickSeeds(struct PartitionVars *p)
91 {
92  int i, j, seed0 = 0, seed1 = 0;
93  RectReal worst, waste, area[MAXCARD + 1];
94 
95  for (i = 0; i < p->total; i++)
96  area[i] = RTreeRectSphericalVolume(&BranchBuf[i].rect);
97 
98  worst = -CoverSplitArea - 1;
99  for (i = 0; i < p->total - 1; i++) {
100  for (j = i + 1; j < p->total; j++) {
101  struct Rect one_rect;
102 
103  one_rect = RTreeCombineRect(&BranchBuf[i].rect,
104  &BranchBuf[j].rect);
105  waste = RTreeRectSphericalVolume(&one_rect) - area[i] - area[j];
106  if (waste > worst) {
107  worst = waste;
108  seed0 = i;
109  seed1 = j;
110  }
111  }
112  }
113  RTreeClassify(seed0, 0, p);
114  RTreeClassify(seed1, 1, p);
115 }
116 
117 
118 
119 
120 /*-----------------------------------------------------------------------------
121 | Copy branches from the buffer into two nodes according to the partition.
122 -----------------------------------------------------------------------------*/
123 static void RTreeLoadNodes(struct Node *n, struct Node *q,
124  struct PartitionVars *p)
125 {
126  int i;
127 
128  assert(n);
129  assert(q);
130  assert(p);
131 
132  for (i = 0; i < p->total; i++) {
133  assert(p->partition[i] == 0 || p->partition[i] == 1);
134  if (p->partition[i] == 0)
135  RTreeAddBranch(&BranchBuf[i], n, NULL);
136  else if (p->partition[i] == 1)
137  RTreeAddBranch(&BranchBuf[i], q, NULL);
138  }
139 }
140 
141 
142 
143 
144 /*-----------------------------------------------------------------------------
145 | Initialize a PartitionVars structure.
146 -----------------------------------------------------------------------------*/
147 static void RTreeInitPVars(struct PartitionVars *p, int maxrects, int minfill)
148 {
149  int i;
150 
151  assert(p);
152 
153  p->count[0] = p->count[1] = 0;
154  p->cover[0] = p->cover[1] = RTreeNullRect();
155  p->area[0] = p->area[1] = (RectReal) 0;
156  p->total = maxrects;
157  p->minfill = minfill;
158  for (i = 0; i < maxrects; i++) {
159  p->taken[i] = FALSE;
160  p->partition[i] = -1;
161  }
162 }
163 
164 
165 
166 
167 /*-----------------------------------------------------------------------------
168 | Print out data for a partition from PartitionVars struct.
169 -----------------------------------------------------------------------------*/
170 static void RTreePrintPVars(struct PartitionVars *p)
171 {
172  int i;
173 
174  assert(p);
175 
176  fprintf(stdout, "\npartition:\n");
177  for (i = 0; i < p->total; i++) {
178  fprintf(stdout, "%3d\t", i);
179  }
180  fprintf(stdout, "\n");
181  for (i = 0; i < p->total; i++) {
182  if (p->taken[i])
183  fprintf(stdout, " t\t");
184  else
185  fprintf(stdout, "\t");
186  }
187  fprintf(stdout, "\n");
188  for (i = 0; i < p->total; i++) {
189  fprintf(stdout, "%3d\t", p->partition[i]);
190  }
191  fprintf(stdout, "\n");
192 
193  fprintf(stdout, "count[0] = %d area = %f\n", p->count[0], p->area[0]);
194  fprintf(stdout, "count[1] = %d area = %f\n", p->count[1], p->area[1]);
195  if (p->area[0] + p->area[1] > 0) {
196  fprintf(stdout, "total area = %f effectiveness = %3.2f\n",
197  p->area[0] + p->area[1],
198  (float)CoverSplitArea / (p->area[0] + p->area[1]));
199  }
200  fprintf(stdout, "cover[0]:\n");
201  RTreePrintRect(&p->cover[0], 0);
202 
203  fprintf(stdout, "cover[1]:\n");
204  RTreePrintRect(&p->cover[1], 0);
205 }
206 
207 
208 /*-----------------------------------------------------------------------------
209 | Method #0 for choosing a partition:
210 | As the seeds for the two groups, pick the two rects that would waste the
211 | most area if covered by a single rectangle, i.e. evidently the worst pair
212 | to have in the same group.
213 | Of the remaining, one at a time is chosen to be put in one of the two groups.
214 | The one chosen is the one with the greatest difference in area expansion
215 | depending on which group - the rect most strongly attracted to one group
216 | and repelled from the other.
217 | If one group gets too full (more would force other group to violate min
218 | fill requirement) then other group gets the rest.
219 | These last are the ones that can go in either group most easily.
220 -----------------------------------------------------------------------------*/
221 static void RTreeMethodZero(struct PartitionVars *p, int minfill)
222 {
223  int i;
224  RectReal biggestDiff;
225  int group, chosen = 0, betterGroup = 0;
226 
227  assert(p);
228 
229  RTreeInitPVars(p, BranchCount, minfill);
230  RTreePickSeeds(p);
231 
232  while (p->count[0] + p->count[1] < p->total
233  && p->count[0] < p->total - p->minfill
234  && p->count[1] < p->total - p->minfill) {
235  biggestDiff = (RectReal) - 1.;
236  for (i = 0; i < p->total; i++) {
237  if (!p->taken[i]) {
238  struct Rect *r, rect_0, rect_1;
239  RectReal growth0, growth1, diff;
240 
241  r = &BranchBuf[i].rect;
242  rect_0 = RTreeCombineRect(r, &p->cover[0]);
243  rect_1 = RTreeCombineRect(r, &p->cover[1]);
244  growth0 = RTreeRectSphericalVolume(&rect_0) - p->area[0];
245  growth1 = RTreeRectSphericalVolume(&rect_1) - p->area[1];
246  diff = growth1 - growth0;
247  if (diff >= 0)
248  group = 0;
249  else {
250  group = 1;
251  diff = -diff;
252  }
253 
254  if (diff > biggestDiff) {
255  biggestDiff = diff;
256  chosen = i;
257  betterGroup = group;
258  }
259  else if (diff == biggestDiff &&
260  p->count[group] < p->count[betterGroup]) {
261  chosen = i;
262  betterGroup = group;
263  }
264  }
265  }
266  RTreeClassify(chosen, betterGroup, p);
267  }
268 
269  /* if one group too full, put remaining rects in the other */
270  if (p->count[0] + p->count[1] < p->total) {
271  if (p->count[0] >= p->total - p->minfill)
272  group = 1;
273  else
274  group = 0;
275  for (i = 0; i < p->total; i++) {
276  if (!p->taken[i])
277  RTreeClassify(i, group, p);
278  }
279  }
280 
281  assert(p->count[0] + p->count[1] == p->total);
282  assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill);
283 }
284 
285 
286 /*-----------------------------------------------------------------------------
287 | Split a node.
288 | Divides the nodes branches and the extra one between two nodes.
289 | Old node is one of the new ones, and one really new one is created.
290 | Tries more than one method for choosing a partition, uses best result.
291 -----------------------------------------------------------------------------*/
292 void RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn)
293 {
294  struct PartitionVars *p;
295  int level;
296 
297  assert(n);
298  assert(b);
299 
300  /* load all the branches into a buffer, initialize old node */
301  level = n->level;
302  RTreeGetBranches(n, b);
303 
304  /* find partition */
305  p = &Partitions[0];
306  /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */
307  RTreeMethodZero(p, level > 0 ? MinNodeFill : MinLeafFill);
308 
309  /*
310  * put branches from buffer into 2 nodes
311  * according to chosen partition
312  */
313  *nn = RTreeNewNode();
314  (*nn)->level = n->level = level;
315  RTreeLoadNodes(n, *nn, p);
316  assert(n->count + (*nn)->count == p->total);
317 }
struct PartitionVars Partitions[METHODS]
Definition: split_q.c:30
struct Rect CoverSplit
Definition: split_q.c:26
struct Branch BranchBuf[MAXCARD+1]
Definition: split_q.c:24
double RectReal
Definition: index.h:25
float b
Definition: named_colr.c:8
int taken[MAXCARD+1]
Definition: split_q.h:27
struct Node * child
Definition: index.h:50
#define FALSE
Definition: dbfopen.c:117
tuple q
Definition: forms.py:2019
int minfill
Definition: split_q.h:26
struct Rect rect
Definition: index.h:49
float r
Definition: named_colr.c:8
Definition: index.h:56
int RTreeAddBranch(struct Branch *, struct Node *, struct Node **)
Definition: node.c:179
RectReal RTreeRectSphericalVolume(struct Rect *R)
Definition: rect.c:253
int BranchCount
Definition: split_q.c:25
int partition[MAXCARD+1]
Definition: split_q.h:25
struct Rect cover[2]
Definition: split_q.h:29
void RTreeSplitNode(struct Node *, struct Branch *, struct Node **)
Definition: split_q.c:292
Definition: index.h:47
RectReal area[2]
Definition: split_q.h:30
struct Node * RTreeNewNode(void)
Definition: node.c:44
RectReal CoverSplitArea
Definition: split_q.c:27
#define TRUE
Definition: dbfopen.c:118
void RTreePrintRect(struct Rect *, int)
Definition: rect.c:130
int count[2]
Definition: split_q.h:28
struct Rect RTreeNullRect(void)
Definition: rect.c:52
return NULL
Definition: dbfopen.c:1394
struct Rect RTreeCombineRect(struct Rect *, struct Rect *)
Definition: rect.c:305
int count
Definition: index.h:58
#define MinNodeFill
Definition: card.h:26
#define MAXKIDS(n)
Definition: card.h:29
void RTreeInitNode(struct Node *)
Definition: node.c:32
int level
Definition: index.h:59
Definition: index.h:40
#define MinLeafFill
Definition: card.h:27
#define METHODS
Definition: split_q.h:22
int n
Definition: dataquad.c:291
#define MAXCARD
Definition: index.h:54
struct Branch branch[MAXCARD]
Definition: index.h:60