Элементы векторной графики средствами VB6

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

          Общие соображения

   Основные примитивы графики VB6, такие, как точка, прямая линия, прямоугольник и окружность, полностью или приблизительно соответствуют основным элементам векторной графики, что наводит на мысль, что проблем с реализацией этих элементов не будет. Между тем, такая нужная вещь, как заливка произвольного контура, в VB6 не предусмотрена. Также, как и не предусмотрена полупрозрачность изображения. И то, и другое можно было бы сделать поточечно, и хотя такой алгоритм требует значительного времени, но совсем отказываться от полупрозрачности и от заливки не хочется,  поскольку без этих опций графика сильно обеднеет.    И как же быть?
   
   Решение есть - это зачерчивание объектов векторной графики прямыми линиями, которое легко делается, и, более того, свойство Picture.DrawStyle позволяет рисовать графические примитивы тонкими пунктирами и штрих пунктирами различных сортов, и было бы неправильным от этой возможности отказываться.
   Тактика тут такая - то, что предоставляет нам среда программирования, нужно использовать по полной программе, а к более сложным вещам подходить с осторожностью. Использовать их по мере необходимости.
   Одними из таких необходимых вещей являются кривые Безье и фигуры, составленные из этих кривых. Опять же, почему бы расширить класс фигур, не требуя от них обязательной замкнутости в смысле точного примыкания кривой Безье к своим соседям. Такое решение позволило бы, например, выразить черты лица персонажа в одной единственной фигуре, отделив их от абриса головы, выраженного другой фигурой.
   Как показывает эксперимент, перемещение этих фигур друг относительно друга создаёт живую мимику и очень подходит для создания анимации - https://stihi.ru/2009/09/24/5790 .
   Так постепенно, шаг за шагом, создавалась общая концепция, о которой я вам сейчас расскажу.

         Векторная графика как особый вид рисования

  Графические элементы и не задумывались первоначально, как таковые. Программа-то предназначалась для художественного рисования, и в ней существовало общее разделение на обычное рисование и рисование кистями.

  Обычное рисование, это то, что предусмотрено самой средой VB6, то есть
рисование точками – оператором PSet(X,Y), и рисование линиями с помощью оператора Line (X1,Y1)-(X2,Y2). И даже кругов в этом обычном рисовании не было. Круги и длинные прямые линии появились в рисовании позже, как некие его опции. Так же, как опция, появился и веер – красивая фигура в виде спиц, расходящихся из одной точки.
  Потом, к этим опциям добавилась кривая Безье – линия с двумя плавными изгибами. Рисовалась эта линия двумя способами – как отдельная линия, и как серия линий, одна в продолжение другой.
  Вот эти-то особые опции рисования и легли в основу будущей векторной графики.

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

  Нужен ещё и переключатель режимов.
  Пока режим векторной графики у нас не включён, то мы занимаемся просто рисованием. Например, нарисовали веер, и, нажав кнопку «закрепить», закрепили нарисованное оператором Picture1.Picture = Picture1.Image на поле нашего рисунка.
  Но если режим векторной графики включён, то помимо закрепления нарисованного образа, мы этой же кнопкой отправляем параметры нарисованного элемента в специальный массив, в котором эти параметры записываются в отдельную строку, или в несколько строк. 
               
             Массив векторной графики
 
   Главное, простота во всём. В частности, и в представлении созданных элементов векторной графики внутри программы.
   Внутри, да и вне программы тоже, созданные векторные элементы записываются в форме строк в двухмерный целочисленный массив. Строка массива, это его развёртка по одному из индексов, а номер строки, это значение другого индекса массива. Чтобы было понятно, о каком массиве идёт речь, называется он «массивом элементов векторной графики» или массивом G.
   
   Вот, к примеру, распечатка начала массива G, с первой строки которого идут параметры фигуры Безье с логотипом 36 – той фигуры, на которую на иллюстрации указывает стрелочка поинтера:

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

        1>     36  194  278  2  5  0  199  267  0  12095  3  #10
   2      0  194  278  187  283  159  263  152  260  0  0
   3      0  152  260  141  230  165  119  167  120  0  0
   4      0  167  120  168  117  181  78  181  78  0  0
   5      0  181  78  181  78  184  100  184  100  0  0
   6      0  184  100  184  100  190  102  190  102  0  0

  Мы видим, что фигура 36 представлена шестью строками – первой, титульной, и пятью дополнительными, в каждой из которых записаны координаты точек кривых Безье, составляющих фигуру.
  Координаты X,Y первой точки первой кривой 194 278 повторены в титульной строке вслед за её логотипом. Далее идёт 2 - ссылка на начало дополнительных строк, и 5 – число этих строк, те есть, число кривых, составляющих фигуру.
  Далее, вслед за нулём (эта позиция для логотипа 36 означает стиль тонких линий, которыми производится зачерчивание – 0 это сплошные линии), идут числа 199 267, это координаты той точки, из которой расходятся линии зачерчивания.
  Далее – два числа, определяющие цвет обводки (0 – чёрный цвет) и цвет заполнения (зачерчивания). А за ними – число 3, это значение свойства Picture.DrawWidth - толщина линий обводки. Если мы на месте стиля зачерчивания поставим не 0,1,2,3 или 4, то тогда зачерчивание будет проводиться линиями этой толщины и линии будут более частыми, так что у нас получится не зачерчивание, а сплошная заливка. То есть, вариаций для заполнения фигуры цветом есть много.

  Кстати о цвете. Поскольку три компоненты цвета RGB, располагаясь по возрастающим битам, составляют число из 8х3=24 бит, то это число не помещается в 16 разрядов целого числа, и его приходится преобразовывать в составное число 5х3=15, отнимая по три младших бита у каждого цвета. Поэтому цвет векторной графики получается слегка огрублённым, однако на практике такое огрубление совершенно незаметно.
  Возможно, подумав об этом заранее, мне следовало бы создать массив G не из чисел типа Integer, а из чисел типа Long, на быстродействии вычислений это вряд ли скажется, но что сделано, то сделано, и пока переделывать векторную графику я не буду.

  Последним в титульной строке идёт число 10 со значком # перед ним. Это число означает номер группы, в которую элемент векторной графики помещён. Если элемент только что создан, и ни в какую группу не помещён, то это число равно нулю, и оно не печатается.

  Распечатка строк предваряется шапкой под названием "просмотр массива G", в которой указано число строк, входящих в массив, и напоминается о принятых логотипах. Это сделано для удобства и лучшего понимания пользователем – поскольку векторная графика хранится в обычных текстовых файлах, и хранится именно в таком виде, то пользователь имеет возможность открывать эти файлы в блокнотике, разбираться с тем, что в них написано, и даже править написанное, памятуя правда о том, что ссылки нужно давать на существующие строки списка.

     Работа в графическом редакторе

   Сделать массив и поместить туда графические элементы, это ещё полдела. Нужно ещё продумать, как с этим массивом работать. Как эти элементы перемещать, поворачивать, изменять, заменять, копировать или удалять, если это понадобится. То есть – как их редактировать?

   У графического редактора, после того, как мы раскроем его панель, кликнув по кнопочке «графика» имеется много строк, и каждая из них, это своеобразная кнопка управления. Строки эти можно видеть на иллюстрации справа.

   Клик по верхней строке «Редактор G» включает редактор, а клик по строке «Закрыть –Х» выключает его и сворачивает панель.
   Клик по левой части строки «Заг.txt/ещё» открывает окно для загрузки файла, содержащего графику, а клик на правой части на слове «ещё» открывает это же окно для загрузки графики в дополнение к уже имеющейся.
    Нас интересует строка «Нарисовать». Клик по этой строке запускает прогон массива G, во время которого элементы графики рисуются в том порядке, в котором они находятся в массиве. Разумеется, каждый элемент рисуется своим способом, в соответствии со считанным из массива логотипом.
    В процессе прогона делается ещё одно вещь – номера титульных строк вместе с координатами начальных точек элемента запоминаются с специальном массиве, что используется в дальнейшем для показа этих начальных точек и выбора среди них нужной.
    Начальные точки графических элементов будут показаны на рисунке кружочками, так, как это видно на иллюстрации, если кликнуть по строке «Показать». При этом режим рисования отключается, редактор переходит в режим Показа, и кликами правой кнопки мыши мы можем выбирать на чертеже нужную нам точку.
    Выбрав точку, мы можем перемещать выбранный элемент, или, двигая метку поворота, изменять размер элемента и поворачивать его. Чтобы закрепить новое положение элемента на рисунке, кликаем по кнопке «закрепить». Если же перемещённый нами элемент включён в группу с другими элементами той же группы, то вместе с ним могут быть перемещены и другие элементы. То же самое относится и к некоторым преобразованиям элементов – вместе с выбранным элементом преобразуются и все элементы той же группы.

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

       Иерархия элементов в группах

    Равенство элементов по группам определяется с учётом иерархии номеров групп. Например, пять фигур Безье, составляющие абрис головы девушки, отнесены к общей группе #10. Все элементы большого яблока отнесены к группе #20, а элементы маленького яблока – к группе #21.
    Если ластик не включён, и кнопка ластика серая, то элементы всех групп перемещаются в режиме Показа совершенно раздельно.
    При включённом сиреневом ластике устанавливается иерархия первого уровня (по единицам), при которой можно совместно переместить или абрис головы, или верхнее яблоко, или нижнее яблоко.
    При включённом синем ластике устанавливается иерархия второго уровня (по десяткам). В этот случае группы #20 и #21 считаются одинаковыми, поскольку число десятков в номерах этих групп одинаково, а вот группа #10 имеет число десятков =1. Поэтому раздельно перемещаются абрис головы, и два яблока сразу.
    При включённом розовом ластике устанавливается иерархия третьего уровня (по сотням). Поскольку число сотен во всех группах одинаково и равно нулю, то и перемещаются все элементы графики сразу.
   
    Объединение графических элементов в группы, и возможность их раздельного перемещения с учётом иерархии номеров, позволяет эффективно и просто использовать векторную графику для целей анимации.
 Совместное движение таких анимированных персонажей можно видеть здесь - http://yadi.sk/i/dXJhifQ8dv4KVg

    В заключение отмечу, что попытка создать векторную графику средствами Визуал Бейсика 6 оказалась вполне успешной.
_________
3.08.2020

ДОПОЛНЕНИЕ. Краткое описание действия строк панели Редактора

Редактор G  -включение Редактора

Нарисова/ть –рисуется вся графика / кроме выбранного элемента

Показать Ok –переход в режим Показа и показ начальных точек
                и возвращение в режим рисования

Параметры   -устанавливаются параметры для рисования такого же
                элемента, как выбранный

Удалить/Изв –элемент удаляется / извлекается (дублируется и дубль
                записывается как новый элемент)

По---замена –выбранный элемент переставляется (ставится перед строкой
                № которой указан в текст.поле) / только что созданный
                элемент заменяет эл-т с указанным № строки

Очистить/ J –массив G очищается / выбранная фигура Безье разбивается
                на отдельные кривые, но сама сохраняется в массиве,
                или –кривые Безье, начиная с выбранной, объединяются
                в фигуру.

Закрыть --X" –редактор закрывается   

------отмена –только что записанный элемент удаляется

Сохр.txt/svg –массив G сохраняется на диске как текстовый файл
                / графика записывается в файл в формате svg

Сохранить G  -массив G упорядочивается и сохраняется в двоичном формате
         (упорядочивание массива позволяет удалить неиспользуемые строки)

Загрузить    -записанный в двоичном формате массив считывается

кр.-----просм –краткий просмотр (без дополнительных строк) и
                / полный просмотр

Заг.txt/ещё   -загрузить графику из текстового файла / добавить графику
    
____________


Рецензии