CGPathContainsPoint не работает в iOS 12? Возможен ли обходной путь? - PullRequest
0 голосов
/ 03 января 2019

Я постараюсь сохранить это коротким.

Возьмите следующий тестовый код:

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 |ограничительная рамка содержит точку = 0

Тот же код на iOS 12 возвращает:

путь содержит точку = 1 |ограничивающая рамка содержит точку = 0

Как вы можете видеть, в iOS 12 CGPathContainsPoint говорит, что моя testPoint находится внутри фигуры, даже если ограничительная рамка фигуры говорит, что это не так.

Изменение правила заполнения на NO в CGPathContainsPoint ничего не меняет.

Есть ли решение для этого?Я пробовал яблочные форумы раньше, но, похоже, никто не отвечает там.

Спасибо за любую помощь!

Ответы [ 2 ]

0 голосов
/ 03 января 2019

Я вижу то же поведение, которое вы описываете. Интересно, что если вы вручную закроете путь, это, похоже, сработает. Например, это то же самое, что и ваш путь, за исключением добавления строки с комментарием:

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);
0 голосов
/ 03 января 2019

Подтвердили эту проблему на том же симуляторе с 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

...