Задание: область отображения

Задание: область отображения

Никита Малявин

В этот раз попробую дать задание в форме текста -- на камеру говорить тяжело, микрофон еле работает, да и вам зачем эти 30 минут видео смотреть, при том, что задание довольно прямолинейное, хоть и как всегда не без подковырки 🤔

Инструмент "Zoom" в Paint.net

Продолжаем наполнять палитру инструментов. В этот раз вам нужно сделать два новых тула: "лупу" и "руку" (а не то, что вы подумали!)

Рука перемещает "камеру". Этого на картинке не видно, но это так!

HandTool и ZoomTool никакие фигуры новые не добавляют. Вместо этого, они работают с областью отображения, или, можно сказать, с камерой. Ещё в техническом языке используется слово Viewport.

Вьюпорт -- это соответствие реальных мировых координат и координат окна. Когда я говорю в этом контексте "реальный мир", я имею в виду, конечно мир фигур пеинта. Это абсурдно и смешно, но в прочей литературе, в том числе в связанной с разработкой игр, вы часто встретите словосочетание "world coordinates transform" [1][2][3]

Как задать вьюпорт

Есть несколько способов это сделать. С одной стороны, мы отображаем некоторый прямоугольник из пространства фигур ((x1,y1),(x2,y2)) в пространство битмапа ((0,0), (width, height)). Простая линейная формула опишет преобразование для каждого пикселя.

Другой способ -- хранить непосредственно сдвиг и масштаб:

struct Viewport { double x, y, scale; }

Во втором способе формула преобразования становится совсем простая:

x = (x-vp.x) * vp.scale,

где vp -- переменная типа Viewport, а x -- очередная координата некоторой фигуры. Очевидно, для y формула аналогична.

Для первого способа необходимо сначала вычислить scale:

ScaleX = width / (x2-x1);

Как видите, в этом случае мы можем получить два параметра масштабирования, по одному для икса и для игрека, и они могут быть неравны! Отношение ScaleX/ScaleY называется аспект [4] и обозначает вытянутость картинки.

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

Два способа

ZoomTool работает в двух режимах -- можно выделить некоторую область, в которую он смасштабирует изображение. Можно просто кликнуть -- тогда изображение "просто приблизится". При клике правой кнопкой мыши изображение отдалится

"Просто приближение"

Может показаться на первый взгляд, что этот режим самый простой в реализации, особенно если выбрать второй способ реализации вьюпорта:

всего лишь на клик делаем

vp.scale *= ToolScale; (или правильнее прибавлять??)

Однако во всех граф. редакторах приближение происходит именно туда, куда кликнул пользователь.

Значит, предварительно вычисляется новый прямоугольник для отображения мировых координат!

NewWidth = (vp.x2-vp.x1) / ToolScale; (или умножить???)

Offset = (NewWidth - (vp.x2 - vp.x1)) / 2;

vp.x1 += Offset;

vp.x2 -= Offset;

Тога для первого способа хранения вьюпорта потребуется ещё пара строчек для трансформации

Заключение

Реализуйте два новых тула: HandTool и ZoomTool: HandTool двигает камеру/вьюпорт, ZoomTool масштабирует по клику и по выделенной области.

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

Сохраняйте aspect ratio! Удачи!

Кайлу Катарну не удалось сохранить aspect ratio. Надеюсь, вы будете в этом более успешны


Report Page