How to draw a proper polylines on google maps [closed] - ios

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have successfully drawn a polyline from point a to point b, but for some reason , it shows linear line not the correct waypoints
Here's the code
let path = GMSMutablePath()
path.addLatitude(3.1970044, longitude:101.7389365)
path.addLatitude(3.2058354, longitude:101.729536)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 5.0
polyline.geodesic = true
polyline.map = mapView
I was expecting that it would be doing some waypoints, but it just shows straight polylines

self.googleMapsView is the google maps view.
Example : self.getDirections("26.9211992,75.8185761", destination: "26.8472496,75.7691909", waypoints: ["26.8686811,75.7568383"], travelMode: nil, completionHandler: nil)
Example: google direction link
https://maps.googleapis.com/maps/api/directions/json?origin=26.9211992,75.8185761&destination=26.8472496,75.7691909&waypoints=optimize:true|26.8686811,75.7568383
let baseURLGeocode = "https://maps.googleapis.com/maps/api/geocode/json?"
let baseURLDirections = "https://maps.googleapis.com/maps/api/directions/json?"
var selectedRoute: Dictionary<NSObject, AnyObject>!
var overviewPolyline: Dictionary<NSObject, AnyObject>!
var originCoordinate: CLLocationCoordinate2D!
var destinationCoordinate: CLLocationCoordinate2D!
func getDirections(origin: String!, destination: String!, waypoints: Array<String>!, travelMode: AnyObject!, completionHandler: ((status: String, success: Bool) -> Void)?) {
if let originLocation = origin {
if let destinationLocation = destination {
var directionsURLString = baseURLDirections + "origin=" + originLocation + "&destination=" + destinationLocation
if let routeWaypoints = waypoints {
directionsURLString += "&waypoints=optimize:true"
for waypoint in routeWaypoints {
directionsURLString += "|" + waypoint
}
}
print(directionsURLString)
directionsURLString = directionsURLString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let directionsURL = NSURL(string: directionsURLString)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let directionsData = NSData(contentsOfURL: directionsURL!)
do{
let dictionary: Dictionary<NSObject, AnyObject> = try NSJSONSerialization.JSONObjectWithData(directionsData!, options: NSJSONReadingOptions.MutableContainers) as! Dictionary<NSObject, AnyObject>
let status = dictionary["status"] as! String
if status == "OK" {
self.selectedRoute = (dictionary["routes"] as! Array<Dictionary<NSObject, AnyObject>>)[0]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as! Dictionary<NSObject, AnyObject>
let legs = self.selectedRoute["legs"] as! Array<Dictionary<NSObject, AnyObject>>
let startLocationDictionary = legs[0]["start_location"] as! Dictionary<NSObject, AnyObject>
self.originCoordinate = CLLocationCoordinate2DMake(startLocationDictionary["lat"] as! Double, startLocationDictionary["lng"] as! Double)
let endLocationDictionary = legs[legs.count - 1]["end_location"] as! Dictionary<NSObject, AnyObject>
self.destinationCoordinate = CLLocationCoordinate2DMake(endLocationDictionary["lat"] as! Double, endLocationDictionary["lng"] as! Double)
let originAddress = legs[0]["start_address"] as! String
let destinationAddress = legs[legs.count - 1]["end_address"] as! String
let originMarker = GMSMarker(position: self.originCoordinate)
originMarker.map = self.googleMapsView
originMarker.icon = GMSMarker.markerImageWithColor(UIColor.greenColor())
originMarker.title = originAddress
let destinationMarker = GMSMarker(position: self.destinationCoordinate)
destinationMarker.map = self.googleMapsView
destinationMarker.icon = GMSMarker.markerImageWithColor(UIColor.redColor())
destinationMarker.title = destinationAddress
if waypoints != nil && waypoints.count > 0 {
for waypoint in waypoints {
let lat: Double = (waypoint.componentsSeparatedByString(",")[0] as NSString).doubleValue
let lng: Double = (waypoint.componentsSeparatedByString(",")[1] as NSString).doubleValue
let marker = GMSMarker(position: CLLocationCoordinate2DMake(lat, lng))
marker.map = self.googleMapsView
marker.icon = GMSMarker.markerImageWithColor(UIColor.purpleColor())
}
}
let route = self.overviewPolyline["points"] as! String
let path: GMSPath = GMSPath(fromEncodedPath: route)!
let routePolyline = GMSPolyline(path: path)
routePolyline.map = self.googleMapsView
}
else {
print("status")
//completionHandler(status: status, success: false)
}
}
catch {
print("catch")
// completionHandler(status: "", success: false)
}
})
}
else {
print("Destination is nil.")
//completionHandler(status: "Destination is nil.", success: false)
}
}
else {
print("Origin is nil")
//completionHandler(status: "Origin is nil", success: false)
}
}

For Swift 3.0
Please use this code...
func getDirections(origin: String!, destination: String!, waypoints: Array<String>!, travelMode: AnyObject!, completionHandler: ((_ status: String, _ success: Bool) -> Void)?) {
if let originLocation = origin {
if let destinationLocation = destination {
var directionsURLString = baseURLDirections + "origin=" + originLocation + "&destination=" + destinationLocation
if let routeWaypoints = waypoints {
directionsURLString += "&waypoints=optimize:true"
for waypoint in routeWaypoints {
directionsURLString += "|" + waypoint
}
}
print(directionsURLString)
directionsURLString = directionsURLString.addingPercentEscapes(using: String.Encoding.utf8)!
let directionsURL = NSURL(string: directionsURLString)
DispatchQueue.main.async( execute: { () -> Void in
let directionsData = NSData(contentsOf: directionsURL! as URL)
do{
let dictionary: Dictionary<String, AnyObject> = try JSONSerialization.jsonObject(with: directionsData! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String, AnyObject>
let status = dictionary["status"] as! String
if status == "OK" {
self.selectedRoute = (dictionary["routes"] as! Array<Dictionary<String, AnyObject>>)[0]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as! Dictionary<String, AnyObject>
let legs = self.selectedRoute["legs"] as! Array<Dictionary<String, AnyObject>>
let startLocationDictionary = legs[0]["start_location"] as! Dictionary<String, AnyObject>
self.originCoordinate = CLLocationCoordinate2DMake(startLocationDictionary["lat"] as! Double, startLocationDictionary["lng"] as! Double)
let endLocationDictionary = legs[legs.count - 1]["end_location"] as! Dictionary<String, AnyObject>
self.destinationCoordinate = CLLocationCoordinate2DMake(endLocationDictionary["lat"] as! Double, endLocationDictionary["lng"] as! Double)
let originAddress = legs[0]["start_address"] as! String
let destinationAddress = legs[legs.count - 1]["end_address"] as! String
let originMarker = GMSMarker(position: self.originCoordinate)
originMarker.map = self.mapView
originMarker.icon = UIImage(named: "mapIcon")
originMarker.title = originAddress
let destinationMarker = GMSMarker(position: self.destinationCoordinate)
destinationMarker.map = self.mapView
destinationMarker.icon = UIImage(named: "mapIcon")
destinationMarker.title = destinationAddress
if waypoints != nil && waypoints.count > 0 {
for waypoint in waypoints {
let lat: Double = (waypoint.components(separatedBy: ",")[0] as NSString).doubleValue
let lng: Double = (waypoint.components(separatedBy: ",")[1] as NSString).doubleValue
let marker = GMSMarker(position: CLLocationCoordinate2DMake(lat, lng))
marker.map = self.mapView
marker.icon = UIImage(named: "mapIcon")
}
}
let route = self.overviewPolyline["points"] as! String
let path: GMSPath = GMSPath(fromEncodedPath: route)!
let routePolyline = GMSPolyline(path: path)
routePolyline.map = self.mapView
routePolyline.strokeColor = UIColor(red: 44, green: 134, blue: 200)
routePolyline.strokeWidth = 3.0
}
else {
print("status")
//completionHandler(status: status, success: false)
}
}
catch {
print("catch")
// completionHandler(status: "", success: false)
}
})
}
else {
print("Destination is nil.")
//completionHandler(status: "Destination is nil.", success: false)
}
}
else {
print("Origin is nil")
//completionHandler(status: "Origin is nil", success: false)
}
}

func drawMap ()
{
let str = String(format:"https://maps.googleapis.com/maps/api/directions/json?origin=\(originLatitude),\(originlongitude)&destination=\(destinationlatitude),\(destinationlongitude)&key=AIzaSyC8HZTqt2wsl14eI_cKxxxxxxxxxxxx")
Alamofire.request(str).responseJSON { (responseObject) -> Void in
let resJson = JSON(responseObject.result.value!)
print(resJson)
if(resJson["status"].rawString()! == "ZERO_RESULTS")
{
}
else if(resJson["status"].rawString()! == "NOT_FOUND")
{
}
else{
let routes : NSArray = resJson["routes"].rawValue as! NSArray
print(routes)
let position = CLLocationCoordinate2D(latitude: self.sellerlatitude, longitude: self.sellerlongitude)
let marker = GMSMarker(position: position)
marker.icon = UIImage(named: "mapCurrent")
marker.title = "Customer have selected same location as yours"
marker.map = self.Gmap
let position2 = CLLocationCoordinate2D(latitude: self.Buyyerlatitude, longitude: self.Buyyerlongitude)
let marker1 = GMSMarker(position: position2)
marker1.icon = UIImage(named: "makeupmarker")
marker1.title = self.locationAddress
marker1.map = self.Gmap
let pathv : NSArray = routes.value(forKey: "overview_polyline") as! NSArray
print(pathv)
let paths : NSArray = pathv.value(forKey: "points") as! NSArray
print(paths)
let newPath = GMSPath.init(fromEncodedPath: paths[0] as! String)
let polyLine = GMSPolyline(path: newPath)
polyLine.strokeWidth = 3
polyLine.strokeColor = UIColor.blue
polyLine.map = self.Gmap
let bounds = GMSCoordinateBounds(coordinate: position, coordinate: position2)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(170, 30, 30, 30))
self.Gmap!.moveCamera(update)
}
}
}
For swift 5
func drawMap(SourceCordinate : CLLocationCoordinate2D, destinationcordinate :CLLocationCoordinate2D)
{
self.mapView.clear()
let str = String(format:"https://maps.googleapis.com/maps/api/directions/json?origin=\(SourceCordinate.latitude),\(SourceCordinate.longitude)&destination=\(destinationcordinate.latitude),\(destinationcordinate.longitude)&key=\(googleServiceKey)")
print(str)
Alamofire.request(str).responseJSON { (responseObject) -> Void in
let resJson = JSON(responseObject.result.value!)
print(resJson)
let routes : NSArray = resJson["routes"].rawValue as! NSArray
if(resJson["status"].rawString()! == "ZERO_RESULTS"){}
else if(resJson["status"].rawString()! == "NOT_FOUND"){}
else if routes.count == 0{}
else{
let routes : NSArray = resJson["routes"].rawValue as! NSArray
let position = CLLocationCoordinate2D(latitude: SourceCordinate.latitude, longitude: SourceCordinate.longitude)
/*let marker = GMSMarker(position: position)
marker.icon = #imageLiteral(resourceName: "ic_usermaplocation")//UIImage(named: "ic_MapPinGreyIcon")
marker.title = "" // Addres
marker.map = self.mapView
let position2 = CLLocationCoordinate2D(latitude: destinationcordinate.latitude, longitude: destinationcordinate.longitude)
let marker1 = GMSMarker(position: position2)
marker1.icon = #imageLiteral(resourceName: "ic_usermaplocation")//UIImage(named: "ic_LocationPinRedIcon")
marker1.title = "" // Destination Address
marker1.map = self.mapView*/
let pathv : NSArray = routes.value(forKey: "overview_polyline") as! NSArray
let paths : NSArray = pathv.value(forKey: "points") as! NSArray
let newPath = GMSPath.init(fromEncodedPath: paths[0] as! String)
let polyLine = GMSPolyline(path: newPath)
polyLine.strokeWidth = 5
polyLine.strokeColor = .black
let ThemeOrange = GMSStrokeStyle.solidColor( .black)
let OrangeToBlue = GMSStrokeStyle.gradient(from: .black, to: .black)
polyLine.spans = [GMSStyleSpan(style: ThemeOrange),
GMSStyleSpan(style: ThemeOrange),
GMSStyleSpan(style: OrangeToBlue)]
polyLine.map = self.mapView
let camera = GMSCameraPosition.camera(withLatitude: self.sourceLat, longitude: self.sourceLong, zoom: 15.0)
self.mapView.animate(to: camera)
/*let bounds = GMSCoordinateBounds(coordinate: position, coordinate: position2)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: 100, left: 100, bottom: 400, right: 100))
self.objMapVIew!.moveCamera(update)*/
}
}
}

A small improvement to Azharhussain Shaikh's answer.
func drawMap (src: CLLocationCoordinate2D, dst: CLLocationCoordinate2D) {
let str = String(format:"https://maps.googleapis.com/maps/api/directions/json?origin=\(src.latitude),\(src.longitude)&destination=\(dst.latitude),\(dst.longitude)&key=AIzaSyBKV************")
Alamofire.request(str).responseJSON { (responseObject) -> Void in
let resJson = JSON(responseObject.result.value!)
print(resJson)
if(resJson["status"].rawString()! == "ZERO_RESULTS")
{
}
else if(resJson["status"].rawString()! == "NOT_FOUND")
{
}
else{
let routes : NSArray = resJson["routes"].rawValue as! NSArray
print(routes)
let position = CLLocationCoordinate2D(latitude: src.latitude, longitude: src.longitude)
let marker = GMSMarker(position: position)
marker.icon = UIImage(named: "mapCurrent")
marker.title = "Customer have selected same location as yours"
marker.map = self.mapView
let position2 = CLLocationCoordinate2D(latitude: dst.latitude, longitude: dst.longitude)
let marker1 = GMSMarker(position: position2)
marker1.icon = UIImage(named: "makeupmarker")
marker1.title = "aa"
marker1.map = self.mapView
let pathv : NSArray = routes.value(forKey: "overview_polyline") as! NSArray
print(pathv)
let paths : NSArray = pathv.value(forKey: "points") as! NSArray
print(paths)
let newPath = GMSPath.init(fromEncodedPath: paths[0] as! String)
let polyLine = GMSPolyline(path: newPath)
polyLine.strokeWidth = 3
polyLine.strokeColor = UIColor.blue
polyLine.map = self.mapView
let bounds = GMSCoordinateBounds(coordinate: position, coordinate: position2)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(170, 30, 30, 30))
self.mapView!.moveCamera(update)
}
}
}
To call the function :
let fromLoc = CLLocationCoordinate2DMake(latitude1, longitude1)
let toLoc = CLLocationCoordinate2DMake(latitude2, longitude2)
drawMap(src: fromLoc, dst: toLoc)
What I have changed:
1. Parameter passing
2. Position was given statically. I changed it.

You need to get all the points for the route. To get the route you need to use Google Direction API https://developers.google.com/maps/documentation/directions/. Then use the 1st result of array that will be the shortest one, use the encoded path to draw a poly line using pathFromEncodedPath: method.

Related

Google map in ios direction route not work correctly in swift

I'm trying to draw direction route for two locations.I use this function to route.The problem is that it dosnt work for locations that were drawn before.even I close the app and run again but it dosnt work for previous coordinates as soon as I change the given lat or lon it works for new route! any idea?
func route(){
let origin = "35.6800,51.3819"
let destination = "35.6820,51.3769"
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=\(googleApiKey)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
let routes = json["routes"] as! NSArray
self.mapView.clear()
OperationQueue.main.addOperation({
var route = routes[0] as! NSDictionary
let routeOverviewPolyline:NSDictionary = (route as! NSDictionary).value(forKey: "overview_polyline") as! NSDictionary
let points = routeOverviewPolyline .object(forKey: "points")
let path = GMSPath.init(fromEncodedPath: points! as! String)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 3
let bounds = GMSCoordinateBounds(path: path!)
self.mapView!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 30.0))
polyline.map = self.mapView
//}
})
}catch let error as NSError{
print("error:\(error)")
}
}
}).resume()
}
Add this Variable to use code
var arrayPolyline = [GMSPolyline]()
var selectedRought:String!
func LoadMapRoute()
{
let origin = "35.6800,51.3819"
let destination = "35.6820,51.3769"
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=\(googleApiKey)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler:
{
(data, response, error) in
if(error != nil)
{
print("error")
}
else
{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
let arrRouts = json["routes"] as! NSArray
for polyline in self.arrayPolyline
{
polyline.map = nil;
}
self.arrayPolyline.removeAll()
let pathForRought:GMSMutablePath = GMSMutablePath()
if (arrRouts.count == 0)
{
let distance:CLLocationDistance = CLLocation.init(latitude: self.source.latitude, longitude: self.source.longitude).distance(from: CLLocation.init(latitude: self.destination.latitude, longitude: self.destination.longitude))
pathForRought.add(self.source)
pathForRought.add(self.destination)
let polyline = GMSPolyline.init(path: pathForRought)
self.selectedRought = pathForRought.encodedPath()
polyline.strokeWidth = 5
polyline.strokeColor = UIColor.blue
polyline.isTappable = true
self.arrayPolyline.append(polyline)
if (distance > 8000000)
{
polyline.geodesic = false
}
else
{
polyline.geodesic = true
}
polyline.map = self.mapView;
}
else
{
for (index, element) in arrRouts.enumerated()
{
let dicData:NSDictionary = element as! NSDictionary
let routeOverviewPolyline = dicData["overview_polyline"] as! NSDictionary
let path = GMSPath.init(fromEncodedPath: routeOverviewPolyline["points"] as! String)
let polyline = GMSPolyline.init(path: path)
polyline.isTappable = true
self.arrayPolyline.append(polyline)
polyline.strokeWidth = 5
if index == 0
{
self.selectedRought = routeOverviewPolyline["points"] as? String
polyline.strokeColor = UIColor.blue;
}
else
{
polyline.strokeColor = UIColor.darkGray;
}
polyline.geodesic = true;
}
for po in self.arrayPolyline.reversed()
{
po.map = self.mapView;
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)
{
let bounds:GMSCoordinateBounds = GMSCoordinateBounds.init(path: GMSPath.init(fromEncodedPath: self.selectedRought)!)
self.mapView.animate(with: GMSCameraUpdate.fit(bounds))
}
}
catch let error as NSError
{
print("error:\(error)")
}
}
}).resume()
}

Show Path on GoogleMaps in Swift4

My question is I want to draw the time between two points and my both location are coming from different controllers
for my first Location :-
extension HomeViewController: PickupLocationDelegate {
func didSelectLocation(place: GooglePlaceModel?) {
guard let place = place else {return}
enter_Location_TF.text = place.name
customDirectionViewTwo.isHidden = false
direction_Button.isHidden = true
location_Button.setImage(UIImage(named: "directionPoint")?.withRenderingMode(.alwaysOriginal), for: .normal)
pickupMarkers.forEach { (marker) in
marker.map = nil
}
let position = CLLocationCoordinate2D(latitude: place.latitude , longitude: place.longitude)
print(position)
let path = GMSMutablePath()
path.add(CLLocationCoordinate2D(latitude: place.latitude, longitude: place.longitude))
let marker = GMSMarker()
marker.position = position
marker.map = mapView
mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
pickupMarkers.append(marker)
}
}// My second location:-
extension HomeViewController: DropLocationDelegate {
func didSelectDrop(location: GooglePlaceModel?) {
guard let location = location else {return}
dropLocationLbl?.text = location.name
let position = CLLocationCoordinate2D(latitude: location.latitude , longitude: location.longitude)
print(position)
let marker = GMSMarker(position: position)
marker.icon = #imageLiteral(resourceName: "icon-drop-location")
marker.map = mapView
mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
pickupMarkers.append(marker)
let path = GMSMutablePath()
path.add(CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude))
pickupMarkers.forEach { (marker) in
path.add(marker.position)
}
let bounds = GMSCoordinateBounds(path: path)
mapView?.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
}
}
marker are showing correctly but the path is not showing. I used the
GMSMutable path to draw the line between location but this is not working properly. Any help?
Preconditions
You need to get a Google directions api Key following this link
How to get a Google Directions API key and you also need to add this line
GMSPlacesClient.provideAPIKey("Your API KEY")
in your AppDelegate didFinishLaunchingWithOptions method
Now our issue
To find a path you need to use a method like this one, using googleapis.directions request, passing two CLLocationCoordinate2D then in the closure you will get an array of CLLocationCoordinate2D which are the waypoints of your path
public func getWaypointsAsArrayOfCoordinates(startLocation: CLLocationCoordinate2D, endLocation: CLLocationCoordinate2D, mode:String? = "walking", lang:String? = "en", finishedClosure:#escaping (([CLLocationCoordinate2D])->Void)){
var resultedArray:[CLLocationCoordinate2D] = []
let urlWithParams = "https://maps.googleapis.com/maps/api/directions/json" + self.customEncodedParameters(parametersDict: ["origin":"\(startLocation.latitude),\(startLocation.longitude)", "destination": "\(endLocation.latitude),\(endLocation.longitude)", "mode": mode!, "key":googleDirectionsApiKey, "language" : lang!])
var urlRequest = URLRequest(url: URL(string: urlWithParams)!)
urlRequest.httpMethod = "GET"
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if let _ = error {
} else {
do {
if let jsonData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary {
let status = jsonData["status"] as! String
if(status == "OK") {
for routeDict in jsonData["routes"] as! Array<Dictionary<String, AnyObject>>
{
let legs = routeDict["legs"] as! Array<Dictionary<String, AnyObject>>
for leg in legs
{
let steps = leg["steps"] as! Array<Dictionary<String, AnyObject>>
for (index,step) in steps.enumerated(){
let start = step["start_location"] as! Dictionary<String,Any>
let end = step["end_location"] as! Dictionary<String,Any>
resultedArray.append(CLLocationCoordinate2D(latitude: start["lat"] as! CLLocationDegrees, longitude: start["lng"] as! CLLocationDegrees))
if(index == steps.count - 1) {
resultedArray.append(CLLocationCoordinate2D(latitude: end["lat"] as! CLLocationDegrees, longitude: end["lng"] as! CLLocationDegrees))
}
}
}
}
finishedClosure(resultedArray)
}
else {
print("not found")
finishedClosure([])
}
}
} catch {
print(error)
finishedClosure([])
}
}
}.resume()
}
Edit (Added missing function)
private func customEncodedParameters(parametersDict:[String:String]) ->String
{
let charactersAllowed = CharacterSet.urlQueryAllowed
var returnStr = ""
for key in parametersDict.keys {
if(returnStr.count == 0)
{
returnStr += "?"
returnStr += key.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
returnStr += "="
returnStr += parametersDict[key]!.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
}else{
returnStr += "&"
returnStr += key.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
returnStr += "="
returnStr += parametersDict[key]!.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
}
}
return returnStr
}
Then you can use it in your code like this
extension HomeViewController: DropLocationDelegate {
func didSelectDrop(location: GooglePlaceModel?) {
guard let location = location else {return}
dropLocationLbl?.text = location.name
let position = CLLocationCoordinate2D(latitude: location.latitude , longitude: location.longitude)
print(position)
let marker = GMSMarker(position: position)
marker.icon = #imageLiteral(resourceName: "icon-drop-location")
marker.map = mapView
mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
pickupMarkers.append(marker)
self.getWaypointsAsArrayOfCoordinates(startLocation: pickupMarkers.first.position , endLocation: pickupMarkers.last.position) { [weak self] (arrayOfCoordinates) in
DispatchQueue.main.async {
let path = GMSMutablePath()
for coordinate in arrayOfCoordinates {
path.add(coordinate)
}
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 2
polyline.strokeColor = UIColor.red
polyline.map = self?.mapView
let bounds = GMSCoordinateBounds(path: path)
self?.mapView?.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
}
}
}
}

PolyLines not showing in google maps

I want show path between destination and source on google map. I am google direction api's getting route between of co-ordinates , I am getting response and set on google map but not showing on map . My code is
func getPolylineRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D){
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=true&mode=driving&key=AIzaSyAyU5txJ86b25-_l0DW-IldSKGGYqQJn3M")!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
DispatchQueue.main.async {
if error != nil {
print(error!.localizedDescription)
AppManager.dissmissHud()
}
else {
do {
if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]{
guard let routes = json["routes"] as? NSArray else {
DispatchQueue.main.async {
AppManager.dissmissHud()
}
return
}
if (routes.count > 0) {
let overview_polyline = routes[0] as? NSDictionary
let dictPolyline = overview_polyline?["overview_polyline"] as? NSDictionary
let points = dictPolyline?.object(forKey: "points") as? String
self.showPath(polyStr: points!)
DispatchQueue.main.async {
AppManager.dissmissHud()
let bounds = GMSCoordinateBounds(coordinate: source, coordinate: destination)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(75, 20, 20, 20))
self.vwMap!.moveCamera(update)
}
}
else {
DispatchQueue.main.async {
AppManager.dissmissHud()
}
}
}
}
catch {
print("error in JSONSerialization")
DispatchQueue.main.async {
AppManager.dissmissHud()
}
}
}
}
})
task.resume()
}
func drawPlyLineOnMap() {
let source : CLLocationCoordinate2D = CLLocationCoordinate2DMake(Double((model?.fromAddressLatitude)!), Double((model?.fromAddressLongtitude)!))
let destination : CLLocationCoordinate2D = CLLocationCoordinate2DMake(Double((model?.toAddressLatitude)!), Double((model?.toAddressLongtitude)!))
self.vwMap.clear()
//Source pin
let marker = GMSMarker()
let markerImage = UIImage(named: "from_pin")!.withRenderingMode(.alwaysOriginal)
let markerView = UIImageView(image: markerImage)
marker.position = source
marker.iconView = markerView
//marker.userData = dict
marker.map = vwMap
//Destination pin
let markerTo = GMSMarker()
let markerImageTo = UIImage(named: "to_red_pin")!.withRenderingMode(.alwaysOriginal)
let markerViewTo = UIImageView(image: markerImageTo)
markerTo.position = destination
// marker.userData = dict
markerTo.iconView = markerViewTo
markerTo.map = vwMap
var arrAdTemp:[AddressTableModel] = []
arrAdTemp.append(contentsOf: arrAddresses)
arrAdTemp.removeLast()
arrAdTemp.removeFirst()
for obj in arrAdTemp {
print(obj.strLatitude)
print(obj.strLongtitude)
let stopOver : CLLocationCoordinate2D = CLLocationCoordinate2DMake(obj.strLatitude, obj.strLongtitude)
let markerStop = GMSMarker()
let markerImageStop = UIImage(named: "to_red_pin")!.withRenderingMode(.alwaysOriginal)
let markerViewStop = UIImageView(image: markerImageStop)
markerStop.position = stopOver
//marker.userData = dict
markerStop.iconView = markerViewStop
markerStop.map = vwMap
}
self.getPolylineRoute(from: source, to: destination)
}
func showPath(polyStr :String){
let path = GMSPath(fromEncodedPath: polyStr)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.strokeColor = UIColor.black
polyline.map = vwMap // Your map view
}
I have tried lot of answer give below but not working for me. Please help me.
1st answer tried
2nd answer tried
3rd answer tried
you are setting wrong bounds so it is not showing on your map . I have tried your code it is working fine . Please change your bounds area as (0,0,0,0)
func getPolylineRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D){
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=true&mode=driving&key=AIzaSyAyU5txJ86b25-_l0DW-IldSKGGYqQJn3M")!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
DispatchQueue.main.async {
if error != nil {
print(error!.localizedDescription)
AppManager.dissmissHud()
}
else {
do {
if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]{
guard let routes = json["routes"] as? NSArray else {
DispatchQueue.main.async {
AppManager.dissmissHud()
}
return
}
if (routes.count > 0) {
let overview_polyline = routes[0] as? NSDictionary
let dictPolyline = overview_polyline?["overview_polyline"] as? NSDictionary
let points = dictPolyline?.object(forKey: "points") as? String
self.showPath(polyStr: points!)
DispatchQueue.main.async {
AppManager.dissmissHud()
let bounds = GMSCoordinateBounds(coordinate: source, coordinate: destination)
//below bounds change as 0 check it on full screen
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(0, 0, 0, 0))
self.vwMap!.moveCamera(update)
}
}
else {
DispatchQueue.main.async {
AppManager.dissmissHud()
}
}
}
}
catch {
print("error in JSONSerialization")
DispatchQueue.main.async {
AppManager.dissmissHud()
}
}
}
}
})
task.resume()
}
I did the same using this code have a look.
{let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(self.currentLocation.coordinate.latitude),\(self.currentLocation.coordinate.longitude)&destination=\(33.6165),\(73.0962)&key=yourKey")
let request = URLRequest(url: url!)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
// notice that I can omit the types of data, response and error
do{
let json = JSON(data!)
let errornum = json["error"]
if (errornum == true){
}else{
let routes = json["routes"].array
if routes != nil && (routes?.count)! > 0{
let overViewPolyLine = routes![0]["overview_polyline"]["points"].string
let dict = routes![0].dictionaryValue
let distance = dict["legs"]?[0]["distance"]
_ = distance?["text"].stringValue
let duaration = dict["legs"]?[0]["duration"]
_ = duaration?["text"].stringValue
//dict["legs"]?["distance"]["text"].stringValue
print(overViewPolyLine!)
if overViewPolyLine != nil{
DispatchQueue.main.async() {
self.addPolyLineWithEncodedStringInMap(encodedString: overViewPolyLine!)
}
}
}
}
and then
{
func addPolyLineWithEncodedStringInMap(encodedString: String) {
let path = GMSPath(fromEncodedPath: encodedString)!
let polyLine = GMSPolyline(path: path)
polyLine.strokeWidth = 5
polyLine.strokeColor = UIColor.yellow
polyLine.map = self.googleMapsView
let center = CLLocationCoordinate2D(latitude: 33.6165, longitude: 73.0962)
let marker = GMSMarker(position: center)
marker.map = self.googleMapsView
}
func decodePolyline(encodedString: String){
let polyline = Polyline(encodedPolyline: encodedString)
let decodedCoordinates: [CLLocationCoordinate2D]? = polyline.coordinates
for coordinate in decodedCoordinates! {
let marker = GMSMarker(position: coordinate)
marker.icon = UIImage(named: "mapPin")
marker.map = self.googleMapsView
}
}

Function is being executed more than once

I have been knocking my head over this problem for a few days now. I have a function that
1) gets the snapshot values and then stores them into filteredLocations array
2) gets the location the user has pressed on the screen, then measures the distance between the two location points of where they pressed on the screen and the location from the snapshots
3) filters out the locations that meet the users radiusDistance and then places points on the map
The problem that I keep coming across though is with my print statements check 1 and check 2. They are being executed twice when it should only be once.
func addAnnotation(gestureRecognizer:UIGestureRecognizer){
filteredLocations.removeAll()
locations.removeAll()
let sampleRef = FIRDatabase.database().reference().child("SamplePost").child("post")
sampleRef.observeSingleEvent(of:.value, with: {(snapshot) in
if let result = snapshot.children.allObjects as? [FIRDataSnapshot] {
for child in result{
let dictionary = child.value as? [String: AnyObject]
let lat = dictionary?["lat"] as! Double
let long = dictionary?["long"] as! Double
let image = dictionary?["image"] as! String
let text = dictionary?["text"] as! String
let user = dictionary?["user"] as! String
let structure = MapPoints(Latitude: lat, Longitude: long, Image: image, Text: text, User: user)
self.filteredLocations.append(structure)
self.locations.append(structure)
print("check one \(self.filteredLocations.count)")
self.collectionView.reloadData()
}
}
let refined = Double(self.radiusDistanceNumber!)
print("check two \(self.filteredLocations.count)")
if gestureRecognizer.state == UIGestureRecognizerState.began{
self.removePointsAndClearArray()
let touchPoint = gestureRecognizer.location(in: self.mapView)
let newCoordinates = self.mapView.projection.coordinate(for: touchPoint)
let marker = GMSMarker(position: newCoordinates)
marker.title = "Selected location"
self.filteredLocations = self.locations.filter {
(locations) in
let userLocation = newCoordinates
let userLat = userLocation.latitude
let userLong = userLocation.longitude
let coordinateOne = CLLocation(latitude: userLat, longitude: userLong)
let coordinateTwo = CLLocation(latitude: CLLocationDegrees(locations.latitude!), longitude: CLLocationDegrees(locations.longitude!))
let distanceFromPoints = coordinateOne.distance(from: coordinateTwo)
let convertToMiles = distanceFromPoints*0.00062137
return convertToMiles < refined
}
print("check three \(self.filteredLocations.count)")
self.filteredLocations.map {
(location) in
let annotation = GMSMarker()
annotation.position = CLLocationCoordinate2D(latitude: CLLocationDegrees(location.latitude!), longitude: CLLocationDegrees(location.longitude!))
annotation.map = self.mapView
let camera = GMSCameraPosition.camera(withTarget: newCoordinates, zoom: 11)
self.mapView.animate(to: camera)
}
print("amount that is being counted \(self.filteredLocations.count)")
if self.filteredLocations.count <= 0 {
self.collectionView.isUserInteractionEnabled = false
} else{
self.collectionView.isUserInteractionEnabled = true
}
print("amount before reloading collectionView \(self.filteredLocations.count)")
self.collectionView.reloadData()
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: {
})
}
})
}

How to get centre of the route map using GoogleMaps sdk

I want to display an image at the centre of the route map.
Below is the code used for directions between origin and destination:
let camera1 = GMSCameraPosition.camera(withLatitude: 45.4654, longitude:9.1859, zoom: 0.0)
self.mapView = GMSMapView.map(withFrame: cell.mapView.bounds, camera: camera1)
Alamofire.request(url, method: .post, parameters: nil, encoding: JSONEncoding.default, headers: nil)
.validate()
.responseJSON { response in
switch response.result {
case .success:
print(response.result.value!)
print("Validation Successful")
let dictResponse = response.result.value as! NSDictionary
print(dictResponse)
let aryRoutes = dictResponse .value(forKey:"routes" ) as! NSArray
print(aryRoutes)
var aryOverViewPolyLines :NSArray = []
aryOverViewPolyLines = aryRoutes .value(forKey: "overview_polyline") as! NSArray
print(aryOverViewPolyLines)
let strPoints = (aryOverViewPolyLines.value(forKey: "points") as! NSArray).object(at: 0)
let polygon = GMSPolygon()
polygon.path = GMSPath(fromEncodedPath: strPoints as! String)
print(strPoints)
let rectangle = GMSPolyline.init(path: polygon.path)
rectangle.strokeWidth = 2.0
rectangle.strokeColor = .white
rectangle.map = self.mapView
let mapBounds = GMSCoordinateBounds(path: polygon.path!)
self.mapView.animate(with: GMSCameraUpdate.fit(mapBounds, withPadding: 150.0))
case .failure(let error):
print(response.result.value!)
print(error)
}
}
Any suggestions how to solve this issue.
The solution from #mnabaa works by finding the middle path on the polyline. However, some paths could be a lot longer in distance than others. As a result, the point returned by Mnabaa's solution could end up somewhere a lot closer to the point A than the point B depending on the route. The extension below takes this problem into account:
extension GMSPolyline {
var middlePoint: CLLocationCoordinate2D? {
guard let path = path else {
return nil
}
var intermediatePoints: [CLLocationCoordinate2D] = []
for coordinateIndex in 0 ..< path.count() - 1 {
let startCoordinate = path.coordinate(at: coordinateIndex)
let endCoordinate = path.coordinate(at: coordinateIndex + 1)
let startLocation = CLLocation(latitude: startCoordinate.latitude, longitude: startCoordinate.longitude)
let endLocation = CLLocation(latitude: endCoordinate.latitude, longitude: endCoordinate.longitude)
let pathDistance = endLocation.distance(from: startLocation)
let intervalLatIncrement = (endLocation.coordinate.latitude - startLocation.coordinate.latitude) / pathDistance
let intervalLngIncrement = (endLocation.coordinate.longitude - startLocation.coordinate.longitude) / pathDistance
for intervalDistance in 0 ..< Int(pathDistance) {
let intervalLat = startLocation.coordinate.latitude + (intervalLatIncrement * Double(intervalDistance))
let intervalLng = startLocation.coordinate.longitude + (intervalLngIncrement * Double(intervalDistance))
let circleCoordinate = CLLocationCoordinate2D(latitude: intervalLat, longitude: intervalLng)
intermediatePoints.append(circleCoordinate)
}
}
return intermediatePoints[intermediatePoints.count / 2]
}
}
It's based on the article by Dylan Maryk.
func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) {
if let route = overlay as? GMSPolyline{
let coordinate = route.path!.coordinate(at: (route.path!.count()-1) / 2)
route.customMapInfoMarker!.position = CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude)
route.customMapInfoMarker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
route.customMapInfoMarker.map = mapView
route.customMapInfoMarker.iconView = // YOUR CUSTOM IMAGEVIEW HERE
}
}
Extend GMSPolyline
extension GMSPolyline{
fileprivate struct AssociatedKey {
static var infoMarker = GMSMarker()
}
var customMapInfoMarker: GMSMarker! {
get {
if let marker = objc_getAssociatedObject(self, &AssociatedKey.infoMarker) as? GMSMarker {
return marker
}
return GMSMarker()
}
set (newValue){
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKey.infoMarker,
newValue,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}

Resources