Repository navigation
2.0.0 - A Cleaner API
fastquadtree 2.0 Release Notes
fastquadtree 2.0 is a major release focused on API clarity, predictable behavior, and zero-overhead defaults. This release includes breaking changes that simplify the library and improve performance for all use cases.
Breaking Changes
Class Split: track_objects Removed
The track_objects parameter has been removed. Object association is now determined by which class you use.
| v1.x | v2.0 |
|---|---|
QuadTree(..., track_objects=False) |
QuadTree(...) |
QuadTree(..., track_objects=True) |
QuadTreeObjects(...) |
RectQuadTree(..., track_objects=False) |
RectQuadTree(...) |
RectQuadTree(..., track_objects=True) |
RectQuadTreeObjects(...) |
This eliminates runtime branching and keeps the fastest class as the default.
Query Return Types: as_items Removed
Return types are now fixed per class. The as_items parameter no longer exists.
# QuadTree always returns tuples
for id_, x, y in qt.query(rect):
...
# QuadTreeObjects always returns PointItem objects
for item in qt_obj.query(rect):
print(item.id_, item.x, item.y, item.obj)Explicit NumPy Methods
Runtime type detection has been removed. NumPy arrays are no longer accepted by standard methods.
# v1.x (removed)
qt.insert_many(np_array) # worked via runtime detection
# v2.0
qt.insert_many([(1, 2), (3, 4)]) # Python sequences
qt.insert_many_np(np_array) # NumPy arrays
ids, coords = qt.query_np(rect) # NumPy output
ids, coords = qt.nearest_neighbors_np(pt, k=5)Passing a NumPy array to a non-_np method now raises TypeError.
Bulk Insert Returns InsertResult
insert_many() now returns an InsertResult dataclass instead of an int.
result = qt.insert_many(points)
result.count # number inserted
result.start_id # first ID in batch
result.end_id # last ID in batch
result.ids # range(start_id, end_id + 1)Deletion Signature Changed
Non-Objects classes now take coordinates as separate arguments.
# v1.x
qt.delete(id_, (x, y))
rqt.delete(id_, (min_x, min_y, max_x, max_y))
# v2.0
qt.delete(id_, x, y)
rqt.delete(id_, min_x, min_y, max_x, max_y)Objects classes can delete by ID alone since they track coordinates internally.
Serialization Format Changed
The serialization format has been updated. v1 serialized data is not compatible with v2.
# v1.x (removed)
state = qt.to_dict()
qt2 = QuadTree.from_dict(state)
qt2 = QuadTree.from_bytes(data, dtype="f32")
# v2.0
data = qt.to_bytes() # dtype encoded in payload
qt2 = QuadTree.from_bytes(data)Object serialization is now explicit and opt-in for safety:
data = qt_obj.to_bytes(include_objects=True)
qt2 = QuadTreeObjects.from_bytes(data, allow_objects=True)count_items() Removed
Use the standard len() function instead:
n = len(qt)New Features
Custom IDs for Non-Objects Classes
Single inserts now support user-provided IDs for correlating with external data structures.
qt.insert((10, 20), id_=42)
qt.insert((30, 40), id_=1000)Note: The quadtree does not validate ID uniqueness. Users are responsible for avoiding collisions.
__contains__ Support
if (10.0, 20.0) in qt:
print("Point exists")Iteration
for id_, x, y in qt:
...
for item in qt_obj:
print(item.id_, item.x, item.y, item.obj)query_ids() for Objects Classes
Fast path when you only need IDs from an Objects tree:
ids = qt_obj.query_ids(rect) # list[int]update_by_object() for Objects Classes
Update an item's position by finding it via its associated object:
qt_obj.update_by_object(obj, new_x, new_y)
rqt_obj.update_by_object(obj, new_min_x, new_min_y, new_max_x, new_max_y)Location-Based Deletion for Objects Classes
qt_obj.delete_at(x, y) # deletes lowest-ID match at locationObject Deletion by Identity
qt_obj.delete_by_object(obj) # deletes all matches, returns count
qt_obj.delete_one_by_object(obj) # deletes one match (lowest ID)Migration Summary
| Find | Replace |
|---|---|
QuadTree(..., track_objects=True) |
QuadTreeObjects(...) |
RectQuadTree(..., track_objects=True) |
RectQuadTreeObjects(...) |
, track_objects=False |
(remove) |
, as_items=True |
(remove, use Objects class) |
.insert_many(np_array) |
.insert_many_np(np_array) |
.delete(id_, (x, y)) |
.delete(id_, x, y) |
.count_items() |
len(...) |
See the full Migration Guide for detailed upgrade instructions.