Направить ось Y вверх

Ось Y вверх

По умолчанию, ось Y направлена вниз. Иногда требуется направить ось ординат снизу-вверх. Как правило, перенаправление оси влечет за собой неправильное отображение текста. Нарушается логика определения объектов под курсором. Для исправления ситуации привлекаются аффинные преобразования. Хотя всего этого можно избежать.

Рисуем гистограмму

Ситуация, когда нужно сменить направление оси Y вверх, встречается, например, когда рисуем графики. Возьмем в качестве графика гистограмму яркости изображения и нарисуем ее без «ручной» конвертации Y-координат. Думаю, все сталкивались с ситуацией, когда необходимо нарисовать так, как будто ось Y направлена вверх и пишем фразы что-то наподобие:

Y := Height — Y

Так вот, делать подобным образом не будем, просто считаем и выводим как есть.

Шкала нам нужна для контроля за текстом и данными. Рисуем следующей процедурой.

Как видим, все достаточно просто. На выходе получаем такую картинку.

Рис.1. «Честная» гистограмма

График ожидаемо перевернут. Посчитали и вывели данные «честно», как есть, без ручной корректировки Y.

Хочется видеть график в привычном, тетрадном, неперевернутом виде. Так, чтобы 0 находился слева снизу и шкала была снизу вверх. Сейчас сделаем.

Направить ось Y вверх

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

Нас интересует режим MM_ISOTROPIC. Для отрисовки используем обработчик события OnPaint компонента pb: TPaintBox. Ниже фрагмент обработчика, в котором происходит перенаправление оси ординат.

В результате (на скрине обратите внимание на галочку Y Up — искомый CheckBox1.Checked) получаем график, который нас устраивает.

Рис.2. Отличный график

Однако, наблюдаем досадное недразумение с текстом.

Рис.3. Отвратительный текст

Текст ожидаемо отзеркален фразой:

Казалось бы, сейчас самое время для аффинного зеркального преобразования. Но не будем торопиться. Аффинные преобразования — это сила и мощь. Но если есть возможность не прибегать к силе, то лучше этого и не делать.

Нормальный текст

Мы просто прибегнем к помощи «продвинутого» графического режима. Помимо того, что этот режим позволяет применять аффинные преобразования, он умеет правильно выводить текст. Устанавливаем режим единственной фразой:

CheckBox2.Checked соответствует галочке GM_ADVANCED в интерфейсе.

Рис.4. Отличный текст

GDI+

Но нам нужен GDI+. Потому что любим плюшки, которые он предоставляет. Рассмотрим, как поведет себя GDI+ в условиях, когда ось Y направлена вверх.

Конечно, нужно чуть переписать вывод гистограммы под GDI+. Однако, координатный вывод не трогаем. По прежнему никаких корректировок по Y.

Вывод гистограммы и шкалы в GDI+

[свернуть]

Это ровно то же самое, что было написано для GDI.

Рис.5. GDI+ сам по себе продвинутый режим

GDI+ является надстройкой над GDI. И если мы применили какие-то эпические действия к контексту устройства, то они явным образом перетекают в GDI+. Никаких действий с текстом производить не требуется. Мы просто вначале направили ось Y вверх, затем создали на этом контексте TGPGraphics.

Галка на GM_ADVANCED никак не влияет на вывод. GDI+ сам по себе продвинутый режим.

Правильные координаты

Часто необходимо по координатам мыши определять объект под курсором, перемещать по нажатию и т.д. Что делать в ситуации, когда привычный мир перевернут. Можно считать руками конечно. Но лучше использовать специальные функции для этого. Такие функции есть и в GDI, и в GDI+, и в Direct2D.

Для GDI это пара функций DPtoLP и LPtoDP. Нас интересует первая. Так как функция работает на контексте устройства, чуть изменим привычный алгоритм отрисовки. Битмап, на котором рисуем в обработчике OnPaint, освобождать не будем. А будем запоминать его:

А в обработчике OnMouseMove компонента pb: TPaintBox будем выводить реальные и логические координаты.

На рисунке 5 можно видеть результат в правом нижнем углу окна. Происходит вывод реальных координат и в скобках — логических.

Способ 2: Аффинные преобразования

Не могу обойти вниманием свои любимые аффинные преобразования. Рассмотрим сразу для GDI+. У нас есть контекст устройства, не тронутый никакими преобразованиями. Создадим на нем TGPGraphics. Чтобы направить ось Y вверх, установим аффинное преобразование.

Получим перевернутый мир, где ось Y смотрит вверх. Проблему с зеркальным текстом решаем отдельной процедурой вывода.

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

Label1 — реальные координаты. Label2 — логические, которые можно использовать для нахождения объектов, границ и каких-то других операций.

Послесловие

Для полноты картины привожу полный текст обработчика OnPaint.

Направить ось Y вверх

[свернуть]

Для нахождения гистограммы используется следующая функция

Нахождение гистограммы яркости изображения

[свернуть]

Рисовать текст в GDI+ достаточно геморное занятие, поэтому вся рутинная работа с GDI+ сосредоточена в модуле IP76.GDIPRoutines. Также, дополнительно используются модули IP76.DrawUtils и IP76.ColorUtils.


Скачать

Cпасибо за внимание!

Надеюсь, материал был полезен.

Не пропустите новых «интересностей», подписывайтесь на телегу.

Если есть вопросы, с удовольствием отвечу.


Исходники (Delphi XE 7-10) 527 Кб

Исполняемый файл (zip) 1.43 Мб

5 4 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Не нашли ответ на свой вопрос? Задайте его здесь!...x