rect.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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. * COPYRIGHT: (C) 2010 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. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <assert.h>
  20. #include "index.h"
  21. #include <float.h>
  22. #include <math.h>
  23. #define BIG_NUM (FLT_MAX/4.0)
  24. #define Undefined(x, t) ((x)->boundary[0] > (x)->boundary[t->ndims_alloc])
  25. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  26. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  27. /*-----------------------------------------------------------------------------
  28. | Create a new rectangle for a given tree
  29. -----------------------------------------------------------------------------*/
  30. void RTreeNewRect(struct RTree_Rect *r, struct RTree *t)
  31. {
  32. r->boundary = (RectReal *)malloc(t->rectsize);
  33. assert(r->boundary);
  34. }
  35. /*-----------------------------------------------------------------------------
  36. | Initialize a rectangle to have all 0 coordinates.
  37. -----------------------------------------------------------------------------*/
  38. void RTreeInitRect(struct RTree_Rect *r, struct RTree *t)
  39. {
  40. register int i;
  41. for (i = 0; i < t->ndims; i++)
  42. r->boundary[i] = r->boundary[i + t->ndims_alloc] = (RectReal) 0;
  43. }
  44. /*-----------------------------------------------------------------------------
  45. | Return a rect whose first low side is higher than its opposite side -
  46. | interpreted as an undefined rect.
  47. -----------------------------------------------------------------------------*/
  48. void RTreeNullRect(struct RTree_Rect *r, struct RTree *t)
  49. {
  50. register int i;
  51. /* assert(r); */
  52. r->boundary[0] = (RectReal) 1;
  53. r->boundary[t->nsides - 1] = (RectReal) - 1;
  54. for (i = 1; i < t->ndims; i++)
  55. r->boundary[i] = r->boundary[i + t->ndims_alloc] = (RectReal) 0;
  56. return;
  57. }
  58. #if 0
  59. /*-----------------------------------------------------------------------------
  60. | Fills in random coordinates in a rectangle.
  61. | The low side is guaranteed to be less than the high side.
  62. -----------------------------------------------------------------------------*/
  63. void RTreeRandomRect(struct RTree_Rect *R)
  64. {
  65. register struct RTree_Rect *r = R;
  66. register int i;
  67. register RectReal width;
  68. for (i = 0; i < NUMDIMS; i++) {
  69. /* width from 1 to 1000 / 4, more small ones
  70. */
  71. width = drand48() * (1000 / 4) + 1;
  72. /* sprinkle a given size evenly but so they stay in [0,100]
  73. */
  74. r->boundary[i] = drand48() * (1000 - width); /* low side */
  75. r->boundary[i + NUMDIMS] = r->boundary[i] + width; /* high side */
  76. }
  77. }
  78. /*-----------------------------------------------------------------------------
  79. | Fill in the boundaries for a random search rectangle.
  80. | Pass in a pointer to a rect that contains all the data,
  81. | and a pointer to the rect to be filled in.
  82. | Generated rect is centered randomly anywhere in the data area,
  83. | and has size from 0 to the size of the data area in each dimension,
  84. | i.e. search rect can stick out beyond data area.
  85. -----------------------------------------------------------------------------*/
  86. void RTreeSearchRect(struct RTree_Rect *Search, struct RTree_Rect *Data)
  87. {
  88. register struct RTree_Rect *search = Search, *data = Data;
  89. register int i, j;
  90. register RectReal size, center;
  91. assert(search);
  92. assert(data);
  93. for (i = 0; i < NUMDIMS; i++) {
  94. j = i + NUMDIMS; /* index for high side boundary */
  95. if (data->boundary[i] > -BIG_NUM && data->boundary[j] < BIG_NUM) {
  96. size = (drand48() * (data->boundary[j] -
  97. data->boundary[i] + 1)) / 2;
  98. center = data->boundary[i] + drand48() *
  99. (data->boundary[j] - data->boundary[i] + 1);
  100. search->boundary[i] = center - size / 2;
  101. search->boundary[j] = center + size / 2;
  102. }
  103. else { /* some open boundary, search entire dimension */
  104. search->boundary[i] = -BIG_NUM;
  105. search->boundary[j] = BIG_NUM;
  106. }
  107. }
  108. }
  109. #endif
  110. /*-----------------------------------------------------------------------------
  111. | Print out the data for a rectangle.
  112. -----------------------------------------------------------------------------*/
  113. void RTreePrintRect(struct RTree_Rect *R, int depth, struct RTree *t)
  114. {
  115. register struct RTree_Rect *r = R;
  116. register int i;
  117. assert(r);
  118. RTreeTabIn(depth);
  119. fprintf(stdout, "rect:\n");
  120. for (i = 0; i < t->ndims_alloc; i++) {
  121. RTreeTabIn(depth + 1);
  122. fprintf(stdout, "%f\t%f\n", r->boundary[i], r->boundary[i + t->ndims_alloc]);
  123. }
  124. }
  125. /*-----------------------------------------------------------------------------
  126. | Calculate the n-dimensional volume of a rectangle
  127. -----------------------------------------------------------------------------*/
  128. RectReal RTreeRectVolume(struct RTree_Rect *R, struct RTree *t)
  129. {
  130. register struct RTree_Rect *r = R;
  131. register int i;
  132. register RectReal volume = (RectReal) 1;
  133. /* assert(r); */
  134. if (Undefined(r, t))
  135. return (RectReal) 0;
  136. for (i = 0; i < t->ndims; i++)
  137. volume *= r->boundary[i + t->ndims_alloc] - r->boundary[i];
  138. assert(volume >= 0.0);
  139. return volume;
  140. }
  141. /*-----------------------------------------------------------------------------
  142. | Define the NUMDIMS-dimensional volume the unit sphere in that dimension into
  143. | the symbol "UnitSphereVolume"
  144. | Note that if the gamma function is available in the math library and if the
  145. | compiler supports static initialization using functions, this is
  146. | easily computed for any dimension. If not, the value can be precomputed and
  147. | taken from a table. The following code can do it either way.
  148. -----------------------------------------------------------------------------*/
  149. #ifdef gamma
  150. /* computes the volume of an N-dimensional sphere. */
  151. /* derived from formule in "Regular Polytopes" by H.S.M Coxeter */
  152. static double sphere_volume(double dimension)
  153. {
  154. double log_gamma, log_volume;
  155. log_gamma = gamma(dimension / 2.0 + 1);
  156. log_volume = dimension / 2.0 * log(M_PI) - log_gamma;
  157. return exp(log_volume);
  158. }
  159. static const double UnitSphereVolume = sphere_volume(20);
  160. #else
  161. /* Precomputed volumes of the unit spheres for the first few dimensions */
  162. const double UnitSphereVolumes[] = {
  163. 0.000000, /* dimension 0 */
  164. 2.000000, /* dimension 1 */
  165. 3.141593, /* dimension 2 */
  166. 4.188790, /* dimension 3 */
  167. 4.934802, /* dimension 4 */
  168. 5.263789, /* dimension 5 */
  169. 5.167713, /* dimension 6 */
  170. 4.724766, /* dimension 7 */
  171. 4.058712, /* dimension 8 */
  172. 3.298509, /* dimension 9 */
  173. 2.550164, /* dimension 10 */
  174. 1.884104, /* dimension 11 */
  175. 1.335263, /* dimension 12 */
  176. 0.910629, /* dimension 13 */
  177. 0.599265, /* dimension 14 */
  178. 0.381443, /* dimension 15 */
  179. 0.235331, /* dimension 16 */
  180. 0.140981, /* dimension 17 */
  181. 0.082146, /* dimension 18 */
  182. 0.046622, /* dimension 19 */
  183. 0.025807, /* dimension 20 */
  184. };
  185. #if NUMDIMS > 20
  186. # error "not enough precomputed sphere volumes"
  187. #endif
  188. #define UnitSphereVolume UnitSphereVolumes[NUMDIMS]
  189. #endif
  190. /*-----------------------------------------------------------------------------
  191. | Calculate the n-dimensional volume of the bounding sphere of a rectangle
  192. -----------------------------------------------------------------------------*/
  193. #if 0
  194. /*
  195. * A fast approximation to the volume of the bounding sphere for the
  196. * given Rect. By Paul B.
  197. */
  198. RectReal RTreeRectSphericalVolume(struct RTree_Rect *R, struct RTree *t)
  199. {
  200. register struct RTree_Rect *r = R;
  201. register int i;
  202. RectReal maxsize = (RectReal) 0, c_size;
  203. /* assert(r); */
  204. if (Undefined(r, t))
  205. return (RectReal) 0;
  206. for (i = 0; i < t->ndims; i++) {
  207. c_size = r->boundary[i + NUMDIMS] - r->boundary[i];
  208. if (c_size > maxsize)
  209. maxsize = c_size;
  210. }
  211. return (RectReal) (pow(maxsize / 2, NUMDIMS) *
  212. UnitSphereVolumes[t->ndims]);
  213. }
  214. #endif
  215. /*
  216. * The exact volume of the bounding sphere for the given Rect.
  217. */
  218. RectReal RTreeRectSphericalVolume(struct RTree_Rect *r, struct RTree *t)
  219. {
  220. int i;
  221. double sum_of_squares = 0, extent;
  222. /* assert(r); */
  223. if (Undefined(r, t))
  224. return (RectReal) 0;
  225. for (i = 0; i < t->ndims; i++) {
  226. extent = (r->boundary[i + t->ndims_alloc] - r->boundary[i]);
  227. /* extent should be half extent : /4 */
  228. sum_of_squares += extent * extent / 4.;
  229. }
  230. return (RectReal) (pow(sqrt(sum_of_squares), t->ndims) * UnitSphereVolumes[t->ndims]);
  231. }
  232. /*-----------------------------------------------------------------------------
  233. | Calculate the n-dimensional surface area of a rectangle
  234. -----------------------------------------------------------------------------*/
  235. RectReal RTreeRectSurfaceArea(struct RTree_Rect *r, struct RTree *t)
  236. {
  237. int i, j;
  238. RectReal face_area, sum = (RectReal) 0;
  239. /*assert(r); */
  240. if (Undefined(r, t))
  241. return (RectReal) 0;
  242. for (i = 0; i < t->ndims; i++) {
  243. face_area = (RectReal) 1;
  244. for (j = 0; j < t->ndims; j++)
  245. /* exclude i extent from product in this dimension */
  246. if (i != j) {
  247. face_area *= (r->boundary[j + t->ndims_alloc] - r->boundary[j]);
  248. }
  249. sum += face_area;
  250. }
  251. return 2 * sum;
  252. }
  253. /*-----------------------------------------------------------------------------
  254. | Calculate the n-dimensional margin of a rectangle
  255. | the margin is the sum of the lengths of the edges
  256. -----------------------------------------------------------------------------*/
  257. RectReal RTreeRectMargin(struct RTree_Rect *r, struct RTree *t)
  258. {
  259. int i;
  260. RectReal margin = 0.0;
  261. /* assert(r); */
  262. for (i = 0; i < t->ndims; i++) {
  263. margin += r->boundary[i + t->ndims_alloc] - r->boundary[i];
  264. }
  265. return margin;
  266. }
  267. /*-----------------------------------------------------------------------------
  268. | Combine two rectangles, make one that includes both.
  269. -----------------------------------------------------------------------------*/
  270. void RTreeCombineRect(struct RTree_Rect *r1, struct RTree_Rect *r2,
  271. struct RTree_Rect *r3, struct RTree *t)
  272. {
  273. int i, j;
  274. /* assert(r1 && r2 && r3); */
  275. if (Undefined(r1, t)) {
  276. for (i = 0; i < t->nsides; i++)
  277. r3->boundary[i] = r2->boundary[i];
  278. return;
  279. }
  280. if (Undefined(r2, t)) {
  281. for (i = 0; i < t->nsides; i++)
  282. r3->boundary[i] = r1->boundary[i];
  283. return;
  284. }
  285. for (i = 0; i < t->ndims; i++) {
  286. r3->boundary[i] = MIN(r1->boundary[i], r2->boundary[i]);
  287. j = i + t->ndims_alloc;
  288. r3->boundary[j] = MAX(r1->boundary[j], r2->boundary[j]);
  289. }
  290. for (i = t->ndims; i < t->ndims_alloc; i++) {
  291. r3->boundary[i] = 0;
  292. j = i + t->ndims_alloc;
  293. r3->boundary[j] = 0;
  294. }
  295. }
  296. /*-----------------------------------------------------------------------------
  297. | Expand first rectangle to cover second rectangle.
  298. -----------------------------------------------------------------------------*/
  299. void RTreeExpandRect(struct RTree_Rect *r1, struct RTree_Rect *r2,
  300. struct RTree *t)
  301. {
  302. int i, j;
  303. /* assert(r1 && r2); */
  304. if (Undefined(r2, t))
  305. return;
  306. for (i = 0; i < t->ndims; i++) {
  307. r1->boundary[i] = MIN(r1->boundary[i], r2->boundary[i]);
  308. j = i + t->ndims_alloc;
  309. r1->boundary[j] = MAX(r1->boundary[j], r2->boundary[j]);
  310. }
  311. for (i = t->ndims; i < t->ndims_alloc; i++) {
  312. r1->boundary[i] = 0;
  313. j = i + t->ndims_alloc;
  314. r1->boundary[j] = 0;
  315. }
  316. }
  317. /*-----------------------------------------------------------------------------
  318. | Decide whether two rectangles are identical.
  319. -----------------------------------------------------------------------------*/
  320. int RTreeCompareRect(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  321. {
  322. register int i, j;
  323. /* assert(r && s); */
  324. for (i = 0; i < t->ndims; i++) {
  325. j = i + t->ndims_alloc; /* index for high sides */
  326. if (r->boundary[i] != s->boundary[i] ||
  327. r->boundary[j] != s->boundary[j]) {
  328. return 0;
  329. }
  330. }
  331. return 1;
  332. }
  333. /*-----------------------------------------------------------------------------
  334. | Decide whether two rectangles overlap or touch.
  335. -----------------------------------------------------------------------------*/
  336. int RTreeOverlap(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  337. {
  338. register int i, j;
  339. /* assert(r && s); */
  340. for (i = 0; i < t->ndims; i++) {
  341. j = i + t->ndims_alloc; /* index for high sides */
  342. if (r->boundary[i] > s->boundary[j] ||
  343. s->boundary[i] > r->boundary[j]) {
  344. return FALSE;
  345. }
  346. }
  347. return TRUE;
  348. }
  349. /*-----------------------------------------------------------------------------
  350. | Decide whether rectangle s is contained in rectangle r.
  351. -----------------------------------------------------------------------------*/
  352. int RTreeContained(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  353. {
  354. register int i, j;
  355. /* assert(r && s); */
  356. /* undefined rect is contained in any other */
  357. if (Undefined(r, t))
  358. return TRUE;
  359. /* no rect (except an undefined one) is contained in an undef rect */
  360. if (Undefined(s, t))
  361. return FALSE;
  362. for (i = 0; i < t->ndims; i++) {
  363. j = i + t->ndims_alloc; /* index for high sides */
  364. if (s->boundary[i] < r->boundary[i] ||
  365. s->boundary[j] > r->boundary[j])
  366. return FALSE;
  367. }
  368. return TRUE;
  369. }
  370. /*-----------------------------------------------------------------------------
  371. | Decide whether rectangle s fully contains rectangle r.
  372. -----------------------------------------------------------------------------*/
  373. int RTreeContains(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  374. {
  375. register int i, j;
  376. /* assert(r && s); */
  377. /* undefined rect is contained in any other */
  378. if (Undefined(r, t))
  379. return TRUE;
  380. /* no rect (except an undefined one) is contained in an undef rect */
  381. if (Undefined(s, t))
  382. return FALSE;
  383. for (i = 0; i < t->ndims; i++) {
  384. j = i + t->ndims_alloc; /* index for high sides */
  385. if (s->boundary[i] > r->boundary[i] ||
  386. s->boundary[j] < r->boundary[j])
  387. return FALSE;
  388. }
  389. return TRUE;
  390. }