Search code examples
iphoneobjective-cgoogle-maps-api-3mkoverlaygoogle-polyline

Best practice to find if a coordinate is in a given polyline?


For a navigation app, i need to detect when the user deviated from a given driving path(represented as a list of coordinates), so what i want to do is whenever i get a new location update for the user, ill check if this location is in the path. is that too complicated?


Solution

  • For a similar problem I create a path with CGPath and then test if a point is in the path. By controlling the path width you can the amount of deviation rather easily.

    Here is example code, the point to test cones from a touch event:

    - (void)createPath {
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(   path, nil, 400, 300);
        CGPathAddLineToPoint(path, nil, 500, 300);
        CGPathAddLineToPoint(path, nil, 500, 400);
        CGPathAddLineToPoint(path, nil, 400, 400);
        self.pathRef   = path;
    
        CGContextRef context = [self createOffscreenContext];
        CGContextSetLineWidth(context, self.pathWidth);
    
        CGContextBeginPath(context);
        CGContextAddPath(context, self.pathRef);    
    }
    
    - (CGContextRef)createOffscreenContext {
        CFMutableDataRef empty = CFDataCreateMutable(NULL, 0);
        CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData(empty);
        self.offscreenContext = CGPDFContextCreate(consumer, NULL, NULL);
        CGDataConsumerRelease(consumer);
        CFRelease(empty);
    
        return self.offscreenContext;
    }
    
    // Optional, not needed for the test to work
    -(void)drawRect:(CGRect)rect {
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        CGContextSetStrokeColorWithColor(context, self.colorRef);
        CGContextSetLineWidth(context, self.pathWidth);
    
        CGContextAddPath(context, self.pathRef);
        CGContextStrokePath(context);
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
        UITouch *touch = [touches anyObject];
        CGPoint touchPoint = [touch locationInView:self];
    
        BOOL isPointInPath = CGContextPathContainsPoint(self.offscreenContext, touchPoint, kCGPathStroke);
    
        NSLog(@"pip: %d, x: %3.0f, y: %3.0f", isPointInPath, touchPoint.x, touchPoint.y);
    }