Задание: область отображения
Никита МалявинВ этот раз попробую дать задание в форме текста -- на камеру говорить тяжело, микрофон еле работает, да и вам зачем эти 30 минут видео смотреть, при том, что задание довольно прямолинейное, хоть и как всегда не без подковырки 🤔
Продолжаем наполнять палитру инструментов. В этот раз вам нужно сделать два новых тула: "лупу" и "руку" (а не то, что вы подумали!)
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! Удачи!