From 31b7063b6243c4317bb05e16469c17368a51f8b8 Mon Sep 17 00:00:00 2001 From: Alexander Friedrich Date: Mon, 8 Jan 2024 17:46:23 +0100 Subject: [PATCH 1/4] show labels only if they are not hidden later --- shared/public/CollisionGrid.h | 17 +++++++--------- .../symbol/SymbolObjectCollisionWrapper.h | 6 ------ ...iled2dMapVectorSourceSymbolDataManager.cpp | 20 ++++--------------- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/shared/public/CollisionGrid.h b/shared/public/CollisionGrid.h index c12feadec..72121b220 100644 --- a/shared/public/CollisionGrid.h +++ b/shared/public/CollisionGrid.h @@ -98,32 +98,29 @@ class CollisionGrid { } } } + + bool collision = false; for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { + if (!collision) { for (const auto &rect : gridRects[y][x]) { if (CollisionUtil::checkRectCollision(projectedRectangle, rect)) { - return 1; + collision = true; } } for (const auto &circle : gridCircles[y][x]) { if (CollisionUtil::checkRectCircleCollision(projectedRectangle, circle)) { - return 1; + collision = true; } } - - } - } - - // Only insert, when not colliding - for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { - for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { + } gridRects[y][x].push_back(projectedRectangle); } } - if (rectangle.contentHash != 0 && rectangle.symbolSpacing > 0) { spacedRects[rectangle.contentHash].push_back(projectedRectangle); } + if (collision) return 1; return 0; } diff --git a/shared/src/map/layers/tiled/vector/symbol/SymbolObjectCollisionWrapper.h b/shared/src/map/layers/tiled/vector/symbol/SymbolObjectCollisionWrapper.h index c19b713b0..5e794a297 100644 --- a/shared/src/map/layers/tiled/vector/symbol/SymbolObjectCollisionWrapper.h +++ b/shared/src/map/layers/tiled/vector/symbol/SymbolObjectCollisionWrapper.h @@ -42,12 +42,6 @@ class SymbolObjectCollisionWrapper { } bool operator<(const SymbolObjectCollisionWrapper &o) const { - if (isColliding != o.isColliding) { - return isColliding; - } - if (symbolObject->smallestVisibleZoom != o.symbolObject->smallestVisibleZoom) { - return symbolObject->smallestVisibleZoom > o.symbolObject->smallestVisibleZoom; - } if (symbolSortKey == o.symbolSortKey) { return symbolTileIndex > o.symbolTileIndex; } diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp index b3ab657a6..8b60a9ea9 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp @@ -639,22 +639,10 @@ void Tiled2dMapVectorSourceSymbolDataManager::collisionDetection(std::vector(objectsIt->second)) { - symbolGroup.syncAccess([&allObjects, zoomIdentifier, persistingPlacement = persistingSymbolPlacement](auto group){ - const auto &objects = group->getSymbolObjectsForCollision(); - if (persistingPlacement) { - for (auto &object : objects) { - if (object.symbolObject->largestCollisionZoom == -1 || object.symbolObject->largestCollisionZoom < zoomIdentifier) { - allObjects.push_back(object); - } - else { - object.symbolObject->setHideFromCollision(true); - } - } - } else { - for(auto& o : objects) { - allObjects.push_back(o); - } - } + symbolGroup.syncAccess([&allObjects, zoomIdentifier](auto group){ + auto objects = group->getSymbolObjectsForCollision(); + allObjects.reserve(allObjects.size() + objects.size()); + allObjects.insert(allObjects.end(), std::make_move_iterator(objects.begin()), std::make_move_iterator(objects.end())); }); } } From dddb780fd7220ada6a597e5947802806cdf6a073 Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Wed, 24 Jan 2024 16:33:40 +0100 Subject: [PATCH 2/4] Make alwaysInsert toggleable (by style property), also add it for circular collided labels --- shared/public/CollisionGrid.h | 77 ++++++++++++++----- .../tiled/vector/Tiled2dMapVectorLayer.cpp | 9 ++- ...dMapVectorSourceSymbolCollisionManager.cpp | 4 +- ...d2dMapVectorSourceSymbolCollisionManager.h | 2 +- ...iled2dMapVectorSourceSymbolDataManager.cpp | 8 +- .../symbol/Tiled2dMapVectorSymbolObject.cpp | 6 +- 6 files changed, 74 insertions(+), 32 deletions(-) diff --git a/shared/public/CollisionGrid.h b/shared/public/CollisionGrid.h index 72121b220..8aaf388ec 100644 --- a/shared/public/CollisionGrid.h +++ b/shared/public/CollisionGrid.h @@ -49,10 +49,11 @@ struct IndexRange { class CollisionGrid { public: - CollisionGrid(const std::vector &vpMatrix, const Vec2I &size, float gridAngle) + CollisionGrid(const std::vector &vpMatrix, const Vec2I &size, float gridAngle, bool alwaysInsert) : vpMatrix(vpMatrix), size(size), sinNegGridAngle(std::sin(-gridAngle * M_PI / 180.0)), - cosNegGridAngle(std::cos(-gridAngle * M_PI / 180.0)) { + cosNegGridAngle(std::cos(-gridAngle * M_PI / 180.0)), + alwaysInsert(alwaysInsert) { cellSize = std::min(size.x, size.y) / (float) numCellsMinDim; numCellsX = std::ceil(size.x / cellSize) + 2 * numCellsPadding; numCellsY = std::ceil(size.y / cellSize) + 2 * numCellsPadding; @@ -99,39 +100,52 @@ class CollisionGrid { } } - bool collision = false; + bool colliding = false; for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { - if (!collision) { for (const auto &rect : gridRects[y][x]) { if (CollisionUtil::checkRectCollision(projectedRectangle, rect)) { - collision = true; + if (alwaysInsert) { + colliding = true; + break; + } else { + return 1; + } } } for (const auto &circle : gridCircles[y][x]) { if (CollisionUtil::checkRectCircleCollision(projectedRectangle, circle)) { - collision = true; + if (alwaysInsert) { + colliding = true; + break; + } else { + return 1; + } } } - } + } + } + + for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { + for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { gridRects[y][x].push_back(projectedRectangle); } } if (rectangle.contentHash != 0 && rectangle.symbolSpacing > 0) { spacedRects[rectangle.contentHash].push_back(projectedRectangle); } - if (collision) return 1; - return 0; + + return colliding ? 1 : 0; } /** * Add a vector of circles (which are then projected with the provided vpMatrix) and receive the feedback, if they have collided * with the previous content of the grid. Assumed to remain circles in the projected space. Only added, when not colliding! */ - bool addAndCheckCollisionCircles(const std::vector &circles) { + uint8_t addAndCheckCollisionCircles(const std::vector &circles) { if (circles.empty()) { - // No circles -> no collision - return false; + // No circles -> no colliding + return 0; } std::vector> projectedCircles; @@ -145,9 +159,10 @@ class CollisionGrid { if (projectedCircles.empty()) { // no valid IndexRanges - return true; + return 2; } + bool colliding = false; for (const auto &[projectedCircle, indexRange, contentHash, symbolSpacing] : projectedCircles) { if (contentHash != 0 && symbolSpacing > 0) { @@ -156,7 +171,12 @@ class CollisionGrid { for (const auto &other : equalRects->second) { // Assume equal symbol spacing for all primitives with matching content if (CollisionUtil::checkRectCircleCollision(other, projectedCircle, symbolSpacing)) { - return true; + if (alwaysInsert) { + colliding = true; + break; + } else { + return 1; + } } } } @@ -165,7 +185,12 @@ class CollisionGrid { for (const auto &other : equalCircles->second) { // Assume equal symbol spacing for all primitives with matching content if (CollisionUtil::checkCircleCollision(projectedCircle, other, symbolSpacing)) { - return true; + if (alwaysInsert) { + colliding = true; + break; + } else { + return 1; + } } } } @@ -175,20 +200,29 @@ class CollisionGrid { for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { for (const auto &rect : gridRects[y][x]) { if (CollisionUtil::checkRectCircleCollision(rect, projectedCircle)) { - return true; + if (alwaysInsert) { + colliding = true; + break; + } else { + return 1; + } } } for (const auto &circle : gridCircles[y][x]) { if (CollisionUtil::checkCircleCollision(projectedCircle, circle)) { - return true; + if (alwaysInsert) { + colliding = true; + break; + } else { + return 1; + } } } } } } - // Only insert when none colliding - for (const auto &[projectedCircle, indexRange, contentHash, symbolSpacing] : projectedCircles) { + for (const auto &[projectedCircle, indexRange, contentHash, symbolSpacing]: projectedCircles) { for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { gridCircles[y][x].push_back(projectedCircle); @@ -198,7 +232,8 @@ class CollisionGrid { spacedCircles[contentHash].push_back(projectedCircle); } } - return false; + + return colliding ? 1 : 0; } private: @@ -301,5 +336,7 @@ class CollisionGrid { std::unordered_map> spacedRects; std::unordered_map> spacedCircles; + bool alwaysInsert = false; + std::vector temp1 = {0, 0, 0, 0}, temp2 = {0, 0, 0, 0}; }; diff --git a/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayer.cpp b/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayer.cpp index 8e5dbb3f6..cf719a802 100644 --- a/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayer.cpp +++ b/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayer.cpp @@ -561,9 +561,12 @@ void Tiled2dMapVectorLayer::update() { if (now - lastCollitionCheck > 3000 || tilesChanged) { lastCollitionCheck = now; bool enforceUpdate = !prevCollisionStillValid.test_and_set(); - collisionManager.syncAccess([&vpMatrix, &viewportSize, viewportRotation, enforceUpdate](const auto &manager) { - manager->collisionDetection(*vpMatrix, viewportSize, viewportRotation, enforceUpdate); - }); + collisionManager.syncAccess( + [&vpMatrix, &viewportSize, viewportRotation, enforceUpdate, persistingPlacement = mapDescription->persistingSymbolPlacement]( + const auto &manager) { + manager->collisionDetection(*vpMatrix, viewportSize, viewportRotation, enforceUpdate, + persistingPlacement); + }); isAnimating = true; } } diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.cpp b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.cpp index 863e0fb6c..e4893db13 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.cpp @@ -11,7 +11,7 @@ #include "Tiled2dMapVectorSourceSymbolCollisionManager.h" #include "CollisionGrid.h" -void Tiled2dMapVectorSourceSymbolCollisionManager::collisionDetection(const std::vector &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation) { +void Tiled2dMapVectorSourceSymbolCollisionManager::collisionDetection(const std::vector &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation, bool persistingPlacement) { std::vector layers; std::string currentSource; @@ -21,7 +21,7 @@ void Tiled2dMapVectorSourceSymbolCollisionManager::collisionDetection(const std: } lastVpMatrix = vpMatrix; - auto collisionGrid = std::make_shared(vpMatrix, viewportSize, viewportRotation); + auto collisionGrid = std::make_shared(vpMatrix, viewportSize, viewportRotation, persistingPlacement); const auto lambda = [&collisionGrid, &layers](auto manager){ if (auto strongManager = manager.lock()) { diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.h b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.h index e11386702..58b3c44db 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.h +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolCollisionManager.h @@ -18,7 +18,7 @@ class Tiled2dMapVectorSourceSymbolCollisionManager: public ActorObject { public: Tiled2dMapVectorSourceSymbolCollisionManager(const std::unordered_map> &symbolSourceDataManagers, std::shared_ptr mapDescription): symbolSourceDataManagers(symbolSourceDataManagers), mapDescription(mapDescription) {}; - void collisionDetection(const std::vector &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation); + void collisionDetection(const std::vector &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation, bool persistingPlacement); private: std::unordered_map> symbolSourceDataManagers; std::shared_ptr mapDescription; diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp index 8b60a9ea9..1a69f0e5a 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp @@ -639,10 +639,10 @@ void Tiled2dMapVectorSourceSymbolDataManager::collisionDetection(std::vector(objectsIt->second)) { - symbolGroup.syncAccess([&allObjects, zoomIdentifier](auto group){ - auto objects = group->getSymbolObjectsForCollision(); - allObjects.reserve(allObjects.size() + objects.size()); - allObjects.insert(allObjects.end(), std::make_move_iterator(objects.begin()), std::make_move_iterator(objects.end())); + symbolGroup.syncAccess([&allObjects](auto group){ + for(auto& o : group->getSymbolObjectsForCollision()) { + allObjects.push_back(o); + } }); } } diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp index 98e7e3300..723c253a0 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp @@ -873,11 +873,13 @@ void Tiled2dMapVectorSymbolObject::collisionDetection(const double zoomIdentifie std::optional> boundingCircles = getMapAlignedBoundingCircles(zoomIdentifier, textSymbolPlacement != TextSymbolPlacement::POINT, true); // Collide, if no valid boundingCircles if (boundingCircles.has_value()) { - willCollide = collisionGrid->addAndCheckCollisionCircles(*boundingCircles); + auto check = collisionGrid->addAndCheckCollisionCircles(*boundingCircles); + willCollide = check == 1; + outside = check == 2; } else { willCollide = false; + outside = false; } - outside = false; } if (persistingSymbolPlacement) { From c5edfc660989801609d93137c71da0c55c1039ca Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Wed, 24 Jan 2024 16:50:57 +0100 Subject: [PATCH 3/4] Remove unused code --- .../tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp | 8 -------- .../tiled/vector/symbol/Tiled2dMapVectorSymbolObject.h | 3 --- 2 files changed, 11 deletions(-) diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp index 723c253a0..6c75efe81 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp @@ -882,14 +882,6 @@ void Tiled2dMapVectorSymbolObject::collisionDetection(const double zoomIdentifie } } - if (persistingSymbolPlacement) { - if (!willCollide && !outside && zoomIdentifier < smallestVisibleZoom) { - smallestVisibleZoom = zoomIdentifier; - } else if (willCollide && (largestCollisionZoom == -1 || zoomIdentifier > largestCollisionZoom)) { - largestCollisionZoom = zoomIdentifier; - } - } - if (!outside) { setHideFromCollision(willCollide); } diff --git a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.h b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.h index 4c25851f7..d42f84f8d 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.h +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.h @@ -110,9 +110,6 @@ class Tiled2dMapVectorSymbolObject { int customTextureOffset = 0; std::string stringIdentifier; - double smallestVisibleZoom = 999; - double largestCollisionZoom = -1; - private: double lastZoomEvaluation = -1; void evaluateStyleProperties(const double zoomIdentifier); From 33b4ea9502444c17ad060b9892d1a749bc56eb24 Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Wed, 24 Jan 2024 17:34:53 +0100 Subject: [PATCH 4/4] Split collision methods for performance --- shared/public/CollisionGrid.h | 172 +++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 65 deletions(-) diff --git a/shared/public/CollisionGrid.h b/shared/public/CollisionGrid.h index 8aaf388ec..99f41753b 100644 --- a/shared/public/CollisionGrid.h +++ b/shared/public/CollisionGrid.h @@ -100,42 +100,11 @@ class CollisionGrid { } } - bool colliding = false; - for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { - for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { - for (const auto &rect : gridRects[y][x]) { - if (CollisionUtil::checkRectCollision(projectedRectangle, rect)) { - if (alwaysInsert) { - colliding = true; - break; - } else { - return 1; - } - } - } - for (const auto &circle : gridCircles[y][x]) { - if (CollisionUtil::checkRectCircleCollision(projectedRectangle, circle)) { - if (alwaysInsert) { - colliding = true; - break; - } else { - return 1; - } - } - } - } - } - - for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { - for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { - gridRects[y][x].push_back(projectedRectangle); - } - } - if (rectangle.contentHash != 0 && rectangle.symbolSpacing > 0) { - spacedRects[rectangle.contentHash].push_back(projectedRectangle); + if (alwaysInsert) { + return checkRectInsertAlways(rectangle, projectedRectangle, indexRange); + } else { + return checkRectInsertOnCollision(rectangle, projectedRectangle, indexRange); } - - return colliding ? 1 : 0; } /** @@ -149,7 +118,7 @@ class CollisionGrid { } std::vector> projectedCircles; - for (const auto &circle : circles) { + for (const auto &circle: circles) { auto projectedCircle = getProjectedCircle(circle); IndexRange indexRange = getIndexRangeForCircle(projectedCircle); if (indexRange.isValid(numCellsX - 1, numCellsY - 1)) { @@ -162,60 +131,106 @@ class CollisionGrid { return 2; } - bool colliding = false; - for (const auto &[projectedCircle, indexRange, contentHash, symbolSpacing] : projectedCircles) { + for (const auto &[projectedCircle, indexRange, contentHash, symbolSpacing]: projectedCircles) { if (contentHash != 0 && symbolSpacing > 0) { const auto &equalRects = spacedRects.find(contentHash); if (equalRects != spacedRects.end()) { - for (const auto &other : equalRects->second) { + for (const auto &other: equalRects->second) { // Assume equal symbol spacing for all primitives with matching content if (CollisionUtil::checkRectCircleCollision(other, projectedCircle, symbolSpacing)) { - if (alwaysInsert) { - colliding = true; - break; - } else { - return 1; - } + return 1; + } } } const auto &equalCircles = spacedCircles.find(contentHash); if (equalCircles != spacedCircles.end()) { - for (const auto &other : equalCircles->second) { + for (const auto &other: equalCircles->second) { // Assume equal symbol spacing for all primitives with matching content if (CollisionUtil::checkCircleCollision(projectedCircle, other, symbolSpacing)) { - if (alwaysInsert) { - colliding = true; - break; - } else { - return 1; - } + return 1; + } + } + } + } + } + + if (alwaysInsert) { + return checkCirclesInsertAlways(circles, projectedCircles); + } else { + return checkCirclesInsertOnCollision(circles, projectedCircles); + } + } + +private: + uint8_t checkRectInsertOnCollision(const CollisionRectF &rectangle, const RectF &projectedRectangle, const IndexRange &indexRange) { + for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { + for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { + for (const auto &rect: gridRects[y][x]) { + if (CollisionUtil::checkRectCollision(projectedRectangle, rect)) { + return 1; + } + } + for (const auto &circle: gridCircles[y][x]) { + if (CollisionUtil::checkRectCircleCollision(projectedRectangle, circle)) { + return 1; + } + } + } + } + + for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { + for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { + gridRects[y][x].push_back(projectedRectangle); + } + } + if (rectangle.contentHash != 0 && rectangle.symbolSpacing > 0) { + spacedRects[rectangle.contentHash].push_back(projectedRectangle); + } + + return 0; + } + + uint8_t checkRectInsertAlways(const CollisionRectF &rectangle, const RectF &projectedRectangle, const IndexRange &indexRange) { + bool colliding = false; + for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { + for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { + if (!colliding) { + for (const auto &rect: gridRects[y][x]) { + if (CollisionUtil::checkRectCollision(projectedRectangle, rect)) { + colliding = true; + } + } + for (const auto &circle: gridCircles[y][x]) { + if (CollisionUtil::checkRectCircleCollision(projectedRectangle, circle)) { + colliding = true; } } } + gridRects[y][x].push_back(projectedRectangle); } + } + + if (rectangle.contentHash != 0 && rectangle.symbolSpacing > 0) { + spacedRects[rectangle.contentHash].push_back(projectedRectangle); + } + + return colliding ? 1 : 0; + } + uint8_t checkCirclesInsertOnCollision(const std::vector &circles, const std::vector> &projectedCircles) { + for (const auto &[projectedCircle, indexRange, contentHash, symbolSpacing] : projectedCircles) { for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { for (const auto &rect : gridRects[y][x]) { if (CollisionUtil::checkRectCircleCollision(rect, projectedCircle)) { - if (alwaysInsert) { - colliding = true; - break; - } else { - return 1; - } + return 1; } } for (const auto &circle : gridCircles[y][x]) { if (CollisionUtil::checkCircleCollision(projectedCircle, circle)) { - if (alwaysInsert) { - colliding = true; - break; - } else { - return 1; - } + return 1; } } } @@ -233,10 +248,37 @@ class CollisionGrid { } } + return 0; + } + + uint8_t checkCirclesInsertAlways(const std::vector &circles, const std::vector> &projectedCircles) { + bool colliding = false; + for (const auto &[projectedCircle, indexRange, contentHash, symbolSpacing]: projectedCircles) { + for (int16_t y = indexRange.yMin; y <= indexRange.yMax; y++) { + for (int16_t x = indexRange.xMin; x <= indexRange.xMax; x++) { + if (!colliding) { + for (const auto &rect: gridRects[y][x]) { + if (CollisionUtil::checkRectCircleCollision(rect, projectedCircle)) { + colliding = true; + } + } + for (const auto &circle: gridCircles[y][x]) { + if (CollisionUtil::checkCircleCollision(projectedCircle, circle)) { + colliding = true; + } + } + } + gridCircles[y][x].push_back(projectedCircle); + } + } + if (contentHash != 0 && symbolSpacing > 0) { + spacedCircles[contentHash].push_back(projectedCircle); + } + } + return colliding ? 1 : 0; } -private: RectF getProjectedRectangle(const CollisionRectF &rectangle) { temp2[0] = rectangle.x - rectangle.anchorX; // move x to the anchor temp2[1] = rectangle.y - rectangle.anchorY;