API Docs for:
Show:

File: src/lib/interval-tree.coffee

  1.  
  2. SortedList = require './sorted-list'
  3. Node = require './node'
  4. Point = require './point'
  5. Interval = require './interval'
  6. Util = require './util'
  7.  
  8.  
  9. ###*
  10. interval tree
  11.  
  12. @class IntervalTree
  13. @module interval-tree2
  14. ###
  15. class IntervalTree
  16.  
  17.  
  18. ###*
  19. @constructor
  20. @param {Number} center center of the root node
  21. ###
  22. constructor: (center) ->
  23.  
  24. Util.assertNumber center, 'IntervalTree: center'
  25.  
  26. ###*
  27. center => node
  28.  
  29. @property {Object(Node)} nodesByCenter
  30. ###
  31. @nodesByCenter = {}
  32.  
  33.  
  34. ###*
  35. root node
  36.  
  37. @property {Node} root
  38. ###
  39. @root = @createNode(center)
  40.  
  41.  
  42. ###*
  43. interval id => interval
  44.  
  45. @property {Object(Interval)} intervalsById
  46. ###
  47. @intervalsById = {}
  48.  
  49.  
  50. ###*
  51. interval id => node
  52.  
  53. @property {Object(Node)} nodesById
  54. ###
  55. @nodesById = {}
  56.  
  57.  
  58. ###*
  59. sorted list of whole point
  60.  
  61. @property {SortedList(Point)} pointTree
  62. ###
  63. @pointTree = new SortedList('val')
  64.  
  65.  
  66. ###*
  67. unique id candidate of interval without id to be added next time
  68.  
  69. @property {Number} idCandidate
  70. ###
  71. @idCandidate = 0
  72.  
  73.  
  74.  
  75. ###*
  76. add one interval
  77.  
  78. @method add
  79. @public
  80. @param {Number} start start of the interval to create
  81. @param {Number} end end of the interval to create
  82. @param {String|Number} [id] identifier to distinguish intervals. Automatically defiend when not set.
  83. @return {Interval}
  84. ###
  85. add: (start, end, id) ->
  86.  
  87. if @intervalsById[id]?
  88. throw new Error('id ' + id + ' is already registered.')
  89.  
  90. if not id?
  91. while @intervalsById[@idCandidate]?
  92. @idCandidate++
  93. id = @idCandidate
  94.  
  95.  
  96. Util.assertNumber(start, '1st argument of IntervalTree#add()')
  97. Util.assertNumber(end, '2nd argument of IntervalTree#add()')
  98.  
  99. if start >= end
  100. Util.assertOrder(start, end, 'start', 'end')
  101.  
  102.  
  103. interval = new Interval(start, end, id)
  104.  
  105. @pointTree.insert new Point(interval.start, id)
  106. @pointTree.insert new Point(interval.end, id)
  107.  
  108. @intervalsById[id] = interval
  109.  
  110. return @insert interval, @root
  111.  
  112.  
  113. ###*
  114. search intervals
  115. when only one argument is given, return intervals which contains the value
  116. when two arguments are given, ...
  117.  
  118. @method search
  119. @public
  120. @param {Number} val1
  121. @param {Number} val2
  122. @return {Array(Interval)} intervals
  123. ###
  124. search: (val1, val2) ->
  125.  
  126. Util.assertNumber val1, '1st argument at IntervalTree#search()'
  127.  
  128. if not val2?
  129.  
  130. return @pointSearch val1
  131.  
  132. else
  133.  
  134. Util.assertNumber val2, '2nd argument at IntervalTree#search()'
  135. Util.assertOrder val1, val2, '1st argument', '2nd argument', 'IntervalTree#search()'
  136.  
  137. return @rangeSearch val1, val2
  138.  
  139.  
  140. ###*
  141. removes an interval of the given id
  142.  
  143. @method remove
  144. @public
  145. @param {Number|String} id id of the interval to remove
  146. ###
  147. remove: (id) ->
  148.  
  149. interval = @intervalsById[id]
  150.  
  151. return if not interval?
  152.  
  153. node = @nodesById[id]
  154.  
  155. node.remove(interval)
  156.  
  157. delete @nodesById[id]
  158. delete @intervalsById[id]
  159.  
  160.  
  161.  
  162. ###*
  163. search intervals at the given node
  164.  
  165. @method pointSearch
  166. @public
  167. @param {Number} val
  168. @param {Node} [node] current node to search. default is this.root
  169. @return {Array(Interval)}
  170. ###
  171. pointSearch: (val, node = @root, results = []) ->
  172.  
  173. Util.assertNumber(val, '1st argument of IntervalTree#pointSearch()')
  174.  
  175. if val < node.center
  176.  
  177. results = results.concat node.startPointSearch(val)
  178.  
  179. if node.left?
  180. return @pointSearch(val, node.left, results)
  181.  
  182. else
  183. return results
  184.  
  185.  
  186. if val > node.center
  187.  
  188. results = results.concat node.endPointSearch(val)
  189.  
  190. if node.right?
  191. return @pointSearch(val, node.right, results)
  192.  
  193. else
  194. return results
  195.  
  196. # if val is node.center
  197. return results.concat node.getAllIntervals()
  198.  
  199.  
  200. ###*
  201. returns intervals which covers the given start-end interval
  202.  
  203. @method rangeSearch
  204. @public
  205. @param {Number} start start of the interval
  206. @param {Number} end end of the interval
  207. @return {Array(Interval)}
  208. ###
  209. rangeSearch: (start, end) ->
  210.  
  211. Util.assertNumber start, '1st argument at IntervalTree#rangeSearch()'
  212. Util.assertNumber end, '2nd argument at IntervalTree#rangeSearch()'
  213. Util.assertOrder start, end, '1st argument', '2nd argument', 'IntervalTree#rangeSearch()'
  214.  
  215. resultsById = {}
  216.  
  217. # 1. pointSearch to arbitrary point between start and end (here: point = start)
  218. for interval in @pointSearch(start)
  219. resultsById[interval.id] = interval
  220.  
  221. # 2. add intervals whose either point is included in the given range
  222. firstPos = @pointTree.firstPositionOf new Point(start)
  223. lastPos = @pointTree.lastPositionOf new Point(end)
  224.  
  225. for point in @pointTree.slice(firstPos, lastPos + 1)
  226.  
  227. resultsById[point.id] = @intervalsById[point.id]
  228.  
  229. return (interval for id, interval of resultsById)
  230.  
  231.  
  232.  
  233. ###*
  234. insert interval to the given node
  235.  
  236. @method insert
  237. @private
  238. @param {Interval} interval
  239. @param {Node} node node to insert the interval
  240. @return {Interval} inserted interval
  241. ###
  242. insert: (interval, node) ->
  243.  
  244. if interval.end < node.center
  245.  
  246. node.left ?= @createNode(interval.end)
  247.  
  248. return @insert(interval, node.left)
  249.  
  250. if node.center < interval.start
  251.  
  252. node.right ?= @createNode(interval.start)
  253.  
  254. return @insert(interval, node.right)
  255.  
  256. node.insert interval
  257.  
  258. @nodesById[interval.id] = node
  259.  
  260. return interval
  261.  
  262.  
  263.  
  264. ###*
  265. create node by center
  266.  
  267. @method createNode
  268. @private
  269. @param {Number} center
  270. @return {Node} node
  271. ###
  272. createNode: (center) ->
  273.  
  274. node = new Node(center)
  275.  
  276. @nodesByCenter[center] = node
  277.  
  278. return node
  279.  
  280.  
  281. module.exports = IntervalTree
  282.