Как настроить пользовательскую систему координат Quartz2D с масштабированием, позволяющим избежать нечеткого рисования? - PullRequest
5 голосов
/ 21 марта 2010

Эта тема была поцарапана один или два раза, но я все еще озадачен. И Google тоже не дружил.

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

Таким образом, для примера я хочу масштабировать вид так, чтобы при рисовании прямоугольника 10x10 (например, 10-дюймовой рамки) я получал прямоугольник 60x60 пикселей.

Это работает, за исключением того, что прямоугольник, который я получаю, довольно размыт. Другой вопрос здесь получил ответ, который объясняет почему. Однако я не уверен, что понял эту причину, и, более того, я не знаю, как это исправить. Вот мой код:

Я установил свою систему координат в моем awakeFromNib пользовательском методе просмотра:

- (void) awakeFromNib {
    CGAffineTransform scale = CGAffineTransformMakeScale(6.0, 6.0);
    self.transform = scale;
}

А вот моя процедура розыгрыша:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect r = CGRectMake(10., 10., 10., 10.);
    CGFloat lineWidth = 1.0;
    CGContextStrokeRectWithWidth(context, r, lineWidth);
}

Квадрат, который я получаю, масштабируется очень хорошо, но совершенно нечетко. Игра с lineWidth не помогает: когда lineWidth установлен меньше, он становится светлее, но не четче.

Так есть ли способ настроить вид, чтобы иметь масштабированную систему координат, чтобы я мог использовать мои доменные координаты? Или я должен вернуться к реализации масштабирования в моих процедурах рисования?

Обратите внимание, что эта проблема не возникает при переводе или ротации.

Спасибо

Ответы [ 2 ]

10 голосов
/ 22 марта 2010

прямоугольник, который я получил, довольно размыт.

Обычно это происходит потому, что вы нанесли прямоугольник на координаты целых чисел, и ваша ширина линии равна 1.

В PostScript (и, следовательно, в его потомках: AppKit, PDF и Quartz) единицами рисования по умолчанию являются точки, 1 точка точно равна 1/72 дюйма. Mac и iPhone в настоящее время * обрабатывают каждую такую ​​точку как 1 пиксель, независимо от фактического разрешения экрана (ов), поэтому в практическом смысле точки (по умолчанию на Mac и iPhone) равны пикселям.

В PostScript и его потомках интегральные координаты выполняются между точками. Например, 0, 0 - это левый нижний угол нижней левой точки. 1, 0 - это нижний правый угол той же точки (и нижний левый угол следующей точки справа).

Штрих центрируется на пути, по которому вы гладите. Таким образом, половина будет внутри пути, половина снаружи.

В (концептуально) мире Mac с разрешением 72 dpi эти два факта создают проблему. Если 1 pt равен 1 пикселю, и вы применяете 1-pt обводку между двумя пикселями, то половина обводки попадет в каждый из этих пикселей.

Кварц, по крайней мере, отобразит это, закрасив текущий цвет в оба пикселя в половине альфа-цвета. Это определяется тем, насколько пиксель покрыт концептуальным штрихом; если вы использовали ширину линии 1,5 пт, то половина составляет 0,75 пт, что составляет три четверти каждого 1-пт пикселя, поэтому цвет будет отображаться с коэффициентом 0,75 альфа. Это, конечно, приводит к естественному заключению: если вы используете ширину линии 2 пт, каждый пиксель полностью покрыт, поэтому альфа будет равна 1. Поэтому вы можете увидеть этот эффект с 1-пт штрихом, а не 2-х точечный ход.

Есть несколько обходных путей:

  • Перевод на пол-точки: Точно то, что написано на коробке, вы переводите вверх и вправо на пол-пункта, компенсируя вышеупомянутое деление на 1 пт-пополам.

    Это работает в простых случаях, но прекращается, когда вы включаете любые другие преобразования координат, кроме целочисленных переводов. То есть, вы можете перевести на 30, 20, и он все равно будет работать, но если вы переведите на 33 + 1/3, 25.252525 ... или если вы вообще масштабируете или поворачиваете, ваш перевод на половину точки будет бесполезным .

  • Внутренний штрих: сначала обрежьте, затем удвойте ширину линии (потому что вы будете рисовать только половину), затем обведите.

    Это может потребовать gstate juggling, если у вас есть много других рисунков, так как вы не хотите, чтобы обтравочный контур влиял на ваш другой рисунок.

  • Наружный ход: по сути, такой же, как и внутренний ход, за исключением того, что вы перевернули траекторию перед отсечением.

    Может быть лучше (меньше манипулирования gstate), чем внутренний ход, если вы уверены, что пути, которые вы хотите пройти, не будут пересекаться. С другой стороны, если вы также хотите заполнить путь, возвращается жонглирование gstate.

* Это не будет длиться вечно. Apple уже давно намекает на то, что в какой-то момент они собираются изменить по крайней мере разрешение рисования Mac. Основа API для такого изменения в значительной степени все там сейчас; все дело в том, что Apple нажмет кнопку.

2 голосов
/ 21 марта 2010

Ну, как часто, объяснение проблемы приводит меня к решению.

Проблема в том, что свойство преобразования представления применяется к нему после того, как оно было преобразовано в битовый буфер. Преобразование масштабирования должно быть применено перед рисованием, т.е. в методе drawRect. Итак, поцарапайте awakeFromNib, который я дал, и вот правильный drawRect:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGAffineTransform scale = CGAffineTransformMakeScale(6.0, 6.0);
    CGContextConcatCTM(context, scale);
    CGRect r = CGRectMake(10., 10., 10., 10.);
    CGFloat lineWidth = 0.1;
    CGContextStrokeRectWithWidth(context, r, lineWidth);
}
...