I am developing an application in which I need to draw a route between two points using lat/long.
I have used apple API to get polylines and drawing it after decoding it.
Problem:
Route is not in the middle of the road (Attached image_1) or route is misaligned
Below is the code:
NSString* saddr = [NSString stringWithFormat:#"%#,%#",self.lat1.text,self.long1.text];
NSString* daddr = [NSString stringWithFormat:#"%#,%#",self.lat2.text,self.long2.text];
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.apple.com/maps/api/directions/json?origin=%#&destination=%#&sensor=false", saddr, daddr];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
NSError *error;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSUTF8StringEncoding error:&error];
NSData *responseData = [apiResponse dataUsingEncoding:NSUTF8StringEncoding];
NSError* error1;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
options:NSJSONReadingMutableLeaves
error:&error1];
NSLog(#"Error: %#\n%#",[error1 localizedDescription],[error1 localizedFailureReason]);
if([[json objectForKey:#"status"] isEqualToString:#"OK"])
{
NSArray *routes1 = [json objectForKey:#"routes"];
NSDictionary *route = [routes1 lastObject];
if (route)
{
NSString *overviewPolyline = [[route objectForKey: #"overview_polyline"] objectForKey:#"points"];
routes = [self decodePolyLine:overviewPolyline];
//NSLog(#"%#",[routes objectAtIndex:0]);
[self updateRouteView];
[self centerMap];
}
}
-(void) updateRouteView
{
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
decodePolyLine is totally depend n the latitude and longitude you get. So if you get proper latitude and longitude then this case will not happen. Another reason for that tis from iOS6 and above apple is using it's own map so may be they have different latitude and longitude from the Google map.
It's the same problem you described in your other question and it has the same solution. You are using data from two different sources, and the data is different.
Related
-(CLLocationCoordinate2D)getGeoCoding:(NSString *)address
{
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#",address];
NSURL *url = [NSURL URLWithString:req];
NSError *error;
//NSURLResponse *response;
CLLocationCoordinate2D findlocation;
NSData *data = [[NSData alloc]initWithContentsOfURL:url];
NSMutableDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:Nil error:&error];
if(error)
{
NSLog(#"%#",[error localizedDescription]);
findlocation.latitude=0.0;
findlocation.longitude =0.0;
}
else
{
NSArray *results = (NSArray *)responseDictionary[#"results"];
NSDictionary *firstitem = (NSDictionary *)[results objectAtIndex:0];
NSLog(#"%#",firstitem);
NSDictionary *geometry = (NSDictionary *)[firstitem valueForKey:#"geometry"];
NSLog(#"%#",geometry);
NSDictionary *location = (NSDictionary *)[geometry valueForKey:#"location"];
NSLog(#"%#",location);
NSNumber *lat = (NSNumber *)[location valueForKey:#"lat"];
NSLog(#"%#",lat);
NSNumber *lng = (NSNumber *)[location valueForKey:#"lng"];
NSLog(#"%#",lng);
findlocation.latitude = [lat doubleValue];
findlocation.longitude = [lng doubleValue];
}
return findlocation;
}
i getting location from above code.
-(void)getLocation:(id)sender
{
NSString *str = self.textView.text;
CLLocationCoordinate2D location;
location=[self getGeoCoding:str];
self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate=self;
self.mapView.showsUserLocation =YES;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(location, 0.3*METERS_PER_MILES, 0.3*METERS_PER_MILES);
[self.locationManager startUpdatingLocation];
[self.mapView reloadInputViews];
[self.mapView setRegion:viewRegion animated:YES];
}
location code is getting after the above function.
function is called but that do not work in iPhone simulator..?
if the set any setting Please tell me what the problem in code because iPhone simulator map not move from current location..
Is it Possible? How?
Currently i am working in iPhone application, Using CLLocationManager to get Latitude and Longitude values fine.
I didn't know this? How to get the device location (Address) name from this latitude and longitude value? please help me
Thanks in Advance
I tried this:
- (void)viewDidLoad
{
[super viewDidLoad];
LocationManager = [[CLLocationManager alloc]init];
LocationManager.delegate=self;
LocationManager.desiredAccuracy = kCLLocationAccuracyBest;
[LocationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSString * latitude = [[[NSString alloc] initWithFormat:#"%f", newLocation.coordinate.latitude]autorelease];
NSString * longitude = [[[NSString alloc] initWithFormat:#"%f", newLocation.coordinate.longitude]autorelease];
[LocationManager stopUpdatingLocation];
NSLog(#"latitude:%#",latitude);
NSLog(#"longitude:%#",longitude);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[manager stopUpdatingLocation];
lati = [[NSString alloc] initWithFormat:#"%+.6f", newLocation.coordinate.latitude];
NSLog(#"address:%#",lati);
longi = [[NSString alloc] initWithFormat:#"%+.6f", newLocation.coordinate.longitude];
NSLog(#"address:%#",longi);
[geoCoder reverseGeocodeLocation: newLocation completionHandler: ^(NSArray *placemarks, NSError *error)
{
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
address = [[NSString alloc]initWithString:locatedAt];
NSLog(#"address:%#",address);
}];
}
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:32.00 longitude:21.322];
[ceo reverseGeocodeLocation: loc completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"placemark %#",placemark);
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
NSLog(#"addressDictionary %#", placemark.addressDictionary);
NSLog(#"placemark %#",placemark.region);
NSLog(#"placemark %#",placemark.country); // Give Country Name
NSLog(#"placemark %#",placemark.locality); // Extract the city name
NSLog(#"location %#",placemark.name);
NSLog(#"location %#",placemark.ocean);
NSLog(#"location %#",placemark.postalCode);
NSLog(#"location %#",placemark.subLocality);
NSLog(#"location %#",placemark.location);
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
}];
You have ta make some reverse location. You're lucky : Apple provides a class to do that.
See CLGeocoder (for iOS >= 5.0) or MKReverseGeocoder (for iOS < 5.0)
You can use Google Maps API for this (works on any iOS):
NSString *req = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?latlng=%.5f,%.5f&sensor=false&language=da", location.latitude, location.longitude];
NSString *resultString = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
Then you can parse this response to NSDictionary using Any JSON library (SBJSON in this case):
SBJSON *jsonObject = [[SBJSON alloc] init];
NSError *error = nil;
NSDictionary *response = [jsonObject objectWithString:resultString error:&error];
[jsonObject release];
Extracting address:
if (error) {
NSLog(#"Error parsing response string to NSObject: %#",[error localizedDescription]);
}else{
NSString *status = [response valueForKey:#"status"];
if ([status isEqualToString:#"OK"]) {
NSArray *results = [response objectForKey:#"results"];
int count = [results count];
//NSSLog(#"Matches: %i", count);
if (count > 0) {
NSDictionary *result = [results objectAtIndex:0];
NSString *address = [result valueForKey:#"formatted_address"];
}
}
}
You have to create a CLLocation object and pass that on to reverseGeoCoder.
Before iOS 5.0 we have MKReverse Geo-coder class to find this..Now it is deprecated..
We have to use CLGeocoder class in Core Location Framework
I want to get the location name from the coordinate value. Here is code,
- (void)viewWillAppear:(BOOL)animated {
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 39.281516;
zoomLocation.longitude= -76.580806;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
MKCoordinateRegion adjustedRegion = [_mapView regionThatFits:viewRegion];
[_mapView setRegion:adjustedRegion animated:YES];
}
So, From that Latitude and longitude , i want to know that location name.
The Below code shall work in ios5 and above
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:32.00 longitude:21.322]; //insert your coordinates
[ceo reverseGeocodeLocation:loc
completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
if (placemark) {
NSLog(#"placemark %#",placemark);
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
NSLog(#"addressDictionary %#", placemark.addressDictionary);
NSLog(#"placemark %#",placemark.region);
NSLog(#"placemark %#",placemark.country); // Give Country Name
NSLog(#"placemark %#",placemark.locality); // Extract the city name
NSLog(#"location %#",placemark.name);
NSLog(#"location %#",placemark.ocean);
NSLog(#"location %#",placemark.postalCode);
NSLog(#"location %#",placemark.subLocality);
NSLog(#"location %#",placemark.location);
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
}
else {
NSLog(#"Could not locate");
}
}
];
-(NSString *)getAddressFromLatLon:(double)pdblLatitude withLongitude:(double)pdblLongitude
{
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%f,%f&output=csv",pdblLatitude, pdblLongitude];
NSError* error;
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString] encoding:NSASCIIStringEncoding error:&error];
// NSLog(#"%#",locationString);
locationString = [locationString stringByReplacingOccurrencesOfString:#"\"" withString:#""];
return [locationString substringFromIndex:6];
}
Use this method
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation: zoomLocation completionHandler:^(NSArray* placemarks, NSError* error){
}
];
In iOS 5.0 and later, you can use CLGeocoder of Core Location framework, as for iOS lower than 5.0, MKReverseGeocoder of Map Kit Framework. Good luck!
Here is block to get address string from current location
in .h file
typedef void(^addressCompletionBlock)(NSString *);
-(void)getAddressFromLocation:(CLLocation *)location complationBlock:(addressCompletionBlock)completionBlock;
in .m file
#pragma mark - Get Address
-(void)getAddressFromLocation:(CLLocation *)location complationBlock:(addressCompletionBlock)completionBlock
{
//Example URL
//NSString *urlString = #"http://maps.googleapis.com/maps/api/geocode/json?latlng=23.033915,72.524267&sensor=true_or_false";
NSString *urlString = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=true_or_false",location.coordinate.latitude, location.coordinate.longitude];
NSError* error;
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString] encoding:NSASCIIStringEncoding error:&error];
NSArray *jsonObject = [NSJSONSerialization JSONObjectWithData:[locationString dataUsingEncoding:NSUTF8StringEncoding]
options:0 error:NULL];
NSString *strFormatedAddress = [[[jsonObject valueForKey:#"results"] objectAtIndex:0] valueForKey:#"formatted_address"];
completionBlock(strFormatedAddress);
}
and to call function
CLLocation* currentLocation = [[CLLocation alloc] initWithLatitude:[SharedObj.current_Lat floatValue] longitude:[SharedObj.current_Long floatValue]];
[self getAddressFromLocation:currentLocation complationBlock:^(NSString * address) {
if(address) {
NSLog(#"Address:: %#",address);
}
}];
When I trying to launch my app on simulator (3.1.3 , Xcode 3.1.4), it shows me objc_msgSend and application does not launch. This happens only when I alloc NSMUtable Array
This is my code part,
in viewDidLoad,
-(void)viewDidLoad{
locationArray = [[NSMutableArray alloc] initWithObjects:#"new delhi", #"faridabad",#"meerut"];
str1=[locationArray objectAtIndex:0];
str2=[locationArray objectAtIndex:1];
[super viewDidLoad];
}
Then I want to use locationArray objects in following method;
-(CLLocationCoordinate2D) addressLocation1{
double latitude = 0.0;
double longitude = 0.0;
NSString *str= [locationArray NSString *str= [locationArray objectAtIndex:0];
//NSString *str= #"new delhi"
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv",
[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString]];
NSArray *listItems = [locationString componentsSeparatedByString:#","];
if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:#"200"]) {
latitude = [[listItems objectAtIndex:2] doubleValue];
longitude = [[listItems objectAtIndex:3] doubleValue];
}
else {
//Show error
}
CLLocationCoordinate2D location;
location.latitude = latitude;
location.longitude = longitude;
return location;
}
problem occur only when alloc the locationArray, whats wrong with me, please help
thanks
locationArray = [[NSMutableArray alloc] initWithObjects:#"new delhi", #"faridabad",#"meerut"];
Try
locationArray = [[NSMutableArray alloc] initWithObjects:#"new delhi", #"faridabad",#"meerut", nil];
From The NSArray docs you see that for initWithObjects: it requires termination with nil. If you don't want to do that, and you know how many you have, you can use initWithObjects:count:
I have the following code in my app which adds a number of Annotations to a mapview via Google geocoding:
for (PlaceObject *info in mapLocations) {
NSString * addressOne = info.addressOne;
NSString * name = info.name;
NSString * address = [addressOne stringByAppendingString:#",London"];
NSError * error;
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString ] encoding:NSASCIIStringEncoding error:&error];
NSArray *listItems = [locationString componentsSeparatedByString:#","];
double latitude = 0.0;
double longitude = 0.0;
if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:#"200"]) {
latitude = [[listItems objectAtIndex:2] doubleValue];
longitude = [[listItems objectAtIndex:3] doubleValue];
} else {
//Error handling
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude;
coordinate.longitude = longitude;
MyLocation *annotation = [[[MyLocation alloc] initWithName:name address:address coordinate:coordinate] autorelease];
[mapViewLink addAnnotation:annotation];
}
This works, however it takes a long time for the view to appear as it seems to wait until all objects in the array have been looped through (there are about 80).
Is there any way to make the view load and then for the pins to be added as they are created ?
How about this:
for (PlaceObject *info in mapLocations) {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// GET ANNOTATION INFOS
NSString * addressOne = info.addressOne;
NSString * name = info.name;
NSString * address = [addressOne stringByAppendingString:#",London"];
NSError * error;
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString ] encoding:NSASCIIStringEncoding error:&error];
NSArray *listItems = [locationString componentsSeparatedByString:#","];
double latitude = 0.0;
double longitude = 0.0;
if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:#"200"]) {
latitude = [[listItems objectAtIndex:2] doubleValue];
longitude = [[listItems objectAtIndex:3] doubleValue];
} else {
//Error handling
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude;
coordinate.longitude = longitude;
MyLocation *annotation = [[[MyLocation alloc] initWithName:name address:address coordinate:coordinate] autorelease];
dispatch_sync(dispatch_get_main_queue(), ^{
// ADD ANNOTATION
[mapViewLink addAnnotation:annotation];
});
});
}
But please consider to double-check this code. There are definitily things you should do about keeping the threads safe and avoid EXC_BAD_ACCESS.
Where is this code executed in your app?
I'd recommend using NSURLConnection and adding the annotations after the data has been received and parsed. Look here for more info, if you're not familiar with NSURLConnection: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
Yea, you are making the classic error of doing long work (net loading from a URL) in the main (UI) thread. Move this work into a background thread and then have the main thread add the pins. This can be in several ways, by creating another explicit thread, GCD with blocks, or just performSelector in background thread. Easiest way is to probably performSelector in background and then when it has something to add to map, performSelector on main thread.