node.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <stdlib.h>
  11. #include <inttypes.h>
  12. #include <label/index.h>
  13. #include <stdbool.h>
  14. #include <stddef.h>
  15. #include <stdint.h>
  16. #include <stdio.h>
  17. #include <assert.h>
  18. #include <label/node.h>
  19. #include <util/alloc.h>
  20. /* Make a new node and initialize to have all branch cells empty.
  21. */
  22. Node_t *RTreeNewNode(void) {
  23. Node_t *n = gv_alloc(sizeof(Node_t));
  24. InitNode(n);
  25. return n;
  26. }
  27. /* Initialize a Node structure.
  28. */
  29. void InitNode(Node_t * n)
  30. {
  31. n->count = 0;
  32. n->level = -1;
  33. for (size_t i = 0; i < NODECARD; i++)
  34. InitBranch(&(n->branch[i]));
  35. }
  36. /* Initialize one branch cell in a node.
  37. */
  38. void InitBranch(Branch_t * b)
  39. {
  40. InitRect(&(b->rect));
  41. b->child = NULL;
  42. }
  43. #ifdef RTDEBUG
  44. /* Print out the data in a node.
  45. */
  46. void PrintNode(Node_t * n)
  47. {
  48. assert(n);
  49. fprintf(stderr, "node");
  50. if (n->level == 0)
  51. fprintf(stderr, " LEAF");
  52. else if (n->level > 0)
  53. fprintf(stderr, " NONLEAF");
  54. else
  55. fprintf(stderr, " TYPE=?");
  56. fprintf(stderr, " level=%d count=%d child address=%p\n",
  57. n->level, n->count, n);
  58. for (size_t i = 0; i < NODECARD; i++) {
  59. if (n->branch[i].child != NULL)
  60. PrintBranch(i, &n->branch[i]);
  61. }
  62. }
  63. void PrintBranch(int i, Branch_t * b)
  64. {
  65. fprintf(stderr, " child[%d] X%X\n", i, (unsigned int) b->child);
  66. PrintRect(&(b->rect));
  67. }
  68. #endif
  69. /* Find the smallest rectangle that includes all rectangles in
  70. ** branches of a node.
  71. */
  72. Rect_t NodeCover(Node_t * n)
  73. {
  74. Rect_t r;
  75. assert(n);
  76. InitRect(&r);
  77. bool flag = true;
  78. for (size_t i = 0; i < NODECARD; i++)
  79. if (n->branch[i].child) {
  80. if (flag) {
  81. r = n->branch[i].rect;
  82. flag = false;
  83. } else
  84. r = CombineRect(&r, &(n->branch[i].rect));
  85. }
  86. return r;
  87. }
  88. /* Pick a branch. Pick the one that will need the smallest increase
  89. ** in area to accommodate the new rectangle. This will result in the
  90. ** least total area for the covering rectangles in the current node.
  91. ** In case of a tie, pick the one which was smaller before, to get
  92. ** the best resolution when searching.
  93. */
  94. int PickBranch(Rect_t * r, Node_t * n)
  95. {
  96. uint64_t bestIncr = 0;
  97. uint64_t bestArea = 0;
  98. int best=0;
  99. bool bestSet = false;
  100. assert(r && n);
  101. for (int i = 0; i < NODECARD; i++) {
  102. if (n->branch[i].child) {
  103. Rect_t *rr = &n->branch[i].rect;
  104. uint64_t area = RectArea(rr);
  105. Rect_t rect = CombineRect(r, rr);
  106. uint64_t increase = RectArea(&rect) - area;
  107. if (!bestSet || increase < bestIncr) {
  108. best = i;
  109. bestArea = area;
  110. bestIncr = increase;
  111. bestSet = true;
  112. } else if (increase == bestIncr && area < bestArea) {
  113. best = i;
  114. bestArea = area;
  115. bestIncr = increase;
  116. }
  117. # ifdef RTDEBUG
  118. fprintf(stderr,
  119. "i=%d area before=%" PRIu64 " area after=%" PRIu64 " increase=%" PRIu64
  120. "\n", i, area, area + increase, increase);
  121. # endif
  122. }
  123. }
  124. # ifdef RTDEBUG
  125. fprintf(stderr, "\tpicked %d\n", best);
  126. # endif
  127. return best;
  128. }
  129. /* Add a branch to a node. Split the node if necessary.
  130. ** Returns 0 if node not split. Old node updated.
  131. ** Returns 1 if node split, sets *new to address of new node.
  132. ** Old node updated, becomes one of two.
  133. */
  134. int AddBranch(RTree_t * rtp, Branch_t * b, Node_t * n, Node_t ** new)
  135. {
  136. assert(b);
  137. assert(n);
  138. if (n->count < NODECARD) { /* split won't be necessary */
  139. size_t i;
  140. for (i = 0; i < NODECARD; i++) { /* find empty branch */
  141. if (n->branch[i].child == NULL) {
  142. n->branch[i] = *b;
  143. n->count++;
  144. break;
  145. }
  146. }
  147. assert(i < NODECARD);
  148. return 0;
  149. } else {
  150. assert(new);
  151. SplitNode(rtp, n, b, new);
  152. return 1;
  153. }
  154. }
  155. /* Disconnect a dependent node.
  156. */
  157. void DisconBranch(Node_t * n, int i)
  158. {
  159. assert(n && i >= 0 && i < NODECARD);
  160. assert(n->branch[i].child);
  161. InitBranch(&(n->branch[i]));
  162. n->count--;
  163. }