Skip to content

2.0.0 - A Cleaner API

Choose a tag to compare

@Elan456 Elan456 released this 21 Dec 07:00
· 88 commits to main since this release

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 location

Object 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.