How to implement %0.7f in annotation.coordinate? - ios

I have two strings which hold values say for ex:35.5044752 97.3955550
Let me convert it :
double f1=[la doubleValue];
double f2=[lo doubleValue];
(value of f1 and f2 is dynamic say for example f1= "35.5044752" f2="97.3955550" )
if i want to print it in NSLog i will do as follows :
NSLog(#" %f %f ",f1,f2);
And it returns 35.504475 97.395555
hence i change it as
NSLog(#" %0.7f %0.7f ",f1,f2);
And gets the full values like 35.5044752 97.3955550
Now i need it to use in the Coordinate like below:
annotation.coordinate=CLLocationCoordinate2DMake(coord.longitude, coord.longitude);
My Question is how can i implement %0.7f here like which i made in NSlog ?
so that i should take input fully instead of reducing or altering the value.

make a try like this. Directly pass values to obj center
CLLocationCoordinate2D center;
...
else if ([elementName isEqualToString:#"Lat"]) {
center.latitude = [[attributeDict objectForKey:#"degrees"] doubleValue];
}
else if ([elementName isEqualToString:#"Lon"]) {
center.longitude = [[attributeDict objectForKey:#"degrees"] doubleValue];
}
...
OR
Archived the coordinate in foundLocation:
NSNumber *latitudeObject = [NSNumber numberWithDouble:coord.latitude];
NSNumber *longitudeObject = [NSNumber numberWithDouble:coord.longitude];
NSArray *coordinateArray = [NSArray arrayWithObjects:latitudeObject, longitudeObject, nil];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:coordinateArray]
forKey:WhereamiCoordinatePrefKey];
Unarchived the coordinate in viewDidLoad:
NSArray *coordinateArray = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults]
objectForKey:WhereamiCoordinatePrefKey]];
CLLocationCoordinate2D savedCoordinate = CLLocationCoordinate2DMake([[coordinateArray objectAtIndex:0] doubleValue],
[[coordinateArray objectAtIndex:1] doubleValue]);
MKCoordinateRegion savedRegion = MKCoordinateRegionMakeWithDistance(savedCoordinate, 250, 250);
[worldView setRegion:savedRegion animated:YES];

The %0.7f format specifier deals with how your value is displayed, not with how it is stored. A double is always double and has its inherent precision and nothing you can do, short of casting it to another data type, will change that.
As far as I know, the double data type offers the highest floating point precision of the standard data types. If you need greater precision than that, you're going to have to use something other than a double.
In other words, when you perform an operation on a double, it is always calculated to the full precision allowed by the double data type.
For more information on the subject, see the Wikipedia entry on floating point data types.

Related

CLLocation distanceFromLocation result is differ when I calculate

I have used CLLocation's distanceFromLocation: method to calculate distance from some location.
But it's result is slightly different when I calculate by using "Haversine formula".
- (CLLocationDistance)distanceFromCoordinate:(CLLocationCoordinate2D)fromCoord {
double earthRadius = 6371.0; // Earth's radius in Kilometers
// Get the difference between our two points then convert the difference into radians
double nDLat = RADIANS((fromCoord.latitude - self.coordinate.latitude));
double nDLon = RADIANS((fromCoord.longitude - self.coordinate.longitude));
double fromLat = RADIANS(self.coordinate.latitude);
double toLat = RADIANS(fromCoord.latitude);
double nA = pow ( sin(nDLat/2.0), 2 ) + cos(fromLat) * cos(toLat) * pow ( sin(nDLon/2.0), 2 );
double nC = 2.0 * atan2( sqrt(nA), sqrt( 1 - nA ));
double nD = earthRadius * nC;
return nD * 1000.0;
}
CLLocation * loc = [[CLLocation alloc] initWithLatitude:[location.latitude doubleValue]
longitude:[location.longitude doubleValue]];
CLLocationDistance dist = [userLocation distanceFromLocation:loc];
CLLocationDistance dist2 = [userLocation distanceFromCoordinate:loc.coordinate];
Why two values are different?
Should I init location object with horizontalAccuracy and verticalAccuracy?
Your results are different because you are using different code.
You don't say how different.
Totally different? There's a bug in your code.
Big differences for places close together? Maybe your formula has problems with rounding errors.
Differences that grow as places are further apart? Maybe your definition of distance is different. Should be the closest distance on a path along earth surface.
In general, Earth is not a sphere but a spheroid. Taking that into account is more difficult but gives more precise results.
It is slightly different because Earth's Radius is not exact 6371 km. Use the correct Earth's radius, may be you can get better results.
Use the official WGS84 earth radius:
6 378 137 meter
I remember that ios delivers exactly the same result.
Should I init location object with horizontalAccuracy and
verticalAccuracy?
No, for sure not. That attributes are hints how acurate the position might be.
Distance is calculated by latitude and longitude only.
There are not much formulas:
- haversine formula (a bit slower than law of cosines, otherwise fine)
- law of cosines (problematic on small distances if not using 64 bit precision)
- vicenties which i smore acurate, it uses an elipsoidal earth model.
I also got the same problem... so i used google webservice to calculate distance. use this method, you will get accurate distance
-(void)calculateDistance()
{
//http://maps.googleapis.com/maps/api/directions/json?origin=41.742964,-87.995971& destination=41.811511,-87.967923&mode=driving&sensor=false
NSString *LocationUrl = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#,%#&destination=%#,%#&mode=driving&sensor=false",origin.latitude,origin.longitude,destination.latitude,destination.latitude];
NSLog(#"Location URL:%#",LocationUrl);
NSURL *finalurl = [NSURL URLWithString: LocationUrl];
NSLog(#"Final URL = %#",finalurl);
NSData *data = [NSData dataWithContentsOfURL:finalurl];
NSLog(#"Data:-%#",data);
NSError *error;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions error:&error];
// NSLog(#"josn data of location:%#",[json description]);
NSMutableDictionary *routes = [json objectForKey:#"routes"];
NSMutableArray *legs = [routes valueForKey:#"legs"];
NSMutableDictionary *newDistance =[legs valueForKey:#"distance"];
NSMutableArray distanceList =[[newDistance valueForKey:#"text"]objectAtIndex:0];
distance = [[distanceList objectAtIndex:0]floatValue];
NSLog(#"%.1f",distance);
}
Hope it will help you

subtracting latitudes with NSNumber type to find distance

I want to subtract two latitudes from each other to find the shortest distance, but I get this error, "Arithmetic on pointer to interface 'NSNumber', which is not a constant size in non-fragile ABI" If I change the - to a + I get a different error "Invalid operands to binary expression ('NSNumber *' and 'NSNumber *')" I've tried using doubles and many combinations of things, but it just doesn't work.
NSNumber *userLatitude = [NSNumber numberWithDouble:43.55];//sample
NSArray *listOfCities = [managedObjectContext executeFetchRequest:request error:&error];
for (CityList *item in listOfCities){
NSLog(#"latitude is %#",item.latitude);
NSNumber *distanceLat = userLatitude - item.latitude;
I will then insert them into a mutable array along with the longitudes and compare the distance. One possible solution using CLLocation would be
double distance = [usersCurrentLoc distanceFromLocation:otherLoc];
where usersCurrentLoc and otherLoc are both CLLocation variables.
I also want use the latitude and longitudes individually so I can do some custom plotting, and they are also stored separately, so I'd like to figure out the correct data types and most efficient solution.
item.latitude comes from core-data with the data model type of double and X-code auto generated the CityList class with a property of NSNumber * latitude;
If you want subtract two NSNumbers, then use this
NSNumber *distanceLat = [NSNumber numberWithFloat:([userLatitude floatValue] - [item.latitude floatValue])];
This:
NSNumber *distanceLat = userLatitude - item.latitude;
needs to be:
NSNumber *distanceLat = #([userLatitude doubleValue] - item.latitude);
If item.latitude is also an NSNumber then you need to call doubleValue on it too.
NSNumber is an object. You can't do math on the object. You need to use doubleValue to get its value and then you need to wrap the result in a new NSNumber instance.
BTW - why bother with NSNumber here? Why not do:
double userLatitude = 43.55;
double distanceLat = userLatitude - item.latitude;
CLLocationCoordinate2D newCoordinate = [newLocation coordinate];
CLLocationCoordinate2D oldCoordinate = [oldLocation coordinate];
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
The above one can be used to find distance between two locations

How to get a double value from an object posted with NSNotification

I am having issues extracting a double from an NSObject.
I am receiving a notification like so
NSString *key = #"Post";
NSDictionary *dictionary = [notification userInfo];
Post* post = [dictionary objectForKey:key];
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = post.lat;
zoomLocation.longitude = post.lng;
NSLog(#"%f", post.lat);
NSLog(#"%#", post);
The NSLog for post.lat is nan. The NSLog for post is
(entity: Post; id: 0x85e9820 ; data: {
created = "2013-10-08 16:25:36 +0000";
lat = "-33.886336";
lng = "151.209565";
"post_id" = 2418;
})
Hopefully it is something really simple I am missing. Thanks in advance.
EDIT: When I try to use [post.lat doubleValue] it gets an error that prevents building "Bad receiver type 'double'"
ANSWER: I needed to extract the value like this
[[post valueForKey:#"lat"] doubleValue];
I see double quotes around the values of lat and png. That likely means that those values are really strings and not numbers.
If that is the case then you can use NSString#doubleValue to get a converted numeric value that is compatible with CLLocationCoordinate2D.latitude/longitude.
Maybe you can try it like this:
NSDictionary *location = #{#lat,#lng};
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION" object:location];
Then get the location like this:
NSDictionary *location = notification.object;
depends on what class "lat" is. if it is an NSNumber then do [post.lat doubleValue]
Edit: from your updated question we see now that the Post.lat is indeed a double. However, as #St3fan pointed out the double quotes in the entity output make it appear as though that value is a string. So you have a double that is inited to NaN and is used for the property and another lat variable that is a string it would seem. Two separate variables.

How to convert NSMutableArray to CLLocationCoordinate2D

I have NSMutableArray:
userCoordinates = [[d objectForKey:#"geo"] objectForKey:#"coordinates"];
NSLog(#"%#",userCoordinates);
NSLog shows:
(
"19.365367",
"-99.159887"
)
Then I need to convert this array to CllocationCoordinate2D to use it for create annotation.
Sorry my english. Thanks.
It seems that your array contains two NSString objects - to convert them to the appropriate floating-point numbers, use the doubleValue method of NSString:
double lat = [(NSString *)[userCoordinates objectAtIndex:0] doubleValue];
double lon = [(NSString *)[userCoordinates objectAtIndex:1] doubleValue];
CLLocationCoordinate2D coords = (CLLocationCoordinate2D){ lat, lon };

calling [mapView addOverlay:] has no effect

For some reason, when I use [mapView addOverlay:], nothing happens.
Code:
NSData* dataLat = [[NSUserDefaults standardUserDefaults] objectForKey:#"latKey"];
NSArray* overlayLat = [NSKeyedUnarchiver unarchiveObjectWithData:dataLat];
double lats[overlayLat.count];
NSData* dataLong = [[NSUserDefaults standardUserDefaults] objectForKey:#"longKey"];
NSArray* overlayLong = [NSKeyedUnarchiver unarchiveObjectWithData:dataLong];
double longs[overlayLong.count];
for(int iii = 0; iii < overlayLat.count; iii++)
{
NSNumber* a = (NSNumber*)[overlayLat objectAtIndex:iii];
lats[iii] = [a doubleValue];
}
for(int iii = 0; iii < overlayLong.count; iii++)
{
NSNumber* a = (NSNumber*)[overlayLong objectAtIndex:iii];
longs[iii] = [a doubleValue];
}
int size = (sizeof(lats) / sizeof(lats[0]));
NSLog(#"%d", size);
MKMapPoint points[size];
for(int iii = 0; iii < overlayLong.count; iii++)
{
MKMapPoint point = MKMapPointMake(lats[iii], longs[iii]);
if(lats[iii] != 0)
points[iii] = point;
}
for(int iii = 0; iii < 15; iii++)
{
NSLog(#"Lat (x):%f", points[iii].x);
NSLog(#"Long (y):%f", points[iii].y);
}
MKPolyline* line = [MKPolyline polylineWithPoints:points count:size];
[mapView addOverlay:line];
NSLog(#"finished");
The vast majority of this code just accesses the data and turns it into usable coordinates. My question is (because I know that the coordinates are valid because of the NSLogs), why doesn't anything get added to the mapView when addOverlay: is called? I can post more code if need be. Thanks!
The polylineWithPoints:count: method takes a C array of MKMapPoint structs.
An MKMapPoint is not the same as a CLLocationCoordinate2D (latitude, longitude). You are creating MKMapPoint structs using MKMapPointMake but giving it latitude and longitude values. Such an MKMapPoint is not at the expected location.
Either use MKMapPointForCoordinate to create an MKMapPoint from lat/long coordinates or, probably easier, create a C array of CLLocationCoordinate2D structs and call polylineWithCoordinates:count: instead.
Could it be your 'size' is wrong? Your points array will also have missing items anywhere the source data had 0. I'd go with an NSMutableArray and add items to that if they are deemed valid, then count that at the end and pass it to polylineWithPoints.

Resources