Daniel Espina
Daniel Espina

Reputation: 674

How fit all coordinates into the bounds of the map? fitBounds equivalent?

I'm making a running app using the Mapbox API and I'm struggling on how set the bounds of MGLMapView to fit all of the polylines the user created by running. Mapbox has a version of this in JavaScript here: https://www.mapbox.com/mapbox-gl-js/example/zoomto-linestring/

But I have no idea how to implement this using swift. I can't find a fitBounds equivalent.

I'm storing each CLLocationCoordinate2D into a Array called pointsArray and passing that to the result view controller along with the mapView.

I had method of finding the longest distance between two points in the array and set that as the bounds but since the algorithm is O(n^2) it takes way too long to calculate if I have too many points. There were also other cases where that wouldn't fit all points.

If there's any particular code you want to see let me know. Not sure what to show since I have nothing to fit the bounds.

Upvotes: 6

Views: 3344

Answers (3)

R. Cozma
R. Cozma

Reputation: 61

This is my solution :

 
mapView.setVisibleCoordinateBounds(generateCoordinatesBounds(forCoordinates: [myCLLocationCoordinate2D]), animated: true)

func generateCoordinatesBounds(forCoordinates coordinates: [CLLocationCoordinate2D]) -> MGLCoordinateBounds {

var maxN = CLLocationDegrees(), maxS = CLLocationDegrees() , maxE = CLLocationDegrees() , maxW = CLLocationDegrees() for coordinates in coordinates { if coordinates.latitude >= maxN || maxN == 0 { maxN = coordinates.latitude } if coordinates.latitude <= maxS || maxS == 0 { maxS = coordinates.latitude } if coordinates.longitude >= maxE || maxE == 0 { maxE = coordinates.longitude } if coordinates.longitude <= maxW || maxW == 0{ maxW = coordinates.longitude } } let offset = 0.001 let maxNE = CLLocationCoordinate2D(latitude: maxN + offset, longitude: maxE + offset) let maxSW = CLLocationCoordinate2D(latitude: maxS - offset, longitude: maxW - offset) return MGLCoordinateBounds(sw: maxSW, ne: maxNE) }


Upvotes: 6

IT Gypsy
IT Gypsy

Reputation: 658

… or you could just do this instead

    mapView?.setVisibleCoordinates(

        coordinates,
        count: UInt(coordinates.count),
        edgePadding: UIEdgeInsetsMake(20, 20, 20, 20),
        animated: true
    )

Upvotes: 14

Gonzalo Dura&#241;ona
Gonzalo Dura&#241;ona

Reputation: 57

You can do something like this O(n) linear algorithm:

var flyTo = MKMapRectNull

for coordinate in coordinateArray {
    // convert CLCoordinate to MKMapPoint
    MKMapPoint point = MKMapPointForCoordinate (coordinate1);

    let pointRect = MKMapRectMake(point.x, point.y, 0, 0)
    if MKMapRectIsNull(flyTo) {
        flyTo = pointRect
    } else {
        flyTo = MKMapRectUnion(flyTo, pointRect)
    }    
}

let coordNE = getCoordinateFromMapRectanglePoint(x: flyTo.origin.x, y: MKMapRectGetMaxY(flyTo))
let coordSW = getCoordinateFromMapRectanglePoint(x: MKMapRectGetMaxX(flyTo), y: flyTo.origin.y)
let coordinateBound = MGLCoordinateBoundsMake(coordSW, coordNE)

var edgeInsets = UIEdgeInsetsMake(20, 20, 20, 20)

mapView.setVisibleCoordinateBounds(coordinateBound, edgePadding: edgeInsets, animated: true)

----

class func getCoordinateFromMapRectanglePoint(x: Double, y: Double) -> CLLocationCoordinate2D {
    let swMapPoint = MKMapPointMake(x, y)
    return MKCoordinateForMapPoint(swMapPoint)
}

Upvotes: 2

Related Questions