You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: artificialintelligence/04-spacequantization/README.md
+49-4Lines changed: 49 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
Space quantization is a way to sample continuous space to be used in in many fields, such as Artificial Intelligence, Physics, Rendering, and more. Here we are going to focus primarily Spatial Quantization for AI, because it is the base for pathfinding, line of sight, field of view, and many other techniques.
4
4
5
-
Some of the most common techniques for space quantization are: grids, voxels, graphs, quadtrees, octrees, BSP, Spatial Hashing and more. Another notable techniques are line of sight(or field of view), map flooding, caching, and movement zones.
5
+
Some of the most common techniques for space quantization are: grids, voxels, graphs, quadtrees, octrees, KD-trees, BSP, Spatial Hashing and more. Another notable techniques are line of sight(or field of view), map flooding, caching, and movement zones.
6
6
7
7
# Grids
8
8
@@ -166,7 +166,6 @@ Quadtree is a tree data structure where each node has 4 children. It is used to
166
166
167
167
Quadtree is a recursive data structure, so you can implement it using a recursive data structure. The following code is a simple implementation of a quadtree.
168
168
169
-
170
169
```c++
171
170
// this code is not tested, but it should work. It is just an example and send a merge request if you find any errors.
The quadtree is a recursive data structure, so it is not cache friendly. You can optimize it by using a flat array instead of a recursive data structure.
237
+
238
+
239
+
# Octree
240
+
241
+
Section WiP. Send a merge request if you want to contribute.
242
+
243
+
# KD-Tree
244
+
245
+
KD-Trees are a tree data structure that are used to partition a spaces in any dimension (2D, 3D, 4D, etc). They are used to optimize collision detection(Physics), pathfinding(AI), and other algorithms that need to iterate over a space. Also they are also used to optimize rendering, because you can render only the visible part of the space. Pay attention that KD-Trees are not the same as Quadtree and Octrees, even if they are similar.
246
+
247
+
In KD-trees, every node defines an orthogonal partition plan that alternate every deepening level of the tree. The partition plan is defined by a dimension, a value. The dimension is the axis that is used to partition the space, and the value is the position of the partition plan. The partition plan is orthogonal to the axis, so it is a line in 2D, a plane in 3D, and a hyperplane in 4D.
248
+
249
+
# BSP Tree
250
+
251
+
BSP inherits almost all characteristics of KD-Trees, but it is not a tree data structure, it is a graph data structure. The main difference is to instead of being orthogonal you define the plane of the section. The plane is defined by a point and a normal. The normal is the direction of the plane, and the point is a point in the plane.
252
+
253
+
# Spatial Hashing
254
+
255
+
Spatial hashing is a data structure that is used to partition a space. It consists in a hash table where the keys are the positions of the elements, and the values are the elements in buckets. It is very fast to insert and query elements. But it is not good for iteration, because it is not cache friendly.
256
+
257
+
Usually when you want to use a spatial hashing, you create hash functions for the bucket keys, there is no limit on how you do that, but you have to keep in mind that the hash functions have to be fast and have to be good for the distribution of the elements. Here is a good example of a hashing function for 2D vectors.
258
+
259
+
```c++
260
+
namespacestd {
261
+
template<>
262
+
struct hash<Vector2f> {
263
+
// I am assuming size_t is 64 bits and the float is 32 bits
264
+
size_t operator()(const Vector2f& v) const {
265
+
// get the bits of the float in a integer
266
+
uint64_t x = *(uint64_t*)&v.x;
267
+
uint64_t y = *(uint64_t*)&v.y;
268
+
// mix the bits of the floats
269
+
uint64_t hash = x & (y << 32);
270
+
return hash;
271
+
}
272
+
};
273
+
}
274
+
```
275
+
276
+
Pay attention that the hashing function above generates collisions, so you have to use a data structure that can handle collisions. You will use datastructures like `unordered_map<Vector2D, unordered_set<DATATYPE>>` or `unordered_map<Vector2D, vector<DATATYPE>>`. The first one is better for insertion and query, but it is not cache friendly.
277
+
278
+
To avoid having one bucket per every possible position, you have to setup properly the dimension of the bucket, a good sugestion is to alwoys floor the position and have buckets dimension of 1.0f. That would be good enough for most cases.
0 commit comments