maplibre / maplibre-native

MapLibre Native - Interactive vector tile maps for iOS, Android and other platforms.
https://maplibre.org
BSD 2-Clause "Simplified" License
1.01k stars 296 forks source link

Camera does not follow the user properly when edgePaddings are set #958

Open olkiz opened 1 year ago

olkiz commented 1 year ago

Describe the bug This bug was opened in maplibre navigation SDK project (https://github.com/maplibre/maplibre-navigation-ios/issues/1), but In my opinion, there is a bug in maplibre gl native. So to reproduce the bug you should use the build of https://github.com/maplibre/maplibre-navigation-ios.

To Reproduce Steps to reproduce the behavior:

  1. Build a route
  2. Turn on the simulation
  3. Start navigation

Expected behavior The camera should start following the user's fix

Screenshots https://user-images.githubusercontent.com/10522249/228496547-9ce3187d-1c98-407f-bb09-fc34ca02bb19.mp4

Platform information (please complete the following information):

Additional context If remove the edgePaddings argument from the setCamera in NavigationMapView::updateCourseTracking from navigation SDK, the camera starts to follow, but there is no offset (the puck is on the center of the camera).

louwers commented 1 year ago

Could you provide a reproduction of the issue that does not involve maplibre-navigation-ios?

olkiz commented 1 year ago

I'm unsure if I reproduced it well as in maplibre-navigation-sdk, but I see the difference between using edgePadding in setCamera and without it. For location simulation, I've used a freeway drive.

With edgePadding: https://user-images.githubusercontent.com/10522249/229349389-199c76fa-2e8e-46b6-80ef-dbdf9ced4977.mp4

Without edgePadding: https://user-images.githubusercontent.com/10522249/229349445-c2c9f483-6c5f-4743-8054-6b7b9c7631d6.mp4

Code (with edgePadding):

import Foundation
import UIKit
import Mapbox

class ViewController: UIViewController, MLNMapViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        title = "Simple Map"
        // construct style URL
        let styleURL = URL(string: "https://demotiles.maplibre.org/style.json")
        // create the map view
        let mapView = MLNMapView(frame: view.bounds, styleURL: styleURL)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.delegate = self

        mapView.showsUserLocation = true
        mapView.logoView.isHidden = true
        // Set the map’s center coordinate and zoom level.
        mapView.setCenter(
            CLLocationCoordinate2D(latitude: 41.902706, longitude: 12.496398),
            zoomLevel: 10,
            animated: false)
        view.addSubview(mapView)
    }

    func mapView(_ mapView: MLNMapView, didUpdate userLocation: MLNUserLocation?) {
        let contentFrame = self.view.bounds.inset(by: self.view.safeAreaInsets)
        let courseViewWidth = 0.0
        let courseViewHeight = 0.0
        let edgePadding = UIEdgeInsets(top: (50 + courseViewHeight / 2),
                                       left: (50 + courseViewWidth / 2),
                                       bottom: (50 + courseViewHeight / 2),
                                       right: (50 + courseViewWidth / 2))
        let point = CGPoint(x: max(min(contentFrame.midX,
                                  contentFrame.maxX - edgePadding.right),
                              contentFrame.minX + edgePadding.left),
                       y: max(max(min(contentFrame.minY + contentFrame.height * 0.8,
                                      contentFrame.maxY - edgePadding.bottom),
                                  contentFrame.minY + edgePadding.top),
                              contentFrame.minY + contentFrame.height * 0.5))

        let padding = UIEdgeInsets(top: point.y, left: point.x, bottom: self.view.bounds.height - point.y, right: self.view.bounds.width - point.x)

        let function: CAMediaTimingFunction? = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
        guard let userLocation = userLocation else { return }
        if let heading = userLocation.heading {
            mapView.setCamera(MLNMapCamera(lookingAtCenter: userLocation.coordinate, fromDistance: 500, pitch: 45, heading: CLLocationDirection(heading.trueHeading)), withDuration: 1, animationTimingFunction: function, edgePadding: padding, completionHandler: nil)
        } else {
            mapView.setCamera(MLNMapCamera(lookingAtCenter: userLocation.coordinate, fromDistance: 500, pitch: 45, heading: CLLocationDirection(0.0)), withDuration: 1, animationTimingFunction: function, edgePadding: padding, completionHandler: nil)
        }
    }

}

To reproduce without edgePadding, remove from functions mapView.setCamera edgePadding argument.

georgbachmann commented 1 year ago

Is there any status-update on that one? I have the same problem using maplibre-navigation for iOS and it would be awesome to have that workin again :)