create CLLocationCoordinate2D from array - iphone

I have a plist with dictionary of array's with coordinates (stored as strings).
I want to create a CLLocationCoordinate2D from every array and crate an overlay for the map.
I did that -
NSString *thePath = [[NSBundle mainBundle] pathForResource:#"Roots" ofType:#"plist"];
NSDictionary *pointsDic = [[NSDictionary alloc] initWithContentsOfFile:thePath];
NSArray *pointsArray = [NSArray arrayWithArray:[pointsDic objectForKey:#"roade1"]];
CLLocationCoordinate2D pointsToUse[256];
for(int i = 0; i < 256; i++) {
CGPoint p = CGPointFromString([pointsArray objectAtIndex:i]);
pointsToUse[i] = CLLocationCoordinate2DMake(p.x,p.y);
NSLog(#"coord %f",pointsToUse [i].longitude);
NSLog(#"coord %f",pointsToUse [i].latitude);
}
MKPolyline *myPolyline = [MKPolyline polylineWithCoordinates:pointsToUse count:256];
[[self mv] addOverlay:myPolyline];
but the app is crashing without any error.
(BTW when i remove the addOverLay method the app does not crash).
I have 2 questions-
What am i doing wrong?
I have tried to set the pointsArray count as the argument for the CLLocationCoordinate2D like that -
CLLocationCoordinate2D pointsToUse[pointsArray count];
And i am getting an error.
How can i set the CLLocationCoordinate2D dynamically ?
Thanks for any help.
Shani

O.K
The problem was indeed in the viewForOverlay method (thanks aBitObvious and all the rest).
It appears that the line loading of the point from the array is working good.
and for the second question i just separated it to 2 steps:
NSInteger c = [pointsArray count];
CLLocationCoordinate2D pointsToUse[c];
and it worked fine, so if any one is looking for a way to load overlayes from plist, that way is working for me.
Thanks
shani

Related

How can i change the NSArray to MKPolyline polylineWithCoordinates compatible type?

I add a NSTimer to record the location from location manager ,and put ever location into a NSMutableArray.
-(void)OnTimer:(NSTimer *)param{
[self.locationRecoder addObject:self.manager.location];
}
and I add a button to UI, when I click the button, it invoke this method
-(IBAction)Click:(id)sender(){
NSArray *coordinateArray = [self.locationRecorder valueForKeyPath:#"coordinate"];
MKPolyline *lines = [MKPolyline ploylineWithCoordinates:(CLLocationCoordinate2D *)coordinateArray count:coordinateArray.count];
[self.map addOverlay:lines];
}
then there is nothing drawn. did i do something wrong in type cast?
The polylineWithCoordinates method requires a plain C array of structs of type CLLocationCoordinate2D.
After the call to valueForKeyPath, coordinateArray is an NSArray of NSValue objects.
That is not the same thing as a C array of structs.
Casting that NSArray to (CLLocationCoordinate2D *) doesn't convert it to a C array of structs.
Instead, you have to create the C array manually using malloc and looping through the locationRecoder array:
CLLocationCoordinate2D *coordinateArray
= malloc(sizeof(CLLocationCoordinate2D) * locationRecorder.count);
int caIndex = 0;
for (CLLocation *loc in locationRecorder) {
coordinateArray[caIndex] = loc.coordinate;
caIndex++;
}
MKPolyline *lines = [MKPolyline polylineWithCoordinates:coordinateArray
count:locationRecorder.count];
free(coordinateArray);
[self.map addOverlay:lines];

Load only five annotations to MKMapVIew

I have a MKMapView, and I would like to know how I can find the nearest 5 annotations to the user, and only display them on the MKMapView.
My code currently is:
- (void)loadFiveAnnotations {
NSString *string = [[NSString alloc] initWithContentsOfURL:url];
string = [string stringByReplacingOccurrencesOfString:#"\n" withString:#""];
NSArray *chunks = [string componentsSeparatedByString:#";"];
NSArray *keys = [NSArray arrayWithObjects:#"type", #"name", #"street", #"address1", #"address2", #"town", #"county", #"postcode", #"number", #"coffeeclub", #"latlong", nil];
// max should be a multiple of 12 (number of elements in keys array)
NSUInteger max = [chunks count] - ([chunks count] % [keys count]);
NSUInteger i = 0;
while (i < max)
{
NSArray *subarray = [chunks subarrayWithRange:NSMakeRange(i, [keys count])];
NSDictionary *dict = [[NSDictionary alloc] initWithObjects:subarray forKeys:keys];
// do something with dict
NSArray *latlong = [[dict objectForKey:#"latlong"] componentsSeparatedByString:#","];
NSString *latitude = [[latlong objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *longitude = [[latlong objectAtIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
CLLocationDegrees lat = [latitude floatValue];
CLLocationDegrees longi = [longitude floatValue];
Annotation *annotation = [[Annotation alloc] initWithCoordinate:CLLocationCoordinate2DMake(lat, longi)];
annotation.title = [dict objectForKey:#"name"];
annotation.subtitle = [NSString stringWithFormat:#"%#, %#, %#",[dict objectForKey:#"street"],[dict objectForKey:#"county"], [dict objectForKey:#"postcode"]];
[mapView addAnnotation:annotation];
[dict release];
i += [keys count];
}
}
A long answer, already mostly written when Stephen Poletto posted and containing example code on how to use the built-in methods for sorting an array, so I though it was still worth posting though the essential answer is the same (ie, "pick the five closest for yourself, pass only those on"):
You're going to need to sort your annotations by distance for yourself, and submit only the closest five to the MKMapView. If you have two CLLocations then you can get the distance between them using the distanceFromLocation: method (which was getDistanceFrom: prior to iOS 3.2; that name is now deprecated).
So, for example, supposing your Annotation class had a method 'setReferenceLocation:' to which you pass a CLLocation and a getter 'distanceFromReferenceLocation' which returns the distance between the two, you could do:
// create and populate an array containing all potential annotations
NSMutableArray *allPotentialAnnotations = [NSMutableArray array];
for(all potential annotations)
{
Annotation *annotation = [[Annotation alloc]
initWithCoordinate:...whatever...];
[allPotentialAnnotations addObject:annotation];
[annotation release];
}
// set the user's current location as the reference location
[allPotentialAnnotations
makeObjectsPerformSelector:#selector(setReferenceLocation:)
withObject:mapView.userLocation.location];
// sort the array based on distance from the reference location, by
// utilising the getter for 'distanceFromReferenceLocation' defined
// on each annotation (note that the factory method on NSSortDescriptor
// was introduced in iOS 4.0; use an explicit alloc, init, autorelease
// if you're aiming earlier)
NSSortDescriptor *sortDescriptor =
[NSSortDescriptor
sortDescriptorWithKey:#"distanceFromReferenceLocation"
ascending:YES];
[allPotentialAnnotations sortUsingDescriptors:
[NSArray arrayWithObject:sortDescriptor]];
// remove extra annotations if there are more than five
if([allPotentialAnnotations count] > 5)
{
[allPotentialAnnotations
removeObjectsInRange:NSMakeRange(5,
[allPotentialAnnotations count] - 5)];
}
// and, finally, pass on to the MKMapView
[mapView addAnnotations:allPotentialAnnotations];
Depending on where you're loading from, you made need to create a local store (in memory or on disk) for annotations and select the five nearest whenever the user moves. Either register yourself as a CLLocationManager delegate or key-value observe on the map view's userLocation property. If you have quite a lot of potential annotations then sorting all of them is a bit wasteful and you'd be better advised to use a quadtree or a kd-tree.
First you'll need to grab the user's current location. You can build a CLLocationManager and register yourself as the delegate for location updates as follows:
locationManager = [[[CLLocationManager alloc] init] autorelease];
[locationManager setDelegate:self];
[locationManager startUpdatingLocation];
After setting yourself as the delegate, you'll receive the following callback:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
Now that you have the user's location (newLocation), you can find the five closest annotations. There is a handy method in CoreLocation:
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
As you're iterating through your annotations, just store the five nearest locations. You can build a CLLocation out of the 'lat' and 'longi' variables you have using:
- (id)initWithLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude
Hope this helps!

How to get a description for each pin, in Google Maps for the iPhone

I have a problem with MKPointAnnotation. I want to create my iPhone application like this:
Show a pin in Google Maps
Show a description on each pin, pulling that description from a NSMutableArray.
So, My question is, how do I show a description on each pin?
This is my code:
NSMutableArray *points = [[NSMutableArray alloc] init];
for(int i=0; i < [dataTable count]; i++) {
MKPointAnnotation *point =[[MKPointAnnotation alloc] init];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[[dataTable objectAtIndex:i] objectForKey:#"latitude"] floatValue];
coordinate.longitude = [[[dataTable objectAtIndex:i] objectForKey:#"longitude"] floatValue];
[point setCoordinate:coordinate];
[point setTitle:[[dataTable objectAtIndex:i] objectForKey:#"name"]]; //-- name of pin
[points addObject:point];
}
[map addAnnotations:points];
I would adopt the MKAnnotation protocol in my own class and simply override the
- (NSString) title
and implement
- (CLLocationCoordinate2D) coordinate {
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = self.latitude;
theCoordinate.longitude = self.longitude;
return theCoordinate;
}
My class would also have an initialiser that takes all the data it needs (from the array you mentioned)
- (id) initWithTitle:(NSString *)title_ andLatitude:(CLLocationDegrees)latitude_ andLongitude:(CLLocationDegrees)longitude_;
When iterating I would create my own objects and then add them to the collection of annotations.
Cheers...

CLLocationCoordinate2D without knowing how many will be in the array?

I need to build an array using something like the following:
CLLocationCoordinate2D points[4];
points[0] = CLLocationCoordinate2DMake(41.000512, -109.050116);
points[1] = CLLocationCoordinate2DMake(41.002371, -102.052066);
points[2] = CLLocationCoordinate2DMake(36.993076, -102.041981);
points[3] = CLLocationCoordinate2DMake(36.99892, -109.045267);
Problem is, I will never know how many items are going to be in the array, so I can specify the count. Is there a way to create a CLLocationCoordinate2D array, and just insert new coordinates without knowing what the final total will be?
EDIT: My final goal is to use the coordinates to make an MKPolyline, using the polylineWithCoordinates method which needs a CLLocationCoordinate2D array.
// unpacking an array of NSValues into memory
CLLocationCoordinate2D *points = malloc([mutablePoints count] * sizeof(CLLocationCoordinate2D));
for(int i = 0; i < [mutablePoints count]; i++) {
[[mutablePoints objectAtIndex:i] getValue:(points + i)];
}
MKPolyline *myPolyline = [MKPolyline polylineWithCoordinates:points count:[mutablePoints count]];
free(points);
Box them up in an NSValue object and throw them in an NSMutableArray.

How can i show Multiple pins on the map?

i want to show multiple pins on my MapView all with Animation of Dropping pin so how it is possible if any body have sample code then please send send link.i am new in this field.Thanks in Advance.
There are few code samples on developer.apple.com
This
is a simple map example with two pins
Just as you show single pin.. keep the code for single pin in Loop and pass different longitude latitude in loop.. You will get the pins at different location
if([points retainCount] > 0)
{
[points release];
points = nil;
}
if([annotationAry retainCount] > 0)
{
[annotationAry release];
annotationAry = nil;
}
points = [[NSMutableArray alloc]init];
annotationAry = [[NSMutableArray alloc]init];
for(int i=0;i<[longitudeary count];i++)
{
CLLocation* currentLocation1 = [[CLLocation alloc] initWithLatitude:[[latitudeary objectAtIndex:i]doubleValue] longitude:[[longitudeary objectAtIndex:i]doubleValue]];
[points addObject:currentLocation1];
}
for(int i=0;i<[points count];i++)
{
// CREATE THE ANNOTATIONS AND ADD THEM TO THE MAP
CSMapAnnotation* annotation = nil;
// create the start annotation and add it to the array
annotation = [[[CSMapAnnotation alloc] initWithCoordinate:[[points objectAtIndex:i] coordinate]
annotationType:CSMapAnnotationTypeImage
title:#"123456..."
shID:[shIDary objectAtIndex:i]
catID:[catIDary objectAtIndex:i]
ciggUse:[ciggaretteUSEary objectAtIndex:i]
wifiUse:[wifiUSEary objectAtIndex:i]
controller:self]autorelease];
[annotationAry addObject:annotation];
}
[mapViewmy addAnnotations:[NSArray arrayWithArray:annotationAry]];