Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect touch on UIBezierPath stroke, not fill [duplicate]

Possible Duplicate:
How can I check if a user tapped near a CGPath?

I'm following Apple's guide from here

http://developer.apple.com/library/ios/#documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html

to try and detect a touch event only on the stroked portion of my UIBezierPath. If I use the UIBezierPath method, containsPoint, it works fine, but it detects touch events on the stroke and the fill portion of the UIBezierPath, and I want it to only occur on the stroked portion.

Following Apple's guide (at listing 3-6 of the link), I created this function:

- (BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath*)path inFillArea:(BOOL)inFill
{
    CGContextRef context = UIGraphicsGetCurrentContext();    
    CGPathRef cgPath = path.CGPath;    
    BOOL    isHit = NO;

    // Determine the drawing mode to use. Default to    
    // detecting hits on the stroked portion of the path.    
    CGPathDrawingMode mode = kCGPathStroke;    
    if (inFill)        
    {   
        // Look for hits in the fill area of the path instead.
        if (path.usesEvenOddFillRule)
            mode = kCGPathEOFill;
        else
            mode = kCGPathFill;
    }

    // Save the graphics state so that the path can be
    // removed later.
    CGContextSaveGState(context);
    CGContextAddPath(context, cgPath);

   // Do the hit detection.
   isHit = CGContextPathContainsPoint(context, point, mode);
   CGContextRestoreGState(context);
   return isHit;
}

When I call it, I get:

Error: CGContextSaveGState: invalid context 0x0
Error: CGContextAddPath: invalid context 0x0
Error: CGContextPathContainsPoint: invalid context 0x0
Error: CGContextRestoreGState: invalid context 0x0

Here's my view's drawRect function, and my code to create my path:

- (UIBezierPath *) createPath {
    static UIBezierPath *path = nil;
    if(!path) {
        path = [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(35, 45, 250, 250)] retain];
        path.lineWidth = 50.0;
        [path closePath];
    }    
    return path;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
*/ 
- (void)drawRect:(CGRect)rect
{
    // Drawing code

    //draw a circle
    UIBezierPath *aPath = [self createPath];

    //set stroke width
    aPath.lineWidth = 50.0;

    //set stroke color
    [[UIColor blueColor] setStroke];

    //stroke path
    [aPath stroke];

    //close path
    [aPath closePath];

    //add a label at the "top"
    UILabel *topLabel;
    topLabel = [[UILabel alloc]initWithFrame:CGRectMake(120, -5, 80, 25)];
    topLabel.text = @"The Top";
    [self addSubview:topLabel];
}

I'm then trying to call the containsPoint function inside of touchesMoved, like this:

if (![self containsPoint:c onPath:[self createPath] inFillArea:NO]) return;
like image 242
james Avatar asked May 27 '11 00:05

james


1 Answers

When you're currently not drawing (as in the touchesMoved method), there is no current context, so UIGraphicsGetCurrentContext() will return NULL.

As all you're doing with the context is to use its current path, you could just as well use CGPathContainsPoint instead of CGContextPathContainsPoint.

like image 153
omz Avatar answered Sep 22 '22 13:09

omz