RectangleSpatialChecker::QueryResults RectangleSpatialChecker::query(Rect4i rect) { QueryResults results; results.n = 0; if (sweep > 0x7FFFFFFF) { resetSweep(); } sweep++; // This will work as a poor man's bloom filter int resultMask = 0; Vector2i p1 = pointToCell(rect.getTopLeft()); Vector2i p2 = pointToCell(rect.getBottomRight()); int x0 = p1.x; int x1 = p2.x; int y0 = p1.y; int y1 = p2.y; for (int y = y0; y <= y1; y++) { for (int x = x0; x <= x1; x++) { // Go through each rect in each grid element auto& vec = getGridCell(x, y); const size_t n = vec.size(); for (size_t i = 0; i < n; i++) { Entry& e = vec[i]; // Check if they intersect if (e.rect.overlaps(rect)) { // Check if it's already in the buffer if ((resultMask & e.hashMask) != 0) { for (size_t j = 0; j < results.n; j++) { if (resultsBuffer[j] == e.data) { goto endOfCheckLoop; // Oh yeah, baby. I went there. } } } // Hash it in the mask resultMask |= e.hashMask; // Insert into the buffer if (results.n < resultsBuffer.size()) { resultsBuffer[results.n] = e.data; } else { resultsBuffer.push_back(e.data); } results.n++; endOfCheckLoop:; } } } } results.results = resultsBuffer.data(); return results; }
bool RectangleSpatialChecker::updateData(Entry& entry, Rect4i prev, Rect4i next) { if (prev == next) { return false; // Nothing to do here } int x0, x1, y0, y1; x0 = y0 = std::numeric_limits<int>::max(); x1 = y1 = std::numeric_limits<int>::lowest(); Rect4i addRect; Rect4i delRect; bool hasAdd = false; bool hasDel = false; if (prev.getWidth() > 0 && prev.getHeight() > 0) { Vector2i p1 = pointToCell(prev.getTopLeft()); Vector2i p2 = pointToCell(prev.getBottomRight()); delRect = Rect4i(p1, p2); hasDel = true; x0 = p1.x; x1 = p2.x; y0 = p1.y; y1 = p2.y; } if (next.getWidth() > 0 && next.getHeight() > 0) { Vector2i p1 = pointToCell(next.getTopLeft()); Vector2i p2 = pointToCell(next.getBottomRight()); addRect = Rect4i(p1, p2); hasAdd = true; x0 = std::min(x0, p1.x); x1 = std::max(x1, p2.x); y0 = std::min(y0, p1.y); y1 = std::max(y1, p2.y); } for (int y = y0; y <= y1; y++) { for (int x = x0; x <= x1; x++) { Vector2i p(x, y); bool removeHere = hasDel && delRect.isInside(p); bool addHere = hasAdd && addRect.isInside(p); auto& contents = getGridCell(x, y); if (addHere && removeHere) { // Find existing, then update it with new rect for (size_t i = 0; i < contents.size(); i++) { if (contents[i].data == entry.data) { contents[i].rect = next; break; } } } else if (removeHere) { // Remove //int removed = 0; for (size_t i = 0; i < contents.size(); i++) { if (contents[i].data == entry.data) { if (i != contents.size() - 1) { std::swap(contents[i], contents[contents.size() - 1]); } contents.pop_back(); break; // Safe to break because there should only ever be one copy of each object in each cell } } } else if (addHere) { // Insert, making sure to update rect to new value, since "entry" is still outdated contents.push_back(entry); contents.back().rect = next; } } } // Update the main entry itself entry.rect = next; return true; }