rect.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  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. #include <grass/gis.h>
  24. #define BIG_NUM (FLT_MAX/4.0)
  25. #define Undefined(x, t) ((x)->boundary[0] > (x)->boundary[t->ndims_alloc])
  26. /*!
  27. \brief Create a new rectangle for a given tree
  28. This method allocates a new rectangle and initializes
  29. the internal boundary coordinates based on the tree dimension.
  30. Hence a call to RTreeNewBoundary() is not necessary.
  31. \param t The pointer to a RTree struct
  32. \return A new allocated RTree_Rect struct
  33. */
  34. struct RTree_Rect *RTreeAllocRect(struct RTree *t)
  35. {
  36. struct RTree_Rect *r;
  37. assert(t);
  38. r = (struct RTree_Rect *)malloc(sizeof(struct RTree_Rect));
  39. assert(r);
  40. r->boundary = RTreeAllocBoundary(t);
  41. return r;
  42. }
  43. /*!
  44. \brief Delete a rectangle
  45. This method deletes (free) the allocated memory of a rectangle.
  46. \param r The pointer to the rectangle to be deleted
  47. */
  48. void RTreeFreeRect(struct RTree_Rect *r)
  49. {
  50. assert(r);
  51. RTreeFreeBoundary(r);
  52. free(r);
  53. }
  54. /*!
  55. \brief Allocate the boundary array of a rectangle for a given tree
  56. This method allocated the boundary coordinates array in
  57. provided rectangle. It does not release previously allocated memory.
  58. \param r The pointer to rectangle to initialize the boundary coordinates.
  59. This is usually a rectangle that was created on the stack or
  60. self allocated.
  61. \param t The pointer to a RTree struct
  62. */
  63. RectReal *RTreeAllocBoundary(struct RTree *t)
  64. {
  65. RectReal *boundary = (RectReal *)malloc(t->rectsize);
  66. assert(boundary);
  67. return boundary;
  68. }
  69. /*!
  70. \brief Delete the boundary of a rectangle
  71. This method deletes (free) the memory of the boundary of a rectangle
  72. and sets the boundary pointer to NULL.
  73. \param r The pointer to the rectangle to delete the boundary from.
  74. */
  75. void RTreeFreeBoundary(struct RTree_Rect *r)
  76. {
  77. assert(r);
  78. if (r->boundary)
  79. free(r->boundary);
  80. r->boundary = NULL;
  81. }
  82. /*!
  83. \brief Initialize a rectangle to have all 0 coordinates.
  84. */
  85. void RTreeInitRect(struct RTree_Rect *r, struct RTree *t)
  86. {
  87. register int i;
  88. for (i = 0; i < t->ndims_alloc; i++)
  89. r->boundary[i] = r->boundary[i + t->ndims_alloc] = (RectReal) 0;
  90. }
  91. /*!
  92. \brief Set one dimensional coordinates of a rectangle for a given tree.
  93. All coordinates of the rectangle will be initialized to 0 before
  94. the x coordinates are set.
  95. \param r The pointer to the rectangle
  96. \param t The pointer to the RTree
  97. \param x_min The lower x coordinate
  98. \param x_max The higher x coordinate
  99. */
  100. void RTreeSetRect1D(struct RTree_Rect *r, struct RTree *t, double x_min,
  101. double x_max)
  102. {
  103. RTreeInitRect(r, t);
  104. r->boundary[0] = (RectReal)x_min;
  105. r->boundary[t->ndims_alloc] = (RectReal)x_max;
  106. }
  107. /*!
  108. \brief Set two dimensional coordinates of a rectangle for a given tree.
  109. All coordinates of the rectangle will be initialized to 0 before
  110. the x and y coordinates are set.
  111. \param r The pointer to the rectangle
  112. \param t The pointer to the RTree
  113. \param x_min The lower x coordinate
  114. \param x_max The higher x coordinate
  115. \param y_min The lower y coordinate
  116. \param y_max The higher y coordinate
  117. */
  118. void RTreeSetRect2D(struct RTree_Rect *r, struct RTree *t, double x_min,
  119. double x_max, double y_min, double y_max)
  120. {
  121. RTreeInitRect(r, t);
  122. r->boundary[0] = (RectReal)x_min;
  123. r->boundary[t->ndims_alloc] = (RectReal)x_max;
  124. r->boundary[1] = (RectReal)y_min;
  125. r->boundary[1 + t->ndims_alloc] = (RectReal)y_max;
  126. }
  127. /*!
  128. \brief Set three dimensional coordinates of a rectangle for a given tree.
  129. All coordinates of the rectangle will be initialized to 0 before
  130. the x,y and z coordinates are set.
  131. \param r The pointer to the rectangle
  132. \param t The pointer to the RTree
  133. \param x_min The lower x coordinate
  134. \param x_max The higher x coordinate
  135. \param y_min The lower y coordinate
  136. \param y_max The higher y coordinate
  137. \param z_min The lower z coordinate
  138. \param z_max The higher z coordinate
  139. */
  140. void RTreeSetRect3D(struct RTree_Rect *r, struct RTree *t, double x_min,
  141. double x_max, double y_min, double y_max, double z_min,
  142. double z_max)
  143. {
  144. RTreeInitRect(r, t);
  145. r->boundary[0] = (RectReal)x_min;
  146. r->boundary[t->ndims_alloc] = (RectReal)x_max;
  147. r->boundary[1] = (RectReal)y_min;
  148. r->boundary[1 + t->ndims_alloc] = (RectReal)y_max;
  149. r->boundary[2] = (RectReal)z_min;
  150. r->boundary[2 + t->ndims_alloc] = (RectReal)z_max;
  151. }
  152. /*!
  153. \brief Set 4 dimensional coordinates of a rectangle for a given tree.
  154. All coordinates of the rectangle will be initialized to 0 before
  155. the x,y,z and t coordinates are set.
  156. \param r The pointer to the rectangle
  157. \param t The pointer to the RTree
  158. \param x_min The lower x coordinate
  159. \param x_max The higher x coordinate
  160. \param y_min The lower y coordinate
  161. \param y_max The higher y coordinate
  162. \param z_min The lower z coordinate
  163. \param z_max The higher z coordinate
  164. \param t_min The lower t coordinate
  165. \param t_max The higher t coordinate
  166. */
  167. void RTreeSetRect4D(struct RTree_Rect *r, struct RTree *t, double x_min,
  168. double x_max, double y_min, double y_max, double z_min,
  169. double z_max, double t_min, double t_max)
  170. {
  171. assert(t->ndims >= 4);
  172. RTreeInitRect(r, t);
  173. r->boundary[0] = (RectReal)x_min;
  174. r->boundary[t->ndims_alloc] = (RectReal)x_max;
  175. r->boundary[1] = (RectReal)y_min;
  176. r->boundary[1 + t->ndims_alloc] = (RectReal)y_max;
  177. r->boundary[2] = (RectReal)z_min;
  178. r->boundary[2 + t->ndims_alloc] = (RectReal)z_max;
  179. r->boundary[3] = (RectReal)t_min;
  180. r->boundary[3 + t->ndims_alloc] = (RectReal)t_max;
  181. }
  182. /*
  183. Return a rect whose first low side is higher than its opposite side -
  184. interpreted as an undefined rect.
  185. */
  186. void RTreeNullRect(struct RTree_Rect *r, struct RTree *t)
  187. {
  188. register int i;
  189. /* assert(r); */
  190. r->boundary[0] = (RectReal) 1;
  191. r->boundary[t->nsides_alloc - 1] = (RectReal) - 1;
  192. for (i = 1; i < t->ndims_alloc; i++)
  193. r->boundary[i] = r->boundary[i + t->ndims_alloc] = (RectReal) 0;
  194. return;
  195. }
  196. #if 0
  197. /*
  198. Fills in random coordinates in a rectangle.
  199. The low side is guaranteed to be less than the high side.
  200. */
  201. void RTreeRandomRect(struct RTree_Rect *R)
  202. {
  203. register struct RTree_Rect *r = R;
  204. register int i;
  205. register RectReal width;
  206. for (i = 0; i < NUMDIMS; i++) {
  207. /* width from 1 to 1000 / 4, more small ones
  208. */
  209. width = drand48() * (1000 / 4) + 1;
  210. /* sprinkle a given size evenly but so they stay in [0,100]
  211. */
  212. r->boundary[i] = drand48() * (1000 - width); /* low side */
  213. r->boundary[i + NUMDIMS] = r->boundary[i] + width; /* high side */
  214. }
  215. }
  216. /*
  217. Fill in the boundaries for a random search rectangle.
  218. Pass in a pointer to a rect that contains all the data,
  219. and a pointer to the rect to be filled in.
  220. Generated rect is centered randomly anywhere in the data area,
  221. and has size from 0 to the size of the data area in each dimension,
  222. i.e. search rect can stick out beyond data area.
  223. */
  224. void RTreeSearchRect(struct RTree_Rect *Search, struct RTree_Rect *Data)
  225. {
  226. register struct RTree_Rect *search = Search, *data = Data;
  227. register int i, j;
  228. register RectReal size, center;
  229. assert(search);
  230. assert(data);
  231. for (i = 0; i < NUMDIMS; i++) {
  232. j = i + NUMDIMS; /* index for high side boundary */
  233. if (data->boundary[i] > -BIG_NUM && data->boundary[j] < BIG_NUM) {
  234. size = (drand48() * (data->boundary[j] -
  235. data->boundary[i] + 1)) / 2;
  236. center = data->boundary[i] + drand48() *
  237. (data->boundary[j] - data->boundary[i] + 1);
  238. search->boundary[i] = center - size / 2;
  239. search->boundary[j] = center + size / 2;
  240. }
  241. else { /* some open boundary, search entire dimension */
  242. search->boundary[i] = -BIG_NUM;
  243. search->boundary[j] = BIG_NUM;
  244. }
  245. }
  246. }
  247. #endif
  248. /*
  249. Print out the data for a rectangle.
  250. */
  251. void RTreePrintRect(struct RTree_Rect *R, int depth, struct RTree *t)
  252. {
  253. register struct RTree_Rect *r = R;
  254. register int i;
  255. assert(r);
  256. RTreeTabIn(depth);
  257. fprintf(stdout, "rect:\n");
  258. for (i = 0; i < t->ndims_alloc; i++) {
  259. RTreeTabIn(depth + 1);
  260. fprintf(stdout, "%f\t%f\n", r->boundary[i], r->boundary[i + t->ndims_alloc]);
  261. }
  262. }
  263. /*
  264. Calculate the n-dimensional volume of a rectangle
  265. */
  266. RectReal RTreeRectVolume(struct RTree_Rect *R, struct RTree *t)
  267. {
  268. register struct RTree_Rect *r = R;
  269. register int i;
  270. register RectReal volume = (RectReal) 1;
  271. /* assert(r); */
  272. if (Undefined(r, t))
  273. return (RectReal) 0;
  274. for (i = 0; i < t->ndims; i++)
  275. volume *= r->boundary[i + t->ndims_alloc] - r->boundary[i];
  276. assert(volume >= 0.0);
  277. return volume;
  278. }
  279. /*
  280. Define the NUMDIMS-dimensional volume the unit sphere in that dimension into
  281. the symbol "UnitSphereVolume"
  282. Note that if the gamma function is available in the math library and if the
  283. compiler supports static initialization using functions, this is
  284. easily computed for any dimension. If not, the value can be precomputed and
  285. taken from a table. The following code can do it either way.
  286. */
  287. #ifdef gamma
  288. /* computes the volume of an N-dimensional sphere. */
  289. /* derived from formule in "Regular Polytopes" by H.S.M Coxeter */
  290. static double sphere_volume(double dimension)
  291. {
  292. double log_gamma, log_volume;
  293. log_gamma = gamma(dimension / 2.0 + 1);
  294. log_volume = dimension / 2.0 * log(M_PI) - log_gamma;
  295. return exp(log_volume);
  296. }
  297. static const double UnitSphereVolume = sphere_volume(20);
  298. #else
  299. /* Precomputed volumes of the unit spheres for the first few dimensions */
  300. const double UnitSphereVolumes[] = {
  301. 0.000000, /* dimension 0 */
  302. 2.000000, /* dimension 1 */
  303. 3.141593, /* dimension 2 */
  304. 4.188790, /* dimension 3 */
  305. 4.934802, /* dimension 4 */
  306. 5.263789, /* dimension 5 */
  307. 5.167713, /* dimension 6 */
  308. 4.724766, /* dimension 7 */
  309. 4.058712, /* dimension 8 */
  310. 3.298509, /* dimension 9 */
  311. 2.550164, /* dimension 10 */
  312. 1.884104, /* dimension 11 */
  313. 1.335263, /* dimension 12 */
  314. 0.910629, /* dimension 13 */
  315. 0.599265, /* dimension 14 */
  316. 0.381443, /* dimension 15 */
  317. 0.235331, /* dimension 16 */
  318. 0.140981, /* dimension 17 */
  319. 0.082146, /* dimension 18 */
  320. 0.046622, /* dimension 19 */
  321. 0.025807, /* dimension 20 */
  322. };
  323. #if NUMDIMS > 20
  324. # error "not enough precomputed sphere volumes"
  325. #endif
  326. #define UnitSphereVolume UnitSphereVolumes[NUMDIMS]
  327. #endif
  328. /*
  329. Calculate the n-dimensional volume of the bounding sphere of a rectangle
  330. */
  331. #if 0
  332. /*
  333. * A fast approximation to the volume of the bounding sphere for the
  334. * given Rect. By Paul B.
  335. */
  336. RectReal RTreeRectSphericalVolume(struct RTree_Rect *R, struct RTree *t)
  337. {
  338. register struct RTree_Rect *r = R;
  339. register int i;
  340. RectReal maxsize = (RectReal) 0, c_size;
  341. /* assert(r); */
  342. if (Undefined(r, t))
  343. return (RectReal) 0;
  344. for (i = 0; i < t->ndims; i++) {
  345. c_size = r->boundary[i + NUMDIMS] - r->boundary[i];
  346. if (c_size > maxsize)
  347. maxsize = c_size;
  348. }
  349. return (RectReal) (pow(maxsize / 2, NUMDIMS) *
  350. UnitSphereVolumes[t->ndims]);
  351. }
  352. #endif
  353. /*
  354. * The exact volume of the bounding sphere for the given Rect.
  355. */
  356. RectReal RTreeRectSphericalVolume(struct RTree_Rect *r, struct RTree *t)
  357. {
  358. int i;
  359. double sum_of_squares = 0, extent;
  360. /* assert(r); */
  361. if (Undefined(r, t))
  362. return (RectReal) 0;
  363. for (i = 0; i < t->ndims; i++) {
  364. extent = (r->boundary[i + t->ndims_alloc] - r->boundary[i]);
  365. /* extent should be half extent : /4 */
  366. sum_of_squares += extent * extent / 4.;
  367. }
  368. return (RectReal) (pow(sqrt(sum_of_squares), t->ndims) * UnitSphereVolumes[t->ndims]);
  369. }
  370. /*
  371. Calculate the n-dimensional surface area of a rectangle
  372. */
  373. RectReal RTreeRectSurfaceArea(struct RTree_Rect *r, struct RTree *t)
  374. {
  375. int i, j;
  376. RectReal face_area, sum = (RectReal) 0;
  377. /*assert(r); */
  378. if (Undefined(r, t))
  379. return (RectReal) 0;
  380. for (i = 0; i < t->ndims; i++) {
  381. face_area = (RectReal) 1;
  382. for (j = 0; j < t->ndims; j++)
  383. /* exclude i extent from product in this dimension */
  384. if (i != j) {
  385. face_area *= (r->boundary[j + t->ndims_alloc] - r->boundary[j]);
  386. }
  387. sum += face_area;
  388. }
  389. return 2 * sum;
  390. }
  391. /*
  392. Calculate the n-dimensional margin of a rectangle
  393. the margin is the sum of the lengths of the edges
  394. */
  395. RectReal RTreeRectMargin(struct RTree_Rect *r, struct RTree *t)
  396. {
  397. int i;
  398. RectReal margin = 0.0;
  399. /* assert(r); */
  400. for (i = 0; i < t->ndims; i++) {
  401. margin += r->boundary[i + t->ndims_alloc] - r->boundary[i];
  402. }
  403. return margin;
  404. }
  405. /*
  406. Combine two rectangles, make one that includes both.
  407. */
  408. void RTreeCombineRect(struct RTree_Rect *r1, struct RTree_Rect *r2,
  409. struct RTree_Rect *r3, struct RTree *t)
  410. {
  411. int i, j;
  412. /* assert(r1 && r2 && r3); */
  413. if (Undefined(r1, t)) {
  414. for (i = 0; i < t->nsides_alloc; i++)
  415. r3->boundary[i] = r2->boundary[i];
  416. return;
  417. }
  418. if (Undefined(r2, t)) {
  419. for (i = 0; i < t->nsides_alloc; i++)
  420. r3->boundary[i] = r1->boundary[i];
  421. return;
  422. }
  423. for (i = 0; i < t->ndims; i++) {
  424. r3->boundary[i] = MIN(r1->boundary[i], r2->boundary[i]);
  425. j = i + t->ndims_alloc;
  426. r3->boundary[j] = MAX(r1->boundary[j], r2->boundary[j]);
  427. }
  428. for (i = t->ndims; i < t->ndims_alloc; i++) {
  429. r3->boundary[i] = 0;
  430. j = i + t->ndims_alloc;
  431. r3->boundary[j] = 0;
  432. }
  433. }
  434. /*
  435. Expand first rectangle to cover second rectangle.
  436. */
  437. int RTreeExpandRect(struct RTree_Rect *r1, struct RTree_Rect *r2,
  438. struct RTree *t)
  439. {
  440. int i, j, ret = 0;
  441. /* assert(r1 && r2); */
  442. if (Undefined(r2, t))
  443. return ret;
  444. for (i = 0; i < t->ndims; i++) {
  445. if (r1->boundary[i] > r2->boundary[i]) {
  446. r1->boundary[i] = r2->boundary[i];
  447. ret = 1;
  448. }
  449. j = i + t->ndims_alloc;
  450. if (r1->boundary[j] < r2->boundary[j]) {
  451. r1->boundary[j] = r2->boundary[j];
  452. ret = 1;
  453. }
  454. }
  455. for (i = t->ndims; i < t->ndims_alloc; i++) {
  456. r1->boundary[i] = 0;
  457. j = i + t->ndims_alloc;
  458. r1->boundary[j] = 0;
  459. }
  460. return ret;
  461. }
  462. /*
  463. Decide whether two rectangles are identical.
  464. */
  465. int RTreeCompareRect(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  466. {
  467. register int i, j;
  468. /* assert(r && s); */
  469. for (i = 0; i < t->ndims; i++) {
  470. j = i + t->ndims_alloc; /* index for high sides */
  471. if (r->boundary[i] != s->boundary[i] ||
  472. r->boundary[j] != s->boundary[j]) {
  473. return 0;
  474. }
  475. }
  476. return 1;
  477. }
  478. /*
  479. Decide whether two rectangles overlap or touch.
  480. */
  481. int RTreeOverlap(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  482. {
  483. register int i, j;
  484. /* assert(r && s); */
  485. for (i = 0; i < t->ndims; i++) {
  486. j = i + t->ndims_alloc; /* index for high sides */
  487. if (r->boundary[i] > s->boundary[j] ||
  488. s->boundary[i] > r->boundary[j]) {
  489. return FALSE;
  490. }
  491. }
  492. return TRUE;
  493. }
  494. /*
  495. Decide whether rectangle s is contained in rectangle r.
  496. */
  497. int RTreeContained(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  498. {
  499. register int i, j;
  500. /* assert(r && s); */
  501. /* undefined rect is contained in any other */
  502. if (Undefined(r, t))
  503. return TRUE;
  504. /* no rect (except an undefined one) is contained in an undef rect */
  505. if (Undefined(s, t))
  506. return FALSE;
  507. for (i = 0; i < t->ndims; i++) {
  508. j = i + t->ndims_alloc; /* index for high sides */
  509. if (s->boundary[i] < r->boundary[i] ||
  510. s->boundary[j] > r->boundary[j])
  511. return FALSE;
  512. }
  513. return TRUE;
  514. }
  515. /*
  516. Decide whether rectangle s fully contains rectangle r.
  517. */
  518. int RTreeContains(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
  519. {
  520. register int i, j;
  521. /* assert(r && s); */
  522. /* undefined rect is contained in any other */
  523. if (Undefined(r, t))
  524. return TRUE;
  525. /* no rect (except an undefined one) is contained in an undef rect */
  526. if (Undefined(s, t))
  527. return FALSE;
  528. for (i = 0; i < t->ndims; i++) {
  529. j = i + t->ndims_alloc; /* index for high sides */
  530. if (s->boundary[i] > r->boundary[i] ||
  531. s->boundary[j] < r->boundary[j])
  532. return FALSE;
  533. }
  534. return TRUE;
  535. }