Структура массива векторной графики для VB6

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

  И поэтому, приступив к созданию собственной программы, я был сильно озадачен - можно, конечно, заниматься самодеятельностью, но предварительно неплохо было бы посмотреть на то, как это сделано у других. Однако, как я уже сказал, чего нет - того нет. Вопросы программирования подобных вещей даже не поднимаются.
  Тут следовало бы сказать о том, почему я решил заняться собственным программированием в этой области. Программирование - моё давнее хобби, а область векторной графики это совершенно новая для меня тема. Интересная для изучения. А какой способ изучения может быть лучше своей собственной разработки?
  Кроме того, имея предыдущий положительный опыт, я ожидал получить приемлемый результат. Задача состояла в том, чтобы сделать программу предельно простой и, одновременно, как можно более удобной для пользователя. Кроме того, у меня было желание по максимуму использовать возможности среды VB6, это та среда программирования, в которой я работаю и которую хорошо знаю.

  Со средой программирования не всё так просто, поскольку VB6 некоторые вещи, связанные с графикой или анимацией, делать не умеет, или делает медленно.  Визуал Бейсик не поддерживает создание слоёв, и не поддерживает формат, учитывающий прозрачность изображения. Поэтому такие вещи приходится как-то заменять и эмулировать, а это сильно замедляет время счёта.
  Не поддерживает Визуал Бейсик и такую распространённую вещь, как заливка цветом произвольной области, обозначенной контуром. Поэтому в программе, о которой я рассказываю, вместо заливки точками используется зачерчивание прямыми линиями, веером расходящимися из одной точки. Этот метод не столь универсален, поскольку таким способом легко зачерчиваются только относительно простые, в частности, выпуклые контуры, однако он достаточно эффективен и даже даёт некие преференции, поскольку в некоторых случаях такую штриховку интересно показать. Можно, например, получать с её помощью муаровые узоры. Что в общем-то удобно, если мы хотим изобразить крылья стрекозы или хрустальную вазу.

  В этом и состоит общее правило искусства – скудность изобразительных возможностей материала умелый художник обращает в выразительность и красоту своего произведения. Поэтому не только сложные и навороченные программы реалистичной 3Д анимации следует развивать. Успешно развивать можно и более простые её методы. Внимательно используя те случайности и условности (отличия от реальности), которые при этом возникают.
  Вовсе не обязательно изображать реалистичного кота. Кота можно изобразить весьма условно, и посмотрите, как славно он бегает - https://youtu.be/7PlCI8dXqDo


   СТРУКТУРА МАССИВА ГРАФИКИ

  Для хранения элементов векторной графики используется целочисленный массив Pvv(20000, 11). Массив этот можно рассматривать как массив строк. Первый индекс это номер строки, второй индекс – позиция числа в строке.

  В каждой строке находится 12 целых чисел, и строки с этими числами можно увидеть на распечатке, если кликнуть пункт меню «просмотр», или открыть в Блокнотике текстовый файл, в который векторная графика может быть выведена. Другой формат вывода графики это svg файл, он совместим с html протоколом и его можно просмотреть в блокнотике, или увидеть графическое изображение, открыв этот файл в браузере. Третий формат вывода это компактный файл, в котором находятся только пары байт, представляющие целые числа.

  Строки массива Pvv, описывающие графический элемент, разделяются на титульные и дополнительные. В титульной строке в начальной, нулевой позиции, указан логотип элемента. Число 31 это логотип одиночной кривой Безье. О других логотипах напоминает заголовок распечатки –

X  просмотр массива G  31-кр.Безье  36,38-Фигура  16-Паттерн    Nстрок= 7
 ____ 13-Прям-к  14-Круг  22-Прямая  25-Веер  26-Мног-к  27-Полилиния ___

Паттерн, Прямоугольник, Круг и Прямая не требуют для своего описания дополнительных строк. Остальные элементы используют дополнительные строки, содержащие координаты. Строки эти имеют в начальной позиции число 0 и располагаются компактно – одна за другой. Ссылка на начало дополнительных строк находится в третьей позиции титульной строки. В четвёртой позиции указывается число сегментов, составляющих графический элемент. Это может быть число кривых Безье, составляющих фигуру, число вершин многоугольника, число линий, составляющих веер или полилинию.
  По этому числу можно определить число дополнительных строк, достаточное для размещения координат точек, описывающих тот или иной элемент.
  На первой и второй позициях титульной строки, следом за логотипом, стоят координаты начальной точки, с которой ассоциируется весь графический элемент целиком. Передвигая эту точку, мы передвигаем элемент. Можно также и вращать элемент вокруг этой точки.

  Разделение строк на титульные и дополнительные оказывается удобным для удаления, замены или перестановки графических элементов. В самом деле – переставлять приходится только одиночные титульные строки, сохраняя в них ссылки, и оставляя дополнительные строки на прежнем месте.

  В результате этих действий в массиве строк появляются пустые строки, которые, так же как и дополнительные строки, обозначаются нулём в своей начальной позиции. 
  Пустые строки не мешают работе, но делают массив более громоздким и трудно обозримым. Поэтому массив изредка приходится чистить и упорядочивать. Делается эта процедура в процессе записи массива в двоичный файл. Файл этот имеет своё индивидуальное название AGv и расширение txt. Он как раз служит для этой цели, а также для того, чтобы временно запоминать в нём графику в ходе работы. Считанная из этого файла графика оказывается без пустых строк, и она упорядочена – дополнительные строки элементов следуют сразу за своей титульной строкой.

  Осталось объяснить, почему именно это число – 12 выбрано как количество позиций в строке описания графики. Тут я ориентировался на описание кривых Безье.
  В начальной позиции стоит ноль, далее идут 8 целых чисел – это координаты четырёх точек кривой Безье. Потом идёт цвет – цвет абриса и цвет фона. Последняя позиция с индексом 11 отдана номеру группы. Номер этот имеет значение только в титульной строке и показывается в распечатке только в том случае, когда он отличен от нуля.
  Наличие у элемента номера группы позволяет объединять графические элементы в иерархические группы и перемещать их совместно.

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

    ФУНКЦИОНИРОВАНИЕ ПРОГРАММЫ

  Схема функционирования программы DM_Paint в той её части, в которой она связана с векторной графикой, представлена на иллюстрации.

  Имеются три однотипных блока, оформленные как подпрограммы работающие с массивом графики. Это «Создание графических примитивов», «Нарисовать указанный элемент» и «Изменить указанный элемент».
  Однотипны блоки по своей структуре – они разбиты оператором Select на секции, каждая из которых работает с графикой своего логотипа. Иногда работа по разным логотипам совмещается.

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

  Что именно делает блок «Изменить указанный элемент» зависит от установленного флага. Если флаг записи не установлен, то блок действует только по «синему» сценарию (см.иллюстрацию) и показывает изменённый элемент, рисуя его онлайн. Если флаг записи установлен, то блок действует по «красному» сценарию. Он ничего не рисует. Вместо рисования он вносит изменения в массив графики.
  После этого поле рисунка очищается, или оно заполняется задним планом, и на полученном фоне графика перерисовывается.
 
  В этом общем процессе секция блока «Изменить указанный элемент» работает медленно, но она работает только однажды, а секции блока «Нарисовать указанный элемент» в перерисовке задействованы многократно, но зато они и работают быстрее. Потому и понадобилось использовать в программе не один, а два совершенно похожих друг на друга блока.

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

  Алгоритм выбора тут такой - координаты клика мышки сравниваются с координатами в списке Mvv(2000,2). Если координаты по X и Y различаются менее чем на 9 пикселей, то элемент выбирается. Его порядковый номер в списке запоминается, и в следующий раз поиск координат начинается с этого места. Таким способом можно раздельно выбирать любой элемент даже если начальные точки нескольких элементов совпадают.

  Небольшая практика показала высокую гибкость и способность к развитию той структуры, которая была заложена в программу для работы с векторной графикой и с её анимацией.

_________
19.09.2020


Рецензии