Search code examples
iosobjective-cmkmapviewmkoverlaymkpolyline

Polylines are being drawn randomly and in random location on map


I am working diligently on figuring how to get lines to show on my map. I am attempting to draw a line from touches began to touches end.

At the moment I am taking the coords of where I touch, add it to an array, take the cords of where touch end, add it to an array then draw the line. This is my code below.

When I ran the code sadly my line did not show. However while sitting wondering what I was missing (cause my coords are being saved to the array) I kept swiping my screen in frustration and suddenly a line appeared! I closed the program and did the same thing again and as far as I can tell, lines are being drawn randomly, and at the wrong coordinates.

I changed

CLLocationCoordinate2D obh1=CLLocationCoordinate2DMake
    (startTouch.latitude, startTouch.longitude);

to

CLLocationCoordinate2D obh1=CLLocationCoordinate2DMake
    (startTouch.longitude, startTouch.latitude);

to see if I was somehow mixing my coords but the same thing is happening. The lines are being drawn in random locations.

Would appreciate if someone could offer me a little help to solve this.

I have done some work and this is what I have come up with. The 4 lines points you see appear when I click on the map. They are the touches end, the touches begin. I have no idea where they are coming from but not from my code.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches began");

    UITouch *touch = [touches anyObject];

    // Get the specific point that was touched
    CGPoint point = [touch locationInView:self.view];
     //convert toc
    CLLocationCoordinate2D startTouch
    =[self.map convertPoint:point toCoordinateFromView:_map];
    CLLocationCoordinate2D obh1=CLLocationCoordinate2DMake(startTouch.latitude, startTouch.longitude);
    [arrayOfLine addObject: [NSValue valueWithMKCoordinate:obh1]];
    NSLog(@"array: %@", arrayOfLine);
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches END");


    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self.view];
    CLLocationCoordinate2D endTouch
    =[self.map convertPoint:point toCoordinateFromView:_map];
    CLLocationCoordinate2D obh=CLLocationCoordinate2DMake(endTouch.latitude, endTouch.longitude);
        [arrayOfLine addObject: [NSValue valueWithMKCoordinate:obh]];
        NSLog(@"array: %@", arrayOfLine);

            MKPolyline *polygon = [MKPolyline polylineWithCoordinates:&obh count:[arrayOfLine count]];

    [_map addOverlay:polygon];
}

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolyline class]])
    {
        MKPolylineView *overlayView = [[MKPolylineView alloc] initWithPolyline:overlay];

        overlayView.strokeColor     = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        overlayView.lineWidth       = 3;

        return overlayView;
    }

    return nil;
}

enter image description here


Solution

  • The random lines are coming from the code in question.

    The main problem is in touchesEnded in this section:

    CLLocationCoordinate2D obh=CLLocationCoordinate2DMake(endTouch.latitude, endTouch.longitude);
    [arrayOfLine addObject: [NSValue valueWithMKCoordinate:obh]];
    NSLog(@"array: %@", arrayOfLine);
    
    MKPolyline *polygon = [MKPolyline polylineWithCoordinates:&obh count:[arrayOfLine count]];
    


    When calling polylineWithCoordinates, the code is giving the address of obh which is a single CLLocationCoordinate2D struct but the count is set to the number of objects in arrayOfLine which would most likely be two (touch begin + touch end).

    The polylineWithCoordinates method is expecting a plain C array of CLLocationCoordinate2D structs.

    Currently, the code is giving the method only a single struct but the count tells the method to also use the bytes in memory following the single struct as coordinates in the array. The bytes in memory following obh are most likely going to be random values which translate to meaningless coordinates and so you get random lines or no lines at all.


    To fix this, you need to construct a plain C array from arrayOfLine (an Objective-C NSArray).
    Here's one way to do it:

    //REPLACE this existing line with the code below:
    //MKPolyline *polygon = [MKPolyline polylineWithCoordinates:&obh count:[arrayOfLine count]];
    
    CLLocationCoordinate2D coords[arrayOfLine.count];
    
    for (int c = 0; c < arrayOfLine.count; c++)
    {
        NSValue *v = [arrayOfLine objectAtIndex:c];
        coords[c] = v.MKCoordinateValue;
    }
    
    MKPolyline *polygon = [MKPolyline polylineWithCoordinates:coords count:[arrayOfLine count]];
    


    A few other points not directly causing a problem:

    1. In touchesBegan, creating obh1 is unnecessary. startTouch is already a CLLocationCoordinate2D that you can add to the array.
    2. In touchesEnded, creating obh is unnecessary. endTouch is already a CLLocationCoordinate2D that you can add to the array.
    3. Currently, arrayOfLine is not being cleared at any point. This means whenever touches end, all lines the user has drawn are re-drawn (and connected together). Not sure what the intention is but if you only want the current begin+end touch pair to be drawn, then at the top of touchesBegan, do [arrayOfLine removeAllObjects];.
    4. Make sure userInteractionEnabled is set to NO on the map view otherwise it may interfere with the touch methods and cause strange behavior (like touchesEnded not getting called).