fastquadtree 2.3.0__tar.gz → 2.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.github/workflows/docs.yml +3 -3
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.github/workflows/release.yml +57 -12
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.github/workflows/test.yml +4 -4
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.gitignore +4 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.pre-commit-config.yaml +1 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/Cargo.lock +1 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/Cargo.toml +1 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/PKG-INFO +4 -4
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/README.md +3 -3
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/benchmark_np_vs_list.py +6 -6
- fastquadtree-2.4.1/docs/api/pygame.md +8 -0
- fastquadtree-2.4.1/docs/engine_defaults.md +73 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/index.md +2 -2
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/quickstart.md +14 -7
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/runnables.md +2 -2
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/mkdocs.yml +1 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pyproject.toml +1 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_base_quadtree.py +2 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_base_quadtree_objects.py +2 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/point_quadtree.py +2 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/point_quadtree_objects.py +2 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/pygame.py +138 -73
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/rect_quadtree.py +2 -1
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/rect_quadtree_objects.py +2 -1
- fastquadtree-2.4.1/scripts/build_pyodide_wheel.sh +49 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_pygame_integration.py +59 -26
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_core.py +3 -3
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_core.py +3 -3
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/test_pyqtree_shim_compat.py +3 -3
- fastquadtree-2.3.0/docs/api/pygame.md +0 -27
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/LICENSE +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/ballpit.png +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/interactive_v2_rect_screenshot.png +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/interactive_v2_screenshot.png +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/pygame_sprites_demo.png +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/quadtree_bench_throughput.png +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/quadtree_bench_time.png +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/benchmark_native_vs_shim.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/benchmark_serialization_vs_rebuild.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/cross_library_bench.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/__init__.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/engines.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/main.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/optimizer.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/plotting.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/runner.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/runner.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/system_info_collector.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/2.0_migration_guide.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/2.0_proposal.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/insert_result.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/item.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/point_item.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/pyqtree.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/quadtree.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/quadtree_objects.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/rect_item.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/rect_quadtree.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/rect_quadtree_objects.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/benchmark.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/future_features.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/rust_usage.md +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/styles/overrides.css +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/examples/custom_id_example.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/examples/object_tracking_example.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/ballpit.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/interactive.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/interactive_v2.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/interactive_v2_rect.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/pygame_sprites.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pyrightconfig.json +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/__init__.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_common.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_insert_result.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_item.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_obj_store.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/py.typed +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/pyqtree.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/geom.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/lib.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/quadtree.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/rect_quadtree.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/serialization.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/__init__.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/insertions.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/nearest_neighbor.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/query.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/rect_quadtree.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/rectangle_traversal.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/serialization.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_delete.rs +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/__init__.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_common_validation.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_insert_result_and_items.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_internal_edges.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_obj_store.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_serialization_container.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/conftest.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_migration_breaks_and_safety.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_optional_pygame_dependency.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_public_api_contracts.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_core.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_mutation.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_numpy.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_precision.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_serialization.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_core.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_deletion_update.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_numpy.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_serialization.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_mutation.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_numpy.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_serialization.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_deletion_update.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_numpy.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_serialization.py +0 -0
- {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/unconventional_bounds.rs +0 -0
|
@@ -13,14 +13,14 @@ jobs:
|
|
|
13
13
|
build:
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
17
|
with:
|
|
18
18
|
fetch-depth: 0
|
|
19
19
|
fetch-tags: true
|
|
20
|
-
- uses: actions/setup-python@
|
|
20
|
+
- uses: actions/setup-python@v6
|
|
21
21
|
with: { python-version: '3.11' }
|
|
22
22
|
- name: Install uv
|
|
23
|
-
uses: astral-sh/setup-uv@
|
|
23
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
24
24
|
with:
|
|
25
25
|
enable-cache: true
|
|
26
26
|
- run: uv sync --group dev --group docs
|
|
@@ -12,15 +12,15 @@ jobs:
|
|
|
12
12
|
name: Test build
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
16
|
|
|
17
17
|
- name: Set up Python
|
|
18
|
-
uses: actions/setup-python@
|
|
18
|
+
uses: actions/setup-python@v6
|
|
19
19
|
with:
|
|
20
20
|
python-version: "3.9"
|
|
21
21
|
|
|
22
22
|
- name: Install uv
|
|
23
|
-
uses: astral-sh/setup-uv@
|
|
23
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
24
24
|
with:
|
|
25
25
|
enable-cache: true
|
|
26
26
|
|
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
run: cargo test
|
|
46
46
|
|
|
47
47
|
- name: Upload coverage to Codecov
|
|
48
|
-
uses: codecov/codecov-action@
|
|
48
|
+
uses: codecov/codecov-action@v6
|
|
49
49
|
with:
|
|
50
50
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
51
51
|
|
|
@@ -78,42 +78,87 @@ jobs:
|
|
|
78
78
|
manylinux: "2_28"
|
|
79
79
|
|
|
80
80
|
steps:
|
|
81
|
-
- uses: actions/checkout@
|
|
81
|
+
- uses: actions/checkout@v6
|
|
82
82
|
|
|
83
83
|
# Keep Python simple here; maturin-action brings its own Python(s) for builds.
|
|
84
84
|
- name: Set up Python
|
|
85
|
-
uses: actions/setup-python@
|
|
85
|
+
uses: actions/setup-python@v6
|
|
86
86
|
with:
|
|
87
87
|
python-version: "3.9"
|
|
88
88
|
|
|
89
89
|
- name: Build wheels with maturin
|
|
90
|
-
uses: PyO3/maturin-action@v1
|
|
90
|
+
uses: PyO3/maturin-action@v1.51.0
|
|
91
91
|
with:
|
|
92
92
|
command: build
|
|
93
93
|
args: ${{ matrix.maturin_args }}
|
|
94
94
|
manylinux: ${{ matrix.manylinux }}
|
|
95
95
|
|
|
96
96
|
- name: Upload dist artifacts
|
|
97
|
-
uses: actions/upload-artifact@
|
|
97
|
+
uses: actions/upload-artifact@v7
|
|
98
98
|
with:
|
|
99
99
|
name: dist-${{ runner.os }}-${{ matrix.maturin_args }}
|
|
100
100
|
path: dist/*
|
|
101
101
|
|
|
102
|
+
build_pyodide:
|
|
103
|
+
name: Build Pyodide wheel
|
|
104
|
+
needs: test
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
steps:
|
|
107
|
+
- uses: actions/checkout@v6
|
|
108
|
+
|
|
109
|
+
- name: Set up Python
|
|
110
|
+
uses: actions/setup-python@v6
|
|
111
|
+
with:
|
|
112
|
+
python-version: "3.13"
|
|
113
|
+
|
|
114
|
+
- name: Set up Node
|
|
115
|
+
uses: actions/setup-node@v4
|
|
116
|
+
with:
|
|
117
|
+
node-version: "24"
|
|
118
|
+
|
|
119
|
+
- name: Install uv
|
|
120
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
121
|
+
with:
|
|
122
|
+
enable-cache: true
|
|
123
|
+
|
|
124
|
+
- name: Install pyodide CLI
|
|
125
|
+
run: uv tool install pyodide-cli --with pyodide-build
|
|
126
|
+
|
|
127
|
+
- name: Cache Pyodide cross-build environment
|
|
128
|
+
uses: actions/cache@v4
|
|
129
|
+
with:
|
|
130
|
+
path: ~/.cache/fastquadtree-pyodide
|
|
131
|
+
key: pyodide-xbuildenv-${{ runner.os }}-20260401-1.93.0
|
|
132
|
+
|
|
133
|
+
- name: Build Pyodide wheel
|
|
134
|
+
env:
|
|
135
|
+
PYODIDE_XBUILDENV_ROOT: ~/.cache/fastquadtree-pyodide
|
|
136
|
+
PYODIDE_ENV_VERSION: "20260401"
|
|
137
|
+
RUST_TOOLCHAIN: "1.93.0"
|
|
138
|
+
UV_CACHE_DIR: ~/.cache/uv
|
|
139
|
+
run: bash scripts/build_pyodide_wheel.sh
|
|
140
|
+
|
|
141
|
+
- name: Upload Pyodide dist artifact
|
|
142
|
+
uses: actions/upload-artifact@v7
|
|
143
|
+
with:
|
|
144
|
+
name: dist-pyodide
|
|
145
|
+
path: dist/*pyemscripten*_wasm32.whl
|
|
146
|
+
|
|
102
147
|
publish:
|
|
103
148
|
name: Publish distributions to PyPI
|
|
104
|
-
needs: build
|
|
149
|
+
needs: [build, build_pyodide]
|
|
105
150
|
runs-on: ubuntu-latest
|
|
106
151
|
permissions:
|
|
107
152
|
contents: read
|
|
108
153
|
id-token: write # for Trusted Publisher (recommended)
|
|
109
154
|
steps:
|
|
110
|
-
- uses: actions/checkout@
|
|
155
|
+
- uses: actions/checkout@v6
|
|
111
156
|
|
|
112
157
|
- name: Install uv
|
|
113
|
-
uses: astral-sh/setup-uv@
|
|
158
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
114
159
|
|
|
115
160
|
- name: Download all dist artifacts
|
|
116
|
-
uses: actions/download-artifact@
|
|
161
|
+
uses: actions/download-artifact@v8
|
|
117
162
|
with:
|
|
118
163
|
pattern: dist-*
|
|
119
164
|
path: dist
|
|
@@ -13,16 +13,16 @@ jobs:
|
|
|
13
13
|
python-version: ["3.9", "3.14"]
|
|
14
14
|
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
17
|
|
|
18
18
|
- name: Set up Python ${{ matrix.python-version }}
|
|
19
|
-
uses: actions/setup-python@
|
|
19
|
+
uses: actions/setup-python@v6
|
|
20
20
|
with:
|
|
21
21
|
python-version: ${{ matrix.python-version }}
|
|
22
22
|
allow-prereleases: true
|
|
23
23
|
|
|
24
24
|
- name: Install uv
|
|
25
|
-
uses: astral-sh/setup-uv@
|
|
25
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
26
26
|
with:
|
|
27
27
|
enable-cache: true
|
|
28
28
|
|
|
@@ -49,6 +49,6 @@ jobs:
|
|
|
49
49
|
run: cargo test
|
|
50
50
|
|
|
51
51
|
- name: Upload coverage to Codecov
|
|
52
|
-
uses: codecov/codecov-action@
|
|
52
|
+
uses: codecov/codecov-action@v6
|
|
53
53
|
with:
|
|
54
54
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastquadtree
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.1
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -62,7 +62,7 @@ Rust-optimized quadtree with a clean Python API
|
|
|
62
62
|
- Support for [inserting bounding boxes](https://elan456.github.io/fastquadtree/api/rect_quadtree/) or points
|
|
63
63
|
- Fast KNN and range queries
|
|
64
64
|
- Optional object tracking for id ↔ object mapping
|
|
65
|
-
- Mostly drop-in [pygame sprite-group integration](https://elan456.github.io/fastquadtree/api/pygame/) that adds automatic broadphase culling
|
|
65
|
+
- Mostly drop-in [pygame sprite-group integration](https://elan456.github.io/fastquadtree/api/pygame/) that adds automatic broadphase culling plus rect queries and k-NN over sprite rects
|
|
66
66
|
- Fast [serialization](https://elan456.github.io/fastquadtree/benchmark/#serialization-vs-rebuild) to/from bytes
|
|
67
67
|
- Support for multiple data types (f32, f64, i32, i64) for coordinates
|
|
68
68
|
- [100% test coverage](https://codecov.io/gh/Elan456/fastquadtree) and CI on GitHub Actions
|
|
@@ -89,7 +89,7 @@ from fastquadtree.pyqtree import Index # Drop-in pyqtree shim (~10x faster whil
|
|
|
89
89
|
| `QuadTreeObjects` | Points | Yes | Point indexing with attached Python objects. |
|
|
90
90
|
| `RectQuadTreeObjects` | Bounding boxes | Yes | Rectangle indexing with attached objects. |
|
|
91
91
|
| `fastquadtree.pyqtree.Index` | Bounding boxes | Yes | pyqtree-compatible API, much faster. |
|
|
92
|
-
| `fastquadtree.pygame.Group` | pygame sprites | Yes | Mostly drop-in
|
|
92
|
+
| `fastquadtree.pygame.Group` | pygame sprites | Yes | Mostly drop-in `Group` with sprite queries. |
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
## Quickstart
|
|
@@ -173,7 +173,7 @@ See the [benchmark section](https://elan456.github.io/fastquadtree/benchmark/) f
|
|
|
173
173
|
|
|
174
174
|
* `bounds` — tuple `(min_x, min_y, max_x, max_y)` defines the 2D area covered by the quadtree
|
|
175
175
|
* `capacity` — max number of points kept in a leaf before splitting
|
|
176
|
-
* `max_depth` — optional depth cap. If omitted, the
|
|
176
|
+
* `max_depth` — optional depth cap. If omitted, uses the [engine default](https://elan456.github.io/fastquadtree/engine_defaults/#max-depth)
|
|
177
177
|
* `dtype` — data type for coordinates, e.g., `"f32"`, `"f64"`, `"i32"`, `"i64"`
|
|
178
178
|
|
|
179
179
|
### Key Methods
|
|
@@ -32,7 +32,7 @@ Rust-optimized quadtree with a clean Python API
|
|
|
32
32
|
- Support for [inserting bounding boxes](https://elan456.github.io/fastquadtree/api/rect_quadtree/) or points
|
|
33
33
|
- Fast KNN and range queries
|
|
34
34
|
- Optional object tracking for id ↔ object mapping
|
|
35
|
-
- Mostly drop-in [pygame sprite-group integration](https://elan456.github.io/fastquadtree/api/pygame/) that adds automatic broadphase culling
|
|
35
|
+
- Mostly drop-in [pygame sprite-group integration](https://elan456.github.io/fastquadtree/api/pygame/) that adds automatic broadphase culling plus rect queries and k-NN over sprite rects
|
|
36
36
|
- Fast [serialization](https://elan456.github.io/fastquadtree/benchmark/#serialization-vs-rebuild) to/from bytes
|
|
37
37
|
- Support for multiple data types (f32, f64, i32, i64) for coordinates
|
|
38
38
|
- [100% test coverage](https://codecov.io/gh/Elan456/fastquadtree) and CI on GitHub Actions
|
|
@@ -59,7 +59,7 @@ from fastquadtree.pyqtree import Index # Drop-in pyqtree shim (~10x faster whil
|
|
|
59
59
|
| `QuadTreeObjects` | Points | Yes | Point indexing with attached Python objects. |
|
|
60
60
|
| `RectQuadTreeObjects` | Bounding boxes | Yes | Rectangle indexing with attached objects. |
|
|
61
61
|
| `fastquadtree.pyqtree.Index` | Bounding boxes | Yes | pyqtree-compatible API, much faster. |
|
|
62
|
-
| `fastquadtree.pygame.Group` | pygame sprites | Yes | Mostly drop-in
|
|
62
|
+
| `fastquadtree.pygame.Group` | pygame sprites | Yes | Mostly drop-in `Group` with sprite queries. |
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
## Quickstart
|
|
@@ -143,7 +143,7 @@ See the [benchmark section](https://elan456.github.io/fastquadtree/benchmark/) f
|
|
|
143
143
|
|
|
144
144
|
* `bounds` — tuple `(min_x, min_y, max_x, max_y)` defines the 2D area covered by the quadtree
|
|
145
145
|
* `capacity` — max number of points kept in a leaf before splitting
|
|
146
|
-
* `max_depth` — optional depth cap. If omitted, the
|
|
146
|
+
* `max_depth` — optional depth cap. If omitted, uses the [engine default](https://elan456.github.io/fastquadtree/engine_defaults/#max-depth)
|
|
147
147
|
* `dtype` — data type for coordinates, e.g., `"f32"`, `"f64"`, `"i32"`, `"i64"`
|
|
148
148
|
|
|
149
149
|
### Key Methods
|
|
@@ -38,9 +38,9 @@ def _build_tree_np(points_np: np.ndarray) -> float:
|
|
|
38
38
|
# Direct NumPy path
|
|
39
39
|
inserted = qt.insert_many_np(points_np)
|
|
40
40
|
dt = now() - t0
|
|
41
|
-
assert (
|
|
42
|
-
inserted
|
|
43
|
-
)
|
|
41
|
+
assert inserted.count == points_np.shape[0], (
|
|
42
|
+
f"Inserted {inserted} != {points_np.shape[0]}"
|
|
43
|
+
)
|
|
44
44
|
return dt
|
|
45
45
|
|
|
46
46
|
|
|
@@ -49,9 +49,9 @@ def _build_tree_list(points_list: list[tuple[float, float]]) -> float:
|
|
|
49
49
|
qt = ShimQuadTree(BOUNDS, CAPACITY, max_depth=MAX_DEPTH)
|
|
50
50
|
inserted = qt.insert_many(points_list)
|
|
51
51
|
dt = now() - t0
|
|
52
|
-
assert inserted.count == len(
|
|
53
|
-
points_list
|
|
54
|
-
)
|
|
52
|
+
assert inserted.count == len(points_list), (
|
|
53
|
+
f"Inserted {inserted} != {len(points_list)}"
|
|
54
|
+
)
|
|
55
55
|
return dt
|
|
56
56
|
|
|
57
57
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# fastquadtree.pygame
|
|
2
|
+
|
|
3
|
+
!!! note "Optional dependency"
|
|
4
|
+
Core `fastquadtree` APIs do not require pygame. This page documents the
|
|
5
|
+
optional `fastquadtree.pygame` integration, which requires pygame or a
|
|
6
|
+
compatible package such as `pygame-ce` when imported at runtime.
|
|
7
|
+
|
|
8
|
+
::: fastquadtree.pygame
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Engine Defaults
|
|
2
|
+
|
|
3
|
+
## max_depth {#max-depth}
|
|
4
|
+
|
|
5
|
+
When `max_depth=None`, the native Python APIs use a dtype-specific engine
|
|
6
|
+
default. These defaults apply to `QuadTree`, `RectQuadTree`,
|
|
7
|
+
`QuadTreeObjects`, `RectQuadTreeObjects`, and the `fastquadtree.pygame`
|
|
8
|
+
integration when `max_depth` is omitted.
|
|
9
|
+
|
|
10
|
+
| dtype | Engine default `max_depth` |
|
|
11
|
+
|---|---:|
|
|
12
|
+
| `f32` | 24 |
|
|
13
|
+
| `f64` | 53 |
|
|
14
|
+
| `i32` | 32 |
|
|
15
|
+
| `i64` | 64 |
|
|
16
|
+
|
|
17
|
+
Use `get_inner_max_depth()` on a constructed tree to inspect the resolved
|
|
18
|
+
engine value.
|
|
19
|
+
|
|
20
|
+
### Why These Values?
|
|
21
|
+
|
|
22
|
+
Infinite subdivision was the default behavior prior to version 1.4.3. With
|
|
23
|
+
infinite subdivision, inserting two points at the same location could keep
|
|
24
|
+
splitting forever and eventually exhaust memory, as seen in
|
|
25
|
+
[issue #10](https://github.com/Elan456/fastquadtree/issues/10). The engine
|
|
26
|
+
default now caps subdivision before it can become unbounded.
|
|
27
|
+
|
|
28
|
+
One alternative would be for the engine to check for duplicate coordinates
|
|
29
|
+
before splitting. However, doing so would add work to each insert and make
|
|
30
|
+
splitting behavior harder to define for cells that contain a mixture of
|
|
31
|
+
duplicate and nearby non-duplicate points. Letting duplicated points create a
|
|
32
|
+
depth of 24 or 53 in some parts of the tree can also hurt traversal time, so the
|
|
33
|
+
default is a compromise rather than a perfect answer for every workload.
|
|
34
|
+
|
|
35
|
+
The default caps are based on a practical starting point for each dtype. Each
|
|
36
|
+
quadtree level halves a node's width and height:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
cell_width_at_depth_d = world_width / 2^d
|
|
40
|
+
cell_height_at_depth_d = world_height / 2^d
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The chosen defaults are roughly aligned with the binary precision available for
|
|
44
|
+
each coordinate type:
|
|
45
|
+
|
|
46
|
+
- `f32` uses 24 because single-precision floats have about 24 bits of
|
|
47
|
+
significand precision.
|
|
48
|
+
- `f64` uses 53 because double-precision floats have about 53 bits of
|
|
49
|
+
significand precision.
|
|
50
|
+
- `i32` uses 32 and `i64` uses 64 because integer coordinates cannot provide
|
|
51
|
+
more distinct binary subdivision steps than their bit width.
|
|
52
|
+
|
|
53
|
+
These values are safety defaults, not hard limits on useful subdivision. World
|
|
54
|
+
size and data distribution still matter. For example, with `f32` and a world
|
|
55
|
+
width of `1_000_000_000`, depth 24 still leaves cells about 60 units wide:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
1_000_000_000 / 2^24 ~= 59.6
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If most of your points are clustered near the origin and you need to separate
|
|
62
|
+
features smaller than that, more than 24 splits can still be meaningful. In that
|
|
63
|
+
case, pass an explicit `max_depth` larger than the engine default.
|
|
64
|
+
|
|
65
|
+
For `i32` and `i64`, there is generally no situation where you would need more
|
|
66
|
+
than 32 and 64 subdivisions, respectively.
|
|
67
|
+
|
|
68
|
+
The defaults are intended to be a relatively safe starting point. Use tighter
|
|
69
|
+
world bounds, coordinate normalization, or an explicit `max_depth` when your
|
|
70
|
+
world is very large compared with the area where points actually cluster.
|
|
71
|
+
|
|
72
|
+
For best performance, choose a `max_depth` that keeps leaf cells near the scale
|
|
73
|
+
of your typical queries and data spacing.
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
- Support for [inserting bounding boxes](api/rect_quadtree.md) or points
|
|
42
42
|
- Fast KNN and range queries
|
|
43
43
|
- Optional object tracking for id ↔ object mapping
|
|
44
|
-
- Mostly drop-in [pygame sprite-group integration](api/pygame.md) that adds automatic broadphase culling
|
|
44
|
+
- Mostly drop-in [pygame sprite-group integration](api/pygame.md) that adds automatic broadphase culling plus rect queries and k-NN over sprite rects
|
|
45
45
|
- Fast [serialization](benchmark.md#serialization-vs-rebuild) to/from bytes
|
|
46
46
|
- Support for multiple data types (f32, f64, i32, i64) for coordinates
|
|
47
47
|
- [100% test coverage](https://codecov.io/gh/Elan456/fastquadtree) and CI on GitHub Actions
|
|
@@ -63,5 +63,5 @@ from fastquadtree import RectQuadTree # Bounding box handling
|
|
|
63
63
|
from fastquadtree import QuadTreeObjects # Point handling with object tracking
|
|
64
64
|
from fastquadtree import RectQuadTreeObjects # Bounding box handling with object tracking
|
|
65
65
|
from fastquadtree.pyqtree import Index # Drop-in replacement for pyqtree (~10x faster while keeping the same API)
|
|
66
|
-
from fastquadtree.pygame import Group # Mostly drop-in
|
|
66
|
+
from fastquadtree.pygame import Group # Mostly drop-in pygame Group with quadtree queries (pygame install required)
|
|
67
67
|
```
|
|
@@ -103,15 +103,16 @@ Tip: Use `QuadTree` instead of `QuadTreeObjects` for max speed when you do not n
|
|
|
103
103
|
|
|
104
104
|
---
|
|
105
105
|
|
|
106
|
-
## Pygame sprite groups
|
|
106
|
+
## Pygame sprite groups and spatial queries
|
|
107
107
|
|
|
108
|
-
The optional `fastquadtree.pygame` module provides a
|
|
109
|
-
`
|
|
110
|
-
own `spritecollide(...)` APIs
|
|
111
|
-
|
|
108
|
+
The optional `fastquadtree.pygame` module provides a pygame sprite group backed
|
|
109
|
+
by `RectQuadTreeObjects`. It supports normal sprite-group operations, collision
|
|
110
|
+
helpers shaped like pygame's own `spritecollide(...)` APIs, and direct spatial
|
|
111
|
+
queries such as rectangle queries and k-nearest-neighbor search over sprite
|
|
112
|
+
`rect` bounds.
|
|
112
113
|
|
|
113
114
|
This is most useful when you have many static or mostly stable sprites and each
|
|
114
|
-
query touches only a small part of the world. The tradeoff is
|
|
115
|
+
query touches only a small part of the world. The tradeoff is index maintenance:
|
|
115
116
|
moving indexed sprites need `Group.update(...)` or `Group.sync(...)` so the
|
|
116
117
|
index reflects their current rects. If most sprites move every frame, create the
|
|
117
118
|
group with `rebuild_on_update=True` to rebuild the index after each
|
|
@@ -124,14 +125,20 @@ import fastquadtree.pygame as fpygame
|
|
|
124
125
|
world_bounds = (0, 0, 2000, 2000)
|
|
125
126
|
blocks = fpygame.Group(bounds=world_bounds)
|
|
126
127
|
blocks.add(block_sprites)
|
|
128
|
+
blocks.add(enemy_sprite)
|
|
127
129
|
|
|
128
130
|
# Collision helper with the same shape as pygame.sprite.spritecollide.
|
|
129
131
|
hits = fpygame.spritecollide(player, blocks, dokill=False)
|
|
130
132
|
|
|
131
133
|
# Rectangle queries can use pygame.Rect or (min_x, min_y, max_x, max_y) bounds.
|
|
132
|
-
visible = blocks.
|
|
134
|
+
visible = blocks.query(camera_rect, sync=False)
|
|
133
135
|
for sprite in visible:
|
|
134
136
|
screen.blit(sprite.image, sprite.rect.move(-camera_x, -camera_y))
|
|
137
|
+
|
|
138
|
+
# Direct spatial queries return sprites.
|
|
139
|
+
nearest = blocks.nearest_neighbors(player.rect.center, k=5)
|
|
140
|
+
for sprite in nearest:
|
|
141
|
+
print(sprite)
|
|
135
142
|
```
|
|
136
143
|
|
|
137
144
|
pygame is not a required dependency for core `fastquadtree`; install a
|
|
@@ -62,7 +62,7 @@ uv run python interactive/ballpit.py
|
|
|
62
62
|

|
|
63
63
|
|
|
64
64
|
## 3. Pygame sprite group comparison
|
|
65
|
-
- Compare `pygame.sprite.Group` with the
|
|
65
|
+
- Compare `pygame.sprite.Group` with the quadtree-backed `fastquadtree.pygame.Group`
|
|
66
66
|
- Press `G` to switch group backends while the demo is running
|
|
67
67
|
- Uses the fastquadtree-backed group for automatic broadphase culling
|
|
68
68
|
|
|
@@ -70,7 +70,7 @@ This demo creates many static block sprites and a moving player. Player
|
|
|
70
70
|
collision uses the normal `spritecollide(...)` flow for both backends. Viewport
|
|
71
71
|
culling asks "which blocks intersect the camera rect?" The pygame backend
|
|
72
72
|
answers by scanning every block, while the fastquadtree backend can answer the
|
|
73
|
-
same rectangle query through `Group.
|
|
73
|
+
same rectangle query through `Group.query(...)`.
|
|
74
74
|
|
|
75
75
|
The performance tradeoff is tree maintenance. The demo uses static blocks, so
|
|
76
76
|
the fastquadtree group can reuse its index frame after frame. If most indexed
|
|
@@ -296,7 +296,8 @@ class _BaseQuadTree(Generic[G], ABC):
|
|
|
296
296
|
"""
|
|
297
297
|
Return the maximum depth of the quadtree.
|
|
298
298
|
|
|
299
|
-
Useful if you constructed with max_depth=None
|
|
299
|
+
Useful if you constructed with max_depth=None and want to inspect the
|
|
300
|
+
resolved engine default.
|
|
300
301
|
"""
|
|
301
302
|
return self._native.get_max_depth()
|
|
302
303
|
|
|
@@ -692,7 +692,8 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
692
692
|
"""
|
|
693
693
|
Return the maximum depth of the quadtree.
|
|
694
694
|
|
|
695
|
-
Useful if you constructed with max_depth=None
|
|
695
|
+
Useful if you constructed with max_depth=None and want to inspect the
|
|
696
|
+
resolved engine default.
|
|
696
697
|
"""
|
|
697
698
|
return self._native.get_max_depth()
|
|
698
699
|
|
|
@@ -29,7 +29,8 @@ class QuadTree(_BaseQuadTree[Point]):
|
|
|
29
29
|
Args:
|
|
30
30
|
bounds: World bounds as (min_x, min_y, max_x, max_y).
|
|
31
31
|
capacity: Maximum points per node before splitting.
|
|
32
|
-
max_depth: Optional maximum tree depth
|
|
32
|
+
max_depth: Optional maximum tree depth. If omitted, uses the
|
|
33
|
+
[engine default](https://elan456.github.io/fastquadtree/engine_defaults/#max-depth).
|
|
33
34
|
dtype: Coordinate data type ('f32', 'f64', 'i32', 'i64'). Default: 'f32'.
|
|
34
35
|
|
|
35
36
|
Performance:
|
|
@@ -28,7 +28,8 @@ class QuadTreeObjects(_BaseQuadTreeObjects[Point, PointItem]):
|
|
|
28
28
|
Args:
|
|
29
29
|
bounds: World bounds as (min_x, min_y, max_x, max_y).
|
|
30
30
|
capacity: Maximum points per node before splitting.
|
|
31
|
-
max_depth: Optional maximum tree depth
|
|
31
|
+
max_depth: Optional maximum tree depth. If omitted, uses the
|
|
32
|
+
[engine default](https://elan456.github.io/fastquadtree/engine_defaults/#max-depth).
|
|
32
33
|
dtype: Coordinate data type ('f32', 'f64', 'i32', 'i64'). Default: 'f32'.
|
|
33
34
|
|
|
34
35
|
Performance:
|