split_q.c 9.2 KB

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