Skip to content

Commit

Permalink
Add option to restrict the whole visible camera area to the system bo…
Browse files Browse the repository at this point in the history
…unds
  • Loading branch information
maurhofer-ubique committed Feb 8, 2024
1 parent 41b2bf2 commit 2f77f6c
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 34 deletions.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ android {
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared"
cppFlags "-std=c++17 -frtti -fexceptions -O2"
cppFlags "-std=c++17 -frtti -fexceptions -O0"
}
}
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions bridging/android/jni/map/NativeMapCamera2dInterface.cpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions bridging/ios/MCMapCamera2dInterface+Private.mm

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions bridging/ios/MCMapCamera2dInterface.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions djinni/map/core.djinni
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ map_camera_2d_interface = interface +c {

set_rotation_enabled(enabled: bool);
set_snap_to_north_enabled(enabled: bool);
set_bounds_restrict_whole_visible_rect(enabled: bool);

as_camera_interface(): camera_interface;

Expand Down
2 changes: 2 additions & 0 deletions shared/public/MapCamera2dInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class MapCamera2dInterface {

virtual void setSnapToNorthEnabled(bool enabled) = 0;

virtual void setBoundsRestrictWholeVisibleRect(bool enabled) = 0;

virtual /*not-null*/ std::shared_ptr<::CameraInterface> asCameraInterface() = 0;

virtual std::optional<std::vector<float>> getLastVpMatrix() = 0;
Expand Down
125 changes: 93 additions & 32 deletions shared/src/map/camera/MapCamera2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ void MapCamera2d::moveToCenterPositionZoom(const ::Coord &centerPosition, double
return;
Coord currentCenter = this->centerPosition;
inertia = std::nullopt;
Coord positionMapSystem = getBoundsCorrectedCoords(adjustCoordForPadding(centerPosition, zoom));
const auto [positionMapSystem, adjustedZoom] = getBoundsCorrectedCoords(adjustCoordForPadding(centerPosition, zoom), zoom);
if (animated) {
std::lock_guard<std::recursive_mutex> lock(animationMutex);
coordAnimation = std::make_shared<CoordAnimation>(
Expand All @@ -95,12 +95,12 @@ void MapCamera2d::moveToCenterPositionZoom(const ::Coord &centerPosition, double
this->coordAnimation = nullptr;
});
coordAnimation->start();
setZoom(zoom, true);
setZoom(adjustedZoom, true);
mapInterface->invalidate();
} else {
this->centerPosition.x = positionMapSystem.x;
this->centerPosition.y = positionMapSystem.y;
setZoom(zoom, false);
setZoom(adjustedZoom, false);
notifyListeners(ListenerType::BOUNDS);
mapInterface->invalidate();
}
Expand All @@ -111,7 +111,7 @@ void MapCamera2d::moveToCenterPosition(const ::Coord &centerPosition, bool anima
return;
Coord currentCenter = this->centerPosition;
inertia = std::nullopt;
Coord positionMapSystem = getBoundsCorrectedCoords(adjustCoordForPadding(centerPosition, zoom));
const auto [positionMapSystem, adjustedZoom] = getBoundsCorrectedCoords(adjustCoordForPadding(centerPosition, zoom), zoom);
if (animated) {
std::lock_guard<std::recursive_mutex> lock(animationMutex);
coordAnimation = std::make_shared<CoordAnimation>(
Expand Down Expand Up @@ -260,7 +260,12 @@ void MapCamera2d::setPaddingLeft(float padding) {
std::lock_guard<std::recursive_mutex> lock(animationMutex);
if (coordAnimation && coordAnimation->helperCoord.has_value()) {
double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom();
coordAnimation->endValue = getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom));
const auto [adjPosition, adjZoom] =
getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom);
coordAnimation->endValue = adjPosition;
if (zoomAnimation) {
zoomAnimation->endValue = adjZoom;
}
}
}

Expand All @@ -269,7 +274,12 @@ void MapCamera2d::setPaddingRight(float padding) {
std::lock_guard<std::recursive_mutex> lock(animationMutex);
if (coordAnimation && coordAnimation->helperCoord.has_value()) {
double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom();
coordAnimation->endValue = getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom));
const auto [adjPosition, adjZoom] =
getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom);
coordAnimation->endValue = adjPosition;
if (zoomAnimation) {
zoomAnimation->endValue = adjZoom;
}
}
}

Expand All @@ -278,7 +288,12 @@ void MapCamera2d::setPaddingTop(float padding) {
std::lock_guard<std::recursive_mutex> lock(animationMutex);
if (coordAnimation && coordAnimation->helperCoord.has_value()) {
double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom();
coordAnimation->endValue = getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom));
const auto [adjPosition, adjZoom] =
getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom);
coordAnimation->endValue = adjPosition;
if (zoomAnimation) {
zoomAnimation->endValue = adjZoom;
}
}
}

Expand All @@ -287,7 +302,12 @@ void MapCamera2d::setPaddingBottom(float padding) {
std::lock_guard<std::recursive_mutex> lock(animationMutex);
if (coordAnimation && coordAnimation->helperCoord.has_value()) {
double targetZoom = (zoomAnimation) ? zoomAnimation->endValue : getZoom();
coordAnimation->endValue = getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom));
const auto [adjPosition, adjZoom] =
getBoundsCorrectedCoords(adjustCoordForPadding(*coordAnimation->helperCoord, targetZoom), targetZoom);
coordAnimation->endValue = adjPosition;
if (zoomAnimation) {
zoomAnimation->endValue = adjZoom;
}
}
}

Expand Down Expand Up @@ -544,10 +564,11 @@ void MapCamera2d::inertiaStep() {
float yDiffMap = (inertia->velocity.y) * factor * deltaPrev;
inertia->timestampUpdate = now;

centerPosition.x += xDiffMap;
centerPosition.y += yDiffMap;

clampCenterToPaddingCorrectedBounds();
const auto [adjustedPosition, adjustedZoom] = getBoundsCorrectedCoords(
Coord(centerPosition.systemIdentifier,centerPosition.x + xDiffMap,
centerPosition.y + yDiffMap, centerPosition.z), zoom);
centerPosition = adjustedPosition;
zoom = adjustedZoom;

notifyListeners(ListenerType::BOUNDS);
mapInterface->invalidate();
Expand Down Expand Up @@ -789,7 +810,9 @@ void MapCamera2d::setBounds(const RectCoord &bounds) {
RectCoord boundsMapSpace = mapInterface->getCoordinateConverterHelper()->convertRect(mapCoordinateSystem.identifier, bounds);
this->bounds = boundsMapSpace;

centerPosition = getBoundsCorrectedCoords(centerPosition);
const auto [adjPosition, adjZoom] = getBoundsCorrectedCoords(centerPosition, zoom);
centerPosition = adjPosition;
zoom = adjZoom;

mapInterface->invalidate();
}
Expand All @@ -809,20 +832,57 @@ bool MapCamera2d::isInBounds(const Coord &coords) {
return mapCoords.x <= maxHor && mapCoords.x >= minHor && mapCoords.y <= maxVert && mapCoords.y >= minVert;
}

Coord MapCamera2d::getBoundsCorrectedCoords(const Coord &coords) {
Coord mapCoords = mapInterface->getCoordinateConverterHelper()->convert(mapCoordinateSystem.identifier, coords);

std::tuple<Coord, double> MapCamera2d::getBoundsCorrectedCoords(const Coord &position, double zoom) {
auto const &paddingCorrectedBounds = getPaddingCorrectedBounds();

double minHor = std::min(paddingCorrectedBounds.topLeft.x, paddingCorrectedBounds.bottomRight.x);
double maxHor = std::max(paddingCorrectedBounds.topLeft.x, paddingCorrectedBounds.bottomRight.x);
double minVert = std::min(paddingCorrectedBounds.topLeft.y, paddingCorrectedBounds.bottomRight.y);
double maxVert = std::max(paddingCorrectedBounds.topLeft.y, paddingCorrectedBounds.bottomRight.y);
if (!config.boundsRestrictWholeVisibleRect) {
Coord newPosition = Coord(position.systemIdentifier,
std::clamp(position.x,
std::min(paddingCorrectedBounds.topLeft.x, paddingCorrectedBounds.bottomRight.x),
std::max(paddingCorrectedBounds.topLeft.x, paddingCorrectedBounds.bottomRight.x)),
std::clamp(position.y,
std::min(paddingCorrectedBounds.topLeft.y, paddingCorrectedBounds.bottomRight.y),
std::max(paddingCorrectedBounds.topLeft.y, paddingCorrectedBounds.bottomRight.y)),
position.z);
return {newPosition, zoom};
} else {
Vec2I sizeViewport = mapInterface->getRenderingContext()->getViewportSize();

mapCoords.x = std::clamp(mapCoords.x, minHor, maxHor);
mapCoords.y = std::clamp(mapCoords.y, minVert, maxVert);
double zoomFactor = screenPixelAsRealMeterFactor * zoom;

double halfWidth = sizeViewport.x * 0.5 * zoomFactor;
double halfHeight = sizeViewport.y * 0.5 * zoomFactor;

double sinAngle = sin(angle * M_PI / 180.0);
double cosAngle = cos(angle * M_PI / 180.0);

double deltaX = std::abs(halfWidth * cosAngle) + std::abs(halfHeight * sinAngle);
double deltaY = std::abs(halfWidth * sinAngle) + std::abs(halfHeight * cosAngle);

double diffLeft = deltaX - (position.x - paddingCorrectedBounds.topLeft.x);
double diffRight = deltaX - (paddingCorrectedBounds.bottomRight.x - position.x);
double targetScaleDiffFactorX = std::min((paddingCorrectedBounds.bottomRight.x - paddingCorrectedBounds.topLeft.x) / (2.0 * deltaX), 1.0);

double diffTop = deltaY - (paddingCorrectedBounds.topLeft.y - position.y);
double diffBottom = deltaY - (position.y - paddingCorrectedBounds.bottomRight.y);
double targetScaleDiffFactorY = std::min((paddingCorrectedBounds.topLeft.y - paddingCorrectedBounds.bottomRight.y) / (2.0 * deltaY), 1.0);

double targetScaleDiffFactor = std::min(targetScaleDiffFactorX, targetScaleDiffFactorY);
Coord newPosition = position;
if (targetScaleDiffFactorX < 1.0) {
newPosition.x = paddingCorrectedBounds.topLeft.x + (paddingCorrectedBounds.bottomRight.x - paddingCorrectedBounds.topLeft.x) / 2.0;
} else {
newPosition.x += (std::max(0.0, diffLeft) - std::max(0.0, diffRight)) * targetScaleDiffFactor;
}
if (targetScaleDiffFactorY < 1.0) {
newPosition.y = paddingCorrectedBounds.bottomRight.y + (paddingCorrectedBounds.topLeft.y - paddingCorrectedBounds.bottomRight.y) / 2.0;
} else {
newPosition.y += (std::max(0.0, diffBottom) - std::max(0.0, diffTop)) * targetScaleDiffFactor;
}

return mapCoords;
double newZoom = zoom * targetScaleDiffFactor;
return {newPosition, newZoom};
}
}

Coord MapCamera2d::adjustCoordForPadding(const Coord &coords, double targetZoom) {
Expand Down Expand Up @@ -856,18 +916,19 @@ RectCoord MapCamera2d::getPaddingCorrectedBounds() {
}

void MapCamera2d::clampCenterToPaddingCorrectedBounds() {
auto const &paddingCorrectedBounds = getPaddingCorrectedBounds();

centerPosition.x =
std::clamp(centerPosition.x, std::min(paddingCorrectedBounds.topLeft.x, paddingCorrectedBounds.bottomRight.x),
std::max(paddingCorrectedBounds.topLeft.x, paddingCorrectedBounds.bottomRight.x));
centerPosition.y =
std::clamp(centerPosition.y, std::min(paddingCorrectedBounds.topLeft.y, paddingCorrectedBounds.bottomRight.y),
std::max(paddingCorrectedBounds.topLeft.y, paddingCorrectedBounds.bottomRight.y));
const auto [newPosition, newZoom] = getBoundsCorrectedCoords(centerPosition, zoom);
centerPosition = newPosition;
zoom = newZoom;
}


void MapCamera2d::setRotationEnabled(bool enabled) { config.rotationEnabled = enabled; }

void MapCamera2d::setSnapToNorthEnabled(bool enabled) { config.snapToNorthEnabled = enabled; }

float MapCamera2d::getScreenDensityPpi() { return screenDensityPpi; }
void MapCamera2d::setBoundsRestrictWholeVisibleRect(bool enabled) {
config.boundsRestrictWholeVisibleRect = enabled;
clampCenterToPaddingCorrectedBounds();
}

float MapCamera2d::getScreenDensityPpi() { return screenDensityPpi; }
5 changes: 4 additions & 1 deletion shared/src/map/camera/MapCamera2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ class MapCamera2d : public MapCamera2dInterface,

virtual void setSnapToNorthEnabled(bool enabled) override;

void setBoundsRestrictWholeVisibleRect(bool centerOnly) override;

virtual float getScreenDensityPpi() override;

protected:
Expand Down Expand Up @@ -178,6 +180,7 @@ class MapCamera2d : public MapCamera2dInterface,
bool twoFingerZoomEnabled = true;
bool moveEnabled = true;
bool snapToNorthEnabled = true;
bool boundsRestrictWholeVisibleRect = false;
};

long long currentDragTimestamp = 0;
Expand Down Expand Up @@ -217,7 +220,7 @@ class MapCamera2d : public MapCamera2dInterface,
std::shared_ptr<DoubleAnimation> rotationAnimation;

Coord adjustCoordForPadding(const Coord &coords, double targetZoom);
Coord getBoundsCorrectedCoords(const Coord &coords);
std::tuple<Coord, double> getBoundsCorrectedCoords(const Coord &position, double zoom);

RectCoord getPaddingCorrectedBounds();
void clampCenterToPaddingCorrectedBounds();
Expand Down

0 comments on commit 2f77f6c

Please sign in to comment.