CGPathContainsPoint在iOS 12中损坏了吗?有解决方法吗?

时间:2019-01-03 16:31:37

标签: ios objective-c sdk core-graphics cgpath

我会尽量简短。

接受以下测试代码:

CGPath* path =  CGPathCreateMutable();
CGPathMoveToPoint(path, nil, 318.43, 183.47);
CGPathAddCurveToPoint(path, nil, 322.98, 189.32, 327, 194.93, 329.81, 201.62);
CGPathAddLineToPoint(path, nil, 339.36, 182.58);
CGPathCloseSubpath(path);
CGPathMoveToPoint(path, nil, 327.8, 193.04);
CGPathAddCurveToPoint(path, nil, 323.06, 193.04, 323.06, 185.5, 327.8, 185.5);
CGPathAddCurveToPoint(path, nil, 332.54, 185.5, 332.54, 193.04, 327.8, 193.04);
CGPathCloseSubpath(path);
CGRect boundingBox = CGPathGetBoundingBox(path);

CGPoint testPoint = CGPointMake(200,185);

NSLog(@"path contains point=%d | bounding box contains point=%d",CGPathContainsPoint(path, nil,  testPoint, NO), CGRectContainsPoint(boundingBox, testPoint) );

此代码在iOS 10上正确返回:

  

路径包含点= 0 |边界框包含point = 0

iOS 12上的相同代码返回:

  

路径包含point = 1 |边界框包含point = 0

如您所见,在iOS 12上CGPathContainsPoint表示我的testPoint在该形状内,即使该形状的边界框没有显示。

在CGPathContainsPoint中将填充规则更改为NO不会更改任何内容。

有解决方案吗? 我之前尝试过苹果论坛,但似乎没人回答。

谢谢您的帮助!

2 个答案:

答案 0 :(得分:2)

在与iOS 10.3和12.1相同的模拟器上确认了此问题

我不明白为什么会这样,唯一的线索是如果我们删除此行,问题就会消失

CGPathMoveToPoint(path, nil, 327.8, 193.04);
CGPathAddCurveToPoint(path, nil, 323.06, 193.04, 323.06, 185.5, 327.8, 185.5);
CGPathAddCurveToPoint(path, nil, 332.54, 185.5, 332.54, 193.04, 327.8, 193.04);
CGPathCloseSubpath(path);

这可能是由于填充规则或其他原因(例如,由于路径重叠)引起的,无论如何,解决方法是创建单独的路径,然后按如下方式合并其边界框(添加了一些绘图代码以使事物可视化)

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGPoint testPoint = CGPointMake(200,185);
    [[UIColor blueColor] setStroke];
    CGContextStrokeEllipseInRect(context, CGRectMake(testPoint.x - 5, testPoint.y - 5, 10, 10));

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, nil, 318.43, 183.47);
    CGPathAddCurveToPoint(path, nil, 322.98, 189.32, 327, 194.93, 329.81, 201.62);
    CGPathAddLineToPoint(path, nil, 339.36, 182.58);

    CGRect box1 = CGPathGetBoundingBox(path);

    NSLog(@"path 1 contains point=%d | bounding box contains point=%d", CGPathContainsPoint(path, nil,  testPoint, NO), CGRectContainsPoint(box1, testPoint));

    [[UIColor grayColor] setFill];
    [[UIColor redColor] setStroke];
    CGContextAddPath(context, path);
    CGContextClosePath(context);
    CGContextDrawPath(context, kCGPathFillStroke);
    CGPathRelease(path);

    path = CGPathCreateMutable();
    CGPathMoveToPoint(path, nil, 327.8, 193.04);
    CGPathAddCurveToPoint(path, nil, 323.06, 193.04, 323.06, 185.5, 327.8, 185.5);
    CGPathAddCurveToPoint(path, nil, 332.54, 185.5, 332.54, 193.04, 327.8, 193.04);

    CGRect box2 = CGPathGetBoundingBox(path);

    NSLog(@"path 2 contains point=%d | bounding box contains point=%d", CGPathContainsPoint(path, nil,  testPoint, NO), CGRectContainsPoint(box2, testPoint));

    [[UIColor yellowColor] setFill];
    [[UIColor greenColor] setStroke];
    CGContextAddPath(context, path);
    CGContextClosePath(context);
    CGContextDrawPath(context, kCGPathFillStroke);
    CGPathRelease(path);

    CGRect boundingBox = CGRectUnion(box1, box2);
    [[UIColor magentaColor] setStroke];
    CGContextStrokeRect(context, boundingBox);

    NSLog(@"bounding box contains point=%d", CGRectContainsPoint(boundingBox, testPoint));
}

enter image description here

答案 1 :(得分:1)

我看到了您描述的相同行为。有趣的是,如果您手动关闭路径,它似乎可以工作。例如,除了添加带有注释的行之外,这与您的路径相同:

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, nil, 318.43, 183.47);
CGPathAddCurveToPoint(path, nil, 322.98, 189.32, 327, 194.93, 329.81, 201.62);
CGPathAddLineToPoint(path, nil, 339.36, 182.58);
CGPathAddLineToPoint(path, nil, 318.43, 183.47);  // manually add line back to starting point
CGPathCloseSubpath(path);

CGPathMoveToPoint(path, nil, 327.8, 193.04);
CGPathAddCurveToPoint(path, nil, 323.06, 193.04, 323.06, 185.5, 327.8, 185.5);
CGPathAddCurveToPoint(path, nil, 332.54, 185.5, 332.54, 193.04, 327.8, 193.04);
CGPathCloseSubpath(path);

我可能建议尝试自己跟踪起点,并在关闭子路径的任何地方添加一条回线,看看是否能解决该问题。


更莫名其妙的是,两次CGPathMoveToPoint(大声笑)似乎也可以解决。

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, nil, 318.43, 183.47);
CGPathMoveToPoint(path, nil, 318.43, 183.47);   // move the the starting point twice?!?
CGPathAddCurveToPoint(path, nil, 322.98, 189.32, 327, 194.93, 329.81, 201.62);
CGPathAddLineToPoint(path, nil, 339.36, 182.58);
CGPathCloseSubpath(path);

CGPathMoveToPoint(path, nil, 327.8, 193.04);
CGPathAddCurveToPoint(path, nil, 323.06, 193.04, 323.06, 185.5, 327.8, 185.5);
CGPathAddCurveToPoint(path, nil, 332.54, 185.5, 332.54, 193.04, 327.8, 193.04);
CGPathCloseSubpath(path);