index.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. var rbush = require('rbush');
  2. var helpers = require('@turf/helpers');
  3. var meta = require('@turf/meta');
  4. var turfBBox = require('@turf/bbox').default;
  5. var featureEach = meta.featureEach;
  6. var coordEach = meta.coordEach;
  7. var polygon = helpers.polygon;
  8. var featureCollection = helpers.featureCollection;
  9. /**
  10. * GeoJSON implementation of [RBush](https://github.com/mourner/rbush#rbush) spatial index.
  11. *
  12. * @name rbush
  13. * @param {number} [maxEntries=9] defines the maximum number of entries in a tree node. 9 (used by default) is a
  14. * reasonable choice for most applications. Higher value means faster insertion and slower search, and vice versa.
  15. * @returns {RBush} GeoJSON RBush
  16. * @example
  17. * var geojsonRbush = require('geojson-rbush').default;
  18. * var tree = geojsonRbush();
  19. */
  20. function geojsonRbush(maxEntries) {
  21. var tree = new rbush(maxEntries);
  22. /**
  23. * [insert](https://github.com/mourner/rbush#data-format)
  24. *
  25. * @param {Feature} feature insert single GeoJSON Feature
  26. * @returns {RBush} GeoJSON RBush
  27. * @example
  28. * var poly = turf.polygon([[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]);
  29. * tree.insert(poly)
  30. */
  31. tree.insert = function (feature) {
  32. if (feature.type !== 'Feature') throw new Error('invalid feature');
  33. feature.bbox = feature.bbox ? feature.bbox : turfBBox(feature);
  34. return rbush.prototype.insert.call(this, feature);
  35. };
  36. /**
  37. * [load](https://github.com/mourner/rbush#bulk-inserting-data)
  38. *
  39. * @param {FeatureCollection|Array<Feature>} features load entire GeoJSON FeatureCollection
  40. * @returns {RBush} GeoJSON RBush
  41. * @example
  42. * var polys = turf.polygons([
  43. * [[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]],
  44. * [[[-93, 32], [-83, 32], [-83, 39], [-93, 39], [-93, 32]]]
  45. * ]);
  46. * tree.load(polys);
  47. */
  48. tree.load = function (features) {
  49. var load = [];
  50. // Load an Array of Features
  51. if (Array.isArray(features)) {
  52. features.forEach(function (feature) {
  53. if (feature.type !== 'Feature') throw new Error('invalid features');
  54. feature.bbox = feature.bbox ? feature.bbox : turfBBox(feature);
  55. load.push(feature);
  56. });
  57. } else {
  58. // Load a FeatureCollection
  59. featureEach(features, function (feature) {
  60. if (feature.type !== 'Feature') throw new Error('invalid features');
  61. feature.bbox = feature.bbox ? feature.bbox : turfBBox(feature);
  62. load.push(feature);
  63. });
  64. }
  65. return rbush.prototype.load.call(this, load);
  66. };
  67. /**
  68. * [remove](https://github.com/mourner/rbush#removing-data)
  69. *
  70. * @param {Feature} feature remove single GeoJSON Feature
  71. * @param {Function} equals Pass a custom equals function to compare by value for removal.
  72. * @returns {RBush} GeoJSON RBush
  73. * @example
  74. * var poly = turf.polygon([[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]);
  75. *
  76. * tree.remove(poly);
  77. */
  78. tree.remove = function (feature, equals) {
  79. if (feature.type !== 'Feature') throw new Error('invalid feature');
  80. feature.bbox = feature.bbox ? feature.bbox : turfBBox(feature);
  81. return rbush.prototype.remove.call(this, feature, equals);
  82. };
  83. /**
  84. * [clear](https://github.com/mourner/rbush#removing-data)
  85. *
  86. * @returns {RBush} GeoJSON Rbush
  87. * @example
  88. * tree.clear()
  89. */
  90. tree.clear = function () {
  91. return rbush.prototype.clear.call(this);
  92. };
  93. /**
  94. * [search](https://github.com/mourner/rbush#search)
  95. *
  96. * @param {BBox|FeatureCollection|Feature} geojson search with GeoJSON
  97. * @returns {FeatureCollection} all features that intersects with the given GeoJSON.
  98. * @example
  99. * var poly = turf.polygon([[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]);
  100. *
  101. * tree.search(poly);
  102. */
  103. tree.search = function (geojson) {
  104. var features = rbush.prototype.search.call(this, this.toBBox(geojson));
  105. return featureCollection(features);
  106. };
  107. /**
  108. * [collides](https://github.com/mourner/rbush#collisions)
  109. *
  110. * @param {BBox|FeatureCollection|Feature} geojson collides with GeoJSON
  111. * @returns {boolean} true if there are any items intersecting the given GeoJSON, otherwise false.
  112. * @example
  113. * var poly = turf.polygon([[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]);
  114. *
  115. * tree.collides(poly);
  116. */
  117. tree.collides = function (geojson) {
  118. return rbush.prototype.collides.call(this, this.toBBox(geojson));
  119. };
  120. /**
  121. * [all](https://github.com/mourner/rbush#search)
  122. *
  123. * @returns {FeatureCollection} all the features in RBush
  124. * @example
  125. * tree.all()
  126. */
  127. tree.all = function () {
  128. var features = rbush.prototype.all.call(this);
  129. return featureCollection(features);
  130. };
  131. /**
  132. * [toJSON](https://github.com/mourner/rbush#export-and-import)
  133. *
  134. * @returns {any} export data as JSON object
  135. * @example
  136. * var exported = tree.toJSON()
  137. */
  138. tree.toJSON = function () {
  139. return rbush.prototype.toJSON.call(this);
  140. };
  141. /**
  142. * [fromJSON](https://github.com/mourner/rbush#export-and-import)
  143. *
  144. * @param {any} json import previously exported data
  145. * @returns {RBush} GeoJSON RBush
  146. * @example
  147. * var exported = {
  148. * "children": [
  149. * {
  150. * "type": "Feature",
  151. * "geometry": {
  152. * "type": "Point",
  153. * "coordinates": [110, 50]
  154. * },
  155. * "properties": {},
  156. * "bbox": [110, 50, 110, 50]
  157. * }
  158. * ],
  159. * "height": 1,
  160. * "leaf": true,
  161. * "minX": 110,
  162. * "minY": 50,
  163. * "maxX": 110,
  164. * "maxY": 50
  165. * }
  166. * tree.fromJSON(exported)
  167. */
  168. tree.fromJSON = function (json) {
  169. return rbush.prototype.fromJSON.call(this, json);
  170. };
  171. /**
  172. * Converts GeoJSON to {minX, minY, maxX, maxY} schema
  173. *
  174. * @private
  175. * @param {BBox|FeatureCollection|Feature} geojson feature(s) to retrieve BBox from
  176. * @returns {Object} converted to {minX, minY, maxX, maxY}
  177. */
  178. tree.toBBox = function (geojson) {
  179. var bbox;
  180. if (geojson.bbox) bbox = geojson.bbox;
  181. else if (Array.isArray(geojson) && geojson.length === 4) bbox = geojson;
  182. else if (Array.isArray(geojson) && geojson.length === 6) bbox = [geojson[0], geojson[1], geojson[3], geojson[4]];
  183. else if (geojson.type === 'Feature') bbox = turfBBox(geojson);
  184. else if (geojson.type === 'FeatureCollection') bbox = turfBBox(geojson);
  185. else throw new Error('invalid geojson')
  186. return {
  187. minX: bbox[0],
  188. minY: bbox[1],
  189. maxX: bbox[2],
  190. maxY: bbox[3]
  191. };
  192. };
  193. return tree;
  194. }
  195. module.exports = geojsonRbush;
  196. module.exports.default = geojsonRbush;