2015-07-28 5 views
2

Я рисую гистограммы, и у меня есть несколько многоуровневых CGR-элементов, которые находятся непосредственно друг над другом (т. Е. Один прямоугольник rectY является максимальным максимальным прямоугольником). Однако между прямыми все еще есть полупрозрачные промежутки. Есть ли способ исправить это? Я обнаружил, что это также происходит при рисовании, касающемся соседних дуг.Пиксельный зазор между CGRect

Вот скриншот того, что я имею в виду:

enter image description here

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

var upToNowSegmentTotal: CGFloat = 0  
for k in 0..<data[i].bars[j].segments.count { 
     var segmentRect: CGRect = CGRect() 

     if barDirection == "vertical" { 
      let a: CGFloat = translateY(upToNowSegmentTotal) 
      let b: CGFloat = translateY(upToNowSegmentTotal + data[i].bars[j].segments[k].length) 
      upToNowSegmentTotal += data[i].bars[j].segments[k].length 

      var rectY: CGFloat 

      if a > b { 
       rectY = b 
      } else { 
       rectY = a 
      } 

      segmentRect = CGRect(
       x: barWidthPosition, 
       y: rectY, 
       width: barWidthAbsolute, 
       height: abs(a - b) 
     ) 
     } 
} 

Игнорировать материал о ширине баров. Вот функция translateY. В основном, он переводит координаты из окна графика в x/y, который нарисован. Помните, что из-за того, что область окна/графика не изменяется между выпрямленными прямоугольниками, тот же y-вход всегда будет давать одинаковый результат.

private func translateY(y: CGFloat) -> CGFloat { 
    if barsAreReversed { 
     return graphingArea.minY + graphingArea.height * (y - graphingWindow.startValue)/(graphingWindow.length) 
    } else { 
     return graphingArea.maxY - graphingArea.height * (y - graphingWindow.startValue)/(graphingWindow.length) 
    } 
} 

EDIT 2:

Вот упрощенная версия моего кода, который показывает проблему:

override func drawRect(rect: CGRect) { 
    let rect1: CGRect = CGRect(
     x: 0, 
     y: 0, 
     width: 40, 
     height: 33.7 
    ) 
    let rect2: CGRect = CGRect(
     x: 0, 
     y: rect1.height, 
     width: 40, 
     height: 33.5 
    ) 

    let context: CGContextRef = UIGraphicsGetCurrentContext() 

    CGContextSetFillColorWithColor(context, UIColor(red: 1/255, green: 29/255, blue: 29/255, alpha: 1).CGColor) 
    CGContextAddRect(context, rect1) 
    CGContextFillRect(context, rect1) 

    CGContextSetFillColorWithColor(context, UIColor(red: 9/255, green: 47/255, blue: 46/255, alpha: 1).CGColor) 
    CGContextAddRect(context, rect2) 
    CGContextFillRect(context, rect2) 
} 

Он производит это:

enter image description here

+0

Это может быть полезно: http://stackoverflow.com/questions/9975219/cgrectintegral-what-is-the-usage-of -Это. –

+0

Не может быть, что при 100% непрозрачности каждый CGRect полностью перезаписывает все, что находится под ним, даже если у него есть прозрачные части, которые должны быть смешаны? – DefinitelyNotAPlesiosaur

+0

Код, вероятно, слишком много, чтобы показать, так как у меня есть куча сложных функций. Однако я добавлю наиболее важные детали. – DefinitelyNotAPlesiosaur

ответ

2

Это сглаживание. Я могу предотвратить это явление, используя ваш точный код, но используя CGContext, в котором мы сначала вызвали CGContextSetAllowsAntialiasing(context, false). Здесь без что называют:

enter image description here

А вот с что называют:

enter image description here

Но, как уже говорили другие, мы можем получить тот же результат изменив ваши 33.7 и 33.5 на 40, чтобы мы опустились на границы пикселей.

+0

В ситуациях, когда требуется сглаживание, существует ли другое решение? У меня также была эта проблема с диагональными линиями и дугами. – DefinitelyNotAPlesiosaur

+0

Создайте прямоугольники на 0,5 пикселя больше, чем они должны быть, чтобы они располагались на пикселе, а не между –

+0

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

5

Я подозреваю, что в этом конкретном случае исправления, которые вы заполняете, не являются неотъемлемыми, т. Е. У них могут быть источники/высоты, которые по умолчанию отображаются с слегка прозрачными пикселями (сглаживание). Вы можете избежать этого, правильно округлять ваш Y-ось перевод

private func translateY(y: CGFloat) -> CGFloat { 
    if barsAreReversed { 
     return round(graphingArea.minY + graphingArea.height * (y - graphingWindow.startValue)/(graphingWindow.length)) 
    } else { 
     return round(graphingArea.maxY - graphingArea.height * (y - graphingWindow.startValue)/(graphingWindow.length)) 
    } 
} 

с дугами и другими формами это не так легко, однако, вы могли бы попытаться избавиться от него, оставив немного перекрытия между формами. Конечно, как указано матом, вы можете просто отключить сглаживание, и в этом случае эти прозрачные «половинные пиксели» будут отображаться так, как если бы они были полностью полностью внутри прямоугольника.

+1

Несомненно, на краях, отличных от пикселей, система по умолчанию не создает нечеткий край, который показывает фон? Вот игровая площадка, чтобы показать вам, что это не так. Https://www.dropbox.com/s/7r5tj1x6qscic0x/Aliasing.playground.zip?dl=0 Обратите внимание, что ни один из чертежей не сглажен, границы - пиксель совершенный. –

+0

Вам не нужно было ничего менять, потому что вы замаскировали проблему, не позволяя системе рисовать «в меру своих возможностей» с точки зрения соответствия прямоугольника, который он дал. –

+0

@matt: Если вы измените высоту первого прямоугольника на 33.0 (или даже 33.5 на устройстве Retina), то я не вижу никакого сглаживания на границе и никакого «зазора». –

2

Это, вероятно, происходит потому, что координаты прямоугольника, которые вы используете для рисования фигур, являются дробными значениями. В результате Core Graphics выполняет сглаживание по краям этих прямоугольников, когда ваши координаты пересекаются между границами пикселей.

Вы можете решить это, просто округляя координаты прямоугольников перед рисованием.Вы можете использовать функцию CGRectIntegral, которая выполняет этот вид округления, например:

CGContextFillRect(context, CGRectIntegral(rect1)) 
+0

Хорошо, я снимаю свой комментарий! – matt

+0

Прохладный! Мне нравится ваш ответ, кстати, я узнал от него и мог видеть, как я его использую. – Clafou

+0

И я изменил свой ответ, чтобы признать интегральность в качестве другого решения. Вместе у нас есть достаточно решений, чтобы удовлетворить любого! :) – matt

Смежные вопросы