Based on javascript implementation by Patrick DeHaan: github.com/pdehn/jsQuad
Python 2.6+ should work
Demo GUI app is included, to set it up for the first time do:
python bootstrap.py
bin/buildout -c buildout-demo.cfg
bin/develop activate hsmpy
bin/buildout -c buildout-demo.cfg # makes buildout aware of hsmpy
Then you can run it using:
bin/mypy_demo -m demo.demo
Note: demo app has dependency on Tkinter for GUI. If you get
Tkinter-related ImportError try installing python-tk
package on your system.
If you get hsmpy-related error either you didn't activate the hsmpy package using commands above or I've broken compatibility and didn't update demo app.
-
dropped requirements for contained objects to implement
QTenclosed
,QToverlaps
,QTquadrantNode
, those checks are now performed by quadtree - that is enough for coarse querying, exact hit testing is left to the user -
changed requirement for
QTsetParent
andQTgetParent
, see next point -
contained objects are required to expose these two properties (must be able to set their values):
bounds
- 4-tuple specifying sides (left_x, top_y, right_x, bottom_y)qt_data
- will be set by quadpy upon inserting
-
method names converted from camelCase to underscore_format
-
quadrants are placed in different order: TL, TR, BL, BR
-
subdivide
is a method of Node -
original code had following bugs:
- removing would cause infinite loop (jsQuad.js line 120:
.remove
should be._remove
) - removing last element from node didn't remove the node (nor its parents)
- removing would cause infinite loop (jsQuad.js line 120:
-
added method
get_children_under_point
(works by calling get_overlapped_children with zero-dimensions rectangle) -
removed methods:
selectChildren
(useget_children
)selectEnclosed
(useget_enclosed_children
)selectOverlapping
(useget_overlapped_children
)mapChildren
mapEnclosed
mapOverlapping
applyChildren
applyEnclosed
applyOverlapping
Note that although this implementation is currently MX-CIF as the one it's based on, that might change in the future if need be.
original readme below
Author: Patrick DeHaan [email protected]
Brief: MX-CIF Quadtrees implementation in javascript.
MX-CIF quadtrees store region bounded objects in the smallest sub-node that fully encloses them. Nodes may have any number of children and may or may not have four quadrant sub-nodes. The current implementation does not support placing a given object into a multiple trees simultaneously.
This form of quadtree is useful for storing objects with 2d spatial dimensions while providing efficient methods of searching for objects with given spatial properties (overlapping regions, enclosed by regions, enclosing regions, etc.)
Note that it is also perfectly reasonable to store point objects as well, just pretend it's boundaries are the same.
For flexability, this implementation defers certain logic to the contained objects, thus requiring that they provide the following methods:
.QTenclosed(xMin, yMin, xMax, yMax) -> boolean
return true if the object fits entirely within the boundary given.
.QToverlaps(xMin, yMin, xMax, yMax) -> boolean
return true if the object overlaps the boundary given.
.QTquadrantNode(root, x, y) -> number
return null if the object overlaps x or y. If not, return root.q1, root.q2, root.q3, or root.q4, corresponding to the relative quadrant the object is a part of. Quadrant numbers start to the upper left and go counter-clockwise.
.QTsetParent(parent) -> void
store the given parent node somewhere it can be recalled. Previous values may be overwritten (it's not a stack).
.QTgetParent() -> node
return the previously stored parent node.
No access to the objects will occur except through these methods. This enables object boundary definitions to be handled in whatever manner is most suitable for that type. Note that if objects are moved they should call the quadtree's .reinsert(child) method in order to rebuild the tree.
var tree = new Quadtree(xMin, yMin, xMax, yMax, maxDepth);
[xMin], [yMin], [xMax], and [yMax] define the boundaries of the quadtree.
[maxDepth] defines the maximum number of times to subdivide the tree nodes. A value of 0 indicates no subdivisions.
tree.insert(object);
[object] is expected to implement the methods detailed below in order for the quadtree to manage it correctly.
tree.reinsert(child)
[child] is removed from the tree and re-inserted. This method should be used for any object whose boundaries have changed. While the end result is the same, this can be faster than using tree.remove(child) and tree.insert(child). It achieves this by determining how far the child has moved from it's parent. If that value is sufficiently small, fewer insertion recursions are required.
tree.remove(child)
[child] is removed from the tree.
tree.getChildren()
returns all objects in the tree
tree.getEnclosed(xMin, yMin, xMax, yMax)
returns all objects that are entirely enclosed by the given boundary.
tree.getOverlapping(xMin, yMin, xMax, yMax)
return all objects that are overlapping the given boundary.
These methods work like the retrieval methods, but the returned list contains the result of executing [callback] with each object instead of the objects.
tree.map(callback)
tree.mapEnclosed(xMin, yMin, xMax, yMax, callback)
tree.mapOverlapping(xMin, yMin, xMax, yMax, callback)
These functions are nearly identical to the mapping functions, but do not return the results.
tree.apply()
thee.applyEnclosed(...)
tree.applyOverlapping(...)
tree.clear()
This empties the tree (all children and sub-nodes are removed).