I am using CLLocation to work out the distance from the current user location, and an annotation. However I just wanted to know if this would be correct. I am currently using iPhone Simulator for this and according to the MKMapView the iPhone Simulator is situated here:
Lat: 0 Long: -1067024384
The annotation's position is:
workingCoordinate.latitude = 40.763856;
workingCoordinate.longitude = -73.973034;
However if you take a look in google maps you will find out how close these distances are, yet so far apart according to CLLocation. I am using the following code to determine the distance between them both.
CLLocation *loc = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:self.mapView.userLocation.coordinate.latitude longitude:self.mapView.userLocation.coordinate.longitude];
CLLocationDistance dist = [loc distanceFromLocation:loc2];
int distance = dist
NSLog(#"%i", distance);
The distance being NSLogged is 12769908. I believe that this is incorrect, and therefore there must be a problem with my code.
If there is please can you point it out!
You have two bad habits.
You should not depend on simulator in situations need hardware censor status. Especially when you want correct test.
You're handling types incorrectly. So you can't check values correctly. How is the longitude -1067024384? Longitude value is degrees. This means it's valid range is limited -90.0 ~ +90.0 by definition of longitude.
Your longitude value is out of range. This means one of these. You printed the value wrongly or the real value was wrong. Simulator can print wrong value. Or you printed the value with wrong method. You have to try:
Test on real device which has real hardware censors.
If bad result continues after that,
Review ALL of your application code.
Especially for printing, handling values. Check you're using correct types and castings in > each situations. Because you may did buggy operation in somewhere habitually.
And also, I recommend checking all of intermediate values like this.
CLLocationCoordinate2D annocoord = annotation.coordinate;
CLLocationCoordinate2D usercoord = self.mapView.userLocation.coordinate;
NSLog(#"ANNO = %f, %f", annocoord.latitude, annocoord.longitude);
NSLog(#"USER = %f, %f", usercoord.latitude, usercoord.longitude);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:self.mapView.userLocation.coordinate.latitude longitude:self.mapView.userLocation.coordinate.longitude];
NSLog(#"LOC = %f, %f", loc.coordinate.latitude, loc.coordinate.longitude);
NSLog(#"LOC2 = %f, %f", loc2.coordinate.latitude, loc2.coordinate.longitude);
CLLocationDistance dist = [loc distanceFromLocation:loc2];
NSLog(#"DIST: %f", dist); // Wrong formatting may show wrong value!
Try #"%f" and don't cast it that way.
In CLLocation.h
typedef double CLLocationDistance;
Related
Ive got an app that plots mkannotations (i hope i get my terminology right...its kinda confusing) on a mapview.
I have already included the subtitle for when you tap on them.
I have been looking online for a way to include the distance in those callouts but im not quite there yet. I ran across two partial solutions and Im wondering if they should be combined.
First, I didnt have CoreLocation added to my project, I need it right? To be constantly updating my user location and be able to calculate the distances to each point? Or does Mapkit somehow include a user location data that I can use?
Partial Solution A uses this code:
`-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if(!newLocation) return;
if ((oldLocation.coordinate.latitude != newLocation.coordinate.latitude) &&
(oldLocation.coordinate.longitude != newLocation.coordinate.longitude)){
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:oldLocation.coordinate.latitude longitude:oldLocation.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
CLLocationDistance distance = ([loc2 distanceFromLocation:loc1]) * 0.000621371192;
//distance = distance;
NSLog(#"Total Distance %f in miles",distance);
}
}
I understand this method calculates the distance between 2 points. I would somehow need to cycle thru my annotations and create the distance. It seems this would be the more useful one since it constantly recalculates the distances based on the current userLocation. Although, I do wonder about the effectiveness of that. Once you know how far away something is, you rarely wish to be constantly reminded as to how far away it is.
Partial Solution B uses this code:
`- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
CLLocation *pinLocation = [[[CLLocation alloc] initWithLatitude:[(MyAnnotation*)[view annotation] coordinate].latitude longitude:[(MyAnnotation*)[view annotation] coordinate].longitude]];
CLLocation *userLocation = [[CLLocation alloc] initWithLatitude:self._mapView.userLocation.coordinate.latitude longitude:self._mapView.userLocation.coordinate.longitude];
CLLocationDistance distance = [pinLocation distanceFromLocation:userLocation];
NSLog(#"Distance to pin %4.0f", distance);
}
`
In this case, whenever the pin is tapped, the distance is calculated. But Im unclear as to the code for MyAnnotation [view annotation], Im guessing the original poster had his locations based off of a MyAnnotation Class so I changed it to MyLocation and all but 1 error went away. I get an Expected Identifier error at the pinLocation line at the last square bracket for some reason.
I feel the solution is in the tip of my tongue. Just need that little extra push :)
Thanks guys
Just move the code inside the calloutAccessoryControlTapped method right after the line, wherever you have it, that creates the MKAnnotation. Give MKAnnotation subclass a float distance property and set it as the subtitle.
Currently i am working on a Location based application for iPhone/iPad . I have several annotations in my MapKit , what i want to do is to track the location of the user and shows the annotations that are within the 3km . Can somebody give me a start ?
Sorry for the delayed response... the question just fell off my radar.
I'm going to suppose that you have a method that returns a set of NSValue-wrapped CLLocationCoordinate2D structs (the basic approach is the same regardless of what your internal data representations are). You can then filter the list using a method something akin to the following (warning: typed in browser):
NSSet *locations = ...;
CLLocation centerLocation = ...; // Reference location for comparison, maybe from CLLocationManager
CLLocationDistance radius = 3000.; // Radius in meters
NSSet *nearbyLocations = [locations objectsPassingTest:^(id obj, BOOL *stop) {
CLLocationCoordinate2D testCoordinate;
[obj getValue:&testCoordinate];
CLLocation *testLocation = [[CLLocation alloc] initWithLatitude:testCoordinate.latitude
longitude:testCoordinate.longitude];
BOOL returnValue = ([centerLocation distanceFromLocation:testLocation] <= radius);
[testLocation release];
return returnValue;
}
];
With the filtered set of coordinates in hand, you can create MKAnnotation instances and add them to the map in the usual manner, as described in Apple's documentation.
If you have many thousands of test locations then I suppose this approach could start to incur performance issues. You would then want to switch your point storage approach to use, e.g., quadtrees, to reduce the number of points that need to be precision-filtered. But don't optimize prematurely!
Hope that helps!
I am developing an iPhone app. here in my App I have included Google maps.I am showing the highlighted path in map.
Now my Question is how to calculate distance between two point as per path as Apple"s native map App is showing routes with distance.
Thanks in Advance.
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:oldLocation.coordinate.latitude longitude:oldLocation.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.latitude];
CLLocationDistance distance = ([loc2 distanceFromLocation:loc1]) * 0.000621371192;
This may help you.
When running in the simulator, Core Location assigns a fixed set of coordinate values to this property. You must run your application on an iOS-based device to get real location values.
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.latitude];
I am a new iPhone developer learning Objective-C, and am trying to dynamically calculate the distances between the users latitude/longitude coordinates, with latitude/longitude coordinates in a SQLite table. I know that we can use CLLocations method:
(CLLocationDistance)distanceFromLocation:(const CLLocation *)location
to do this, but I'm not sure how to use it given the data that I have. How does one use the above method using pairs of latitude/longitude coordinates, considering the above method only deals with location objects of type CLLocation? Can anyone give me a simple example of how to use this method using two pairs of latitude/longitude coordinates?
Just create CLLocation objects from your data:
// Assumption: lat1, lon1 and lat2, lon2 are double values containing the coordinates
CLLocation *firstLocation = [[[CLLocation alloc] initWithLatitude:lat1 longitude:lon1] autorelease];
CLLocation *secondLocation = [[[CLLocation alloc] initWithLatitude:lat2 longitude:lon2] autorelease];
CLLocationDistance distance = [secondLocation distanceFromLocation:firstLocation];
How is a 1000ft or 1/2 mile distance determined with mapkit? Either a radius from some pin or the distance between two pins.
For example, I center the map on pin A. Pins B, C, and D are also on the map at various distances from pin A. B and C are within 1/2 mile from A but D is 1 mile away. I'd like to know that B and C are within 1/2 mile from A. How can I calculate that?
Since you've stated that the two different points are "pins", I'm going to assume you're using MKPinAnnotationView (or some other annotation view). If not, you're going to have to get the location some other way.
If you have pointers to the annotation objects for these locations, then you can easily call -coordinate on them, create CLLocations from these coordinates (using -initWithLatitude:longitude:), and then use the method -getDistanceFrom to retrieve the distance in meters. From there, it's an easy conversion to miles. All told, the code would look something like this:
CLLocationCoordinate2D pointACoordinate = [pointAAnnotation coordinate];
CLLocation *pointALocation = [[CLLocation alloc] initWithLatitude:pointACoordinate.latitude longitude:pointACoordinate.longitude];
CLLocationCoordinate2D pointBCoordinate = [pointBAnnotation coordinate];
CLLocation *pointBLocation = [[CLLocation alloc] initWithLatitude:pointBCoordinate.latitude longitude:pointBCoordinate.longitude];
double distanceMeters = [pointALocation getDistanceFrom:pointBLocation];
double distanceMiles = (distanceMeters / 1609.344);
You'll end up with the distance in miles, and can compare it from there. Hope this helps.
getDistanceFrom is now deprecated so here's an alternative answer for anyone looking to do this.
CLLocationCoordinate2D pointACoordinate = [pointAAnnotation coordinate];
CLLocation *pointALocation = [[CLLocation alloc] initWithLatitude:pointACoordinate.latitude longitude:pointACoordinate.longitude];
CLLocationCoordinate2D pointBCoordinate = [pointBAnnotation coordinate];
CLLocation *pointBLocation = [[CLLocation alloc] initWithLatitude:pointBCoordinate.latitude longitude:pointBCoordinate.longitude];
float distanceMeters = [pointALocation distanceFromLocation:pointBLocation];
float distanceMiles = (distanceMeters / 1609.344);
[pointALocation release];
[pointBLocation release];
As above, you could use float instead of double and you could cast the results to an int if you don't require the precision of the float like so:
int distanceCastToInt = (int) [pointALocation distanceFromLocation:pointBLocation];
The int is handy if you wanted to give a rough idea of distance in the annotation like so:
pointAAnnotation.title = #"Point A";
pointAAnnotation.subtitle = [NSString stringWithFormat: #"Distance: %im",distanceCastToInt];
The subtitle of the annotation would read "Distance: 50m" for example.
This is Swift 3 equivalent of the given answer:
let pointACoordinate = pointAAnnotation.coordinate
let pointALocation = CLLocation(latitude: pointACoordinate.latitude, longitude: pointACoordinate.longitude)
let pointBCoordinate = pointBAnnotation.coordinate
let pointBLocation = CLLocation(latitude: pointBCoordinate.latitude, longitude: pointBCoordinate.longitude)
let distanceMeters = pointALocation.distance(from: pointBLocation)
let distanceMiles = (distanceMeters / 1609.344)