STRtree.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import ItemBoundable from './ItemBoundable'
  2. import PriorityQueue from '../../util/PriorityQueue'
  3. import hasInterface from '../../../../../hasInterface'
  4. import SpatialIndex from '../SpatialIndex'
  5. import AbstractNode from './AbstractNode'
  6. import Double from '../../../../../java/lang/Double'
  7. import Collections from '../../../../../java/util/Collections'
  8. import BoundablePair from './BoundablePair'
  9. import ArrayList from '../../../../../java/util/ArrayList'
  10. import Comparator from '../../../../../java/util/Comparator'
  11. import Serializable from '../../../../../java/io/Serializable'
  12. import Envelope from '../../geom/Envelope'
  13. import Assert from '../../util/Assert'
  14. import AbstractSTRtree from './AbstractSTRtree'
  15. import ItemDistance from './ItemDistance'
  16. export default class STRtree extends AbstractSTRtree {
  17. constructor() {
  18. super()
  19. STRtree.constructor_.apply(this, arguments)
  20. }
  21. static constructor_() {
  22. if (arguments.length === 0) {
  23. STRtree.constructor_.call(this, STRtree.DEFAULT_NODE_CAPACITY)
  24. } else if (arguments.length === 1) {
  25. const nodeCapacity = arguments[0]
  26. AbstractSTRtree.constructor_.call(this, nodeCapacity)
  27. }
  28. }
  29. static centreX(e) {
  30. return STRtree.avg(e.getMinX(), e.getMaxX())
  31. }
  32. static avg(a, b) {
  33. return (a + b) / 2
  34. }
  35. static getItems(kNearestNeighbors) {
  36. const items = new Array(kNearestNeighbors.size()).fill(null)
  37. let count = 0
  38. while (!kNearestNeighbors.isEmpty()) {
  39. const bp = kNearestNeighbors.poll()
  40. items[count] = bp.getBoundable(0).getItem()
  41. count++
  42. }
  43. return items
  44. }
  45. static centreY(e) {
  46. return STRtree.avg(e.getMinY(), e.getMaxY())
  47. }
  48. createParentBoundablesFromVerticalSlices(verticalSlices, newLevel) {
  49. Assert.isTrue(verticalSlices.length > 0)
  50. const parentBoundables = new ArrayList()
  51. for (let i = 0; i < verticalSlices.length; i++)
  52. parentBoundables.addAll(this.createParentBoundablesFromVerticalSlice(verticalSlices[i], newLevel))
  53. return parentBoundables
  54. }
  55. nearestNeighbourK() {
  56. if (arguments.length === 2) {
  57. const initBndPair = arguments[0], k = arguments[1]
  58. return this.nearestNeighbourK(initBndPair, Double.POSITIVE_INFINITY, k)
  59. } else if (arguments.length === 3) {
  60. const initBndPair = arguments[0], maxDistance = arguments[1], k = arguments[2]
  61. let distanceLowerBound = maxDistance
  62. const priQ = new PriorityQueue()
  63. priQ.add(initBndPair)
  64. const kNearestNeighbors = new PriorityQueue()
  65. while (!priQ.isEmpty() && distanceLowerBound >= 0.0) {
  66. const bndPair = priQ.poll()
  67. const pairDistance = bndPair.getDistance()
  68. if (pairDistance >= distanceLowerBound)
  69. break
  70. if (bndPair.isLeaves())
  71. if (kNearestNeighbors.size() < k) {
  72. kNearestNeighbors.add(bndPair)
  73. } else {
  74. const bp1 = kNearestNeighbors.peek()
  75. if (bp1.getDistance() > pairDistance) {
  76. kNearestNeighbors.poll()
  77. kNearestNeighbors.add(bndPair)
  78. }
  79. const bp2 = kNearestNeighbors.peek()
  80. distanceLowerBound = bp2.getDistance()
  81. }
  82. else
  83. bndPair.expandToQueue(priQ, distanceLowerBound)
  84. }
  85. return STRtree.getItems(kNearestNeighbors)
  86. }
  87. }
  88. createNode(level) {
  89. return new STRtreeNode(level)
  90. }
  91. size() {
  92. if (arguments.length === 0)
  93. return super.size.call(this)
  94. else return super.size.apply(this, arguments)
  95. }
  96. insert() {
  97. if (arguments.length === 2 && (arguments[1] instanceof Object && arguments[0] instanceof Envelope)) {
  98. const itemEnv = arguments[0], item = arguments[1]
  99. if (itemEnv.isNull())
  100. return null
  101. super.insert.call(this, itemEnv, item)
  102. } else {
  103. return super.insert.apply(this, arguments)
  104. }
  105. }
  106. getIntersectsOp() {
  107. return STRtree.intersectsOp
  108. }
  109. verticalSlices(childBoundables, sliceCount) {
  110. const sliceCapacity = Math.trunc(Math.ceil(childBoundables.size() / sliceCount))
  111. const slices = new Array(sliceCount).fill(null)
  112. const i = childBoundables.iterator()
  113. for (let j = 0; j < sliceCount; j++) {
  114. slices[j] = new ArrayList()
  115. let boundablesAddedToSlice = 0
  116. while (i.hasNext() && boundablesAddedToSlice < sliceCapacity) {
  117. const childBoundable = i.next()
  118. slices[j].add(childBoundable)
  119. boundablesAddedToSlice++
  120. }
  121. }
  122. return slices
  123. }
  124. query() {
  125. if (arguments.length === 1) {
  126. const searchEnv = arguments[0]
  127. return super.query.call(this, searchEnv)
  128. } else if (arguments.length === 2) {
  129. const searchEnv = arguments[0], visitor = arguments[1]
  130. super.query.call(this, searchEnv, visitor)
  131. }
  132. }
  133. getComparator() {
  134. return STRtree.yComparator
  135. }
  136. createParentBoundablesFromVerticalSlice(childBoundables, newLevel) {
  137. return super.createParentBoundables.call(this, childBoundables, newLevel)
  138. }
  139. remove() {
  140. if (arguments.length === 2 && (arguments[1] instanceof Object && arguments[0] instanceof Envelope)) {
  141. const itemEnv = arguments[0], item = arguments[1]
  142. return super.remove.call(this, itemEnv, item)
  143. } else {
  144. return super.remove.apply(this, arguments)
  145. }
  146. }
  147. depth() {
  148. if (arguments.length === 0)
  149. return super.depth.call(this)
  150. else return super.depth.apply(this, arguments)
  151. }
  152. createParentBoundables(childBoundables, newLevel) {
  153. Assert.isTrue(!childBoundables.isEmpty())
  154. const minLeafCount = Math.trunc(Math.ceil(childBoundables.size() / this.getNodeCapacity()))
  155. const sortedChildBoundables = new ArrayList(childBoundables)
  156. Collections.sort(sortedChildBoundables, STRtree.xComparator)
  157. const verticalSlices = this.verticalSlices(sortedChildBoundables, Math.trunc(Math.ceil(Math.sqrt(minLeafCount))))
  158. return this.createParentBoundablesFromVerticalSlices(verticalSlices, newLevel)
  159. }
  160. nearestNeighbour() {
  161. if (arguments.length === 1) {
  162. if (hasInterface(arguments[0], ItemDistance)) {
  163. const itemDist = arguments[0]
  164. if (this.isEmpty()) return null
  165. const bp = new BoundablePair(this.getRoot(), this.getRoot(), itemDist)
  166. return this.nearestNeighbour(bp)
  167. } else if (arguments[0] instanceof BoundablePair) {
  168. const initBndPair = arguments[0]
  169. let distanceLowerBound = Double.POSITIVE_INFINITY
  170. let minPair = null
  171. const priQ = new PriorityQueue()
  172. priQ.add(initBndPair)
  173. while (!priQ.isEmpty() && distanceLowerBound > 0.0) {
  174. const bndPair = priQ.poll()
  175. const pairDistance = bndPair.getDistance()
  176. if (pairDistance >= distanceLowerBound) break
  177. if (bndPair.isLeaves()) {
  178. distanceLowerBound = pairDistance
  179. minPair = bndPair
  180. } else {
  181. bndPair.expandToQueue(priQ, distanceLowerBound)
  182. }
  183. }
  184. if (minPair === null) return null
  185. return [minPair.getBoundable(0).getItem(), minPair.getBoundable(1).getItem()]
  186. }
  187. } else if (arguments.length === 2) {
  188. const tree = arguments[0], itemDist = arguments[1]
  189. if (this.isEmpty() || tree.isEmpty()) return null
  190. const bp = new BoundablePair(this.getRoot(), tree.getRoot(), itemDist)
  191. return this.nearestNeighbour(bp)
  192. } else if (arguments.length === 3) {
  193. const env = arguments[0], item = arguments[1], itemDist = arguments[2]
  194. const bnd = new ItemBoundable(env, item)
  195. const bp = new BoundablePair(this.getRoot(), bnd, itemDist)
  196. return this.nearestNeighbour(bp)[0]
  197. } else if (arguments.length === 4) {
  198. const env = arguments[0], item = arguments[1], itemDist = arguments[2], k = arguments[3]
  199. const bnd = new ItemBoundable(env, item)
  200. const bp = new BoundablePair(this.getRoot(), bnd, itemDist)
  201. return this.nearestNeighbourK(bp, k)
  202. }
  203. }
  204. isWithinDistance() {
  205. if (arguments.length === 2) {
  206. const initBndPair = arguments[0], maxDistance = arguments[1]
  207. let distanceUpperBound = Double.POSITIVE_INFINITY
  208. const priQ = new PriorityQueue()
  209. priQ.add(initBndPair)
  210. while (!priQ.isEmpty()) {
  211. const bndPair = priQ.poll()
  212. const pairDistance = bndPair.getDistance()
  213. if (pairDistance > maxDistance) return false
  214. if (bndPair.maximumDistance() <= maxDistance) return true
  215. if (bndPair.isLeaves()) {
  216. distanceUpperBound = pairDistance
  217. if (distanceUpperBound <= maxDistance) return true
  218. } else {
  219. bndPair.expandToQueue(priQ, distanceUpperBound)
  220. }
  221. }
  222. return false
  223. } else if (arguments.length === 3) {
  224. const tree = arguments[0], itemDist = arguments[1], maxDistance = arguments[2]
  225. const bp = new BoundablePair(this.getRoot(), tree.getRoot(), itemDist)
  226. return this.isWithinDistance(bp, maxDistance)
  227. }
  228. }
  229. get interfaces_() {
  230. return [SpatialIndex, Serializable]
  231. }
  232. }
  233. class STRtreeNode extends AbstractNode {
  234. constructor() {
  235. super()
  236. STRtreeNode.constructor_.apply(this, arguments)
  237. }
  238. static constructor_() {
  239. const level = arguments[0]
  240. AbstractNode.constructor_.call(this, level)
  241. }
  242. computeBounds() {
  243. let bounds = null
  244. for (let i = this.getChildBoundables().iterator(); i.hasNext(); ) {
  245. const childBoundable = i.next()
  246. if (bounds === null)
  247. bounds = new Envelope(childBoundable.getBounds())
  248. else
  249. bounds.expandToInclude(childBoundable.getBounds())
  250. }
  251. return bounds
  252. }
  253. }
  254. STRtree.STRtreeNode = STRtreeNode
  255. STRtree.xComparator = new (class {
  256. get interfaces_() {
  257. return [Comparator]
  258. }
  259. compare(o1, o2) {
  260. return AbstractSTRtree.compareDoubles(STRtree.centreX(o1.getBounds()), STRtree.centreX(o2.getBounds()))
  261. }
  262. })()
  263. STRtree.yComparator = new (class {
  264. get interfaces_() {
  265. return [Comparator]
  266. }
  267. compare(o1, o2) {
  268. return AbstractSTRtree.compareDoubles(STRtree.centreY(o1.getBounds()), STRtree.centreY(o2.getBounds()))
  269. }
  270. })()
  271. STRtree.intersectsOp = new (class {
  272. get interfaces_() {
  273. return [IntersectsOp]
  274. }
  275. intersects(aBounds, bBounds) {
  276. return aBounds.intersects(bBounds)
  277. }
  278. })()
  279. STRtree.DEFAULT_NODE_CAPACITY = 10