2

I want to draw route between two CLLocationCoordinates Using Google API. Currently i am using "https://maps.googleapis.com/maps/api/directions/json?" with origin and destination and it is not exactly what i want to do. I want to pass my location instead of location name and then make a route.

Thanks in Advance.

Umesh Sharma
  • 388
  • 5
  • 23

4 Answers4

2

I followed THIS tutorial for Google Maps SDK. And In that tutorial for route user have to add both location name into alertView. But I made some modification into the code so you can directly get the route from use's current location to entered destination location.

First of all get the name of the location from user's current location in observeValueForKeyPath method this way:

var currentLocationName = String()
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    if !didFindMyLocation {
        let myLocation: CLLocation = change[NSKeyValueChangeNewKey] as! CLLocation
        let geoCoder = CLGeocoder()
        let location = CLLocation(latitude: myLocation.coordinate.latitude, longitude: myLocation.coordinate.longitude)

        geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
            let placeArray = placemarks as? [CLPlacemark]

            // Place details
            var placeMark: CLPlacemark!
            placeMark = placeArray?[0]

            // Address dictionary
            println(placeMark.addressDictionary)

            // Location name
            if let locationName = placeMark.addressDictionary["Name"] as? NSString {
                println(locationName)
            }

            // Street address
            if let street = placeMark.addressDictionary["Thoroughfare"] as? NSString {
                println(street)
            }

            // City
            if let city = placeMark.addressDictionary["City"] as? NSString {
                //get city name.
                self.currentLocationName = city as String
                println(city)
            }

            // Zip code
            if let zip = placeMark.addressDictionary["ZIP"] as? NSString {
                println(zip)
            }

            // Country
            if let country = placeMark.addressDictionary["Country"] as? NSString {
                println(country)
            }

        })
        viewMap.camera = GMSCameraPosition.cameraWithTarget(myLocation.coordinate, zoom: 10.0)
        viewMap.settings.myLocationButton = true

        didFindMyLocation = true
    }
}

Now in createRoute method give that city name or what ever you want as origin like this:

@IBAction func createRoute(sender: AnyObject) {

    let addressAlert = UIAlertController(title: "Create Route", message: "Connect locations with a route:", preferredStyle: UIAlertControllerStyle.Alert)

    addressAlert.addTextFieldWithConfigurationHandler { (textField) -> Void in
        //give a origin for route
        textField.text = self.currentLocationName
        textField.userInteractionEnabled = false
    }

    addressAlert.addTextFieldWithConfigurationHandler { (textField) -> Void in
        textField.placeholder = "Destination?"
    }


    let createRouteAction = UIAlertAction(title: "Create Route", style: UIAlertActionStyle.Default) { (alertAction) -> Void in
        let origin = (addressAlert.textFields![0] as! UITextField).text as String
        let destination = (addressAlert.textFields![1] as! UITextField).text as String

        self.mapTasks.getDirections(origin, destination: destination, waypoints: nil, travelMode: nil, completionHandler: { (status, success) -> Void in
            if success {
                self.configureMapAndMarkersForRoute()
                self.drawRoute()
                self.displayRouteInfo()
            }
            else {
                println(status)
            }
        })
    }

    let closeAction = UIAlertAction(title: "Close", style: UIAlertActionStyle.Cancel) { (alertAction) -> Void in

    }

    addressAlert.addAction(createRouteAction)
    addressAlert.addAction(closeAction)

    presentViewController(addressAlert, animated: true, completion: nil)
}

Hope it helps.

Dharmesh Kheni
  • 71,228
  • 33
  • 160
  • 165
1

Well i have used A MapKit wrapper from here - https://github.com/varshylmobile/MapManager

This wrapper provides several classes like

directionsUsingGoogle(#from:NSString, to:NSString,directionCompletionHandler:DirectionsCompletionHandler)

directionsUsingGoogle(#from:CLLocationCoordinate2D, to:CLLocationCoordinate2D,directionCompletionHandler:DirectionsCompletionHandler)

directionsUsingGoogle(#from:CLLocationCoordinate2D, to:NSString,directionCompletionHandler:DirectionsCompletionHandler)

Here you can pass your CLLocationCoordinate2D in the above methods.

Rajat
  • 10,977
  • 3
  • 38
  • 55
  • Though this code must be working fine but was not the case i am looking for. Still i upvoted your answer because you tried to help my friend. Cheers :) – Umesh Sharma Sep 10 '15 at 11:30
  • I dont understand why it cant help you, you have to pass `CLLocationCoordinates` in it and it will draw the route from those two `CLLocationCoordinates` using this method `directionsUsingGoogle(#from:CLLocationCoordinate2D, to:CLLocationCoordinate2D,directionCompletionHandler:DirectionsCompletionHandler)`, or do you have any another requirement? – Rajat Sep 10 '15 at 11:35
  • I had to clear that path too. I am unable to clear that and had to make a lot of changes. I found another way to do that however. I made a class of my own from your methods and used a huge chunk of your code as is – Umesh Sharma Sep 10 '15 at 11:40
1
- (void)pathCall {
    if ([_txtAddressCity.text isEqualToString:@""] || [_txtaddressNumber.text isEqualToString:@""] || [_txtAddressState.text isEqualToString:@""] ||
        [_txtAddressStreet.text isEqualToString:@""] || [_txtAddressZip.text isEqualToString:@""])
    {
        //[PCToastMessage toastWithDuration:2.0 andText:NSLocalizedString(@"All fields are compulsory in location.",Nil) inView:self.view];
        return ;
    }
    else
    {
        _endingAddress=[[NSMutableString alloc] initWithString:_txtaddressNumber.text];
        [_endingAddress appendString:[NSString stringWithFormat:@",+%@",_txtAddressStreet.text]];
        [_endingAddress appendString:[NSString stringWithFormat:@",+%@",_txtAddressCity.text]];
        [_endingAddress appendString:[NSString stringWithFormat:@",+%@",_txtAddressState.text]];
        [_endingAddress appendString:[NSString stringWithFormat:@",+%@",_txtAddressZip.text]];
        [_endingAddress appendString:[_endingAddress stringByReplacingOccurrencesOfString:@" " withString: @"+"]];

        NSMutableString *mode= [[NSMutableString alloc]init];
        if (_selectedRowOfPicker==1 || _selectedRowOfPicker==0) {
            [mode appendString:@"driving"];
        }
        else if(_selectedRowOfPicker==2)
        {
            [mode appendString:@"bicycling"];
        }
        else if(_selectedRowOfPicker==3)
        {
            [mode appendString:@"walking"];
        }

       NSURL *url=[[NSURL alloc] initWithString:[NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&mode=%@",[_startingAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],[_endingAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],mode]];

        NSURLResponse *res;
        NSError *err;
        NSData *data=[NSURLConnection sendSynchronousRequest:[[NSURLRequest alloc] initWithURL:url] returningResponse:&res error:&err];
        NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];

        NSMutableArray *totalSeconds;
        totalSeconds = [[NSMutableArray alloc]init];

        NSArray *routes=dic[@"routes"];
        path1 = [GMSMutablePath path];

        if (routes.count != 0) {
            NSArray *legs=routes[0][@"legs"];
            NSArray *steps=legs[0][@"steps"];
            NSDictionary *duration=legs[0][@"duration"];
            NSString *totalSeconds = [duration valueForKey:@"value"];
            NSDictionary *start_address=legs[0][@"start_location"];
            NSDictionary *end_address=legs[0][@"end_location"];
            source.latitude = [[start_address valueForKey:@"lat"] doubleValue];
            source.longitude = [[start_address valueForKey:@"lng"] doubleValue];
            dest.latitude = [[end_address valueForKey:@"lat"] doubleValue];
            dest.longitude = [[end_address valueForKey:@"lng"] doubleValue];
            NSMutableArray *textsteps=[[NSMutableArray alloc] init];
            NSMutableArray *latlong=[[NSMutableArray alloc]init];
            for(int i=0; i< [steps count]; i++){

                NSString *html=steps[i][@"html_instructions"];
                [latlong addObject:steps[i][@"end_location"]];
                [textsteps addObject:html];
                NSString *polyLinePoints = [[steps[i] objectForKey:@"polyline"] objectForKey:@"points"];
                GMSPath *polyLinePath = [GMSPath pathFromEncodedPath:polyLinePoints];
                for (int p=0; p<polyLinePath.count; p++) {
                    [path1 addCoordinate:[polyLinePath coordinateAtIndex:p]];
                }
            }
            self.detailedSteps=textsteps;
            [self showDirection:latlong];

            [_lblJourneyHours setTextColor:[UIColor colorWithWhite:0.33 alpha:1.0]];
            _lblJourneyHours.text = [NSString stringWithFormat:@"%.02f", ([totalSeconds floatValue]/60)/60];
        }
        else
        {
            _lblJourneyHours.textColor = [UIColor redColor];
            _lblJourneyHours.text = @"No route found.";
        }
    }
}
-(void)showDirection:(NSMutableArray*) latlong{
    path = [GMSMutablePath path];
    bounds = [[GMSCoordinateBounds alloc] init];
    if (latlong.count !=0) {
        for(int i=0; i<[latlong count]; i++){
            double lat=[latlong[i][@"lat"] doubleValue];
            double lng=[latlong[i][@"lng"] doubleValue];
            CLLocationCoordinate2D temp;
            temp.latitude=lat;
            temp.longitude=lng;
            bounds = [bounds includingCoordinate:temp];
            [path addLatitude:lat longitude:lng];
        }
    }
}
- (IBAction)showMAP:(UIButton *)sender {
    [self hideKeyboard];

    if ([_txtAddressCity.text isEqualToString:@""] || [_txtaddressNumber.text isEqualToString:@""] || [_txtAddressState.text isEqualToString:@""] ||
        [_txtAddressStreet.text isEqualToString:@""] || [_txtAddressZip.text isEqualToString:@""])
    {
        [PCToastMessage toastWithDuration:2.0 andText:NSLocalizedString(@"All fields are compulsory in location.",Nil) inView:self.view];
        return ;
    }
    if ([_lblJourneyHours.text isEqualToString:@"No route found."])
    {
        [PCToastMessage toastWithDuration:2.0 andText:NSLocalizedString(@"No route found.",Nil) inView:self.view];
        return ;
    }
    else
    {
        _mapButton.userInteractionEnabled = NO;
        popUp = [[UIView alloc]initWithFrame:CGRectMake(self.view.frame.origin.x,0, self.view.frame.size.width, self.view.frame.size.height)];
        GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:source.latitude longitude:source.longitude zoom:7];//23.0300° N, 72.5800° E
        mapView = [GMSMapView mapWithFrame:CGRectMake(popUp.frame.origin.x+10, popUp.frame.origin.y+10, popUp.frame.size.width-20, popUp.frame.size.height-20) camera:camera];
        [mapView animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds withPadding:30.0f]];
        popUp.backgroundColor = [UIColor whiteColor];
        popUp.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
        [self.view addSubview:popUp];

        GMSPolyline *polyline = [GMSPolyline polylineWithPath:path1];
        polyline.strokeColor = [UIColor blueColor];
        polyline.strokeWidth = 3.f;
        mapView.myLocationEnabled=YES;
        polyline.map =mapView ;

        GMSMarker *marker=[[GMSMarker alloc]init];
        marker.position=CLLocationCoordinate2DMake(source.latitude, source.longitude);
        marker.groundAnchor=CGPointMake(0.52,0.8);

        GMSMarker *marker2=[[GMSMarker alloc]init];
        marker2.position=CLLocationCoordinate2DMake(dest.latitude, dest.longitude);
        marker2.groundAnchor=CGPointMake(0.52,0.8);
        marker.map=mapView;
        marker2.map=mapView;
        [popUp addSubview:mapView];
        UIButton *closeMap = [[UIButton alloc]initWithFrame:CGRectMake(mapView.frame.size.width-17,mapView.frame.origin.y-6 , 35, 35)];
        [closeMap setBackgroundImage:[UIImage imageNamed:@"cross.png"] forState:UIControlStateNormal];
        closeMap.backgroundColor = [UIColor clearColor];
        [closeMap addTarget:self action:@selector(closeMapAction)forControlEvents:UIControlEventTouchUpInside];
        [popUp addSubview:closeMap];

        [UIView animateWithDuration:0.3/1.5 animations:^{
            popUp.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:0.3 animations:^{
                popUp.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);
            } completion:^(BOOL finished) {
                [UIView animateWithDuration:0.1 animations:^{
                    popUp.transform = CGAffineTransformIdentity;
                    _mapButton.userInteractionEnabled = YES;
                }];
            }];
        }];
    }
}
Indrajit Chavda
  • 361
  • 1
  • 2
  • 13
1

You can convert lat long to the given format and then call Google Directions API for the complete route -

let originLat: String = String(format: "%f",self.currentLocation!.coordinate.latitude)
    let originLong: String = String(format: "%f", self.currentLocation!.coordinate.longitude)
    let destLat: String = String(format: "%f", self.destinationLocation!.coordinate.latitude)
    let destLong: String = String(format: "%f", self.destinationLocation!.coordinate.longitude)

    let origin: String = "\(originLat), \(originLong)"
    let destination: String = "\(destLat), \(destLong)"


var params: [String: String] = [:]

    params.updateValue("YOUR_GOOGLE_API_KEY", forKey: "key")
    //        params.updateValue("50000", forKey: "radius")
    params.updateValue("driving", forKey: "mode")
    params.updateValue(origin, forKey: "origin")
    params.updateValue(destination, forKey: "destination")
    params.updateValue("best_guess", forKey: "traffic_model")
    params.updateValue("imperial", forKey: "units")

    let departureTime = NSDate().timeIntervalSince1970
    params.updateValue(String(format:"%.0f", departureTime), forKey: "departure_time")

    let pm = setGetParameters(params)
    let method = "GET"

    let finalUrl = "https://maps.googleapis.com/maps/api/directions/json?\(pm)"
    NSLog("Url for directions call - \(finalUrl)")

    // Create URL Request
    var request: NSMutableURLRequest!

    let urlStr : NSString = finalUrl.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
    let nsUrl: NSURL = NSURL(string: urlStr as String)!

    request = NSMutableURLRequest(URL: nsUrl)
    request.HTTPMethod = method
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json", forHTTPHeaderField: "Accept")
    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData

    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithRequest(request) {
        (data, response, error) -> Void in

        // Handle incoming data like you would in synchronous request
        NSLog("Got response from Get Directions API")
        callBack(data: data, response: response, error: error)
    }

    task.resume()
Rishabh Wadhwa
  • 171
  • 2
  • 8