Почему соединение не округляется, когда линия удваивается? - PullRequest
9 голосов
/ 03 мая 2011

У меня есть следующий код:

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

    CGContextSetFillColorWithColor(c, [UIColor blackColor].CGColor);
    CGContextFillRect(c, rect);

    CGContextSetLineJoin(c, kCGLineJoinRound);
    CGContextSetLineCap(c, kCGLineCapRound);
    CGContextSetLineWidth(c, 50.0);

    CGContextSetStrokeColorWithColor(c, [UIColor redColor].CGColor);
    CGContextBeginPath(c);
    CGContextMoveToPoint(c, 60, 60);
    CGContextAddLineToPoint(c, 60, 250);
    CGContextAddLineToPoint(c, 60, 249);
    CGContextStrokePath(c);

    CGContextSetStrokeColorWithColor(c, [UIColor blueColor].CGColor);
    CGContextBeginPath(c);
    CGContextMoveToPoint(c, 160, 60);
    CGContextAddLineToPoint(c, 160, 250);
    CGContextAddLineToPoint(c, 160.01, 249);
    CGContextStrokePath(c);
}

Это создает следующий вывод:

Output of the code

Есть ли веская причина, по которой нижний край красной фигурыне округляется?Или это ошибка в Core Graphics, когда линия точно удваивается?

Ответы [ 2 ]

4 голосов
/ 23 июня 2011

Это определенно ошибка.Если вы попытаетесь добавить еще одну строку к пути, вы увидите, как Core Graphics не может с ней справиться.

CGContextMoveToPoint(c, 60.0, 60.0);
CGContextAddLineToPoint(c, 60.0, 250.0);
CGContextAddLineToPoint(c, 60.0, 249.0);
CGContextAddLineToPoint(c, 60.0, 250.0);

enter image description here

Это как если бы маскирование создавало закругленные заглавные буквыи соединения становятся инвертированными, когда удваиваются.

3 голосов
/ 24 июня 2011

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

Обходной путь - обнаружить этот случай и добавить очень короткий отрезок линии, перпендикулярный существующей линии, примерно так:

- (void)addPtToPath:(CGPoint)newPt {
    // CoreGraphics seems to have a bug if a path doubles back on itself.
    // Detect that and apply a workaround.
    CGPoint curPt = CGPathGetCurrentPoint(self.currentPath);
    if (!CGPointEqualToPoint(newPt, curPt)) {
        CGFloat slope1 = (curPt.y - prevPt.y) / (curPt.x - prevPt.x);
        CGFloat slope2 = (curPt.y - newPt.y) / (curPt.x - newPt.x);
        CGFloat diff;
        BOOL between;
        if (isinf(slope1) && isinf(slope2)) {
            // Special-case vertical lines
            diff = 0;
            between = ((prevPt.y < curPt.y) != (curPt.y < newPt.y));
        } else {
            diff = slope1 - slope2;
            between = ((prevPt.x < curPt.x) != (curPt.x < newPt.x));
        }
        if (between && diff > -0.1 && diff < 0.1) {
            //NSLog(@"Hack alert! (%g,%g) (%g,%g) (%g,%g) => %g %g => %g", prevPt.x, prevPt.y, curPt.x, curPt.y, newPt.x, newPt.y, slope1, slope2, diff);
            if (isinf(slope1)) {
                curPt.x += 0.1;
            } else if (slope1 == 0) {
                curPt.y += 0.1;
            } else if (slope1 < -1 || slope1 > 1) {
                curPt.x += 0.1; curPt.y -= 0.1 / slope1;
            } else {
                curPt.x -= 0.1 * slope1; curPt.y += 0.1;
            }
            CGPathAddLineToPoint(self.currentPath, NULL, curPt.x, curPt.y);
        }
        prevPt = curPt;
    }
    CGPathAddLineToPoint(self.currentPath, NULL, newPt.x, newPt.y);
}

Для этого нужен один ивар с именем prevPt, и он работает по пути в иваре currentPath.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...