Remove travelled path from GMSPolyline on GMSMapView Swift iOS - ios

I am using google distance api ["https://maps.googleapis.com/maps/api/directions/json?origin=" +start.latitude + "," + start.longitude +"&destination=" + end.latitude +"," + end.longitude + "&alternatives=false" +"&mode=driving&key=" + key;] to get route from start location to end location.
I am using the following code to draw route between my start and destination location
func drawPath()
{
if polylines != nil {
polylines?.map = nil
polylines = nil
}
if animationPolyline != nil {
self.animationIndex = 0
self.animationPath = GMSMutablePath()
self.animationPolyline.map = nil
if self.timer != nil {
self.timer.invalidate()
}
}
setupStartRideLocationMarkup(CLLocationCoordinate2D(latitude: (currentLocation?.coordinate.latitude)!, longitude: (currentLocation?.coordinate.longitude)!))
if currentLocation != nil && destinationLocation != nil {
let origin = "\((currentLocation?.coordinate.latitude)!),\((currentLocation?.coordinate.longitude)!)"
let destination = "\((destinationLocation?.latitude)!),\((destinationLocation?.longitude)!)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=MY_API_KEY"
Alamofire.request(url).responseJSON { response in
let json = JSON(data: response.data!)
self.jsonRoute = json
let routes = json["routes"].arrayValue
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
self.path = GMSPath.init(fromEncodedPath: points!)!
self.polylines = GMSPolyline.init(path: self.path)
self.polylines?.geodesic = true
self.polylines?.strokeWidth = 5
self.polylines?.strokeColor = UIColor.black
self.polylines?.map = self.mapView
}
self.shouldDrawPathToStartLocation()
self.shouldDrawPathToEndLocation()
if routes.count > 0 {
self.startAnimatingMap()
}
}
}
}
As you can see I am initialising path with encoded path from the api. Now I want to remove travelled GMSPolyline from the overall path How can I do that? My current intiuation is that it will be from didUpdateLocations Here's my code of didUpdateLocations method
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
currentLocation = locations.last!
let camera = GMSCameraPosition.camera(withLatitude: (currentLocation?.coordinate.latitude)!,
longitude: (currentLocation?.coordinate.longitude)!,
zoom: zoomLevel)
if (mapView?.isHidden)! {
mapView?.isHidden = false
mapView?.camera = camera
} else {
mapView?.animate(to: camera)
}
updatePolyLineIfRequired()
}
And in updatePolyLineIfRequired I want to remove travelled poly lines
func updatePolyLineIfRequired(){
if GMSGeometryIsLocationOnPath((currentLocation?.coordinate)!, path, true) {
if startPolyline != nil {
startPolyline?.map = nil
startPolyline = nil
}
}
}
I want to implement solution like Uber or Careem where travelled drawn GMSPolyline gets removed till user current location.
Thanks in Advance
P.S I am using Alamofire SwiftyJSON

There are two solutions for this:-
Calling Directions Api each time didUpdateLocations function is called.(Not efficient)
Removing the travelled coordinates from the GMSPath.
Calling Directions api will be not useful unless your request limit for Direction api is less.
For removing the travelled coordinates from the path:-
//Call this function in didUpdateLocations
func updateTravelledPath(currentLoc: CLLocationCoordinate2D){
var index = 0
for i in 0..<self.path.count(){
let pathLat = Double(self.path.coordinate(at: i).latitude).rounded(toPlaces: 3)
let pathLong = Double(self.path.coordinate(at: i).longitude).rounded(toPlaces: 3)
let currentLaenter code heret = Double(currentLoc.latitude).rounded(toPlaces: 3)
let currentLong = Double(currentLoc.longitude).rounded(toPlaces: 3)
if currentLat == pathLat && currentLong == pathLong{
index = Int(i)
break //Breaking the loop when the index found
}
}
//Creating new path from the current location to the destination
let newPath = GMSMutablePath()
for i in index..<Int(self.path.count()){
newPath.add(self.path.coordinate(at: UInt(i)))
}
self.path = newPath
self.polyline.map = nil
self.polyline = GMSPolyline(path: self.path)
self.polyline.strokeColor = UIColor.darkGray
self.polyline.strokeWidth = 2.0
self.polyline.map = self.mapView
}
The lat and longs are rounded of so that if the user is nearby the travelled location. Use the following extension to round of upto 3 decimal places or more according to requirement.
extension Double {
// Rounds the double to decimal places value
func rounded(toPlaces places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}

Related

How can I draw a polyline in ARKit using latitude and longitude?

Currently I can render the spheres using latitude and longitude in ARKit Geolocation Tracking , can anyone please guide me how can I draw polyline between 2 CLLocation in ARKit .
here is a full code to create poly line between two points and also set a width and color of that poly line
var locManager = CLLocationManager()
var currentLocation: CLLocation!
let annotation = MKPointAnnotation()
let annotation2 = MKPointAnnotation()
// MARK:- DRIVER -
var driverLatitute:String!
var driverLongitude:String!
// MARK:- RESTAURANT -
var restaurantLatitude:String!
var restaurantLongitude:String!
IN VIEW DID LOAD
// MARK:- 1 ( MAP ) -
self.locManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
self.locManager.delegate = self
self.locManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.locManager.startUpdatingLocation()
print("UPDATE UPDATE")
}
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {
print("")
}
DELEGATE METHODS
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//print("**********************")
//print("Long \(manager.location!.coordinate.longitude)")
//print("Lati \(manager.location!.coordinate.latitude)")
//print("Alt \(manager.location!.altitude)")
//print("Speed \(manager.location!.speed)")
//print("Accu \(manager.location!.horizontalAccuracy)")
//print("**********************")
//print(Double((vendorLatitute as NSString).doubleValue))
//print(Double((vendorLongitute as NSString).doubleValue))
/*
// restaurant
self.restaurantLatitude = (dict["deliveryLat"] as! String)
self.restaurantLongitude = (dict["deliveryLong"] as! String)
// driver
self.driverLatitute = (dict["resturentLatitude"] as! String)
self.driverLongitude = (dict["resturentLongitude"] as! String)
*/
let restaurantLatitudeDouble = Double(self.restaurantLatitude)
let restaurantLongitudeDouble = Double(self.restaurantLongitude)
let driverLatitudeDouble = Double("\(manager.location!.coordinate.latitude)") //Double(self.driverLatitute)
let driverLongitudeDouble = Double("\(manager.location!.coordinate.longitude)") // Double(self.driverLongitude)
let coordinate₀ = CLLocation(latitude: restaurantLatitudeDouble!, longitude: restaurantLongitudeDouble!)
let coordinate₁ = CLLocation(latitude: driverLatitudeDouble!, longitude: driverLongitudeDouble!)
/************************************** RESTAURANT LATITUTDE AND LONGITUDE ********************************/
// first location
let sourceLocation = CLLocationCoordinate2D(latitude: restaurantLatitudeDouble!, longitude: restaurantLongitudeDouble!)
/********************************************************************************************************************/
/************************************* DRIVER LATITUTDE AND LINGITUDE ******************************************/
// second location
let destinationLocation = CLLocationCoordinate2D(latitude: driverLatitudeDouble!, longitude: driverLongitudeDouble!)
/********************************************************************************************************************/
//print(sourceLocation)
//print(destinationLocation)
let sourcePin = customPin(pinTitle: "You", pinSubTitle: "", location: sourceLocation)
let destinationPin = customPin(pinTitle: "Driver", pinSubTitle: "", location: destinationLocation)
/***************** REMOVE PREVIUOS ANNOTATION TO GENERATE NEW ANNOTATION *******************************************/
self.mapView.removeAnnotations(self.mapView.annotations)
/********************************************************************************************************************/
self.mapView.addAnnotation(sourcePin)
self.mapView.addAnnotation(destinationPin)
let sourcePlaceMark = MKPlacemark(coordinate: sourceLocation)
let destinationPlaceMark = MKPlacemark(coordinate: destinationLocation)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: sourcePlaceMark)
directionRequest.destination = MKMapItem(placemark: destinationPlaceMark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { [self] (response, error) in
guard let directionResonse = response else {
if let error = error {
print("we have error getting directions==\(error.localizedDescription)")
}
return
}
/***************** REMOVE PREVIUOS POLYLINE TO GENERATE NEW POLYLINE *******************************/
let overlays = self.mapView.overlays
self.mapView.removeOverlays(overlays)
/************************************************************************************/
/***************** GET DISTANCE BETWEEN TWO CORDINATES *******************************/
let distanceInMeters = coordinate₀.distance(from: coordinate₁)
// print(distanceInMeters as Any)
// remove decimal
let distanceFloat: Double = (distanceInMeters as Any as! Double)
// print(distanceFloat as Any)
// self.lblDistance.text = (String(format: "Distance : %.0f Miles away", distanceFloat/1609.344))
self.lblTotalDistance.text = (String(format: "Distance : %.0f Miles away", distanceFloat/1609.344))
// print(distanceFloat/1609.344)
// print(String(format: "Distance : %.0f Miles away", distanceFloat/1609.344))
let s:String = String(format: "%.0f",distanceFloat/1609.344)
// print(s as Any)
/************************************************************************************/
/***************** GENERATE NEW POLYLINE *******************************/
let route = directionResonse.routes[0]
self.mapView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
self.mapView.setRegion(MKCoordinateRegion(rect), animated: true)
/************************************************************************************/
}
self.mapView.delegate = self
print("update location after 5 sec")
// self.locManager.stopUpdatingLocation()
// speed = distance / time
}
// line width of poly line
//MARK:- MapKit delegates -
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.blue
renderer.lineWidth = 4.0
return renderer
}

Calculating trip distance core location swift

I have an application where I calculate distance travelled like the Uber application. When a driver starts a trip, the location begins to change even though a start point has been specified in the search for a ride, a driver could decide to pass an alternative route or pass long places and routes because he/ she does not know the shortest route, how then do I calculate the total distance.
The starting location is the location the driver hits start button
The end location is the location the driver hits stop button
this is my code so far
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
lastLocation = locations.last!
endTrip(locations.last)
if !hasSetInitialLocation {
let camera = GMSCameraPosition.camera(withTarget: lastLocation!.coordinate, zoom: 17)
self.mapView.animate(to: camera)
hasSetInitialLocation = true
endTrip(lastLocation)
MqttManager.instance.connectToServer()
}
}
func endTrip(endLoaction: CLLocation) {
guard let statusChange = source.getStatusChange() else{return}
var distanceTraveled: Double = 0.0
let initialLocation = CLLocation(latitude: (statusChange.meta?.location?.lat)!, longitude: (statusChange.meta?.location?.lng)!)
let distance = initialLocation.distance(from: endLoaction)
distanceTraveled += distance
let distanceInKM = Utility.convertCLLocationDistanceToKiloMeters(targetDistance: distanceTraveled)
}
How can i calculate the distance to reflect the total distance moved by the driver since there could be a change in route from the proposed start point and end point.
The driver hits a button called start trip, I want to get the distance from that moment till the moment he hits the button end trip
this implementation could be got from a similar working code like these but the only difference is that their is a start button which passes the coordinates at that point and a stop coordinate which is the end of the coordinate.
enum DistanceValue: Int {
case meters, miles
}
func calculateDistanceBetweenLocations(_ firstLocation: CLLocation, secondLocation: CLLocation, valueType: DistanceValue) -> Double {
var distance = 0.0
let meters = firstLocation.distance(from: secondLocation)
distance += meters
switch valueType {
case .meters:
return distance
case .miles:
let miles = distance
return miles
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if startLocation == nil {
startLocation = locations.first
} else if let location = locations.last {
runDistance += lastLocation.distance(from: location)
let calc = calculateDistanceBetweenLocations(lastLocation, secondLocation: location, valueType: .meters)
print("TOTAL LOC 1 \(calc)")
print("TOTAL LOC 2 \(runDistance)")
}
lastLocation = locations.last
}
as shown in my print statements print("TOTAL LOC 1 \(calc)")
print("TOTAL LOC 2 \(runDistance)") how can I make
calc the same with runDistance
here is what is printed in the console
TOTAL LOC 10.29331530774379
TOTAL LOC 2 10.29331530774379
TOTAL LOC 2.2655118031831587
TOTAL LOC 2 12.558827110926948
If you get the distance like this using the first and last coordinate it always returns the wrong value because it can't identify the actual traveling path.
I did resolve the same issue with using the following code.
use GoogleMaps
> pod 'GoogleMaps'
Make the coordinates array while the driver is moving on a route.
var arr = [Any]()
// Driving lat long co-ordinateds continues add in this array according to your expectation either update location or perticuler time duration.
// make GMSMutablePath of your co-ordinates
let path = GMSMutablePath()
for obj in arr{
print(obj)
if let lat = (obj as? NSDictionary)?.value(forKey: PARAMETERS.LET) as? String{
path.addLatitude(Double(lat)!, longitude: Double(((obj as? NSDictionary)?.value(forKey: PARAMETERS.LONG) as? String)!)!)
}
}
print(path) // Here is your traveling path
let km = GMSGeometryLength(path)
print(km) // your total traveling distance.
I did it in this app and it's working fine.
Hope it will helps you :)
OR without GoogleMaps
You have to come with locations, an array of CLLocationCoordinate2D, for yourself, as per your code, though.
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
// MARK: - Variables
let locationManager = CLLocationManager()
// MARK: - IBOutlet
#IBOutlet weak var mapView: MKMapView!
// MARK: - IBAction
#IBAction func distanceTapped(_ sender: UIBarButtonItem) {
let locations: [CLLocationCoordinate2D] = [...]
var total: Double = 0.0
for i in 0..<locations.count - 1 {
let start = locations[i]
let end = locations[i + 1]
let distance = getDistance(from: start, to: end)
total += distance
}
print(total)
}
func getDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> CLLocationDistance {
// By Aviel Gross
// https://stackoverflow.com/questions/11077425/finding-distance-between-cllocationcoordinate2d-points
let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
let to = CLLocation(latitude: to.latitude, longitude: to.longitude)
return from.distance(from: to)
}
}
Output
A simple function to calculate distance (in meters) given an array of CLLocationCoordinate2D. Uses reduce instead of array iteration.
func computeDistance(from points: [CLLocationCoordinate2D]) -> Double {
guard let first = points.first else { return 0.0 }
var prevPoint = first
return points.reduce(0.0) { (count, point) -> Double in
let newCount = count + CLLocation(latitude: prevPoint.latitude, longitude: prevPoint.longitude).distance(
from: CLLocation(latitude: point.latitude, longitude: point.longitude))
prevPoint = point
return newCount
}
}
I like to use an extension for that
extension Array where Element: CLLocation {
var distance: Double {
guard count > 1 else { return 0 }
var previous = self[0]
return reduce(0) { (result, location) -> Double in
let distance = location.distance(from: previous)
previous = location
return result + distance
}
}
}
Usage:
locations.distance

Add two coordinates in a button function to launch mapKit and start navigation between two points (Swift)

I'm using this class
import UIKit
import CoreLocation
import GoogleMaps
import GooglePlaces
import SwiftyJSON
import Alamofire
import MapKit
class FinalClass: UIViewController {
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var bottomInfoView: UIView!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var distanceLabel: UILabel!
var userLocation:CLLocationCoordinate2D?
var places:[QPlace] = []
var index:Int = -1
var locationStart = CLLocation()
var locationEnd = CLLocation()
var mapView:GMSMapView!
var marker:GMSMarker?
override func loadView() {
super.loadView()
}
override func viewDidLoad() {
super.viewDidLoad()
guard index >= 0, places.count > 0 else {
return
}
let place = places[index]
let lat = place.location?.latitude ?? 1.310844
let lng = place.location?.longitude ?? 103.866048
// Google map view
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 12.5)
mapView = GMSMapView.map(withFrame: self.view.bounds, camera: camera)
mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth, .flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin]
self.containerView.addSubview(mapView)
// Add gesture
addSwipeGesture()
didSelect(place: place)
if userLocation != nil {
addMarkerAtCurrentLocation(userLocation!)
}
}
func addSwipeGesture() {
let directions: [UISwipeGestureRecognizerDirection] = [.right, .left]
for direction in directions {
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(sender:)))
gesture.direction = direction
self.bottomInfoView.addGestureRecognizer(gesture)
}
}
func addMarkerAtCurrentLocation(_ userLocation: CLLocationCoordinate2D) {
let marker = GMSMarker()
marker.position = userLocation
marker.title = "Your location"
marker.map = mapView
}
func didSelect(place:QPlace) {
guard let coordinates = place.location else {
return
}
// clear current marker
marker?.map = nil
// add marker
marker = GMSMarker()
marker?.position = coordinates
marker?.title = place.name
marker?.map = mapView
mapView.selectedMarker = marker
moveToMarker(marker!)
// update bottom info panel view
let desc = place.getDescription()
descriptionLabel.text = desc.characters.count > 0 ? desc : "-"
distanceLabel.text = "-"
// update distance
if userLocation != nil {
let dist = distance(from: userLocation!, to: coordinates)
distanceLabel.text = String.init(format: "Distance %.2f meters", dist)
self.drawPath(startLocation: userLocation!, endLocation: coordinates)
}
title = place.name
}
func moveToMarker(_ marker: GMSMarker) {
let camera = GMSCameraPosition.camera(withLatitude: marker.position.latitude,
longitude: marker.position.longitude,
zoom: 12.5)
self.mapView.animate(to: camera)
}
// distance between two coordinates
func distance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> CLLocationDistance {
let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
let to = CLLocation(latitude: to.latitude, longitude: to.longitude)
return from.distance(from: to)
}
func handleSwipe(sender: UISwipeGestureRecognizer) {
guard index >= 0, places.count > 0 else {
return
}
if sender.direction == .left {
if index < places.count - 2 {
index += 1
didSelect(place: places[index])
}
} else if sender.direction == .right {
if index > 1 {
index -= 1
didSelect(place: places[index])
}
}
}
func drawPath(startLocation: CLLocationCoordinate2D, endLocation: CLLocationCoordinate2D) {
let from = CLLocation(latitude: startLocation.latitude, longitude: startLocation.longitude)
let to = CLLocation(latitude: endLocation.latitude, longitude: endLocation.longitude)
let origin = "\(from.coordinate.latitude),\(from.coordinate.longitude)"
let destination = "\(to.coordinate.latitude),\(to.coordinate.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // HTTP URL response
print(response.data as Any) // server data
print(response.result as Any) // result of response serialization
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
// print route using Polyline
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.black
polyline.map = self.mapView
}
}
}
#IBAction func navigationStart(_ sender: Any) {
}
with a google maps to add place markers, draw the direction on the map and show the distance between two points, now i would like to launch the navigator between startLocation: userLocation! and endLocation: coordinates but with some research i saw that i can not launch the navigator in the same view, i need to open the maps application, so i decided to add the MapKit and a button
#IBAction func navigationStart(_ sender: Any) {
}
so how can i do that by pressing the button the map application opens with direction from userLocation to coordinates ? I already looked to similar question but is a little different to my problem, because i already have the points but in different format.
Your question is a little confusing but if you want to open the maps app and show direction from a user's current location to another point on the map then you don't need to pass the user's location, just the destination:
Swift 4:
let coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246)
let placeMark = MKPlacemark(coordinate: coordinate)
let mapItem = MKMapItem(placemark: placeMark)
mapItem.name = "Big Ben"
mapItem.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving])
Objective C:
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246);
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate: coordinate];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:#"Big Ben"];
[mapItem openInMapsWithLaunchOptions:#{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving}];

NMACoreRouter calculateRouteWithStops no callback (swift)

I'm trying to create a route using Here API in Swift but I'm having some issues because the completion block is never called so I cannot know exactly what is the problem.
Here is my code:
let coreRoute = NMACoreRouter()
let startPoint = NMAGeoCoordinates(latitude: latitude1, longitude: longitude1)
let waypoint1 = NMAWaypoint(geoCoordinates: startPoint)
let middlePoint = NMAGeoCoordinates(latitude: latitude2, longitude: longitude2)
let waypoint2 = NMAWaypoint(geoCoordinates: middlePoint, waypointType: NMAWaypointType.ViaWaypoint)
let endPoint = NMAGeoCoordinates(latitude: latitude3, longitude: longitude3)
let waypoint3 = NMAWaypoint(geoCoordinates: endPoint, waypointType: NMAWaypointType.StopWaypoint)
let stopList = [waypoint1, waypoint2, waypoint3] // I have also tried adding the NMAGeoCoordinates to array but still no callback
let routingMode = NMARoutingMode(routingType: NMARoutingType.Fastest, transportMode: NMATransportMode.Car, routingOptions: 0)
coreRoute.calculateRouteWithStops(stopList, routingMode: routingMode) { (routeResult: NMARouteResult?, error: NMARoutingError?) in
if error == nil && routeResult != nil && routeResult!.routes.count > 0 {
let route = routeResult!.routes.first as! NMARoute
let mapRoute = NMAMapRoute(route: route)
self.mapView.addMapObject(mapRoute)
} else {
// Handle error
}
}
Does anyone have any idea about this problem?
P.S. There is no problem with the app id, app code and license key. The NMAApplicationContext is successfully set in AppDelegate
Found the solution!
You need to declare NMACoreRouter object as a class variable.
class <Class_Name> {
var coreRouter: NMACoreRouter!
func <Your_Function>() {
coreRoute = NMACoreRouter()
let startPoint = NMAGeoCoordinates(latitude: latitude1, longitude: longitude1)
let waypoint1 = NMAWaypoint(geoCoordinates: startPoint)
let middlePoint = NMAGeoCoordinates(latitude: latitude2, longitude: longitude2)
let waypoint2 = NMAWaypoint(geoCoordinates: middlePoint, waypointType: NMAWaypointType.ViaWaypoint)
let endPoint = NMAGeoCoordinates(latitude: latitude3, longitude: longitude3)
let waypoint3 = NMAWaypoint(geoCoordinates: endPoint, waypointType: NMAWaypointType.StopWaypoint)
let stopList = [waypoint1, waypoint2, waypoint3] // I have also tried adding the NMAGeoCoordinates to array but still no callback
let routingMode = NMARoutingMode(routingType: NMARoutingType.Fastest, transportMode: NMATransportMode.Car, routingOptions: 0)
coreRoute.calculateRouteWithStops(stopList, routingMode: routingMode) { (routeResult: NMARouteResult?, error: NMARoutingError?) in
if error == nil && routeResult != nil && routeResult!.routes.count > 0 {
let route = routeResult!.routes.first as! NMARoute
let mapRoute = NMAMapRoute(route: route)
self.mapView.addMapObject(mapRoute)
} else {
// Handle error
}
}
}
}
EDIT: Navigation Code
let navigationManager = NMANavigationManager.sharedNavigationManager()
navigationManager.delegate = self
navigationManager.map = mapView
navigationManager.startTurnByTurnNavigationWithRoute(route)
navigationManager.startTrackingWithTransportMode(.Car)
//Simulation
sharedPositioningManager.dataSource = NMARoutePositionSource(route: route)

Is it possible to have custom reverse geocoding?

Currently, I'm utilizing reverse geocoding to simply convert a longitude and latitude to a locality and sub locality.
Is it possible for me to override this and essentially have it return custom strings at my discretion given that I provide it with the coordinates? Any thoughts?
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
locationManager.stopUpdatingLocation()
if(locations.count > 0){
let location = locations[0] as! CLLocation
// println(location.coordinate)
if let currentLocatino = currLocation {
if CLLocation(latitude: currentLocatino.latitude, longitude: currentLocatino.longitude).distanceFromLocation(location) > 500 {
currLocation = location.coordinate
self.skip = 0
self.loadObjects()
}
}
else {
currLocation = location.coordinate
self.skip = 0
self.loadObjects()
}
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: currLocation!.latitude, longitude: currLocation!.longitude), completionHandler: {(placemarks, error) -> Void in
if error != nil {
println("Reverse geocoder failed with error" + error.localizedDescription)
return
}
if placemarks.count > 0 {
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateStyle = .MediumStyle
formatter.stringFromDate(date)
let pm = placemarks[0] as! CLPlacemark
var testifempty = "\(pm.subLocality)"
if testifempty == "nil"
{
self.locationManager.startUpdatingLocation()
if let lbutton = self.lbutton{
lbutton.text = "Hello " + "\(pm.locality)" //+ "\n" + formatter.stringFromDate(date)
}
}
else
{
self.locationManager.startUpdatingLocation()
if let lbutton = self.lbutton {
lbutton.text = "Hello " + "\(pm.subLocality)\n" // + formatter.stringFromDate(date)
}
}
}
else {
println("Problem with the data received from geocoder")
}
})
} else {
println("Cannot fetch your location")
}
}
If you know what the names are, you might try a switch that swapped out matching strings.
var locale_string
switch locale_string {
case “name1”:
let displayed_locale_name = “changed_name1”
case “name2”:
let displayed_locale_name = “changed_name2”
...
}
Then, the default case where you haven't identified the locale could accept the string as it is.
I got the idea from the Swift2 Programming Language Guide, page 17.
Reverse geocoding is basically a spatial query. I would suggest to define a map with spatial boundaries, assign each boundary an attribute for both locality and sub-locality.
With that map, you can run your set of coordinates against it and assign them the same attributes as the coordinate fits in one of the spatial boundaries.

Resources