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.
Files changed (117) hide show
  1. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.github/workflows/docs.yml +3 -3
  2. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.github/workflows/release.yml +57 -12
  3. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.github/workflows/test.yml +4 -4
  4. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.gitignore +4 -1
  5. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/.pre-commit-config.yaml +1 -1
  6. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/Cargo.lock +1 -1
  7. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/Cargo.toml +1 -1
  8. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/PKG-INFO +4 -4
  9. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/README.md +3 -3
  10. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/benchmark_np_vs_list.py +6 -6
  11. fastquadtree-2.4.1/docs/api/pygame.md +8 -0
  12. fastquadtree-2.4.1/docs/engine_defaults.md +73 -0
  13. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/index.md +2 -2
  14. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/quickstart.md +14 -7
  15. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/runnables.md +2 -2
  16. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/mkdocs.yml +1 -0
  17. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pyproject.toml +1 -1
  18. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_base_quadtree.py +2 -1
  19. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_base_quadtree_objects.py +2 -1
  20. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/point_quadtree.py +2 -1
  21. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/point_quadtree_objects.py +2 -1
  22. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/pygame.py +138 -73
  23. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/rect_quadtree.py +2 -1
  24. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/rect_quadtree_objects.py +2 -1
  25. fastquadtree-2.4.1/scripts/build_pyodide_wheel.sh +49 -0
  26. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_pygame_integration.py +59 -26
  27. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_core.py +3 -3
  28. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_core.py +3 -3
  29. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/test_pyqtree_shim_compat.py +3 -3
  30. fastquadtree-2.3.0/docs/api/pygame.md +0 -27
  31. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/LICENSE +0 -0
  32. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/ballpit.png +0 -0
  33. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/interactive_v2_rect_screenshot.png +0 -0
  34. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/interactive_v2_screenshot.png +0 -0
  35. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/pygame_sprites_demo.png +0 -0
  36. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/quadtree_bench_throughput.png +0 -0
  37. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/assets/quadtree_bench_time.png +0 -0
  38. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/benchmark_native_vs_shim.py +0 -0
  39. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/benchmark_serialization_vs_rebuild.py +0 -0
  40. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/cross_library_bench.py +0 -0
  41. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/__init__.py +0 -0
  42. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/engines.py +0 -0
  43. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/main.py +0 -0
  44. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/optimizer.py +0 -0
  45. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/plotting.py +0 -0
  46. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/quadtree_bench/runner.py +0 -0
  47. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/runner.py +0 -0
  48. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/benchmarks/system_info_collector.py +0 -0
  49. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/2.0_migration_guide.md +0 -0
  50. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/2.0_proposal.md +0 -0
  51. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/insert_result.md +0 -0
  52. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/item.md +0 -0
  53. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/point_item.md +0 -0
  54. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/pyqtree.md +0 -0
  55. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/quadtree.md +0 -0
  56. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/quadtree_objects.md +0 -0
  57. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/rect_item.md +0 -0
  58. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/rect_quadtree.md +0 -0
  59. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/api/rect_quadtree_objects.md +0 -0
  60. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/benchmark.md +0 -0
  61. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/future_features.md +0 -0
  62. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/rust_usage.md +0 -0
  63. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/docs/styles/overrides.css +0 -0
  64. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/examples/custom_id_example.py +0 -0
  65. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/examples/object_tracking_example.py +0 -0
  66. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/ballpit.py +0 -0
  67. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/interactive.py +0 -0
  68. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/interactive_v2.py +0 -0
  69. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/interactive_v2_rect.py +0 -0
  70. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/interactive/pygame_sprites.py +0 -0
  71. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pyrightconfig.json +0 -0
  72. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/__init__.py +0 -0
  73. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_common.py +0 -0
  74. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_insert_result.py +0 -0
  75. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_item.py +0 -0
  76. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/_obj_store.py +0 -0
  77. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/py.typed +0 -0
  78. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/pysrc/fastquadtree/pyqtree.py +0 -0
  79. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/geom.rs +0 -0
  80. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/lib.rs +0 -0
  81. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/quadtree.rs +0 -0
  82. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/rect_quadtree.rs +0 -0
  83. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/src/serialization.rs +0 -0
  84. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/__init__.py +0 -0
  85. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/insertions.rs +0 -0
  86. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/nearest_neighbor.rs +0 -0
  87. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/query.rs +0 -0
  88. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/rect_quadtree.rs +0 -0
  89. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/rectangle_traversal.rs +0 -0
  90. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/serialization.rs +0 -0
  91. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_delete.rs +0 -0
  92. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/__init__.py +0 -0
  93. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_common_validation.py +0 -0
  94. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_insert_result_and_items.py +0 -0
  95. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_internal_edges.py +0 -0
  96. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_obj_store.py +0 -0
  97. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/common/test_serialization_container.py +0 -0
  98. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/conftest.py +0 -0
  99. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_migration_breaks_and_safety.py +0 -0
  100. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_optional_pygame_dependency.py +0 -0
  101. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/integration/test_public_api_contracts.py +0 -0
  102. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_core.py +0 -0
  103. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_mutation.py +0 -0
  104. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_numpy.py +0 -0
  105. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_precision.py +0 -0
  106. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points/test_point_quadtree_serialization.py +0 -0
  107. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_core.py +0 -0
  108. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_deletion_update.py +0 -0
  109. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_numpy.py +0 -0
  110. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/points_objects/test_point_quadtree_objects_serialization.py +0 -0
  111. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_mutation.py +0 -0
  112. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_numpy.py +0 -0
  113. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects/test_rect_quadtree_serialization.py +0 -0
  114. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_deletion_update.py +0 -0
  115. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_numpy.py +0 -0
  116. {fastquadtree-2.3.0 → fastquadtree-2.4.1}/tests/test_python/rects_objects/test_rect_quadtree_objects_serialization.py +0 -0
  117. {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@v4
16
+ - uses: actions/checkout@v6
17
17
  with:
18
18
  fetch-depth: 0
19
19
  fetch-tags: true
20
- - uses: actions/setup-python@v5
20
+ - uses: actions/setup-python@v6
21
21
  with: { python-version: '3.11' }
22
22
  - name: Install uv
23
- uses: astral-sh/setup-uv@v7
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@v4
15
+ - uses: actions/checkout@v6
16
16
 
17
17
  - name: Set up Python
18
- uses: actions/setup-python@v5
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@v7
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@v5
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@v4
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@v5
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@v4
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@v4
155
+ - uses: actions/checkout@v6
111
156
 
112
157
  - name: Install uv
113
- uses: astral-sh/setup-uv@v7
158
+ uses: astral-sh/setup-uv@v8.1.0
114
159
 
115
160
  - name: Download all dist artifacts
116
- uses: actions/download-artifact@v4
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@v4
16
+ - uses: actions/checkout@v6
17
17
 
18
18
  - name: Set up Python ${{ matrix.python-version }}
19
- uses: actions/setup-python@v5
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@v7
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@v5
52
+ uses: codecov/codecov-action@v6
53
53
  with:
54
54
  token: ${{ secrets.CODECOV_TOKEN }}
@@ -216,4 +216,7 @@ __marimo__/
216
216
  *.exe
217
217
  *.pdb
218
218
  *.bin
219
- *.lock
219
+ *.lock
220
+
221
+ # pyodide
222
+ .pyodide*
@@ -1,7 +1,7 @@
1
1
  repos:
2
2
  # 0) Python linter and formatter: Ruff
3
3
  - repo: https://github.com/astral-sh/ruff-pre-commit
4
- rev: v0.6.9
4
+ rev: v0.15.15
5
5
  hooks:
6
6
  # Lint + autofix. If Ruff fixes something, the hook exits nonzero to force a re-run.
7
7
  - id: ruff
@@ -44,7 +44,7 @@ dependencies = [
44
44
 
45
45
  [[package]]
46
46
  name = "fastquadtree"
47
- version = "2.3.0"
47
+ version = "2.4.1"
48
48
  dependencies = [
49
49
  "num-traits",
50
50
  "numpy",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "fastquadtree"
3
- version = "2.3.0"
3
+ version = "2.4.1"
4
4
  edition = "2021"
5
5
  rust-version = "1.89"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastquadtree
3
- Version: 2.3.0
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 for faster collision detection (depending on workload)
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 replacement for `pygame.sprite.Group` with quadtree indexing for faster collision detection. |
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 tree can keep splitting as needed
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 for faster collision detection (depending on workload)
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 replacement for `pygame.sprite.Group` with quadtree indexing for faster collision detection. |
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 tree can keep splitting as needed
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.count == points_np.shape[0]
43
- ), f"Inserted {inserted} != {points_np.shape[0]}"
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
- ), f"Inserted {inserted} != {len(points_list)}"
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 for faster collision detection (depending on workload)
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 replacement for pygame.sprite.Group with quadtree indexing (pygame install required)
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 mostly drop-in
109
- `pygame.sprite.Group` replacement plus collision helpers shaped like pygame's
110
- own `spritecollide(...)` APIs. It indexes sprite `rect` bounds to give you
111
- automatic broadphase culling for collision queries and viewport culling.
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 tree maintenance:
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.query_rect(camera_rect, sync=False)
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
  ![Ballpit_Demo_Screenshot](https://raw.githubusercontent.com/Elan456/fastquadtree/main/assets/ballpit.png)
63
63
 
64
64
  ## 3. Pygame sprite group comparison
65
- - Compare `pygame.sprite.Group` with the mostly drop-in `fastquadtree.pygame.Group`
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.query_rect(...)`.
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
@@ -87,6 +87,7 @@ nav:
87
87
  - Benchmark: benchmark.md
88
88
  - Future Features: future_features.md
89
89
  - Rust Usage: rust_usage.md
90
+ - Engine Defaults: engine_defaults.md
90
91
  - API:
91
92
  - QuadTree: api/quadtree.md
92
93
  - RectQuadTree: api/rect_quadtree.md
@@ -53,7 +53,7 @@ compatibility = "manylinux_2_28"
53
53
  # uv sync will install the "dev" group by default.
54
54
  [dependency-groups]
55
55
  dev = [ # Testing and build dependencies
56
- "ruff>=0.6.0",
56
+ "ruff>=0.15.15",
57
57
  "pytest>=8.4.2",
58
58
  "pytest-cov>=7.0.0",
59
59
  "coverage>=7.5",
@@ -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 (uses engine default if not specified).
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 (uses engine default if not specified).
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: