Plotting multiple markers in Google Maps - ios

Hi I am working on Google Maps SDK for ios. I want to plot a number of markers in Google maps from NSArray which contains location name, latitude and longitude.
I tried using For loops which seems a little lame already but,
for(int i=0;i<=[myArray count];i++){
self.view = mapView_;
NSString *lat = [[myArray objectAtIndex:i] objectForKey:#"latitude"];
NSString *lon = [[myArray objectAtIndex:i] objectForKey:#"longitude"];
double lt=[lat doubleValue];
double ln=[lon doubleValue];
NSString *name = [[myArray objectAtIndex:i] objectForKey:#"name"];
NSLog(#"%# and %# and %f and %f of %#",lat,lon, lt,ln,name);
GMSMarker *marker = [[GMSMarker alloc] init];
marker.animated=YES;
marker.position = CLLocationCoordinate2DMake(lt,ln);
marker.title = name;
marker.snippet = #"Kathmandu";
marker.map = mapView_;
}
Here myarray is the array that has location name , latitude longitude in string format which I converted it to double. When I run this code Xcode shows me NSRangeException: index beyond bounds, which is probably because I am trying to use same object to display different indexes in same map. But at the same time, I couldnot think of any way to use GMSMarker as array.
I could however plot multiple markers if I used different GMSMarker objects, but that doesnot solve my problem. I made another object like this, using two GMSMarker objects work to show two markers on the same map.
GMSMarker *marker1 = [[GMSMarker alloc] init];
marker1.animated=YES;
marker1.position = CLLocationCoordinate2DMake(lt,ln);
marker1.title = name;
marker1.snippet = #"Kathmandu";
marker1.map = mapView_;
Any help?

But at the same time, I couldnot think of any way to use GMSMarker as array.
try this:
NSMutableArray *markersArray = [[NSMutableArray alloc] init];
for(int i=0;i<[myArray count];i++){
// ... initialise marker here
marker.map = mapView_;
[markersArray addObject:marker];
[marker release];
}

Related

NSMutableArray parsing csv not working?

I have this code where I use NSMutableArray to parse a csv file. There are no errors that stop me from running the app however the map doesn't display anything.
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"Data2" ofType:#"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];
NSMutableArray *allLinedStrings = [[NSMutableArray alloc]initWithArray:[dataStr componentsSeparatedByString:#"\r"]];
NSMutableArray *latitude = [[NSMutableArray alloc]init];
NSMutableArray *longitude = [[NSMutableArray alloc]init];
NSMutableArray *description = [[NSMutableArray alloc]init];
NSMutableArray *address = [[NSMutableArray alloc]init];
NSMutableArray *temperature = [[NSMutableArray alloc]init];
NSMutableArray *time = [[NSMutableArray alloc]init];
NSMutableArray *ambient = [[NSMutableArray alloc]init];
NSMutableArray *filteredLocations = [NSMutableArray array];
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * filteredLocations.count);
for (int idx = 0; idx < [allLinedStrings count]; idx++)
{
NSMutableArray *infos = [[NSMutableArray alloc]initWithArray:[[allLinedStrings objectAtIndex:idx] componentsSeparatedByString:#","]];
if ([infos count] > 1)
{
[latitude addObject:[infos objectAtIndex:4]];
[longitude addObject:[infos objectAtIndex:5]];
[description addObject:[infos objectAtIndex:0]];
[address addObject:[infos objectAtIndex:10]];
[temperature addObject:[infos objectAtIndex:6]];
[time addObject:[infos objectAtIndex:15]];
[ambient addObject:[infos objectAtIndex:8]];
if([[latitude objectAtIndex:4] isEqualToString:#"NULL"] || [[longitude objectAtIndex:5] isEqualToString:#"NULL"] || [[description objectAtIndex:0] isEqualToString:#"NULL"] || [[address objectAtIndex:10]isEqualToString:#"NULL"] || [[temperature objectAtIndex:6] isEqualToString:#"NULL"] || [[time objectAtIndex:15]isEqualToString:#"NULL"] || [[ambient objectAtIndex:8] isEqualToString:#"NULL"]) {continue;}
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[latitude objectAtIndex:4] doubleValue];
coordinate.longitude = [[longitude objectAtIndex:5] doubleValue];
Location *annotation = [[Location alloc] initWithName:[description objectAtIndex:0] address:[address objectAtIndex:10] temperature:[temperature objectAtIndex:6] time:[time objectAtIndex:15] ambient:[ambient objectAtIndex:8] coordinate:coordinate] ;
[mapview addAnnotation:annotation];
[filteredLocations addObject:annotation];
MKMapPoint point = MKMapPointForCoordinate(coordinate);
pointArr[idx] = point;
}
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:filteredLocations.count];
[self.mapview addOverlay:self.routeLine];
free(pointArr);
MKMapRect zoomRect = MKMapRectNull;
for (id <MKAnnotation> annotation in mapview.annotations)
{
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
[mapview setVisibleMapRect:zoomRect animated:YES];
self.mapview.delegate = self;
}
I guess there must be something wrong with how I'm calling the objects or maybe the MKMapPoint but I don't manage to find what's blocking the app from displaying the data. I've tried using both "initWithObjects" and removing "if ([infos count] > 1){" but when ran it crashed showing a breakdown point in "NSMutableArray *latitude = [[NSMutableArray alloc]init];".
Based on your previous questions about this project, you want to do the following at a high level:
Parse a CSV file where each line has coordinate data. Ignore lines that have "null" data. (For the purpose of this answer, let's ignore that one could use a pre-built CSV parser, or use a different format altogether.)
Show annotations for lines with "good" data.
Connect all the annotations with a line.
For requirement 1 (R1), you already know how to load the CSV file, loop through the lines, and identify the lines with "null" data.
For requirement 2 (R2), after some research, you know that you can create and add annotations to the map one at a time and the map doesn't need to know ahead of time how many you will add so that means the first two requirements could be done in the same loop.
For requirement 3 (R3), after some research, you know that to create and add a polyline to the map, you need to know ahead of time how many points will be in the line.
For R1 and R2, you will be looping through the lines of the CSV and identify the non-null lines.
So that means you will know how many points will be in the polyline after the loop that handles R1 and R2. That means the polyline must be created after that loop.
But to create the polyline, you need not just the point count but the coordinates for each point as well.
That means while looping through the lines in the CSV, you need to save the coordinate data somewhere (in the same order it appeared in the CSV).
In Objective-C, a convenient structure that allows you to add data to it without knowing in advance how many objects will be added is an NSMutableArray.
So now we have this very high-level plan:
Loop through the CSV file, ignore lines with null data, create and add annotations, add the line data to an NSMutableArray (NSMA).
Create a polyline using the point data in NSMA, add the polyline to the map.
With this plan, we see we need one NSMutableArray. Notice that in the existing code, you have a Location class that holds (or could hold) all the data from each line of the CSV.
That means we could simply add these Location objects to the NSMA. NSMutableArrays can hold any type of object (they don't have to be just NSStrings).
So here's a slightly more detailed plan:
Initialize an NSMutableArray called filteredLocations (eg. NSMutableArray *filteredLocations = [NSMutableArray array];).
Loop through the CSV file, ignore lines with null data, create a Location object and add as an annotation, add the Location object to filteredLocations (eg. [filteredLocations addObject:annotation];).
Initialize (malloc) a C array to hold the points of the polyline with the point count being the count of filteredLocations.
Loop through filteredLocations, add point from filteredLocations to the C array.
Create and add a polyline to the map.
In this plan note we have two separate loops: The first one is for R1 and R2. The second one is for R3.
If required, I will post sample code that implements this plan.
First, just to explain your latest NSRangeException error, it is happening on this line:
if([[latitude objectAtIndex:4] isEqualToString:#"NULL"] || ...
because you've declared latitude as an array and the first time the if executes in the loop, latitude only has one object (a few lines above this if you do [latitude addObject:...). The index of an array starts at zero so the bounds of an array with one object are zero to zero hence the error message saying index 4 beyond bounds [0 .. 0].
There are many other issues with the rest of the code.
There is not enough room in this answer to explain in detail.
I urge you, if possible, to stop, step back and re-start with a much simpler project or tutorials and, most importantly, learn the absolute basics of programming in general.
Here is an example of code that should work based on your sample data:
-(void)viewDidLoad
{
[super viewDidLoad];
self.mapview.delegate = self;
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"Data2" ofType:#"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];
NSArray *allLinedStrings = [dataStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSMutableArray *filteredLocations = [NSMutableArray array];
for (int idx = 0; idx < [allLinedStrings count]; idx++)
{
NSArray *infos = [[allLinedStrings objectAtIndex:idx] componentsSeparatedByString:#","];
if ([infos count] > 15)
{
NSString *latitude = [infos objectAtIndex:4];
NSString *longitude = [infos objectAtIndex:5];
NSString *description = [infos objectAtIndex:0];
NSString *address = [infos objectAtIndex:10];
NSString *temperature = [infos objectAtIndex:6];
NSString *time = [infos objectAtIndex:15];
NSString *ambient = [infos objectAtIndex:8];
if([latitude isEqualToString:#"NULL"]
|| [longitude isEqualToString:#"NULL"]
|| [description isEqualToString:#"NULL"]
|| [address isEqualToString:#"NULL"]
|| [temperature isEqualToString:#"NULL"]
|| [time isEqualToString:#"NULL"]
|| [ambient isEqualToString:#"NULL"])
{
continue;
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = [latitude doubleValue];
coordinate.longitude = [longitude doubleValue];
Location *annotation = [[Location alloc] initWithName:description
address:address
temperature:temperature
time:time
ambient:ambient
coordinate:coordinate];
[mapview addAnnotation:annotation];
[filteredLocations addObject:annotation];
}
}
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * filteredLocations.count);
for (int flIndex = 0; flIndex < filteredLocations.count; flIndex++)
{
Location *location = [filteredLocations objectAtIndex:flIndex];
MKMapPoint point = MKMapPointForCoordinate(location.coordinate);
pointArr[flIndex] = point;
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:filteredLocations.count];
[self.mapview addOverlay:self.routeLine];
free(pointArr);
[self.mapview showAnnotations:self.mapview.annotations animated:YES];
}

Adding annotations from a KML file to an MKMapView

I am trying to load data from a KML file over to an MKMapView. I was able to parse the data into an array and now I am trying to create annotations on the map for each item.
Using the code below, I was able to create annotations on the map but the location is not correct:
Parser *parser = [[Parser alloc] initWithContentsOfURL:url];
parser.rowName = #"Placemark";
parser.elementNames = #[#"name", #"address", #"coordinates", #"description"];
[parser parse];
//parseItem is an array returned with all data after items are parsed.
for (NSDictionary *locationDetails in parser.parseItems) {
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.title = locationDetails[#"name"];
NSArray *coordinates = [locationDetails[#"coordinates"] componentsSeparatedByString:#","];
annotation.coordinate = CLLocationCoordinate2DMake([coordinates[0] floatValue], [coordinates[1] floatValue]);
[self.mapView addAnnotation:annotation];
}
The result of the NSLog of the coordinates was:
coords=-73.96300100000001,40.682846,0
So it looks like the coordinates are coming in longitude,latitude order but the CLLocationCoordinate2DMake function takes latitude,longitude.
Unless the coordinates are supposed to be in Antarctica instead of New York City, try:
annotation.coordinate = CLLocationCoordinate2DMake(
[coordinates[1] doubleValue],
[coordinates[0] doubleValue]);
Also note you should change floatValue to doubleValue for more accurate placement (it will also match the type of CLLocationDegrees which is a synonym for double).

Google Maps - Make route line follow streets when map zoomed in

I'm getting the same issue as described in following SO questions:
(The route lines is not following the streets when I zoom in)
MapKit - Make route line follow streets when map zoomed in
and
Route drawing on Google Maps for iOS not following the street lines
But seems there are no any answer which solved mentioned issue.
I'm adding to points to the my GMSMapView map by following function:
-(void) addPointToMap:(CLLocationCoordinate2D) coordinate
{
CLLocationCoordinate2D position = CLLocationCoordinate2DMake(
coordinate.latitude,
coordinate.longitude);
GMSMarker *marker = [GMSMarker markerWithPosition:position];
marker.map = mapView_;
[waypoints_ addObject:marker];
NSString *positionString = [[NSString alloc] initWithFormat:#"%f,%f",
coordinate.latitude,coordinate.longitude];
[waypointStrings_ addObject:positionString];
if([waypoints_ count]>1){
NSString *sensor = #"false";
NSArray *parameters = [NSArray arrayWithObjects:sensor, waypointStrings_,
nil];
NSArray *keys = [NSArray arrayWithObjects:#"sensor", #"waypoints", nil];
NSDictionary *query = [NSDictionary dictionaryWithObjects:parameters
forKeys:keys];
MDDirectionService *mds=[[MDDirectionService alloc] init];
SEL selector = #selector(addDirections:);
[mds setDirectionsQuery:query
withSelector:selector
withDelegate:self];
}
}
and here are setDirectionsQuery function:
static NSString *kMDDirectionsURL = #"http://maps.googleapis.com/maps/api/directions/json?";
- (void)setDirectionsQuery:(NSDictionary *)query withSelector:(SEL)selector
withDelegate:(id)delegate{
NSArray *waypoints = [query objectForKey:#"waypoints"];
NSString *origin = [waypoints objectAtIndex:0];
int waypointCount = [waypoints count];
int destinationPos = waypointCount -1;
NSString *destination = [waypoints objectAtIndex:destinationPos];
NSString *sensor = [query objectForKey:#"sensor"];
NSMutableString *url =
[NSMutableString stringWithFormat:#"%#&origin=%#&destination=%#&sensor=%#",
kMDDirectionsURL,origin,destination, sensor];
if(waypointCount>2) {
[url appendString:#"&waypoints=optimize:true"];
int wpCount = waypointCount-2;
for(int i=1;i<wpCount;i++){
[url appendString: #"|"];
[url appendString:[waypoints objectAtIndex:i]];
}
}
url = [url
stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
_directionsURL = [NSURL URLWithString:url];
[self retrieveDirections:selector withDelegate:delegate];
}
Note: I have followed this Google tutorial and modified it a little bit:
https://www.youtube.com/watch?v=AdV7bCWuDYg
Thanks in advance, any help will be appreciated!
Finally I have found solution, Thanks to the WWJD's last edit in his question!
Route drawing on Google Maps for iOS not following the street lines
From the answer:
What I basically did before was that I was getting and working only with the information I'm receiving in the routes while if you check the JSON file you're receiving from Google Directions API, you'll see that you receive much more information in the and the . This is the information we need to produce the proper results and the right polyline.

how to remove particular markers from GMS?

I asked earlier how to show different markerInfoWindow in this question,
and now I'm trying to delete a particular marker when the user clicks on the button on the left corner.
first in .h file :
NSMutableArray *ADSMarray;
GMSMarker *adsMarker;
Then I created Ads marker like this:
for (int l=0 ; l<self.ADS.count; l++) {
CLLocationCoordinate2D pos = CLLocationCoordinate2DMake([[[self.ADS objectAtIndex:l] objectForKey:#"lati"] doubleValue],[[[self.ADS objectAtIndex:l] objectForKey:#"longi"] doubleValue]);
NSLog(#"Ads:: %f",[[[self.ADS objectAtIndex:l] objectForKey:#"longi"] doubleValue]);
adsMarker = [[GMSMarker alloc]init];
adsMarker.position=pos;
//marker.infoWindowAnchor = CGPointMake(0.44f, 0.45f);
adsMarker.draggable = NO;
adsMarker.appearAnimation=YES;
NSMutableArray*tempArray = [[NSMutableArray
alloc] init];
[tempArray addObject:#"ADS"];
[tempArray addObject:[self.ADS objectAtIndex:l]];
adsMarker.userData = tempArray;
adsMarker.map = mapView_;
adsMarker.icon=[GMSMarker markerImageWithColor:[UIColor blueColor]];
}
then in IBAction to remove them I wrote:
for (int i =0; i<self.ADS.count; i++) {
// adsMarker.map = nil;
[adsMarker setMap:nil];
}
When you add a marker store a reference to it. Then when you want to remove it, set its map property to nil - that will remove it from the map.
if you want to remove all markers in MapView you can use clear method that already built in GSM ..
Example:
[self.mapView clear];
link:
Remove a marker
and if you want to remove all markers with specific color you can use this code if the user click on blue markers button :
NSArray *blueMarkers = #[ markerBlue1, markerBlue2 ];
NSArray *greenMarkers = #[ markerGreen1, markerGreen2 ];
NSArray *purpleMarkers = #[ markerPurple1, markerPurple2 ];
for (GMSMarker *marker in blueMarkers ){
marker.map = nil;
}
To remove all markers
mapView.clear()
To remove a specific marker
myMarker.map = nil

plot marker on Google Maps iOS from JSON file

I would like to plot markers on Google Maps for iOS, and this by including JSON file that will includes longitude and latitude. I can do it manually in the code, by replacing the values.
The problem is that I don't know how to show new markers on the map from JSON file.
Here is my code :
- (void)addDefaultMarkers {
// Add a custom 'glow' marker around Sydney.
GMSMarker *sydneyMarker = [[GMSMarker alloc] init];
sydneyMarker.title = #"Sydney!";
sydneyMarker.icon = [UIImage imageNamed:#"glow-marker"];
sydneyMarker.position = CLLocationCoordinate2DMake(25.062718, 55.130761);
sydneyMarker.map = mapView_;
GMSMarker *melbourneMarker = [[GMSMarker alloc] init];
melbourneMarker.title = #"Melbourne!";
melbourneMarker.icon = [UIImage imageNamed:#"arrow"];
melbourneMarker.position = CLLocationCoordinate2DMake(25.100822, 55.17467);
melbourneMarker.map = mapView_;
}
Any ideas on how to do it ?
chech my question in this link, stackoverflow.com/questions/20902732/…. This link will help,
First of all parse the json data. And collect it as array or dictionary, then U can directly plot the value in map
The first two lines are to parse the data into an array
SBJsonParser *jsonParser = [SBJsonParser new];
NSArray *jsonData = (NSArray *) [jsonParser objectWithString:outputData error:nil];
then, the loop should continue till the no. of values,
for(int i=0;i<[jsonData count];i++)
{
NSDictionary *dict=(NSDictionary *)[jsonData objectAtIndex:i];
Nslog(#"%#",dict);
double la=[[dict objectForKey:#"latitude"] doubleValue];
double lo=[[dict objectForKey:#"longitude"] doubleValue];
CLLocation * loca=[[CLLocation alloc]initWithLatitude:la longitude:lo];
CLLocationCoordinate2D coordi=loca.coordinate;
marker=[GMSMarker markerWithPosition:coordi];
marker.snippet = #"Hello World";
marker.animated = YES;
marker.map = mapView;
}

Resources