1

Basically, I want to draw a Polyline with this code. As you can see, I have the Overlay method ready, I only need to know how to call MKPolyline in the (void)viewDidLoad

[UPDATE] OK so I managed to draw Polylines. However, the lines don't make sense, they connect some pins with no order and then 4 of the pins release a line directed to the north west of the map, I need to know how to make it line one pin to another in an ordered manner.

- (void)viewDidLoad {
[super viewDidLoad];



NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];

NSArray* allLinedStrings = [dataStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];

MKMapPoint northEastPoint;
MKMapPoint southWestPoint;

MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);

for(int idx = 0; idx < allLinedStrings.count; idx++)
{

    NSString* currentPointString = [allLinedStrings objectAtIndex:idx];
    NSArray* infos = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];
    if ([infos count] > 1)
    {
        NSString * latitude = [infos objectAtIndex:1];
        NSString * longitude = [infos objectAtIndex:2];
        NSString * Description =[infos objectAtIndex:3];
        NSString * address = [infos objectAtIndex:4];

        CLLocationCoordinate2D coordinate;
        coordinate.latitude = latitude.doubleValue;
        coordinate.longitude = longitude.doubleValue;
        Location *annotation = [[Location alloc] initWithName:Description address:address coordinate:coordinate] ;
        [mapview addAnnotation:annotation];

        MKMapPoint point = MKMapPointForCoordinate(coordinate);

        //
        // adjust the bounding box
        //

        // if it is the first point, just use them, since we have nothing to compare to yet.
        if (idx == 0) {
            northEastPoint = point;
            southWestPoint = point;
        }
        else
        {
            if (point.x > northEastPoint.x)
                northEastPoint.x = point.x;
            if(point.y > northEastPoint.y)
                northEastPoint.y = point.y;
            if (point.x < southWestPoint.x)
                southWestPoint.x = point.x;
            if (point.y < southWestPoint.y)
                southWestPoint.y = point.y;
        }

        pointArr[idx] = point;

    }

    self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];

    _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);
    [self.mapview addOverlay:self.routeLine];

}


    }
  }
}         
 - (MKOverlayRenderer *)mapView:(MKMapView *)mapView
        rendererForOverlay:(id < MKOverlay >)overlay
 {
 MKPolylineRenderer *renderer =
 [[MKPolylineRenderer alloc] initWithPolyline:overlay];
 renderer.strokeColor = [[UIColor orangeColor] colorWithAlphaComponent:1];
 renderer.lineWidth = 6.0;
renderer.lineDashPattern = @[@2, @10];
renderer.alpha = 0.5;

return renderer;

}

Also, my csv file if its of any help

01,51.751782,-0.238992, Location 1, 1st Stop
02,51.815020,-0.200418, Location 2, 2nd Stop
03,51.755462,-0.340392, Location 3, 3rd Stop
04,51.660507,-0.389374, Location 4, 4th Stop
05,51.798323,-0.081622, Location 5, 5th Stop
KJTWF
  • 9
  • 8
  • Look at `MKPolyline`? – Larme Mar 06 '15 at 16:38
  • I know how to apply it when I have fixed coordinates in my app, I even have the Overlay method ready. – KJTWF Mar 06 '15 at 16:45
  • So post the code for your Overlay method and tell us what it is about making it work with data from a CSV file that is a problem for you. – Duncan C Mar 06 '15 at 17:02
  • This has _nothing_ to do with the CSV format. You are already able to parse the coordinates and add annotations. Did you search at all on Google or StackOverflow for `MKPolyline`? Did you look at the documentation for `MKPolyline`? There are plenty of examples. Try something then edit your question with the updated code. –  Mar 07 '15 at 13:06
  • What I mean is that I don't know how to apply it in CSV format, not that CSV format is the problem itself. Yes, I did and keep doing a lot of research and as I said and you can see the overlay method is there and I can perfectly apply it with fixed coordinates, it is when extracting the coordinates and not having a fixed number of locations where I have the trouble. – KJTWF Mar 07 '15 at 13:15
  • Here's one approach: While you are looping through the coordinates in your existing for-loop, you could add each annotation object to an NSMutableArray. In the end, the NSMA will give you a count. Now loop through the NSMA to build a C array of coordinates to create the MKPolyline. Then call addOverlay. Example which you'll need to modify a bit: http://stackoverflow.com/questions/13077334/how-can-i-change-the-nsarray-to-mkpolyline-polylinewithcoordinates-compatible-ty –  Mar 07 '15 at 14:30
  • I'll post a detailed answer later but notice the overlay is being added as _each_ coordinate is added to the array (before all the rest of the coordinates in the array are set). This causes the lines going to the northwest. Create and add the overlay after the loop. –  Mar 08 '15 at 15:45
  • Thank you Anna. I've changed the creation of the Overlay on different positions I even removed " _rect" in some of them and tried different combinations but I always get the same result. It may be the formula I wrote or something that has to do with the axis. – KJTWF Mar 08 '15 at 20:32

1 Answers1

0

An overlay is being added as each coordinate is added to the C array (before all the rest of the coordinates in the array are set). This causes the lines going to the northwest. Create and add the overlay after the loop.

Here's a summary of the current code with just the relevant parts pointed out:

MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);

for(int idx = 0; idx < allLinedStrings.count; idx++)
{
    //some code that gets "infos" (current coordinate's data)...

    if ([infos count] > 1)
    {
        //some code that creates and adds an annotation...

        MKMapPoint point = MKMapPointForCoordinate(coordinate);

        //some code that calculates the "bounding box" (irrelevant)...

        pointArr[idx] = point;    
    }

    self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];

    //_routeRect = ... (irrelevant)

    [self.mapview addOverlay:self.routeLine];

} //end of for-loop

Notice that the addOverlay call is inside the for-loop which means a polyline overlay is added for each coordinate.

But at each iteration, the pointArr array has not been fully populated yet:

  • When pointArr[0] is set to location 1, pointArr[1] to pointArr[4] are not set yet and contain either zero or random values.
  • When pointArr[1] is set to location 2, pointArr[2] to pointArr[4] are not set yet and contain either zero or random values, etc...

With the pointArr partially set like this at each coordinate/iteration, the polyline is being added resulting in the random lines going into the northwest.


Instead, create and add the polyline overlay once and after the for-loop and after pointArr is fully populated:

MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);

for(int idx = 0; idx < allLinedStrings.count; idx++)
{
    //some code that gets "infos" (current coordinate's data)...

    if ([infos count] > 1)
    {
        //some code that creates and adds an annotation...

        MKMapPoint point = MKMapPointForCoordinate(coordinate);

        //some code that calculates the "bounding box" (irrelevant)...

        pointArr[idx] = point;    
    }

    //_routeRect = ... (irrelevant)

} //end of for-loop

self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];

[self.mapview addOverlay:self.routeLine];


A few other points:
  1. This malloc is technically wrong:

    MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * allLinedStrings.count);
    

    It's defining an array of MKMapPoint structs but using the size of CLLocationCoordinate2D structs. Since you are intending to add MKMapPoint structs, you should use that struct's size instead:

    MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * allLinedStrings.count);
    

    The reason it still "works" the wrong way is because MKMapPoint and CLLocationCoordinate2D happen to be the same size.

  2. You are allocating the C array with malloc but not freeing the memory. After pointArr is no longer needed, you should call free:

    self.routeLine = [MKPolyline polylineWithPoints:pointArr count:allLinedStrings.count];
    [self.mapview addOverlay:self.routeLine];
    free(pointArr);
    
  3. Just FYI: Since you have CLLocationCoordinate2D coordinate values to begin with, you can just create the polyline using polylineWithCoordinates and save the trouble of converting them to MKMapPoints.

  4. The bounding box calculation seems more complex than necessary. It's simpler to initialize the MKMapRect to MKMapRectNull and then add each annotation's MKMapPoint to it using MKMapRectUnion. See this answer for an example. Even simpler than that is to just call [self.mapview showAnnotations:self.mapview.annotations animated:YES]; after all the annotations are added.

Community
  • 1
  • 1