Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Persisting Placement #579

Merged
merged 4 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 53 additions & 19 deletions shared/public/CollisionGrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ struct IndexRange {

class CollisionGrid {
public:
CollisionGrid(const std::vector<float> &vpMatrix, const Vec2I &size, float gridAngle)
CollisionGrid(const std::vector<float> &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;
Expand Down Expand Up @@ -98,43 +99,53 @@ 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)) {
return 1;
if (alwaysInsert) {
colliding = true;
break;
} else {
return 1;
}
}
}
for (const auto &circle : gridCircles[y][x]) {
if (CollisionUtil::checkRectCircleCollision(projectedRectangle, circle)) {
return 1;
if (alwaysInsert) {
colliding = true;
break;
} else {
return 1;
}
}
}

}
}

// 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);
}
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<CollisionCircleF> &circles) {
uint8_t addAndCheckCollisionCircles(const std::vector<CollisionCircleF> &circles) {
if (circles.empty()) {
// No circles -> no collision
return false;
// No circles -> no colliding
return 0;
}

std::vector<std::tuple<CircleF, IndexRange, size_t, int16_t>> projectedCircles;
Expand All @@ -148,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) {
Expand All @@ -159,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;
}
}
}
}
Expand All @@ -168,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;
}
}
}
}
Expand All @@ -178,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);
Expand All @@ -201,7 +232,8 @@ class CollisionGrid {
spacedCircles[contentHash].push_back(projectedCircle);
}
}
return false;

return colliding ? 1 : 0;
}

private:
Expand Down Expand Up @@ -304,5 +336,7 @@ class CollisionGrid {
std::unordered_map<size_t, std::vector<RectF>> spacedRects;
std::unordered_map<size_t, std::vector<CircleF>> spacedCircles;

bool alwaysInsert = false;

std::vector<float> temp1 = {0, 0, 0, 0}, temp2 = {0, 0, 0, 0};
};
9 changes: 6 additions & 3 deletions shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "Tiled2dMapVectorSourceSymbolCollisionManager.h"
#include "CollisionGrid.h"

void Tiled2dMapVectorSourceSymbolCollisionManager::collisionDetection(const std::vector<float> &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation) {
void Tiled2dMapVectorSourceSymbolCollisionManager::collisionDetection(const std::vector<float> &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation, bool persistingPlacement) {
std::vector<std::string> layers;
std::string currentSource;

Expand All @@ -21,7 +21,7 @@ void Tiled2dMapVectorSourceSymbolCollisionManager::collisionDetection(const std:
}
lastVpMatrix = vpMatrix;

auto collisionGrid = std::make_shared<CollisionGrid>(vpMatrix, viewportSize, viewportRotation);
auto collisionGrid = std::make_shared<CollisionGrid>(vpMatrix, viewportSize, viewportRotation, persistingPlacement);

const auto lambda = [&collisionGrid, &layers](auto manager){
if (auto strongManager = manager.lock()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Tiled2dMapVectorSourceSymbolCollisionManager: public ActorObject {
public:
Tiled2dMapVectorSourceSymbolCollisionManager(const std::unordered_map<std::string, WeakActor<Tiled2dMapVectorSourceSymbolDataManager>> &symbolSourceDataManagers,
std::shared_ptr<VectorMapDescription> mapDescription): symbolSourceDataManagers(symbolSourceDataManagers), mapDescription(mapDescription) {};
void collisionDetection(const std::vector<float> &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation);
void collisionDetection(const std::vector<float> &vpMatrix, const Vec2I &viewportSize, float viewportRotation, bool enforceRecomputation, bool persistingPlacement);
private:
std::unordered_map<std::string, WeakActor<Tiled2dMapVectorSourceSymbolDataManager>> symbolSourceDataManagers;
std::shared_ptr<VectorMapDescription> mapDescription;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -639,21 +639,9 @@ void Tiled2dMapVectorSourceSymbolDataManager::collisionDetection(std::vector<std
const auto objectsIt = symbolGroupsMap.find(layerIdentifier);
if (objectsIt != symbolGroupsMap.end()) {
for (auto &symbolGroup: std::get<1>(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](auto group){
for(auto& o : group->getSymbolObjectsForCollision()) {
allObjects.push_back(o);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -873,18 +873,12 @@ void Tiled2dMapVectorSymbolObject::collisionDetection(const double zoomIdentifie
std::optional<std::vector<CollisionCircleF>> 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;
}

if (persistingSymbolPlacement) {
if (!willCollide && !outside && zoomIdentifier < smallestVisibleZoom) {
smallestVisibleZoom = zoomIdentifier;
} else if (willCollide && (largestCollisionZoom == -1 || zoomIdentifier > largestCollisionZoom)) {
largestCollisionZoom = zoomIdentifier;
outside = false;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading