rect.c 20 KB

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