Заливка и зачерчивание для векторной графики

   Заполненные цветом контуры - фигуры Безье, составляют основу векторной графики. Передвигая и деформируя контуры и накладывая фигуры на фон, можно довольно просто получать последовательность кадров анимационного фильма, не перерисовывая заново каждый кадр.

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

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

   Линии зачерчивания, расходятся веером из заранее выбранной точки, а точка выбирается так, чтобы лучи, доходя до контура, не пересекали бы на этом пути другие части контура.
   Естественно, что не всякий контур может быть зачерчен с соблюдением этого условия. Фигуру с красным контуром (см.иллюстрацию) веером зачертить невозможно. При заполнении цветом таких фигур без заливки не обойтись.

   В предыдущей статье обсуждался алгоритм быстрой заливки контура по равномерно окрашенному фону - http://proza.ru/2020/10/16/1478
   Небольшое изменение этого алгоритма позволяет перейти от заливки, ориентированной на цвет фона, к заливке, ориентированной на цвет контура. Проблема совпадения цвета контура с цветом деталей, по которым ведётся заливка, решается просто – все цвета в квадрате заливаемой области корректируются путём обнуления младших битов цвета.

   Для этого методом PaintPicture проводится операция And между квадратом, окрашенным в цвет (254,254,254), и квадратом, центр которого находится в начальной точке заливки. В результате такого действия заливаемая область фигуры лишается младших битов цвета, но цвет при этом изменяется настолько незначительно, что глазом это незаметно.
   Между тем, цвета, предназначенные для прочерчивания контура фигуры Безье и для её заливки тоже меняются – в них принудительно устанавливаются младшие биты цвета.
   Таким образом, фигура Безье выводится немного изменёнными цветами на немного изменённую в цветовом отношении основу. Поэтому красный и розовый цвета того и другого, имея различие в младших битах, не путаются друг с другом.

   В общем, заливка фигур векторной графики происходит вполне успешно. Не менее успешно, чем их зачерчивание, и оба этих способа заполнения контуров цветом могут быть реализованы средствами Визуал Бейсик 6.
__________
28.10.2020


ПРИЛОЖЕНИЕ. Подпрограммы для заливки контура в среде VB6.

Public Sub ZALc(XX As Integer, YY As Integer) 'подготовка цвета для рисования и заливки фигуры 37
  OldC = (OldC And &HFEFEFE) + &H10101: cBack = (cBack And &HFEFEFE) + &H10101:
  Form1.Picture1.PaintPicture Form1.Picture13, XX - 101, YY - 101, , , 0, 0, 201, 201, vbSrcAnd
End Sub
'=========

Public Sub ZAL1(XX As Integer, YY As Integer) 'заливка внутри контура заданного цвета
Dim Xo As Integer, Yo As Integer, Xm As Integer, Ym As Integer, Ca As Long, Cb As Long, C As Long
Dim Y As Integer, X1 As Integer, X2 As Integer, K As Integer, P As Integer
Dim I As Integer, I1 As Integer, I2 As Integer, DW As Integer, Pm As Integer

  Cb = OldC: Ca = cBack: If Cb = Ca Then Exit Sub 'цвет контура и цвет заливки
  DW = Form1.Picture1.DrawWidth: Form1.Picture1.DrawWidth = 1:
  Xo = XX - 100: Xm = XX + 100: Yo = YY - 100: Ym = YY + 100:
  Y = YY: I = XX
2 I = I - 1: If I < Xo Then X1 = Xo: GoTo 3 'делаем линию-затравку ============
  C = Form1.Picture1.Point(I, Y): If C = Cb Then Else GoTo 2
  X1 = I + 1
3 I = XX
4 I = I + 1: If I > Xm Then X2 = Xm: GoTo 5
  C = Form1.Picture1.Point(I, Y): If C = Cb Then Else GoTo 4
  X2 = I - 1:
5 Form1.Picture1.Line (X1, Y)-(X2 + 1, Y), Ca     ': Exit Sub
  P = 2: YXXk(1, 0) = Y: YXXk(1, 1) = X1: YXXk(1, 2) = X2: YXXk(1, 3) = -1:
         YXXk(2, 0) = Y: YXXk(2, 1) = X1: YXXk(2, 2) = X2: YXXk(2, 3) = 1: 'записываем затравку в стек
         
10 If P < 1 Then Form1.Picture1.DrawWidth = DW: Form1.Text2 = Str(Pm): Exit Sub 'ВЫХОД
   If P > Pm Then Pm = P
   K = YXXk(P, 3): Y = YXXk(P, 0) + K: X1 = YXXk(P, 1): X2 = YXXk(P, 2): P = P - 1 'читаем из стека
   If Y < Yo Or Y > Ym Then GoTo 10
   I = X1: C = Form1.Picture1.Point(I, Y):
   
   If C <> Cb And C <> Ca Then 'ищем I1 слева =======================
   'Form1.Picture1.PSet (I, Y), Ca:
12 I = I - 1: If I < Xo Then GoTo 13
   C = Form1.Picture1.Point(I, Y): If C = Cb Or C = Ca Then Else GoTo 12
13 I1 = I + 1: I = X1
14 I = I + 1: If I > Xm Then GoTo 15
   C = Form1.Picture1.Point(I, Y): If C = Cb Or C = Ca Then Else GoTo 14
15 I2 = I - 1
   If I1 < X1 - 1 Then P = P + 1: YXXk(P, 0) = Y: YXXk(P, 1) = I1: YXXk(P, 2) = X1 - 2: YXXk(P, 3) = -K:
   GoTo 26: End If
   
22 I = I + 1: If I > X2 Then GoTo 10 'ищем I1 справа ==================
   C = Form1.Picture1.Point(I, Y):
   'If C = Cb Then I1 = I: GoTo 23 Else GoTo 22
   If C = Cb Or C = Ca Then GoTo 22 Else I1 = I:
23 I = I + 1: If I > Xm Then GoTo 25
   C = Form1.Picture1.Point(I, Y):
   If C = Cb Or C = Ca Then Else GoTo 23
25 I2 = I - 1:
26 If I2 > X2 + 1 Then P = P + 1: YXXk(P, 0) = Y: YXXk(P, 1) = X2 + 2: YXXk(P, 2) = I2: YXXk(P, 3) = -K:
   If X2 > I2 + 1 Then P = P + 1: YXXk(P, 0) = Y - K: YXXk(P, 1) = I2 + 1: YXXk(P, 2) = X2: YXXk(P, 3) = K:
   P = P + 1: YXXk(P, 0) = Y: YXXk(P, 1) = I1: YXXk(P, 2) = I2: YXXk(P, 3) = K: 'основной путь
   Form1.Picture1.Line (I1, Y)-(I2 + 1, Y), Ca: 'заливаем линию
   GoTo 10
End Sub


Рецензии