From a8154db6af95ecc570883594ca01c00cdb2ff850 Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Wed, 24 Jan 2024 16:33:40 +0100 Subject: [PATCH] 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 7c1e09b28..25a341200 100644 --- a/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayer.cpp +++ b/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayer.cpp @@ -559,9 +559,12 @@ void Tiled2dMapVectorLayer::update() { if (now - lastCollitionCheck > 2000 || 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 4da4d5ed8..84a0a4218 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSourceSymbolDataManager.cpp @@ -627,10 +627,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 c1084d85e..660d8a7fd 100644 --- a/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp +++ b/shared/src/map/layers/tiled/vector/symbol/Tiled2dMapVectorSymbolObject.cpp @@ -866,11 +866,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) {