diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-10-21 19:06:58 +0200 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-10-21 19:06:58 +0200 |
commit | fab0fccc0aaa18e915bcd08e81e5a04177e435cd (patch) | |
tree | 0e8e51ff61c88b60d1f845bc9fde20ea5ba7099b /QuadTreeCollisionChecker.cpp | |
parent | 10ce9f45b9551dc103272c2b2374db1c1e3b8bcb (diff) |
fix quad tree collision checker
Diffstat (limited to 'QuadTreeCollisionChecker.cpp')
-rw-r--r-- | QuadTreeCollisionChecker.cpp | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/QuadTreeCollisionChecker.cpp b/QuadTreeCollisionChecker.cpp new file mode 100644 index 0000000..0d211c0 --- /dev/null +++ b/QuadTreeCollisionChecker.cpp @@ -0,0 +1,103 @@ +#include <memory> + +#include "QuadTreeCollisionChecker.h" +#include "Museum.h" + +using namespace std; + +QuadTreeCollisionChecker::QuadTreeCollisionChecker(Museum & museum) : CollisionChecker(museum) { + this->boundary = { + .x = 0.0, + .y = 0.0, + .width = static_cast<float>(museum.canvas.data.columns), + .height = static_cast<float>(museum.canvas.data.rows), + }; + + this->artists = museum.people.get_artists(); + for (auto & _ : this->artists) this->artists_size++; + + if (this->artists_size > this->capacity) + this->subdivide(); +} + +QuadTreeCollisionChecker::QuadTreeCollisionChecker(const QuadTreeCollisionChecker * parent, const Rectangle & boundary) : CollisionChecker(parent->museum) { + this->boundary = boundary; + + this->artists = parent->artists; + this->artists_size = parent->artists_size; + + this->cull(); + + if (this->artists_size > this->capacity) + this->subdivide(); +} + +void QuadTreeCollisionChecker::subdivide() { + float half_width = this->boundary.width / 2; + float half_height = this->boundary.height / 2; + + // squares smaller than artists will subdivide infinitely + if (half_width <= 0.5) return; + if (half_height <= 0.5) return; + + this->subtree[0] = unique_ptr<QuadTreeCollisionChecker>(new QuadTreeCollisionChecker(this, { + .x = this->boundary.x, + .y = this->boundary.y, + .width = half_width, + .height = half_height, + })); + this->subtree[1] = unique_ptr<QuadTreeCollisionChecker>(new QuadTreeCollisionChecker(this, { + .x = this->boundary.x + half_width, + .y = this->boundary.y, + .width = half_width, + .height = half_height, + })); + this->subtree[2] = unique_ptr<QuadTreeCollisionChecker>(new QuadTreeCollisionChecker(this, { + .x = this->boundary.x, + .y = this->boundary.y + half_height, + .width = half_width, + .height = half_height, + })); + this->subtree[3] = unique_ptr<QuadTreeCollisionChecker>(new QuadTreeCollisionChecker(this, { + .x = this->boundary.x + half_width, + .y = this->boundary.y + half_height, + .width = half_width, + .height = half_height, + })); + + // now all artists are stored in subtrees, so they no longer have to be + // stored in this quad + this->artists.clear(); + this->artists_size = 0; +} + +void QuadTreeCollisionChecker::cull() { + // remove artists that are *completely* outside the boundary + this->artists_size -= this->artists.remove_if([this](const Artist * artist) -> bool { + if (artist->data.x + 0.5 < this->boundary.x) return true; + if (artist->data.y + 0.5 < this->boundary.y) return true; + if (artist->data.x > this->boundary.x + this->boundary.width) return true; + if (artist->data.y > this->boundary.y + this->boundary.height) return true; + return false; + }); +} + +void QuadTreeCollisionChecker::check() { + if (this->artists_size > 0) { + auto begin = this->artists.begin(); + auto end = this->artists.end(); + for (Artist * artist : this->artists) artist->colliding = false; + for (auto it1 = begin; it1 != end; ++it1) { + auto it2 = it1; + ++it2; + for (; it2 != end; ++it2) { + this->compare(**it1, **it2); + } + } + } + for (size_t i = 0; i < 4; i++) { + if (this->subtree[i] == nullptr) continue; + this->subtree[i]->check(); + } +} + |