PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/postgis-1.5.3/postgis/lwgeom_rtree.c

#
C | 531 lines | 353 code | 93 blank | 85 comment | 41 complexity | a531a9e978de050f32e1beae66b9469d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. /**********************************************************************
  2. * $Id: lwgeom_rtree.c 7140 2011-05-13 01:01:26Z chodgson $
  3. *
  4. * PostGIS - Spatial Types for PostgreSQL
  5. * http://postgis.refractions.net
  6. * Copyright 2001-2005 Refractions Research Inc.
  7. *
  8. * This is free software; you can redistribute and/or modify it under
  9. * the terms of the GNU General Public Licence. See the COPYING file.
  10. *
  11. **********************************************************************/
  12. #include "lwgeom_pg.h"
  13. #include "liblwgeom.h"
  14. #include "lwgeom_rtree.h"
  15. Datum LWGEOM_polygon_index(PG_FUNCTION_ARGS);
  16. /**
  17. * Creates an rtree given a pointer to the point array.
  18. * Must copy the point array.
  19. */
  20. RTREE_NODE *createTree(POINTARRAY *pointArray)
  21. {
  22. RTREE_NODE *root;
  23. RTREE_NODE** nodes = lwalloc(sizeof(RTREE_NODE*) * pointArray->npoints);
  24. int i, nodeCount;
  25. int childNodes, parentNodes;
  26. LWDEBUGF(2, "createTree called with pointarray %p", pointArray);
  27. nodeCount = pointArray->npoints - 1;
  28. LWDEBUGF(3, "Total leaf nodes: %d", nodeCount);
  29. /*
  30. * Create a leaf node for every line segment.
  31. */
  32. for (i = 0; i < nodeCount; i++)
  33. {
  34. nodes[i] = createLeafNode(pointArray, i);
  35. }
  36. /*
  37. * Next we group nodes by pairs. If there's an odd number of nodes,
  38. * we bring the last node up a level as is. Continue until we have
  39. * a single top node.
  40. */
  41. childNodes = nodeCount;
  42. parentNodes = nodeCount / 2;
  43. while (parentNodes > 0)
  44. {
  45. LWDEBUGF(3, "Merging %d children into %d parents.", childNodes, parentNodes);
  46. i = 0;
  47. while (i < parentNodes)
  48. {
  49. nodes[i] = createInteriorNode(nodes[i*2], nodes[i*2+1]);
  50. i++;
  51. }
  52. /*
  53. * Check for an odd numbered final node.
  54. */
  55. if (parentNodes * 2 < childNodes)
  56. {
  57. LWDEBUGF(3, "Shuffling child %d to parent %d", childNodes - 1, i);
  58. nodes[i] = nodes[childNodes - 1];
  59. parentNodes++;
  60. }
  61. childNodes = parentNodes;
  62. parentNodes = parentNodes / 2;
  63. }
  64. root = nodes[0];
  65. lwfree(nodes);
  66. LWDEBUGF(3, "createTree returning %p", root);
  67. return root;
  68. }
  69. /**
  70. * Creates an interior node given the children.
  71. */
  72. RTREE_NODE *createInteriorNode(RTREE_NODE *left, RTREE_NODE *right)
  73. {
  74. RTREE_NODE *parent;
  75. LWDEBUGF(2, "createInteriorNode called for children %p, %p", left, right);
  76. parent = lwalloc(sizeof(RTREE_NODE));
  77. parent->leftNode = left;
  78. parent->rightNode = right;
  79. parent->interval = mergeIntervals(left->interval, right->interval);
  80. parent->segment = NULL;
  81. LWDEBUGF(3, "createInteriorNode returning %p", parent);
  82. return parent;
  83. }
  84. /**
  85. * Creates a leaf node given the pointer to the start point of the segment.
  86. */
  87. RTREE_NODE *createLeafNode(POINTARRAY *pa, int startPoint)
  88. {
  89. RTREE_NODE *parent;
  90. LWLINE *line;
  91. double value1;
  92. double value2;
  93. POINT4D tmp;
  94. POINTARRAY *npa;
  95. LWDEBUGF(2, "createLeafNode called for point %d of %p", startPoint, pa);
  96. if (pa->npoints < startPoint + 2)
  97. {
  98. lwerror("createLeafNode: npoints = %d, startPoint = %d", pa->npoints, startPoint);
  99. }
  100. /*
  101. * The given point array will be part of a geometry that will be freed
  102. * independently of the index. Since we may want to cache the index,
  103. * we must create independent arrays.
  104. */
  105. npa = lwalloc(sizeof(POINTARRAY));
  106. npa->dims = 0;
  107. npa->npoints = 2;
  108. TYPE_SETZM(npa->dims, 0, 0);
  109. npa->serialized_pointlist = lwalloc(pointArray_ptsize(pa) * 2);
  110. getPoint4d_p(pa, startPoint, &tmp);
  111. setPoint4d(npa, 0, &tmp);
  112. value1 = tmp.y;
  113. getPoint4d_p(pa, startPoint + 1, &tmp);
  114. setPoint4d(npa, 1, &tmp);
  115. value2 = tmp.y;
  116. line = lwline_construct(-1, NULL, npa);
  117. parent = lwalloc(sizeof(RTREE_NODE));
  118. parent->interval = createInterval(value1, value2);
  119. parent->segment = line;
  120. parent->leftNode = NULL;
  121. parent->rightNode = NULL;
  122. LWDEBUGF(3, "createLeafNode returning %p", parent);
  123. return parent;
  124. }
  125. /**
  126. * Creates an interval with the total extents of the two given intervals.
  127. */
  128. INTERVAL *mergeIntervals(INTERVAL *inter1, INTERVAL *inter2)
  129. {
  130. INTERVAL *interval;
  131. LWDEBUGF(2, "mergeIntervals called with %p, %p", inter1, inter2);
  132. interval = lwalloc(sizeof(INTERVAL));
  133. interval->max = FP_MAX(inter1->max, inter2->max);
  134. interval->min = FP_MIN(inter1->min, inter2->min);
  135. LWDEBUGF(3, "interval min = %8.3f, max = %8.3f", interval->min, interval->max);
  136. return interval;
  137. }
  138. /**
  139. * Creates an interval given the min and max values, in arbitrary order.
  140. */
  141. INTERVAL *createInterval(double value1, double value2)
  142. {
  143. INTERVAL *interval;
  144. LWDEBUGF(2, "createInterval called with %8.3f, %8.3f", value1, value2);
  145. interval = lwalloc(sizeof(INTERVAL));
  146. interval->max = FP_MAX(value1, value2);
  147. interval->min = FP_MIN(value1, value2);
  148. LWDEBUGF(3, "interval min = %8.3f, max = %8.3f", interval->min, interval->max);
  149. return interval;
  150. }
  151. /**
  152. * Recursively frees the child nodes, the interval and the line before
  153. * freeing the root node.
  154. */
  155. void freeTree(RTREE_NODE *root)
  156. {
  157. LWDEBUGF(2, "freeTree called for %p", root);
  158. if (root->leftNode)
  159. freeTree(root->leftNode);
  160. if (root->rightNode)
  161. freeTree(root->rightNode);
  162. lwfree(root->interval);
  163. if (root->segment)
  164. {
  165. lwfree(root->segment->points->serialized_pointlist);
  166. lwfree(root->segment->points);
  167. lwgeom_release((LWGEOM *)root->segment);
  168. }
  169. lwfree(root);
  170. }
  171. /**
  172. * Free the cache object and all the sub-objects properly.
  173. */
  174. void clearCache(RTREE_POLY_CACHE *cache)
  175. {
  176. int g, r, i;
  177. LWDEBUGF(2, "clearCache called for %p", cache);
  178. i = 0;
  179. for (g = 0; g < cache->polyCount; g++)
  180. {
  181. for (r = 0; r < cache->ringCounts[g]; r++)
  182. {
  183. freeTree(cache->ringIndices[i]);
  184. i++;
  185. }
  186. }
  187. lwfree(cache->ringIndices);
  188. lwfree(cache->ringCounts);
  189. lwfree(cache->poly);
  190. cache->poly = 0;
  191. cache->ringIndices = 0;
  192. cache->ringCounts = 0;
  193. cache->polyCount = 0;
  194. }
  195. /**
  196. * Retrieves a collection of line segments given the root and crossing value.
  197. * The collection is a multilinestring consisting of two point lines
  198. * representing the segments of the ring that may be crossed by the
  199. * horizontal projection line at the given y value.
  200. */
  201. LWMLINE *findLineSegments(RTREE_NODE *root, double value)
  202. {
  203. LWMLINE *tmp, *result;
  204. LWGEOM **lwgeoms;
  205. LWDEBUGF(2, "findLineSegments called for tree %p and value %8.3f", root, value);
  206. result = NULL;
  207. if (!isContained(root->interval, value))
  208. {
  209. LWDEBUGF(3, "findLineSegments %p: not contained.", root);
  210. return NULL;
  211. }
  212. /* If there is a segment defined for this node, include it. */
  213. if (root->segment)
  214. {
  215. LWDEBUGF(3, "findLineSegments %p: adding segment %p %d.", root, root->segment, TYPE_GETTYPE(root->segment->type));
  216. lwgeoms = lwalloc(sizeof(LWGEOM *));
  217. lwgeoms[0] = (LWGEOM *)root->segment;
  218. LWDEBUGF(3, "Found geom %p, type %d, dim %d", root->segment, TYPE_GETTYPE(root->segment->type), TYPE_GETZM(root->segment->type));
  219. result = (LWMLINE *)lwcollection_construct(lwgeom_makeType_full(0, 0, 0, MULTILINETYPE, 0), -1, NULL, 1, lwgeoms);
  220. }
  221. /* If there is a left child node, recursively include its results. */
  222. if (root->leftNode)
  223. {
  224. LWDEBUGF(3, "findLineSegments %p: recursing left.", root);
  225. tmp = findLineSegments(root->leftNode, value);
  226. if (tmp)
  227. {
  228. LWDEBUGF(3, "Found geom %p, type %d, dim %d", tmp, TYPE_GETTYPE(tmp->type), TYPE_GETZM(tmp->type));
  229. if (result)
  230. result = mergeMultiLines(result, tmp);
  231. else
  232. result = tmp;
  233. }
  234. }
  235. /* Same for any right child. */
  236. if (root->rightNode)
  237. {
  238. LWDEBUGF(3, "findLineSegments %p: recursing right.", root);
  239. tmp = findLineSegments(root->rightNode, value);
  240. if (tmp)
  241. {
  242. LWDEBUGF(3, "Found geom %p, type %d, dim %d", tmp, TYPE_GETTYPE(tmp->type), TYPE_GETZM(tmp->type));
  243. if (result)
  244. result = mergeMultiLines(result, tmp);
  245. else
  246. result = tmp;
  247. }
  248. }
  249. return result;
  250. }
  251. /** Merges two multilinestrings into a single multilinestring. */
  252. LWMLINE *mergeMultiLines(LWMLINE *line1, LWMLINE *line2)
  253. {
  254. LWGEOM **geoms;
  255. LWCOLLECTION *col;
  256. int i, j, ngeoms;
  257. LWDEBUGF(2, "mergeMultiLines called on %p, %d, %d; %p, %d, %d", line1, line1->ngeoms, TYPE_GETTYPE(line1->type), line2, line2->ngeoms, TYPE_GETTYPE(line2->type));
  258. ngeoms = line1->ngeoms + line2->ngeoms;
  259. geoms = lwalloc(sizeof(LWGEOM *) * ngeoms);
  260. j = 0;
  261. for (i = 0; i < line1->ngeoms; i++, j++)
  262. {
  263. geoms[j] = lwgeom_clone((LWGEOM *)line1->geoms[i]);
  264. }
  265. for (i = 0; i < line2->ngeoms; i++, j++)
  266. {
  267. geoms[j] = lwgeom_clone((LWGEOM *)line2->geoms[i]);
  268. }
  269. col = lwcollection_construct(MULTILINETYPE, -1, NULL, ngeoms, geoms);
  270. LWDEBUGF(3, "mergeMultiLines returning %p, %d, %d", col, col->ngeoms, TYPE_GETTYPE(col->type));
  271. return (LWMLINE *)col;
  272. }
  273. /**
  274. * Returns 1 if min < value <= max, 0 otherwise. */
  275. uint32 isContained(INTERVAL *interval, double value)
  276. {
  277. return FP_CONTAINS_INCL(interval->min, value, interval->max) ? 1 : 0;
  278. }
  279. PG_FUNCTION_INFO_V1(LWGEOM_polygon_index);
  280. Datum LWGEOM_polygon_index(PG_FUNCTION_ARGS)
  281. {
  282. PG_LWGEOM *igeom, *result;
  283. LWGEOM *geom;
  284. LWPOLY *poly;
  285. LWMLINE *mline;
  286. RTREE_NODE *root;
  287. double yval;
  288. #if POSTGIS_DEBUG_LEVEL > 0
  289. int i = 0;
  290. #endif
  291. POSTGIS_DEBUG(2, "polygon_index called.");
  292. result = NULL;
  293. igeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
  294. yval = PG_GETARG_FLOAT8(1);
  295. geom = lwgeom_deserialize(SERIALIZED_FORM(igeom));
  296. if (TYPE_GETTYPE(geom->type) != POLYGONTYPE)
  297. {
  298. lwgeom_release(geom);
  299. PG_FREE_IF_COPY(igeom, 0);
  300. PG_RETURN_NULL();
  301. }
  302. poly = (LWPOLY *)geom;
  303. root = createTree(poly->rings[0]);
  304. mline = findLineSegments(root, yval);
  305. #if POSTGIS_DEBUG_LEVEL >= 3
  306. POSTGIS_DEBUGF(3, "mline returned %p %d", mline, TYPE_GETTYPE(mline->type));
  307. for (i = 0; i < mline->ngeoms; i++)
  308. {
  309. POSTGIS_DEBUGF(3, "geom[%d] %p %d", i, mline->geoms[i], TYPE_GETTYPE(mline->geoms[i]->type));
  310. }
  311. #endif
  312. if (mline)
  313. result = pglwgeom_serialize((LWGEOM *)mline);
  314. POSTGIS_DEBUGF(3, "returning result %p", result);
  315. lwfree(root);
  316. PG_FREE_IF_COPY(igeom, 0);
  317. lwgeom_release((LWGEOM *)poly);
  318. lwgeom_release((LWGEOM *)mline);
  319. PG_RETURN_POINTER(result);
  320. }
  321. RTREE_POLY_CACHE * createCache()
  322. {
  323. RTREE_POLY_CACHE *result;
  324. result = lwalloc(sizeof(RTREE_POLY_CACHE));
  325. result->polyCount = 0;
  326. result->ringCounts = 0;
  327. result->ringIndices = 0;
  328. result->poly = 0;
  329. result->type = 1;
  330. return result;
  331. }
  332. void populateCache(RTREE_POLY_CACHE *currentCache, LWGEOM *lwgeom, uchar *serializedPoly)
  333. {
  334. int i, p, r, length;
  335. LWMPOLY *mpoly;
  336. LWPOLY *poly;
  337. int nrings;
  338. LWDEBUGF(2, "populateCache called with cache %p geom %p", currentCache, lwgeom);
  339. if (TYPE_GETTYPE(lwgeom->type) == MULTIPOLYGONTYPE)
  340. {
  341. LWDEBUG(2, "populateCache MULTIPOLYGON");
  342. mpoly = (LWMPOLY *)lwgeom;
  343. nrings = 0;
  344. /*
  345. ** Count the total number of rings.
  346. */
  347. currentCache->polyCount = mpoly->ngeoms;
  348. currentCache->ringCounts = lwalloc(sizeof(int) * mpoly->ngeoms);
  349. for ( i = 0; i < mpoly->ngeoms; i++ )
  350. {
  351. currentCache->ringCounts[i] = mpoly->geoms[i]->nrings;
  352. nrings += mpoly->geoms[i]->nrings;
  353. }
  354. currentCache->ringIndices = lwalloc(sizeof(RTREE_NODE *) * nrings);
  355. /*
  356. ** Load the array in geometry order, each outer ring followed by the inner rings
  357. ** associated with that outer ring
  358. */
  359. i = 0;
  360. for ( p = 0; p < mpoly->ngeoms; p++ )
  361. {
  362. for ( r = 0; r < mpoly->geoms[p]->nrings; r++ )
  363. {
  364. currentCache->ringIndices[i] = createTree(mpoly->geoms[p]->rings[r]);
  365. i++;
  366. }
  367. }
  368. }
  369. else if ( TYPE_GETTYPE(lwgeom->type) == POLYGONTYPE )
  370. {
  371. LWDEBUG(2, "populateCache POLYGON");
  372. poly = (LWPOLY *)lwgeom;
  373. currentCache->polyCount = 1;
  374. currentCache->ringCounts = lwalloc(sizeof(int));
  375. currentCache->ringCounts[0] = poly->nrings;
  376. /*
  377. ** Just load the rings on in order
  378. */
  379. currentCache->ringIndices = lwalloc(sizeof(RTREE_NODE *) * poly->nrings);
  380. for ( i = 0; i < poly->nrings; i++ )
  381. {
  382. currentCache->ringIndices[i] = createTree(poly->rings[i]);
  383. }
  384. }
  385. else
  386. {
  387. /* Uh oh, shouldn't be here. */
  388. return;
  389. }
  390. /*
  391. ** Copy the serialized form of the polygon into the cache so
  392. ** we can test for equality against subsequent polygons.
  393. */
  394. length = lwgeom_size(serializedPoly);
  395. currentCache->poly = lwalloc(length);
  396. memcpy(currentCache->poly, serializedPoly, length);
  397. LWDEBUGF(3, "populateCache returning %p", currentCache);
  398. }
  399. /**
  400. * Creates a new cachable index if needed, or returns the current cache if
  401. * it is applicable to the current polygon.
  402. * The memory context must be changed to function scope before calling this
  403. * method. The method will allocate memory for the cache it creates,
  404. * as well as freeing the memory of any cache that is no longer applicable.
  405. */
  406. RTREE_POLY_CACHE *retrieveCache(LWGEOM *lwgeom, uchar *serializedPoly, RTREE_POLY_CACHE *currentCache)
  407. {
  408. int length;
  409. LWDEBUGF(2, "retrieveCache called with %p %p %p", lwgeom, serializedPoly, currentCache);
  410. /* Make sure this isn't someone else's cache object. */
  411. if ( currentCache && currentCache->type != 1 ) currentCache = NULL;
  412. if (!currentCache)
  413. {
  414. LWDEBUG(3, "No existing cache, create one.");
  415. return createCache();
  416. }
  417. if (!(currentCache->poly))
  418. {
  419. LWDEBUG(3, "Cache contains no polygon, populating it.");
  420. populateCache(currentCache, lwgeom, serializedPoly);
  421. return currentCache;
  422. }
  423. length = lwgeom_size(serializedPoly);
  424. if (lwgeom_size(currentCache->poly) != length)
  425. {
  426. LWDEBUG(3, "Polygon size mismatch, creating new cache.");
  427. clearCache(currentCache);
  428. return currentCache;
  429. }
  430. if ( memcmp(serializedPoly, currentCache->poly, length) )
  431. {
  432. LWDEBUG(3, "Polygon mismatch, creating new cache.");
  433. clearCache(currentCache);
  434. return currentCache;
  435. }
  436. LWDEBUGF(3, "Polygon match, retaining current cache, %p.", currentCache);
  437. return currentCache;
  438. }