CGPathContainsPoint 在 iOS 12 中损坏?是否有解决方法?
CGPathContainsPoint broken in iOS 12? Is a workaround possible?
我会尽量保持简短。
拿下面的测试代码:
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) );
此代码 returns 在 iOS 10:
上正确
path contains point=0 | bounding box contains point=0
iOS 12 returns:
上的相同代码
path contains point=1 | bounding box contains point=0
如您所见,在 iOS 12 CGPathContainsPoint 上说我的测试点在形状内部,即使形状的边界框说它不是。
在 CGPathContainsPoint 中将填充规则更改为 NO 不会改变任何内容。
有解决办法吗?
我以前试过苹果论坛,但似乎没有人在那里回答。
感谢您的帮助!
在与 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));
}
我看到了与您描述的相同的行为。有趣的是,如果您手动关闭路径,它似乎可以工作。例如,这与您的路径相同,除了添加带有注释的行:
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);
我会尽量保持简短。
拿下面的测试代码:
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) );
此代码 returns 在 iOS 10:
上正确path contains point=0 | bounding box contains point=0
iOS 12 returns:
上的相同代码path contains point=1 | bounding box contains point=0
如您所见,在 iOS 12 CGPathContainsPoint 上说我的测试点在形状内部,即使形状的边界框说它不是。
在 CGPathContainsPoint 中将填充规则更改为 NO 不会改变任何内容。
有解决办法吗? 我以前试过苹果论坛,但似乎没有人在那里回答。
感谢您的帮助!
在与 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));
}
我看到了与您描述的相同的行为。有趣的是,如果您手动关闭路径,它似乎可以工作。例如,这与您的路径相同,除了添加带有注释的行:
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);