#pragma once #include #include #include #include class UIEntity; /** * SpatialHash - O(1) average spatial queries for entities (#115) * * Divides the grid into buckets and tracks which entities are in each bucket. * Queries only check entities in nearby buckets instead of all entities. * * Performance characteristics: * - Insert: O(1) * - Remove: O(n) where n = entities in bucket (typically small) * - Update position: O(n) where n = entities in bucket * - Query radius: O(k) where k = entities in checked buckets (vs O(N) for all entities) */ class SpatialHash { public: // Default bucket size of 32 cells balances memory and query performance explicit SpatialHash(int bucket_size = 32); // Insert entity into spatial hash based on current position void insert(std::shared_ptr entity); // Remove entity from spatial hash void remove(std::shared_ptr entity); // Update entity position - call when entity moves // This removes from old bucket and inserts into new bucket if needed void update(std::shared_ptr entity, float old_x, float old_y); // Update entity position using integer cell coordinates (#295) // Removes from old bucket and inserts into new based on cell_position void updateCell(std::shared_ptr entity, int old_x, int old_y); // Query all entities at a specific cell (uses cell_position for matching) // O(n) where n = entities in the bucket containing this cell std::vector> queryCell(int x, int y) const; // Query all entities within radius of a point // Returns entities whose positions are within the circular radius std::vector> queryRadius(float x, float y, float radius) const; // Clear all entities from the hash void clear(); // Get statistics for debugging size_t bucketCount() const { return buckets.size(); } private: int bucket_size; // Hash function for bucket coordinates struct PairHash { size_t operator()(const std::pair& p) const { // Combine hash of both coordinates return std::hash()(p.first) ^ (std::hash()(p.second) << 16); } }; // Map from bucket coordinates to list of entities in that bucket // Using weak_ptr to avoid preventing entity deletion std::unordered_map, std::vector>, PairHash> buckets; // Get bucket coordinates for a world position std::pair getBucket(float x, float y) const { return { static_cast(std::floor(x / bucket_size)), static_cast(std::floor(y / bucket_size)) }; } // Get all bucket coordinates that overlap with a radius query std::vector> getBucketsInRadius(float x, float y, float radius) const; };