1

I am trying to draw route on mapview using the google direction API . I am using the solution from the stackoverflow itself but i am getting some errors regarding intializers . Also will the directions route will be same as google map itself or a straight one . Any help is Appreciated. Also where should i call this methods I am getting error as

Cannot invoke initializer for type 'GMSCoordinateBounds' with an argument list of type '(coordinate: String, String, coordinate: String, String)'

Below is the Code .

 func getRouteSteps(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {

        let session = URLSession.shared

        let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(lat),\(long)&destination=\(directionlat),\(directionlong)&sensor=false&mode=driving&key=\(API KEY)")!

        let task = session.dataTask(with: url, completionHandler: {
            (data, response, error) in

            guard error == nil else {
                print(error!.localizedDescription)
                return
            }

            guard let jsonResult = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] else {

                print("error in JSONSerialization")
                return

            }



            guard let routes = jsonResult!["routes"] as? [Any] else {
                return
            }

            guard let route = routes[0] as? [String: Any] else {
                return
            }

            guard let legs = route["legs"] as? [Any] else {
                return
            }

            guard let leg = legs[0] as? [String: Any] else {
                return
            }

            guard let steps = leg["steps"] as? [Any] else {
                return
            }
            for item in steps {

                guard let step = item as? [String: Any] else {
                    return
                }

                guard let polyline = step["polyline"] as? [String: Any] else {
                    return
                }

                guard let polyLineString = polyline["points"] as? String else {
                    return
                }

                //Call this method to draw path on map
                DispatchQueue.main.async {
                    self.drawPath(from: polyLineString)
                }

            }
        })
        task.resume()
    } 

Function to draw polyline

 func drawPath(from polyStr: String){
        let mapView: GMSMapView
        let path = GMSPath(fromEncodedPath: polyStr)
        let polyline = GMSPolyline(path: path)
        polyline.strokeWidth = 3.0
        polyline.map = mapView // Google MapView

//
        let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: "\(lat)","\(long)", coordinate: "\(directionlat)","\(directionlong)")) as? [String : AnyObject]
        mapView.moveCamera(cameraUpdate)
        let currentZoom = mapView.camera.zoom
        mapView.animate(toZoom: currentZoom - 1.4)
    }

Keshu R.
  • 5,045
  • 1
  • 18
  • 38
Deven Nazare
  • 538
  • 5
  • 24

2 Answers2

2

GMSCoordinatesBounds takes CLLocationCoordinates2D type as parameter, not String.

replace

let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: "\(lat)","\(long)", coordinate: "\(directionlat)","\(directionlong)")) as? [String : AnyObject]

with

let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(long)), coordinate: CLLocationCoordinate2D(latitude: Double(directionlat), longitude: Double(directionlat))))

and once you have added the mapView to your view controller and got the coordinates, call your function

self.getRouteSteps(from source: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(long)), destination: CLLocationCoordinate2D(latitude: Double(directionlat), longitude: Double(directionlat)))
Keshu R.
  • 5,045
  • 1
  • 18
  • 38
  • Actually i am storing the directionlat and directiolong as a string ! and there i am getting error as " Cannot convert value of type 'String' to expected argument type 'CLLocationDegrees' (aka 'Double') " – Deven Nazare Feb 10 '20 at 06:19
  • @DevenNazare did you try my code? I have already made that correction. – Keshu R. Feb 10 '20 at 06:32
  • R yes i tried thats where i am getting the above error . Also where should i call the methods to draw the route – Deven Nazare Feb 10 '20 at 06:39
  • @DevenNazare check my answer again. you are not doing it right. – Keshu R. Feb 10 '20 at 06:42
  • Yes the error got solved ! But where should i call this methods ?? and how?? – Deven Nazare Feb 10 '20 at 06:46
  • @DevenNazare once you have added the mapView to your view controller and got the coordinates, call your function – Keshu R. Feb 10 '20 at 06:52
  • i have many different points on the map . which parameters should i pass to which function so that when i click on the direction button routes should be drawn – Deven Nazare Feb 10 '20 at 07:01
  • @DevenNazare your `getRouteSteps` function takes two parameters. one is `source` and one is `destination`. What is so confusing about it? Just pass the source and destination coordinates in `getRouteSteps` function to show the route. – Keshu R. Feb 10 '20 at 07:06
  • i called this function as ** getRouteSteps(fromsource: "\(lat),\(long)", todestination: "\(directionlat),\(directionlong)") ** on the direction button and it gave me error as ----- Cannot convert value of type 'String' to expected argument type 'CLLocationCoordinate2D' @Keshu R. – Deven Nazare Feb 10 '20 at 07:20
  • @DevenNazare i have already updated in the answer how to call the function . `self.getRouteSteps(from source: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(long)), destination: Double(directionlat), longitude: Double(directionlat)))` – Keshu R. Feb 10 '20 at 07:22
  • Cannot convert value of type '(Double?, longitude: Double?)' to expected argument type 'CLLocationCoordinate2D' @ keshu R – Deven Nazare Feb 10 '20 at 07:35
  • @DevenNazare `self.getRouteSteps(from source: CLLocationCoordinate2D(latitude: Double(lat) ?? 0.0, longitude: Double(long) ?? 0.0), destination: Double(directionlat) ?? 0.0, longitude: Double(directionlat) ?? 0.0))` . – Keshu R. Feb 10 '20 at 07:39
  • self.getRouteSteps(fromsource: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(long)), todestination: Double(cordlat), longitude: Double(cordlong)) . Getting error as extra argument longitude in call . @Keshu R. – Deven Nazare Feb 10 '20 at 09:51
  • @DevenNazare ah sorry i missed : `self.getRouteSteps(from source: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(long)), destination: CLLocationCoordinate2D(latitude: Double(directionlat), longitude: Double(directionlat)))` . But these are the kind of issues which you should be able to fix by youself. This is basic Swift. – Keshu R. Feb 10 '20 at 09:56
  • Thanks ! its Working now !! really appreciate your help ! but how to clear the polyline if i want to draw a new one the polyline are not getting cleared – Deven Nazare Feb 10 '20 at 10:55
  • @DevenNazare you can do `mapView.clear()` before adding a new polyline. – Keshu R. Feb 10 '20 at 10:56
  • but doing this will also remove my Map markers right??? @Keshu R. – Deven Nazare Feb 10 '20 at 11:14
  • @DevenNazare this will help: https://stackoverflow.com/questions/44427897/swift-3-how-to-remove-the-tracked-polyline-in-google-map – Keshu R. Feb 10 '20 at 11:15
1

You can try this, use the below to fetch direction:

  //This function is used to fetch the directions from origin to destination

private func fetchDirection(destinationLat: CLLocationDegrees, destinationLong: CLLocationDegrees) {

    //Here you need to set your origin and destination points and mode

    if let location = locationManager.location {


            guard let url = URL(string: "\("https://maps.googleapis.com/maps/api/directions/json")?origin=\(location.coordinate.latitude),\(location.coordinate.longitude)&destination=\(destinationLat),\(destinationLong)&key=\(Constants.MapKey)") else { return }

            let task = URLSession.shared.dataTask(with: url) { [unowned self](data, response, error) -> Void in

                do {

                    guard let data = data else { return }

                    let decoder = JSONDecoder()

                    decoder.keyDecodingStrategy = .convertFromSnakeCase

                    guard let mapData = try? decoder.decode(MapModel.self, from: data) else { return }

                    if let points = mapData.routes.first?.overviewPolyline.points {

                        self.drawRoute(points: points)

                    }
                }

            }

            task.resume()

    }
}

Use this to draw the route on the map:

    //This function is used to draw the routes

private func drawRoute(points: String) {


        let path = GMSPath.init(fromEncodedPath: points)
        let singleLine = GMSPolyline.init(path: path)
        self.polylines.append(singleLine)
        singleLine.strokeWidth = 6.0
        let gradientColor: GMSStrokeStyle = GMSStrokeStyle.gradient(from: .red, to: .blue)
        singleLine.spans = [GMSStyleSpan.init(style: gradientColor)]

        if  self.polylines.count > 0 {

            self.polylines.forEach{ $0.map = nil }

        }

        singleLine.map = self.mapView

}

And, here is the MapModel

struct MapModel: Decodable {

let status: String
let routes: [Routes]
}

struct Routes: Decodable {

let overviewPolyline: OverviewPolyline
}

struct OverviewPolyline: Decodable {

let points: String
}

I hope you are familiar with Codables and also, I have called the drawRoute function when I received the points.

Rob
  • 2,086
  • 18
  • 25