Прямоугольная мозаика в WPF без ущерба для точности субпикселей? - PullRequest
1 голос
/ 27 мая 2010

У меня была проблема, описанная в вопросе Бесшовное разбиение прямоугольников в WPF , но я не очень доволен ответами, данными там.

Я рисую гистограмму, рисуя множество прямоугольников рядом друг с другом. В зависимости от масштаба холста, содержащего их, между некоторыми из них видны небольшие промежутки в результате субпиксельного рендеринга.

Из приведенного выше вопроса я узнал, как привести мои прямоугольники в соответствие с пикселями экрана, устраняя этот эффект.

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

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 02 июня 2010

причина проблемы

В субпиксельных фигурах используется альфа-смешение внутри пикселя. К сожалению, не существует алгоритма альфа-смешивания, который бы приводил к плавному смешиванию прямоугольников при стыковке.

Например, если:

  • Цвет фона белый
  • Цвет переднего плана черный, а
  • У вас есть два прямоугольника, каждый из которых покрывает половину одного пикселя

Каждый прямоугольник будет окрашен в черный цвет с непрозрачностью 50%. Первый преобразует белый пиксель в серый. Второй преобразует его в более темный серый, но не черный. Если эти прямоугольники продолжают оставаться черными в смежных пикселях, то среди черного вы видите темно-серый пиксель.

Два типа решений

Существует два основных способа решения этой проблемы:

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

Как использовать одну геометрию

Если у вас есть только набор прямоугольников, вы можете создать простой элемент управления, который закрашивает весь набор прямоугольников с помощью одной PathGeometry, содержащей комбинированную форму. Чтобы проиллюстрировать идею, если у вас было два прямоугольника рядом друг с другом разной высоты, например:

<Rectangle Canvas.Left="0" Canvas.Top="0" Width="1.5" Height="2" Fill="Red" />
<Rectangle Canvas.Left="1.5" Canvas.Top="0" Width="1.5" Height="4" Fill="Red" />

Вы можете отобразить его с помощью одной PathGeometry, например так:

<Path Data="M0,0 L0,2 L1.5,2 L1.5,4 L3,4 L3,0 Z" Fill="Red" />

Практический способ реализовать это:

  • Нарисуйте свои прямоугольники прозрачной кистью, чтобы они были кликабельными, но не видимыми
  • Добавить элемент управления Path под прямоугольниками в Z-порядке
  • Привязка данных к свойству Data элемента управления Path к источнику данных с помощью преобразователя, который создает геометрию.

Если вы используете систему макетов для позиционирования ваших прямоугольников, вы можете вместо этого использовать AdornerLayer, создав Adorner для каждого прямоугольника, а затем при рендеринге украшателей вычислить объединенный путь для первого и сделать остальные невидимыми.

Выше предполагается, что легко сгенерировать PathGeometry из исходных данных. Для более сложных сценариев элемент управления Path может быть разделен на подклассы для поиска в визуальном дереве его родителя указанных фигур и использования общих геометрических алгоритмов для вычисления PathGeometry, который представляет их объединение без лишних ребер.

Если ваши прямоугольники будут иметь несколько цветов, вы можете использовать несколько элементов управления Path по одному на цвет или создать объект Drawing и показать это.

Вот структура кода для построения PathGeometry:

var geo = new PathGeometry();
var figure = new PathFigure();
var segment = new PolyLineSegment();
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
segment.Points.Add(...);
figure.Segments.Add(segment);
geo.Figures.Add(figure);

Как заставить исходный рендеринг иметь высокое разрешение

Для принудительного рендеринга с более высоким разрешением:

  1. Внутреннее построение диаграммы в несколько раз больше, чем вы хотите отобразить, например, оборачивая ее в ViewBox.
  2. Используйте VisualBrush или RenderTargetBitmap, чтобы заставить вашу диаграмму отображаться отдельно
  3. Добавьте прямоугольник, нарисованный этим VisualBrush, в ваш пользовательский интерфейс

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

Эта проблема, конечно же, не существует с RenderTargetBitmap, так как вы указываете нужное разрешение, но может быть сложно понять, когда повторно визуализировать растровое изображение. Если вы выполняете повторную визуализацию только при изменениях данных, вы можете использовать событие, но если вы хотите, чтобы какое-либо визуальное изменение вызвало повторную визуализацию, это сложнее.

1 голос
/ 27 мая 2010

Цель 4.0, использовать округление макета (запись в блоге с демонстрацией).

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