2014-09-19 1 views
1

Я экспериментировал с двумя формами. Во-первых один тип кадра и его код ниже:Странное поведение метода заполнения в разных видах UIBezierPath

((х, у) является происхождение моей UIView и (ш, ч) является его размер)

[bpath moveToPoint:CGPointMake(x, y)]; 
[bpath addLineToPoint:CGPointMake(x + w, y)]; 
[bpath addLineToPoint:CGPointMake(x + w, y + h)]; 
[bpath addLineToPoint:CGPointMake(x, y + h)]; 
[bpath closePath]; 

[bpath moveToPoint:CGPointMake(x + 100, y + 100)]; 
[bpath addLineToPoint:CGPointMake(x + 100, y + 50)]; 
[bpath addLineToPoint:CGPointMake(x + 50, y + 50)]; 
[bpath addLineToPoint:CGPointMake(x + 50, y + 100)]; 
[bpath closePath]; 

Это дает мне следующий результат :

И второй один круг внутри круга. Его код ниже:

[bpath moveToPoint:CGPointMake(x + w, y + h * 0.5)]; 
[bpath addArcWithCenter:CGPointMake(x + w * 0.5, y + h * 0.5) radius:midx startAngle:0 endAngle:2 * M_PI clockwise:YES]; 

[bpath moveToPoint:CGPointMake(x + w * 0.75, y + h * 0.5)]; 
[bpath addArcWithCenter:CGPointMake(x + w * 0.5, y + h * 0.5) radius:0.25 * w startAngle:0 endAngle:2 * M_PI clockwise:YES]; 

А для этого я получил что-то, как показано ниже:

enter image description here

Я применил [bpath fill] к обоим путям. Итак, почему существует разница в шаблоне заполнения. (Я попробовал добавить closePath во 2-й случай, но это не имело никакого значения).

Кроме того, есть ли способ получить аналогичную картину заполнения 1-й формы для второго? (я знаю, что это может быть сделано путем добавления второго пути для внутреннего круга, но я хочу сделать это в одном пути)

Update: Я заметил, что если я использую containsPoint на 2-й путь, он возвращает FALSE когда касание точка находится внутри внутреннего круга и возвращает TRUE только тогда, когда точка касания находится между двумя кругами. Аналогичное поведение проявляется и в 1-й форме.

ответ

3

Чтобы второй пример сделал отверстие, вам необходимо установить usesEvenOddFillRule.

bpath.usesEvenOddFillRule = YES; 
[bpath fill]; 

Вот мой рабочий код:

UIBezierPath *bpath = [UIBezierPath bezierPath]; 
CGFloat x = rect.origin.x; 
CGFloat y = rect.origin.y; 
CGFloat w = rect.size.width; 
CGFloat h = rect.size.height; 
CGFloat midx = (x + w)/2; 

[bpath moveToPoint:CGPointMake(x + w, y + h * 0.5)]; 
[bpath addArcWithCenter:CGPointMake(x + w * 0.5, y + h * 0.5) radius:midx startAngle:0 endAngle:2 * M_PI clockwise:YES]; 

[bpath moveToPoint:CGPointMake(x + w * 0.75, y + h * 0.5)]; 
[bpath addArcWithCenter:CGPointMake(x + w * 0.5, y + h * 0.5) radius:0.25 * w startAngle:0 endAngle:2 * M_PI clockwise:YES]; 

[[UIColor blueColor] set]; 
bpath.usesEvenOddFillRule = YES; 
[bpath fill]; 

Результат:

Result image

Update:

После игры вокруг с кодом немного, я узнал, почему ваш первый экс ample производит дыру, а ваша вторая - нет: речь идет о направлении путей!

На первом пути внешний квадрат рисуется по часовой стрелке, а внутренний квадрат - против часовой стрелки. Это, похоже, делает нулевое правило для заполнения, считая внутренний прямоугольник «вне».

Но круги крутятся в одном направлении. Если изменить направление внутреннего круга это будет сделать отверстие даже без установки usesEvenOddFillRule:

[bpath addArcWithCenter:CGPointMake(x + w * 0.5, y + h * 0.5) radius:0.25 * w startAngle:2*M_PI endAngle:0 clockwise:NO]; 

(Обратите внимание, что запуск и угол конца перепутаны и clockwise:NO).

+0

Как я уже упоминал в последней строке, я уже пытался добавить [bpath closePath], и никаких изменений не было. Я попробовал useEvenOddFillRule, но все тот же результат. – blancos

+0

@blancos: Смотрите мое редактирование. Это работает для меня. – DarkDust

+0

Это сработало. Спасибо за решение. Но все еще интересно о 1-й форме. Я не использовал useEvenOddFillRule для этой формы, но в этом случае правильный шаблон заполнения был правильным. Любые причины такого поведения? – blancos

0

Второй пример также требует [bpath closePath].Первый пример содержит два закрытых подпутника, но в настоящее время второй пример содержит только один незакрытый путь.