КулЛиб - Классная библиотека! Скачать книги бесплатно
Всего книг - 712668 томов
Объем библиотеки - 1401 Гб.
Всего авторов - 274519
Пользователей - 125063

Новое на форуме

Новое в блогах

Впечатления

Влад и мир про Шенгальц: Черные ножи (Альтернативная история)

Читать не интересно. Стиль написания - тягомотина и небывальщина. Как вы представляете 16 летнего пацана за 180, худого, болезненного, с больным сердцем, недоедающего, работающего по 12 часов в цеху по сборке танков, при этом имеющий силы вставать пораньше и заниматься спортом и тренировкой. Тут и здоровый человек сдохнет. Как всегда автор пишет о чём не имеет представление. Я лично общался с рабочим на заводе Свердлова, производившего

  подробнее ...

Рейтинг: 0 ( 0 за, 0 против).
Влад и мир про Владимиров: Ирландец 2 (Альтернативная история)

Написано хорошо. Но сама тема не моя. Становление мафиози! Не люблю ворьё. Вор на воре сидит и вором погоняет и о ворах книжки сочиняет! Любой вор всегда себя считает жертвой обстоятельств, мол не сам, а жизнь такая! А жизнь кругом такая, потому, что сам ты такой! С арифметикой у автора тоже всё печально, как и у ГГ. Простая задачка. Есть игроки, сдающие определённую сумму для участия в игре и получающие определённое количество фишек. Если в

  подробнее ...

Рейтинг: 0 ( 0 за, 0 против).
DXBCKT про Дамиров: Курсант: Назад в СССР (Детективная фантастика)

Месяца 3-4 назад прочел (а вернее прослушал в аудиоверсии) данную книгу - а руки (прокомментировать ее) все никак не доходили)) Ну а вот на выходных, появилось время - за сим, я наконец-таки сподобился это сделать))

С одной стороны - казалось бы вполне «знакомая и местами изьезженная» тема (чуть не сказал - пластинка)) С другой же, именно нюансы порой позволяют отличить очередной «шаблон», от действительно интересной вещи...

В начале

  подробнее ...

Рейтинг: +1 ( 1 за, 0 против).
DXBCKT про Стариков: Геополитика: Как это делается (Политика и дипломатия)

Вообще-то если честно, то я даже не собирался брать эту книгу... Однако - отсутствие иного выбора и низкая цена (после 3 или 4-го захода в книжный) все таки "сделали свое черное дело" и книга была куплена))

Не собирался же ее брать изначально поскольку (давным давно до этого) после прочтения одной "явно неудавшейся" книги автора, навсегда зарекся это делать... Но потом до меня все-таки дошло что (это все же) не "очередная злободневная" (читай

  подробнее ...

Рейтинг: +1 ( 1 за, 0 против).
DXBCKT про Москаленко: Малой. Книга 3 (Боевая фантастика)

Третья часть делает еще более явный уклон в экзотерику и несмотря на все стсндартные шаблоны Eve-вселенной (базы знаний, нейросети и прочие девайсы) все сводится к очередной "ступени самосознания" и общения "в Астралях")) А уж почти каждодневные "глюки-подключения-беседы" с "проснувшейся планетой" (в виде галлюцинации - в образе симпатичной девчонки) так и вообще...))

В общем герою (лишь формально вникающему в разные железки и нейросети)

  подробнее ...

Рейтинг: +1 ( 1 за, 0 против).

C#.программирование 2D и 3D векторной графики [Н. А. Тюкачев] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]

Н. А. ТЮКАЧЕВ,
В. Г. ХЛЕБОСТРОЕВ

C#. ПРОГРАММИРОВАНИЕ
2D И 3D ВЕКТОРНОЙ
ГРАФИКИ
Учебное пособие
Издание четвертое, стереотипное

•САНКТПЕТЕРБУРГ•
•МОСКВА•
•КРАСНОДАР•
2020

УДК 004
ББК 32.973я73
Т 98

Тюкачев Н. А. C#. Программирование 2D и 3D векторной
графики : учебное пособие / Н. А. Тюкачев, В. Г. Хлебостроев. —
4е изд., стер. — СанктПетербург : Лань, 2020. — 320 с. + CD. —
(Учебники для вузов. Специальная литература). — Текст : непо
средственный.
ISBN 9785811447541
Книга посвящена программированию векторной графики. Описываются
основные методы графических классов и приводятся примеры их исполь
зования, рассматриваются аффинные преобразования на плоскости и
в трехмерном пространстве и различные виды проецирования. Приводится
обзор различных моделей трехмерных тел. Одна из них посвящена сложной
теме — бинарные операции над множествами. Описан лучевой алгоритм
определения принадлежности точки многоугольнику и многограннику.
Описывается библиотека OpenGL и основные команды этой библиотеки.
Приводятся простые примеры 2D графики.
Книга рассчитана на бакалавров направлений подготовки «Прикладная
математика и информатика», «Математика и компьютерные науки»,
«Фундаментальная информатика и информационные технологии», «Мате
матическое обеспечение и администрирование информационных систем»,
«Информатика и вычислительная техника», «Информационные системы
и технологии», «Программная инженерия», «Информационная безопас
ность», студентов специальностей «Компьютерная безопасность» и «Инфор
мационноаналитические системы безопасности», а также учащихся
старших классов и лиц, самостоятельно изучающих языки программи
рования.

УДК 004
ББК 32.973018я73
Рецензент
М. Г. МАТВЕЕВ — доктор технических наук, профессор, зав. кафедрой
информационных технологий управления Воронежского государственного
университета.

Обложка
Е. А. ВЛАСОВА

© Издательство «Лань», 2020
© Н. А. Тюкачев,
В. Г. Хлебостроев, 2020
© Издательство «Лань»,
художественное оформление, 2020

ВВЕДЕНИЕ
Компьютерная обработка графической информации сводится к
решению трех классов задач.
1. Задачи распознавания образа: на основе имеющегося оцифрованного
изображения осуществить идентификацию объекта, то есть получить его
описание. Здесь выполняется преобразование изображение → описание
объекта.
2. Задача
обработки
изображения:
осуществить
преобразование
имеющегося изображения с целью изменения его свойств. Выполняется
преобразование изображение → изображение.
3. Задача построения изображения: по описанию объекта построить его
изображение на графическом устройстве. Здесь выполняется
преобразование описание объекта → изображение.
Именно этой третьей задаче посвящена эта книга. При этом описание
объекта должно иметь вид математической модели. Таким образом, в рамках
компьютерной графики решаются две основные подзадачи:
– построение математической модели изображаемого объекта;
– визуализация объекта в соответствии с этой моделью.
В книге изложены основы программирования 2D и 3D графики на
языке C# в среде .Net Framework, описаны свойства и методы классов
Graphics, Color, Pen, Brush, Font, предназначенных для рисования.
Описаны модели цветов: RGB (Red, Green, Blue), CMY (Cyan,
Magenta, Yellow), CMYK, HSB и Lab.
В третьей главе рассмотрены задачи: интерполяции полиномами,
интерполяции кубическими сплайнами, сглаживания и аппроксимации. Далее
в этой главе рассматриваются аффинные преобразования на плоскости и в
пространстве. Достаточно подробно описываются виды проецирования –
ортографическое, аксонометрическое, косоугольное и центральное.
Приведена классификация моделей трехмерных тел: каркасные модели,
граничные, поверхностные модели, сплошные модели.
В четвертой главе обсуждаются простые графические проекты:
сортировка элементов массива, морфинг, падение глобуса, велосипед,
деформация изображений, растровый редактор, редактирование графа.
Вся пятая глава посвящена проекту «Векторный редактор». В ней
обсуждаются структура данных, масштабирование, создание, прорисовка и
изменение объектов, запись и чтение данных.
В шестой главе описаны проекты для построения графиков функций
одной и двух переменных. В этой же главе приведен проект для построения
3

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

4

Глава 1. ОСНОВНЫЕ ГРАФИЧЕСКИЕ КЛАССЫ C#
Возможности визуальной студии .NET позволяют написать сложные
приложения, используя только средства управления, доступные в наборе
компонентов. Набор компонентов включает в себя средства управления для
показа данных (ярлыки, календари, списки и т.д.), наборы (радио-кнопки,
CheckBoxes, списки и т.д.) и контейнеры для сбора данных (DataGrids,
TextBox и т.д.). Кроме того, несколько средств управления и компонентов
управляют датой и временем (Timer и т.д.).
Однако, часто возникает необходимость показывать данные, используя
инструменты доступа через GDI+ (Graphics Device Interface — интерфейс
графических устройств) и графические объекты.
Для демонстрации возможностей этих инструментов эта и следующая
главы описывают основы программирования графики с простыми программами.

1.1. ПРОСТРАНСТВА ИМЕН ГРАФИЧЕСКИХ КЛАССОВ
Классы, предназначенные для рисования, заключены в библиотеку
System.Drawing.dll, которая определяет несколько пространств имен.
Таблица 1.1
Основные пространства имен GDI+
Пространство имен
Назначение
System.Drawing
Определяет типы для визуализации: шрифты,
перья, кисти и т.п. Содержит класс Graphics
Drawing.Drawing2D
Представляет классы, используемые для более
развитой функциональности графики
(градиентные кисти, концы перьев,
геометрические трансформации и т.п.)
Drawing.Printing
Определяет классы, позволяющие печатать на
бумаге, взаимодействовать с принтером и
форматировать общий вид печати
Drawing.Imaging
Определяет классы, позволяющие работать с
графическими файлами (изменять палитры,
извлекать метаданные изображений,
манипулировать метафайлами и т.п.)
System.DrawingText Позволяет работать с коллекциями шрифтов
5

1.2. ПРОСТРАНСТВО ИМЕН SYSTEM.DRAWING
Большинство графических классов и других типов находится в
пространстве имен System.Drawing. В нем есть классы, представляющие
кисти, перья, шрифты и изображения. Пространство имен System.Drawing
определяет также множество служебных структур и классов, таких как
Color, Point, Size и Rectangle. В таблице 1.2 перечислены
некоторые основные типы.
Таблица 1.2
Основные типы пространства имен System.Drawing
Класс
Назначение
Bitmap
Представляет полотно для рисования в памяти.
Инкапсулирует изображения (*.bmp и т.п.)
Brush
Объекты кистей используются для заполнения
Brushes
внутренних областей графических фигур, таких как
SolidBrush
прямоугольники, эллипсы и многоугольники.
SystemBrushes
У класса SolidBrush есть свойство Color
TextureBrush
Color
Определяют
множество
статических
свойств,
SystemColors
используемых для получения цветов перьев и кистей
Font
Инкапсулирует свойства шрифта (название, стиль,
FontFamily
курсив, размер и т.п.). FontFamily предоставляет
абстракцию для группы шрифтов, имеющих
сходный дизайн, но различия в стиле
Graphics
Представляет поверхность рисования и множество
методов для визуализации текста, изображений и
геометрических шаблонов
Icon
Представляют пиктограммы, а также набор
SystemIcons
стандартных системных пиктограмм
Image
Image — абстрактный базовый класс,
ImageAnimator
предоставляющий функциональность для классов
Bitmap, Icon и Cursor. Класс
ImageAnimator анимирует изображение
Pen
Перья — это объекты, используемые для рисования
Pens
линий. Класс Реn определяет набор статических
SystemPens
свойств, возвращающих Реn заданного цвета
Point
Структуры описывают целые или вещественные
PointF
координаты (х, у)
Rectangle
Структуры описывают прямоугольные области с
RectangleF
целыми или вещественными параметрами
Size
Структуры описывают ширину/высоту с целыми
SizeF
или вещественными параметрами
6

Продолжение табл. 1.2
Назначение
Используется для инкапсуляции различных средств
текстовой компоновки (например, выравнивание,
межстрочный интервал и т.п.)
Region
Тип описывает внутреннюю часть геометрического
образа, состоящего из прямоугольников и путей
Все эти классы будут далее описаны, поскольку ими приходится
пользоваться, но перед переходом к ним давайте подробно изучим основной
класс Graphics.
Класс
StringFormat

1.3. КЛАСС GRAPHICS
Класс Graphics представляет GDI+ поверхность рисования.
Графический объект поддерживает для поверхности рисования: масштаб,
единицы, ориентацию поверхности рисования.
Приведем пример простейшего приложения, которое на форме рисует
эллипс:
Листинг 1.1. Простейшая графическая программа
public partial class FormMain : Form
{
Graphics g;
private void Draw()
{
g = CreateGraphics();
g.Clear(Color.White);
g.DrawEllipse(Pens.Black,10,10,200,100);
g.Dispose();
}
private void FormMain_Paint(object sender,
PaintEventArgs e)
{
Draw();
}
}

Результат работы программы показан на рисунке 1.1.

Рис. 1.1. Простейшая графическая программа

7

Отметим важные моменты, которые необходимо соблюдать при
создании любого GDI-проекта:
– должно быть определено свойство g класса Graphics;
– необходимо создать обработчик события onPaint, в котором
будет вызываться метод рисования Draw().
В методе Draw():
– методом CreateGraphics() необходимо создать объект g;
– методом Clear() очистить поверхность рисования;
– что-нибудь нарисовать;
– освободить память от объекта g.
Класс Graphics содержит много свойств. Часто используемые
свойства перечислены в таблице 1.3, большинство которых будет
демонстрироваться позже. Все они позволяют не только читать себя, но и
изменять.
Таблица 1.3
Свойства класса Graphics
Свойство
Класс
Описание
Clip
Region
Возвращает или задает объект Region,
ограничивающий область рисования
данного объекта
DpiX /
Float /
Задает значение горизонтального и
DpiY
single
вертикального разрешения в точках на
дюйм
PageScale Float /
Задает значение для масштабирования
single
между универсальными единицами и
единицами страницы
PageUnit
GraphicsUnit Возвращает или задает единицу
измерения для координат страницы
данного объекта
Свойство PageScale устанавливает масштабирование между
мировыми единицами и единицами страницы.

1.4. КООРДИНАТЫ
В определении декартовой системы координат оси X и Y проходят так,
как показано на рисунке 1.2. Значения справа и выше центра координат
являются положительными, а значения слева и ниже – отрицательными.

8

Рис. 1.2. Декартовы координаты

В графических программных средах система координат имеет начало
координат в верхнем левом углу, и оси координат направлены направо и
вниз, как показано на рисунке 1.3.

Рис. 1.3. Мировые координаты

Координаты, используемые в методах класса Graphics, называют
мировыми координатами.

1.5. ПРЕОБРАЗОВАНИЕ КООРДИНАТ
Мировые координаты преобразовываются в координаты страницы
мировыми
преобразованиями.
Мировые
преобразования,
например
TranslateTransform(), ScaleTransform() и RotateTransform(),
9

используются для того, чтобы установить центр и поворот системы
координат.
Свойство PageUnit устанавливает единицу для преобразования и
масштабирования рисунков. Эти единицы – одно из возможных
GraphicsUnits-перечисленных значений, приведенных в таблице 1.4.
Таблица 1.4
Перечисление GraphicsUnits
Перечисленная
Единица измерения
Display
1/75 дюйма
Document
1/300 дюйма
Inch
1 дюйм
Millimeter
1 миллиметр
Pixel
1 пиксел
Point
1/72 дюйма
World
Мировые единицы
В следующем примере рисуется 6 эллипсов с различными единицами
измерения.
Листинг 1.2. Рисование эллипсов с различными единицами измерения
private void Draw()
{
g = CreateGraphics();
g.Clear(Color.White);
g.PageUnit = GraphicsUnit.Pixel;
g.DrawEllipse(Pens.Black, 10, 10, 200, 100);
g.PageUnit = GraphicsUnit.Display;
g.DrawEllipse(Pens.Black, 10, 10, 200, 100);
g.PageUnit = GraphicsUnit.Point;
g.DrawEllipse(Pens.Black, 10, 10, 200, 100);
g.PageUnit = GraphicsUnit.Millimeter;
g.DrawEllipse(Pens.Black, 10, 10, 20, 10);
g.PageUnit = GraphicsUnit.Document;
g.DrawEllipse(Pens.Black, 10, 10, 200, 100);
Pen myPen = new Pen(Color.Black,0.05F);
g.PageUnit = GraphicsUnit.Inch;
g.DrawEllipse(myPen, 1, 1, 2, 1);
g.Dispose();
}

10

Для первых пяти эллипсов используется перо толщиной 1, а для
шестого эллипса создается перо толщиной 0,05 дюйма. Результаты работы
программы представлены на рисунке 1.4.

Рис. 1.4. Эллипсы с различными единицами измерения




Отметим, что:
эллипсы, нарисованные с единицами измерения Pixel и Display,
совпали между собой;
линия эллипса, нарисованная с единицей измерения миллиметр, имеет
толщину 1 мм.

1.6. ГРАФИЧЕСКИЕ МЕТОДЫ
Класс Graphics содержит много методов для рисования линий на
графическом устройстве. Имена этих методов начинаются с Draw:
DrawArc
DrawBezier
DrawBeziers
DrawClosedCurve
DrawCurve
DrawEllipse

DrawIcon
DrawIconUnstretched
DrawImage
DrawImageUnscaled
DrawLine
DrawLines

DrawPath
DrawPie
DrawPolygon
DrawRectangle
DrawRectangles
DrawString

Графический класс Graphics также включает в себя методы
заполнения областей, имена которых начинаются с Fill:
FillClosedCurve FillPie
FillRectangles
FillEllipse
FillPolygon
FillRegion
FillPath
FillRectangle
Методы Draw*** рисуют контур фигуры; методы
заполняют фигуры цветом и стилем текущей кисти.
Часто используемые методы представлены в таблице 1.5.
Метод
Clear

Fill***

Таблица 1.5
Методы класса Graphics
Описание
Очищает полотно рисования и заполняет ее
указанным цветом
11

Метод
DrawString
DrawLine
FillEllipse
MeasureString
RotateTransform

ScaleTransform

TransformPoints
TranslateTransform

Продолжение табл. 1.5
Описание
Рисует строку, используя установленные
кисть и шрифт
Рисует отрезок прямой линии между двумя
точками
Заполняет эллипс, ограниченный
прямоугольником
Возвращает размер прямоугольника, в
котором нарисована строка.
Применяет вращение, определенное
матрицей трансформации, к мировой
системе координат
Применяет масштабирование системы
координат, определенное матрицей
трансформации
Трансформирует массив точек, используя
матрицу трансформации
Применяет смещение графического объекта,
определенное матрицей трансформации

12

Глава 2. ПРОСТРАНСТВО ИМЕН SYSTEM.DRAWING
Пространство имен System.Drawing содержит в себе пять
пространств имен.
1. Пространство имен Design содержит классы, которые расширяют
логические и графические возможности интерфейса пользователя (UI).
Классы этого пространства имен используются для создания
настраиваемой панели элементов; редакторов значений определенных
типов, которые могут редактировать и графически представлять
значения поддерживаемых типов; преобразователей, которые могут
преобразовывать значения определенных типов. Это пространство имен
предоставляет базовую архитектуру для создания расширений
пользовательского интерфейса времени разработки.
2. Пространство имен Drawing2D предоставляет расширенные
функциональные возможности векторной и двумерной графики. В этом
пространстве содержатся классы графики и графических контуров;
типы, относящиеся к матрице преобразования; классы Brush;
перечисления, связанные с линиями; перечисления, связанные с
заполнением фигур и контуров.
3. Пространство имен Imaging расширяет функциональные возможности
визуализации изображения, реализованные в пространстве имен
System.Drawing:
– класс Metafile содержит методы для записи метафайлов;
– класс Encoder предоставляет возможность расширить GDI+ для
поддержки любого формата изображений;
– класс PropertyItem содержит методы для сохранения метафайлов в
файлах изображений и их извлечения.
4. Пространство имен Printing обеспечивает функции, связанные с
печатью.
5. Пространство имен Text предоставляет расширенные функциональные
возможности для работы с текстом.
Так как базовые графические средства реализованы в пространстве
имен System.Drawing, то изучение графических свойств и методов
начнем с этого пространства имен.

13

2.1. СОЗДАНИЕ И УДАЛЕНИЕ ОБЪЕКТА КЛАССА GRAPHICS
Класс Graphics содержит поверхность рисования. Существуют три
вида поверхностей рисования:
– окна и компоненты;
– страницы, отправляемые на принтер;
– битовые карты и изображения в памяти.
Класс Graphics предоставляет методы для рисования на любой из этих
поверхностей рисования. Его можно использовать для рисования дуг, кривых,
кривых Безье, эллипсов, изображений, линий, прямоугольников и текста.
2.1.1. СОЗДАНИЕ ПОВЕРХНОСТИ РИСОВАНИЯ
Объект Graphics для формы можно получить минимум четырьмя
различными способами.
Первый способ. Вызов метода рисования в обработчике события
Paint():
private void FormMain_Paint(object sender, PaintEventArgs e)
{
Draw(e.Graphics);
}

Свойство e.Graphics типа Graphics показывает на полотно
рисования FormMain.
Второй способ. Переопределение метода OnPaint(). Класс Form
наследует метод OnPaint() из класса Control, и этот метод является
обработчиком события Paint, которое генерируется при каждом
перерисовывании элемента управления. Объект Graphics можно получить
из класса PaintEventArgs, который передается событием:
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
// рисование
}

В других случаях может потребоваться выполнение рисования
непосредственно в окне, не дожидаясь генерации события Paint. Такая
ситуация может возникать для устранения мерцания при создании кода для
выбора графического объекта в окне или перетаскивании объекта мышью.
Третий способ. Объект Graphics можно получить, вызывая в форме
метод CreateGraphics():
Graphics g = this.CreateGraphics();
// рисование
g.Dispose();

14

В этом случае рисование будет происходить на форме. Для рисования
на любом другом элементе, например на панели panel1, необходимо
немного изменить код:
Graphics g = panel1.CreateGraphics();

Четвертый способ. При выборе графического объекта в окне или
перетаскивании объекта мышью может возникать мерцание. Для устранения
мерцания необходимо рисовать в памяти на bitmap, а затем копировать
bitmap на полотно рисования формы:
Graphics gScreen;
public FormMain()
{
InitializeComponent();
gScreen = this.CreateGraphics();
}
public void Draw()
{
Bitmap bitmap = new Bitmap(Width, Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
Draw(g);
gScreen.DrawImage(bitmap, ClientRectangle);
}
bitmap.Dispose();
}

2.1.2. УДАЛЕНИЕ ОБЪЕКТОВ РИСОВАНИЯ
При разработке приложений, использующих GDI+, приходится иметь
дело с несколькими типами данных, для которых важно вызывать метод
Dispose(), иначе некоторые ресурсы не будут освобождены. Например,
классы Graphics, Pen, Brush, Font реализуют интерфейс IDisposable.
При получении объекта Graphics из метода OnPaint() или
Paint() он не создается, поэтому метод Dispose() вызывать не надо. Но
при вызове метода CreateGraphics() вызов метода Dispose()
обязателен, если объект Graphics описан и создается в методе рисования.
Для освобождения памяти можно использовать такой код:
g = this.CreateGraphics();
try
{
// рисование
}

15

finally
{
if (g != null)
((IDisposable)g).Dispose();
}

Существует более простой способ работы с объектами, которые
необходимо удалять. Для этого предназначена конструкция using, которая
автоматически вызывает метод Dispose(), когда объект выходит из блока
using. Следующий код демонстрирует применение ключевого слова using
и полностью эквивалентен предыдущему:
using (Graphics g = this.CreateGraphics() )
{
// рисование
}

Создание и удаление объектов рисования занимает определенное
время, потеря которого заметна при частой прорисовке, например при
перемещении мыши или создании мульпликаций. Поэтому графические
объекты можно создать один раз, например в конструкторе FormMain()
или в методе FormMain_Load(). Тогда нет необходимости после
завершения рисования удалять объекты рисования.
2.1.3. ПОРЯДОК ВЫПОЛНЕНИЯ ДЕЙСТВИЙ ПРИ РИСОВАНИИ
1.
2.

Описать поле g класса Graphics в классе FormMain.
Создать метод рисования Draw():
private void Draw(Graphics g)
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
// рисование типа g.DrawLine()
}

3.

Создать метод onPaint(), в котором направить g на e.Graphics и
вызвать метод Draw():

private void FormMain_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
Draw(g);
}

2.2. СТРУКТУРЫ ПРЕДСТАВЛЕНИЯ КООРДИНАТ
Для указания координат при рисовании используются три структуры:
Point (точка), Size (размер) и Rectangle (прямоугольник).
16

Структуры Point или PointF используются для представления
точки, имеющей целочисленные или вещественные координаты X и Y. Они
представляют собой точку на двумерной плоскости, то есть координаты
пикселя. Методы, такие как DrawLine(), DrawRectangle(), принимают
Point в качестве аргумента. Создание структуры Point выполняется
следующим образом:
Point р = new Point (1, 1);

Для получения координат X и Y структуры Point используют свойства
X и Y. Эти свойства объявлены только для чтения. Поэтому конструкция
p.X = 2. Изменения следует производить так: р = new Point (2, 1).
Структуры Size и SizeF используются для представления размера в
пикселях. Структура содержит свойства ширину Width и высоту Height.
Создание структуры Size выполняется следующим образом:
Size s = new Size (12, 5);

Структуры Rectangle и RectangleF используются для указания
координат прямоугольника. Свойство Point определяет верхний левый угол
прямоугольника, а свойство Size — его размеры. Существует по два
конструктора структур Rectangle и RectangleF. Один принимает в
качестве аргументов позицию X, позицию Y, ширину и высоту. Второй
принимает свойства типа Point и Size. Ниже приведены два примера
объявления и конструирования структуры Rectangle:
Rectangle rl = new Rectangle (2, 2, 5, 6);
Point p = new Point (2, 2);
Size s = new Size (5, 6);
Rectangle r2 = new Rectangle (p, s);

Для получения и установки расположения и размеров структуры
Rectangle предусмотрены некоторые свойства. Другие полезные свойства
и методы для решения таких задач:
– определение принадлежности точки прямоугольнику;
– пересекается ли прямоугольник с другим прямоугольником;
– пересечение, вычитание, объединения двух прямоугольников.

2.3. КЛАССЫ COLOR, PEN, BRUSH, FONT
Перо и кисть ипользуются для отображения линий, фигур и текста.
Перо является экземпляром класса Pen и назначается при рисования линий и
сложных фигур. Кисть — экземпляр класса Brush и используется при
заполнении фигур или для рисования текста. Объекты Color используются
перьями и кистями для указания цвета.
17

2.3.1. КЛАСС C OLOR
Для работы с цветами пространство имен System.Drawing содержит
следующие классы и структуры:
– Color – структура представляет цвета в виде каналов альфа
(прозрачность), красного, зеленого и синего (ARGB). Каждый
канал – это целое от 0 до 255;
– KnownColor – перечислимый тип. Содержит системные цвета;
– SystemColors – свойства этого класса являются структурами
Color, которые представляют собой цвета Windows.
Структура Color используется для представления различных цветов.
Цвета используются перьями и кистями для указания цвета при
визуализации.
Существует около 150 системных цветов, которые могут быть
доступны через структуру Color. Например:
Color myColor;
myColor = Color.Red;
myColor = Color.Aquamarine;
myColor = Color.LightGoldenrodYellow;
myColor = Color.PapayaWhip;
myColor = Color.Tomato;

Можно также создавать определяемые цвета с помощью метода
Color.FromArgb(). Этот метод позволяет указать долю отдельных
составляющих компонентов красного, синего и зеленого цветов:
Color myColor;
myColor = Color.FromArgb(23,56,78);

Каждый компонент должен быть целым числом от 0 до 255, где 0
означает отсутствие цвета, а 255 – полное насыщение указанного цвета.
Например:
Color.FromArgb(0,0,0) - черный,
Color.FromArgb(255,255,255) - белый.

С помощью метода FromArgb() можно назначить компонент альфа.
Альфа определяет прозрачность объектов за рисуемым графическим
объектом. Альфа-компонент – первый из четырех аргументов в методе
Color.FromArgb() и может быть целым числом в диапазоне от 0 до 255:
Color myColor;
myColor = Color.FromArgb(127, 23, 56, 78);

Можно также создать цвет с альфа-компонентом, назначив альфакомпонент для ранее определенного цвета:
Color myColor;
myColor = Color.FromArgb(128, Color.Red);

Модель цветов RGB не единственно возможная. Еще одна модель
представления цвета — разбиение его на три компонента: оттенок,
18

насыщенность и яркость (HSB). Структура Color содержит методы для
выполнения этой задачи:
– GetHue() — возвращает значение оттенка;
– GetSaturation() — возвращает значение насыщенности;
– GetBrightness() — возвращает значение яркости.
Более подробно о моделях цветов поговорим в пункте 2.8.
2.3.2. КЛАСС PEN
Перо назначается для рисования линий, кривых и фигур. В таблице 2.1
приведены классы перьев.
Таблица 2.1
Классы перьев
Класс
Описание
Pen

Определяет объект, используемый для рисования линий

Pens

Класс для стандартных цветов

SystemPens Свойства этого класса являются объектами Pen, то есть
цветом элемента изображения Windows толщиной 1
Класс Pen имеет 4 конструктора:
Pen(Brush brush);
Pen(Color color);
Pen(Brush brush, float width);
Pen(Color color, float width).
Экземпляр класса после завершения работы с ним необходимо
уничтожить методом Dispose(), который освобождает все ресурсы,
используемые данным объектом Pen.
Перо обладает следующими свойствами:
– Brush – получает или задает объект Brush;
– Color – получает или задает цвет пера;
– float Width – получает или устанавливает толщину пера Pen в
единицах объекта;
– PenType – получает или задает стиль линий;
– DashStyle – задает пользовательский стиль пунктирных линий.
Свойство PenType перечислимого типа задает вид заполнения,
используемый объектом Pen, и может принимать следующие значения:
– SolidColor – задает сплошное заполнение;
– HatchFill – задает заполнение штриховкой;





19





TextureFill – задает заполнение с текстурой точечного рисунка;
PathGradient – задает градиентное заполнение контура;
LinearGradient – задает линейное градиентное заполнение.
Свойство перечислимого типа DashStyle может принимать
следующие значения:
– Solid – сплошная линия;
– Dash – линия, состоящая из штрихов;
– Dot – линия, состоящая из точек;
– DashDot – штрих-пунктирная линия;
– DashDotDot – линия, состоящая из шаблонов «штрих-две точки»;
– Custom – задает произвольный тип пунктирных линий.
В следующем примере создается черное перо:
// черное
Pen myPen
// черное
Pen myPen

перо толщиной 1
= new Pen(Color.Black);
перо толщиной 5
= new Pen(Color.Black, 5);

Ниже показывается создание пера, основанное на существующей кисти
с именем myBrush:
//перо с такими же свойствами, как у кисти myBrush толщиной 1
SolidBrush myBrush = new SolidBrush(Color.Red);
Pen myPen = new Pen(myBrush);
//перо с такими же свойствами, как у кисти myBrush толщиной 5
Pen myPen = new Pen(myBrush, 5);

Если перо создано, то его можно использовать для рисования линий.
Ниже показано использование пера для рисования эллипса:
Pen myPen = new Pen(Color.Black);
g.DrawEllipse(myPen, 20, 30, 10, 50);

Для пера можно изменить свойства, влияющие на вид линии. Свойства
пера:
– Color и Width — цвет и толщина;
– StartCap и EndCap — стандартные (различные стрелки) или
пользовательские фигуры в начале или в конце отрезка прямой
линии;
– DashStyle — сплошная, пунктирная или пользовательская
пунктирная линия;
– DashCap — позволяет настраивать концы линии;
– DashPattern — создает перо произвольного стиля. Этому
свойству необходимо передать массив четной длины, в котором
задаются длины рисуемых интервалов и пропусков между ними.
20

Ниже приведен пример (рис. 2.1), демонстрирующий использование
этого свойства:
Pen p = new Pen(Color.Black, 3);
float[] f = { 15, 5, 10, 5, 1, 1 };
p.DashPattern = f;
g.DrawRectangle(p, 10, 10, 80, 300);

Рис. 2.1. Рисование эллипса пером произвольного стиля

Также у класса Pen есть несколько методов, позволяющих изменять
матрицу геометрического преобразования объекта Pen.
2.3.3. КЛАСС BRUSH
Кисти используются для рисования сплошных фигур и отображения
текста. В таблице 2.2 приведены классы кистей, каждый из которых
наследуется от класса Brush.
Таблица 2.2
Классы кистей
Класс Brush
Описание
SolidBrush

Сплошная заливка

HatchBrush

Сплошная заливка, позволяет выбрать из
представленных шаблонов

TextureBrush

Кисть, использующая изображение

LinearGradientBrush Рисует двумя цветами, смешивая цвета вдоль
указанной линии. В начале линии назначается
один цвет, в конце — другой
PathGradientBrush

Задается полигон, в каждой вершине которого
назначается свой цвет

Экземпляры класса Brush после завершения работы необходимо
уничтожать методом Dispose().

21

2.3.3.1. Класс SolidBrush
У класса SolidBrush добавляется только одно свойство Color.
Пример, приведенный ниже, показывает, как нарисовать сплошной
красный эллипс на форме. Эллипс будет соответствовать размерам
прямоугольника, предоставленного для него ClientRectangle:
Graphics g = this.CreateGraphics();
SolidBrush myBrush = new SolidBrush(Color.Red);
g.FillEllipse(myBrush, ClientRectangle);
myBrush.Dispose();

2.3.3.2. Класс HatchBrush
В классе HatchBrush добавляется три свойства:
– Color BackgroundColor – цвет интервалов между линиями
штриховки;
– Color ForegroundColor – цвет линий штриховки;
– HatchStyle HatchStyle – стиль штриховки.
Перечислимый стиль HatchStyle предоставляет несколько десятков
различных стилей штриховки.
Класс HatchBrush позволяет выбрать стиль кисти из большого
разнообразия представленных шаблонов для рисования, а не сплошной цвет.
Следующий пример показывает создание HatchBrush, который рисует
шаблоном Plaid (плед), используя красный цвет как forecolor и синий –
как свойство backcolor:
HatchBrush aHatchBrush = new HatchBrush(HatchStyle.Plaid,
Color.Red, Color.Blue);

2.3.3.3. Класс TextureBrush
Можно создать кисть TextureBrush, содержащую изображение, и
рисовать фигуры, которые затем будут залиты этим изображением. На основе
текстурной кисти можно создать перо для рисования линий или шрифт для
для прорисовки строк.
Класс TextureBrush позволяет в качестве кисти использовать
изображение, хранящееся в свойстве Image. Свойство перечислимого типа
WrapMode указывает, как накладывается текстура, если она меньше, чем
заполняемая область. Это свойство может принимать следующие значения:
– Tile – наложение градиента или текстуры;
– TileFlipX – перед наложением разворачивает текстуру или
градиент горизонтально;
– TileFlipY – перед наложением разворачивает текстуру или
градиент вертикально;
– TileFlipXY – перед наложением разворачивает текстуру или
градиент горизонтально и вертикально;
– Clamp – не производится наложение текстуры или градиента.
22

Класс содержит 8 конструкторов:
TextureBrush(Image bitmap);
TextureBrush(Image image, Rectangle dstRect);
TextureBrush(Image image, RectangleF dstRect);
TextureBrush(Image image, WrapMode wrapMode);
TextureBrush(Image image, Rectangle dstRect,
ImageAttributes imageAttr);
– TextureBrush(Image image, RectangleF dstRect,
ImageAttributes imageAttr);
– TextureBrush(Image image, WrapMode wrapMode,
Rectangle dstRect);
– TextureBrush(Image image, WrapMode wrapMode,
RectangleF dstRect).
Текстурная кисть заполняет фигуры или текст с помощью изображение
как шаблон. Следующий пример показывает, как создать кисть – экземпляр
класса TextureBrush, которая рисует с помощью изображения из файла с
именем myPic.bmp:






TextureBrush myBrush =
new TextureBrush(new Bitmap("myPic.bmp"));

2.3.3.4. Класс LinearGradientBrush
Класс линейных градиентных заливок LinearGradientBrush
обладает следующими важными свойствами:
– Color[] LinearColors – получает или задает начальный и
конечный цвета градиента;
– Rectangle – получает прямоугольную область, которая определяет
начальную и конечную точки градиента;
– Matrix Transform – получает или задает копию объекта
Matrix, определяющего локальное геометрическое преобразование;
– WrapMode – получает или задает перечисление WrapMode,
определяющее режим переноса объекта.
У этого класса есть несколько методов, позволяющих изменять матрицу
геометрического преобразования объекта LinearGradientBrush.
2.3.3.5. Класс PathGradientBrush
Класс многоцветной градиентной кисти содержит 5 конструкторов и
следующие важные свойства:
– PointF CenterPoint – получает или задает центральную точку
градиента контура;
– PointF FocusScales – получает или задает точку фокуса для
градиентного перехода;
23



Color[] SurroundColors – получает или задает массив цветов,
соответствующих точкам контура, заполняемого объектом
PathGradientBrush;
– WrapMode – получает или задает объект, определяющий режим
переноса для этого объекта PathGradientBrush.
Для работы с градиентными заливками предназначены следующие
методы:
– SetBlendTriangularShape(float focus) – создает градиент
с цветом центра и линейным переходом к одному окружающему
цвету;
– SetBlendTriangularShape(float
focus,
float
scale) – создает градиент с цветом центра и линейным переходом
к каждому из окружающих цветов;
– SetSigmaBellShape(float focus) – создает градиентную
кисть, которая изменяет цвет, начиная с центра контура и заканчивая
границей контура. Переход от одного цвета к другому выполняется
на основе колоколообразной кривой;
– SetSigmaBellShape(float focus, float scale) –
создает градиентную кисть, которая изменяет цвет, начиная с центра
контура и заканчивая границей контура. Переход от одного цвета к
другому выполняется на основе колоколообразной кривой.
Градиентные кисти обеспечивают поддержку сложных затенений.
С помощью LinearGradientBrush можно создать гладкую заливку
постепенным смешиванием двух цветов вдоль линейного градиента.
Следующий пример показывает, как рисовать формы с градиентом, который
постепенно смешивает цвета от красного до желтого:
Graphics g = this.CreateGraphics();
LinearGradientBrush myBrush =
new LinearGradientBrush(ClientRectangle,
Color.Red, Color.Yellow, LinearGradientMode.Vertical);
g.FillRectangle(myBrush, ClientRectangle);

PathGradientBrush поддерживает много вариантов более сложных
затенений и окраски.
2.3.4. ВЫВОД ТЕКСТА С ИСПОЛЬЗОВАНИЕМ КЛАССА FONT
Рассмотрим основные свойства и методы класса Font:
int Height – значение междустрочного интервала шрифта в
точках;
– string Name – имя шрифта;
– float Size – размер максимального пробела шрифта в единицах,
указанных свойством Font.Unit;


24



float SizeInPoints – размер максимального пробела шрифта
(в пунктах);
– FontStyle Style – сведения о стиле для шрифта;
– GraphicsUnit Unit – единица измерения шрифта.
Перечислимый тип FontStyle принимает следующие значения:
– Regular – стандартный текст;
– Bold – текст, выделенный жирным шрифтом;
– Italic – текст, выделенный курсивом;
– Underline – текст, выделенный подчеркиванием;
– Strikeout – текст с линией посредине.
Перечислимый тип GraphicsUnit, задающий единицу измерения,
принимает следующие значения:
– World – единицу мировой системы координат;
– Display – единицу измерения устройства отображения. Обычно это
точки для дисплеев и 1/100, 1/300, 1/600, … – дюйма для принтеров;
– Pixel – точку устройства;
– Point – пункт (1/72 дюйма);
– Inch – дюйм;
– Document – единицу документа (1/300 дюйма);
– Millimeter – миллиметр.
Класс Font имеет 13 конструкторов, самый простой из которых
создает новый шрифт Font, используя размер и стиль:
public Font(FontFamily family,float emSize,FontStyle style);

Параметры конструктора:
family – семейство шрифтов FontFamily или имя шрифта;
emSize – ширина самой широкой буквы нового шрифта (в пунктах);
style – стиль типа FontStyle шрифта.
В следующем примере создается экземпляр класса Font для
прорисовки текста:




Font myFont = new Font("Arial", 7, FontStyle.Bold |
FontStyle.Italic);

Свойство Size представляет размер шрифта. С помощью
перечисления GraphicsUnit в качестве единицы изменения шрифтов
можно указывать одно из следующих значений:
– пункт (1/72 дюйма);
– дисплей (1/72 или 1/100 дюйма);
– документ (1/300 дюйма);
– дюйм;
– миллиметр;
– пиксель.
25

Выбор единицы изменения при написании программы прорисовки
текста, которая должна качественно выводить текст и на дисплеях с очень
высоким разрешением, и на дисплеях с низким разрешением, и на принтерах.
Для вычисления размера прямоугольника, в котором будет выведен
текст, служит метод MeasureString() объекта Graphics.
Свойство Style определяет вид шрифта: курсивный, полужирный,
зачеркнутый или подчеркнутый.
Замечание. Для объектов Font необходимо после завершения
рвботы с ними вызывать метод Dispose() или использовать блок
using.

2.4. МЕТОДЫ РИСОВАНИЯ КЛАССА GRAPHICS
Методы рисования класса Graphics можно разбить на несколько
групп:
– DrawXXX() – рисование линий;
– FillXXX() – рисование областей;
– DrawString() – рисование строк;
– DrawImage() – копирование изображений.
При рисовании графических объектов используются следующие
параметры:
– точка ::= x,y | Point;
– прямоугольник
::=
Rectangle
|
Point,Size
|
x1, y1, Width, Height;
– массив точек ::= Point[];
– карандаш ::= Pen;
– перо ::= Brush;
– шрифт ::= Font;
и некоторые другие параметры.
Все методы рисования многократно переопределяются с различными
сочетаниями сигнатуры.
2.4.1. МЕТОДЫ РИСОВАНИЯ ЛИНИЙ DRAW***()
В эту группу методов входят:
DrawArc(Pen
pen,
Rectangle
rect,
float
startAngle, float sweepAngle) – дуга, являющаяся частью
эллипса, заданного структурой Rectangle;
– DrawBezier(Pen pen, Point pt1, Point pt2, Point
pt3, Point pt4) – кривая Безье, определяемая четырьмя
точками типа Point;
– DrawBeziers(Pen pen, Point[] points) – несколько
кривых Безье, определяемых массивом точек типа Point;
26




DrawClosedCurve(Pen pen, Point[] points, float
tension, FillMode fillmode) – замкнутая гладкая кривая,
определяемая массивом точек типа Point с указанным натяжением;
– DrawCurve(Pen
pen,
Point[]
points,
float
tension) – гладкая кривая, проходящая через точки массива
Point[] с указанным натяжением;
– DrawEllipse(Pen pen, Rectangle rect) – эллипс,
определяемый ограничивающим прямоугольником типа Rectangle;
– DrawLine(Pen pen, Point pt1, Point pt2) – линия,
соединяющая две точки типа Point;
– DrawLines(Pen pen, Point[] points) – ломанная линии,
определяемая массивом точек типа Point;
– DrawPie(Pen pen, Rectangle rect, float startAngle,
float sweepAngle) – сектор, определяемый эллипсом, заданным
прямоугольником типа Rectangle и двумя радиальными линиями;
– DrawPolygon(Pen pen, Point[] points) – многоугольник,
определяемый массивом точек типа Point;
– DrawRectangle(Pen
pen,
Rectangle
rect)

прямоугольник, определяемый прямоугольником типа Rectangle;
– DrawRectangles(Pen pen, Rectangle[] rects) – набор
прямоугольников,
определяемых
прямоугольниками
типа
Rectangle.
Для методов этой группы необходимо определить параметр класса
Pen. Для гладких кривых необходимо назначить параметр вещественного
типа tension (натяжение), влияющий на вид гладких кривых.
Пример 1. В этом примере рисуется три линии: сплошная линия
толщины 4; линия стиля «точка – тире» и линия с ромбом на конце.
Листинг 2.1. Рисование линий разными стилями
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
myPen = new Pen(Color.Black,4); // сплошная линия
g.DrawLine(myPen,20,20,200,20);
myPen.DashStyle = DashStyle.DashDot; // стиль точка-тире
g.DrawLine(myPen, 20, 30, 200, 30);
// линия с ромбом на конце
myPen.Width = 7;
myPen.EndCap = LineCap.DiamondAnchor;
g.DrawLine(myPen, 20, 40, 200, 40);
}

27

Результаты работы программы представлены на рисунке 2.2.

Рис. 2.2. Рисование линий разными стилями

Пример 2. В этом примере рисуется прямоугольник, эллипс, дуга и
сектор.
Листинг 2.2. Рисование прямоугольника, эллипса, дуги и сектора
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
myPen = new Pen(Color.Black, 1);
int dx = 0;
g.DrawRectangle(myPen,10+dx,10,100,50);
dx += 120;
g.DrawEllipse(myPen, 10 + dx, 10, 100, 50);
dx += 120;
g.DrawArc(myPen, 10 + dx, 10, 100, 50, 0, 315);
dx += 120;
g.DrawPie(myPen, 10 + dx, 10, 100, 50, 0, 315);
}

На рисунке 2.3 представлены результаты работы программы.

Рис. 2.3. Рисование прямоугольника,
эллипса и дуги





Пример 3. Рисование по массиву точек следующих линий (рис. 2.4):
ломаная линия;
линия Безье;
фундаментальная линия с различными коэффициентами натяжения.

28

Листинг 2.3. Рисование фигур по массиву точек
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
myPen = new Pen(Color.Black, 1);
Point[] p = {new Point() {X=10,Y=10},
new Point() {X=15,Y=30},
new Point() {X=30,Y=50},
new Point() {X=40,Y=30},
new Point() {X=60,Y=10},
new Point() {X=80,Y=30},
new Point() {X=100,Y=10},
};
g.DrawLines(myPen,p);
g.DrawBeziers(myPen, p);
// фундаментальная линия, натяжение = 0
g.DrawCurve(myPen, p, 0);
// фундаментальная линия, натяжение = 1
g.DrawCurve(myPen, p, 1);
// фундаментальная линия, натяжение = 3
g.DrawCurve(myPen, p, 3);
}

Рис. 2.4. Рисование ломаной линии, линии Безье и фундаментальной линии

Пример 4. В следующем коде реализовано построение полигона и
фундаментальной замкнутой линии с натяжением 0.5 (рис. 2.5).
Листинг 2.4. Рисование полигона и фундаментальной замкнутой линии
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
myPen = new Pen(Color.Black, 1);
Point[] p = {new Point() {X=20, Y=60},
new Point() {X=60, Y=40},
new Point() {X=120, Y=20},

29

new Point() {X=200, Y=40},
new Point() {X=160, Y=60},
new Point() {X=120, Y=100},
new Point() {X=40, Y=80},
};
g.DrawPolygon(myPen,p);
ChangePoint(ref p);
float tension = 0.5F;
g.DrawClosedCurve(myPen, p, tension,
FillMode.Alternate);
}

Рис. 2.5. Полигон и фундаментальная замкнутая линия

2.4.2. МЕТОДЫ РИСОВАНИЯ ЗАМКНУТЫХ ОБЛАСТЕЙ FILL***()
Методы этой группы предназначены для рисования замкнутых
областей и используют для заливки кисть brush:
– FillClosedCurve(Brush
brush,
Point[]
points,
FillMode
fillmode,
float
tension) – заполняет
внутреннюю часть замкнутой гладкой кривой, проходящей через
массив точек типа Point, используя кисть и натяжение;
– FillEllipse(Brush brush, Rectangle rect) – рисует
внутреннюю часть эллипса;
– FillPath(Brush brush, GraphicsPath path) – рисует
внутреннюю часть объекта GraphicsPath. Кисть brush
определяет параметры заливки. Объект path представляет контур
для заливки;
– FillPie(Brush
brush,
Rectangle
rect,
float
startAngle, float sweepAngle) – заполняет внутреннюю
часть сектора, определяемого эллипсом, заданный прямоугольником
типа RectangleF, и двумя радиальными линиями;
– FillPolygon(Brush brush, Point[] points, FillMode
fillMode) – заполняет внутреннюю часть многоугольника,
определенного массивом точек типа Point, используя кисть brush;
30



FillRectangle(Brush brush, Rectangle rect) – заполняет
внутреннюю часть прямоугольника, определяемого прямоугольником
типа Rectangle;
– FillRectangles(Brush brush, Rectangle[] rects) –
заполняет внутреннюю часть набора прямоугольников, определяемых
массивом прямоугольников типа Rectangle;
– FillRegion(Brush brush, Region region) – заполняет
внутреннюю часть объекта Region.
Для всех методов этой группы необходимо назначить кисть класса
Brush. Параметр перечислимого типа FillMode указывает, как
заполняется внутренняя часть замкнутого контура, и может принимать такие
значения:
– Alternate – задается режим заполнения с чередованием;
– Winding – задается режим заполнения с поворотом.
Пример 5. Использование различных кистей для рисования
прямоугольника (рис. 2.6).
Листинг 2.5. Использование различных кистей
SolidBrush mySolidBrush;
TextureBrush myBrushTexture;
HatchBrush myHatchBrush;
LinearGradientBrush myBrushGrad;
HatchStylemyHatchStyle;
LinearGradientMode myLinearGradientMode;
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
myPen = new Pen(Color.Black, 1);
// Рисование сплошной кистью
int dx = 0;
mySolidBrush = new SolidBrush(Color.Silver);
g.FillRectangle(mySolidBrush,20+dx,20,200,100);
// рисование кистью со стандартными стилями
dx += 210;
myHatchStyle = HatchStyle.Cross;
myHatchBrush = new HatchBrush(myHatchStyle,
myPen.Color, mySolidBrush.Color);
g.FillRectangle(myHatchBrush,20+dx,20,200,100);
// рисование кистью с градиентной заливкой
dx += 210;

31

myLinearGradientMode =
LinearGradientMode.Horizontal;
Rectangle r = new Rectangle(20+dx,20,200, 100);
myBrushGrad = new LinearGradientBrush(r,
Color.White,Color.Gray,myLinearGradientMode);
g.FillRectangle(myBrushGrad, r);
// рисование текстурной кистью
dx += 210;
myBrushTexture =
new TextureBrush(new Bitmap("T.bmp"));
g.FillRectangle(myBrushTexture,
new Rectangle(20 + dx, 20, 200, 100));
}

Рис. 2.6. Использование различных кистей

Пример 6. Рисование полигона и фундаментальной линии текстурной
кистью (рис. 2.7).
Листинг 2.6. Рисование текстурной кистью
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
myPen = new Pen(Color.Black, 1);
Point[] p = {new Point() {X=20, Y=60},
new Point() {X=60, Y=40},
new Point() {X=120, Y=20},
new Point() {X=200, Y=40},
new Point() {X=160, Y=60},
new Point() {X=120, Y=100},
new Point() {X=40, Y=80},
};
myBrushTexture =
new TextureBrush(new Bitmap("Help.bmp"));
// полигон
g.FillPolygon(myBrushTexture, p);
g.DrawPolygon(myPen, p);
// замкнутая фундаментальная линия

32

Powered by TCPDF (www.tcpdf.org)

float tension = 0.5F;
g.FillClosedCurve(myBrushTexture, p,
FillMode.Alternate, tension);
g.DrawClosedCurve(myPen, p, tension,
FillMode.Alternate);
// фундаментальная линия с поверотом на 90°
ChangePoint(ref p);
myBrushTexture.RotateTransform(90);
g.FillClosedCurve(myBrushTexture, p,
FillMode.Winding, tension);
g.DrawClosedCurve(myPen, p, tension,
FillMode.Alternate);

}

Рис. 2.7. Рисование полигона и замкнутой фундаментальной линии

Пример 7. Использование градиентных кистей при рисовании
прямоугольника и эллипса (рис. 2.8).
Листинг 2.7. Использование градиентных кистей
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
int W = ClientRectangle.Width;
int H = ClientRectangle.Height;
LinearGradientBrush myBrush =
new LinearGradientBrush(
new Point(0, 0), new Point(W, H),
Color.White, Color.Black);
g.FillRectangle(myBrush, ClientRectangle);
LinearGradientBrush myBrush2 =
new LinearGradientBrush(
new Point(0, 0), new Point(W, H),
Color.Black, Color.White);
g.FillEllipse(myBrush2,25,25,W - 50, H - 50);
myBrush.Dispose();
myBrush2.Dispose();

}

33

Рис. 2.8. Использование градиентных кистей

Пример 8. Использование многоцветной градиентной кисти. В этом
примере мы построим треугольник, у каждой вершины которого будет
назначен свой цвет. На результат существенное влияние оказывает цвет
центральной точки.
Листинг 2.8. Использование многоцветной градиентной кисти
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
Point[] p = {new Point() {X=20, Y=20},
new Point() {X=200, Y=20},
new Point() {X=120, Y=150}};
PathGradientBrush myPathGradientBrush =
new PathGradientBrush(p);
Color c = Color.FromArgb(255/4,255/4,255/4);
myPathGradientBrush.CenterColor = c;
myPathGradientBrush.SurroundColors =
new Color[3]
{ Color.Red, Color.Green, Color.Blue };
g.FillPolygon(myPathGradientBrush, p);
}

На рисунке 2.9 представлен результат работы программы при белом,
черном цвете и 1/4 белого цвета центральной точки.

Рис. 2.9. Использование многоцветной градиентной кисти

34

2.4.3. ВЫВОД СТРОКИ
Для рисования строки в классе Graphics предусмотрено шесть
методов:
– DrawString(string s, Font font, Brush brush,
PointF point);
– DrawString(string s, Font font, Brush brush,
RectangleF layoutRectangle);
– DrawString(string s, Font font, Brush brush,
float x, float y);
– DrawString(string s, Font font, Brush brush,
PointF point,
StringFormat format);
– DrawString(string s, Font font, Brush brush,
RectangleF layoutRectangle, StringFormat format);
– DrawString(string s, Font font, Brush brush,
float x, float y, StringFormat format).
Для всех шести методов необходимо назначить следующие параметры:
строка, шрифт и кисть. Три метода требуют начальную точку и печатают
строку без переноса, начиная от верхнего левого угла, а другие три метода
требуют не точку, а прямоугольник. В последнем случае происходит
разбиение строки на несколько строк и, если часть строк не помещается в
выделенный прямоугольник, то они не печатаются.
При рисовании объект Rectangle используют для указания
координат границ текста. Желательно, чтобы высота этого прямоугольника
была равной высоте шрифта или кратной ей.
параметр
format
типа
Некоторые
методы
используют
StringFormat, выравнивающий строку относительно прямоугольника.
В классе StringFormat содержится информация о размещении текста:
выравнивании и межстрочном интервале. Некоторые свойства этого класса:
– StringAlignment – выравнивание строки текста относительно
прямоугольника;
– FormatFlags – получает или задает параметры перечислимого
типа
StringFormatFlags,
содержащего
сведения
о
форматировании.
Тип StringAlignment позволяет принимать такие значения:
– Near – текст выравнивается по ближнему краю. При размещении
слева направо ближний край – левый. При размещении справа
налево ближний край – правый;
– Center – текст выравнивается по центру прямоугольника;
– Far – текст выравнивается по дальнему краю от положения
прямоугольника. При размещении слева направо дальним
35

положением считается правое. При размещении справа налево
дальним положением считается левое.
Пример 9. Выравнивание текста по правому краю и по центру с
использованием класса StringFormat.
Листинг 2.9. Рисование строки с различными выравниваниями
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
int y = 10;
// Прорисовка текста,
// выровненного по левому краю.
Rectangle rect =
new Rectangle(10, y, 400, Font.Height);
g.DrawRectangle(Pens.Black, rect);
g.DrawString("текст, выровненный по левому
краю", Font, Brushes.Black, rect);
y += Font.Height + 20;
// Прорисовка текста,
// выровненного по правому краю.
myFont = new Font("Arial", 16,
FontStyle.Bold | FontStyle.Italic);
rect = new Rectangle(10, y, 400, myFont.Height);
g.DrawRectangle(Pens.Black, rect);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Far;
g.DrawString("текст, выровненный по правому
краю", myFont, Brushes.Black, rect, sf);
y += myFont.Height + 20;
myFont.Dispose();
// Прорисовка текста, выровненного по центру.
myFont = new Font("Courier New", 12,
FontStyle.Underline);
rect = new Rectangle(10, y, 400, myFont.Height);
g.DrawRectangle(Pens.Black, rect);
sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
g.DrawString("текст, выровненный по центру",
myFont, Brushes.Black, rect, sf);
y += myFont.Height + 20;
myFont.Dispose();

36

// Прорисовка многострочного текста.
myFont = new Font("Times New Roman", 12);
rect = new Rectangle(10,y,120,myFont.Height*4);
g.DrawRectangle(Pens.Black, rect);
String s = "Make it run, Make it right,"+
"Make it small, Make it fast";
g.DrawString(s, myFont, Brushes.Black, rect);
myFont.Dispose();
}

Рис. 2.10. Рисование строк с различным выравниванием

Пример 10. Рисование строки с поворотом (рис. 2.10). Для поворота
необходимо использовать два метода класса Graphics: метод смещения –
TranslateTransform() и метод поворота на заданный угол –
RotateTransform(). После рисования строки необходимо проделать
преобразования в обратном порядке.
Листинг 2.10. Рисование строки с поворотом
private void Draw()
{
Color cl = Color.FromArgb(255, 255, 255);
g.Clear(cl);
myFont = new Font("Arial", 16, FontStyle.Bold);
g.TranslateTransform(200,200);
g.RotateTransform(-45);
g.DrawString("повернутый", myFont,
Brushes.Black,0,0);
g.RotateTransform(45);
g.TranslateTransform(-200, -200);
g.DrawRectangle(myPen,200,200,4,4);
g.TranslateTransform(150, 150);
g.RotateTransform(45);
g.DrawString("текст",myFont,Brushes.Black,0, 0);

37

g.RotateTransform(-45);
g.TranslateTransform(-150, -150);
g.DrawRectangle(myPen, 150, 150, 4, 4);
myFont.Dispose();
}

На рисунке 2.11 прямоугольниками обозначены точки поворота.

Рис. 2.11. Рисование строк с поворотом

2.4.4. КОПИРОВАНИЕ И ИСПОЛЬЗОВАНИЕ ИЗОБРАЖЕНИЙ
Копирование реализуется методами DrawImage(). Это самое
многочисленное семейство методов класса Graphics, насчитывающее
более 30 перегрузок.
Абстрактный класс Image определен в пространстве имен
System.Drawing. У него есть два потомка: Bitmap и Metafile. Класс
Bitmap — общего назначения, обладающий свойствами высоты и ширины.
В примерах этого пункта применяется класс Bitmap.
Замечание. Для объектов Image необходимо после завершения
работы с ними вызывать метод Dispose() или применять блоки using.

Существует
несколько
возможных
источников
растровых
изображений. Растровое изображение можно:
– загрузить из файла;
– скопировать его из другого существующего изображения;
– создать в виде пустого растрового изображения, в котором можно
выполнять рисование.
Изображение в файле может храниться в формате JPEG, GIF, PNG
или BMP.
Выберем файл с помощью элемента openFileDialog1, загрузим
изображение Bitmap из файла и выполним его копирование на поверхность
рисования g с помощью метода DrawImage() в указанный прямоугольник:
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
Bitmap theImage =
new Bitmap(openFileDialog1.FileName);
g.DrawImage(theImage,

38

new Rectangle(10,10,200,200));
theImage.Dispose();
}
openFileDialog1.Dispose();

После копирования необходимо освободить объект theImage,
хранящийся в переменной-члене класса.
Приложение создаст изображение, показанное на рисунке 2.12.

Рис. 2.12. Копирование изображения

Создадим текстурную кисть TextureBrush на основе файла
Star.bmp и рассмотрим три различных примера ее применения:
– рисование эллипса;
– создание пера;
– прорисовка текста.
Чтобы выполнить прорисовку фрагмента текста с использованием
кисти TextureBrush, выполните следующие действия.
Шаг 1. Начав с кода, созданного в предыдущем примере Drawlmage,
добавьте в класс Forml еще одно объявление переменной Image:
partial class Forml : Form
{
private Image theImage;
private Image smallImage;
}

Шаг 2. В методе OnPaint на основе объекта theImg создадим объект
smallImg, указав прямоугольник, высота и ширина которого составляют
половину от размеров объекта theImg:
39

Листинг 2.11. Рисование с использованием текстурной кисти
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, ClientRectangle);
theImg = new Bitmap("Star.bmp");
smallImg = new Bitmap(theImg,
new Size(theImg.Width/2, theImg.Height/2));
Brush tBrush = new TextureBrush(smallImg,
new Rectangle(0,0,smallImg.Width,
smallImg.Height));
g.FillEllipse (tBrush, ClientRectangle);
tBrush.Dispose();
theImg.Dispose();
smallImg.Dispose();
}

После завершения рисования освободим память от двух изображений.

Рис. 2.13. Использование текстурной кисти

Отличие от предыдущего примера состоит в том, что мы вызываем
метод FillEllipse() класса Graphics, передавая ему текстурную кисть
и ClientRectangle.
С помощью объекта TextureBrush создадим перо. Изменим метод
рисования OnPaint() следующим образом.
Листинг 2.12. Рисование с использованием текстурного пера
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g. FillRectangle(Brushes.White,
ClientRectangle);

40

theImg = new Bitmap("Star.bmp");
smallImg = new Bitmap(theImg,
new Size(theImg.Width/2,theImg.Height/2));
Brush tBrush = new TextureBrush(smallImg,
new Rectangle(0,0, smallImg.Width,
smallImg.Height));
Pen tPen = new Pen (tBrush, 40);
g.DrawRectangle(tPen,0,0,
ClientRectangle.Width,ClientRectangle.Height);
tPen.Dispose();
tBrush.Dispose();
}

При запуске этой программы результат должен выглядеть так, как
показано на рисунке 2.14.

Рис. 2.14. Создание пера на основе изображения

В следующем примере выполним рисование текста,
используя
созданный объект TextureBrush. Изменим метод OnPaint().
Листинг 2.13. Рисование строки с использованием текстурной кисти
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, ClientRectangle);
theImg = new Bitmap("Star.bmp");
smallImg = new Bitmap(theImg,
new Size(theImg.Width/2,theImg.Height/2));
Brush tBrush =
new TextureBrush(smallImg,
new Rectangle (0,0, smallImg.Width,

41

smallImg.Height));
Font tFont = new Font ("Times New Roman", 32,
FontStyle.Bold | FontStyle.Italic);
g.DrawString("Hello, from Beginning Visual",
tFont, tBrush, ClientRectangle);
tBrush.Dispose();
tFont.Dispose();
}

При запуске проекта на выполнение на экране должно появиться
изображение, показанное на рисунке 2.15.

Рис. 2.15. Прорисовка текста с использованием изображения

Метод DrawString() в качестве аргументов принимает строку,
шрифт, текстурную кисть и ограничивающий прямоугольник.
2.4.5. РАСТРОВОЕ РИСОВАНИЕ ЛИНИЙ
Существует два режима рисования линий: без сглаживания и со
сглаживанием. В рисовании без сглаживания все пиксели имеют один и тот
же цвет и линия рисуется ступенчато. При рисовании со сглаживанием
некоторые пиксели будут закрашиваться частично, позволяя избавиться от
ступенчатого представления наклонных линий. Однако для более
качественного рисования требуется больше времени для рисования.
На рисунке 2.16 представлена линия, нарисованная без использования
сглаживания, и та же линия, нарисованная с использованием сглаживания.

Рис. 2.16. Линия без сглаживания и со сглаживанием

42

Свойство перечислимого типа SmoothingMode класса Graphics
возвращает или задает качество визуализации графического объекта и может
принимать следующие значения:
– Invalid – недопустимый режим;
– Default – нет сглаживания;
– HighSpeed – высокая скорость: нет сглаживания;
– HighQuality – рисование со сглаживанием;
– None – нет сглаживания;
– AntiAlias – рисование со сглаживанием.
Ниже представлен пример, в котором рисуется эллипс без сглаживания,
со сглаживанием HighQuality и со сглаживанием AntiAlias.
Листинг 2.14. Рисование эллипса с различными сглаживаниями
private void Draw()
{
g = CreateGraphics();
g.Clear(Color.White);
Pen myPen = new Pen(Color.Black, 0.5F);
g.PageUnit = GraphicsUnit.Millimeter;
g.DrawEllipse(myPen, 10, 10, 30, 30);
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawEllipse(myPen, 10 + 35, 10, 30, 30);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawEllipse(myPen, 10 + 70, 10, 30, 30);
}

Результат работы программы представлен на рисунке 2.17.

Рис. 2.17. Рисование эллипса со сглаживанием

Отличия между сглаживанием HighQuality и сглаживанием
AntiAlias в глаза не бросаются. Однако два последних эллипса
существенно отличаются от первого.

43

2.4.6. АЛГОРИТМЫ РИСОВАНИЯ ЛИНИЙ
К алгоритмам рисования линий предъявляются высокие требования:
должны работать быстро;
не должны потреблять большие объёмы оперативной памяти;
не использовать медленную вещественную арифметику;
для каждого пиксела производить как можно меньше вычислений;
линия должна быть связным объектом, то есть его пикселы должны
располагаться рядом друг с другом.
Рассмотрим наиболее известные алгоритмы растеризации отрезка:
рисование DDA-линии, алгоритм Брезенхема и алгоритм Ву.
2.4.6.1. Алгоритм DDA
Самым простым и очевидным способом создания алгоритма рисования
отрезка от точки (x0;y0) до точки (x1;y1) является использование
параметризированного уравнения прямой линии
x(t) = x0 + t *Δx;
y(t) = y0 + t *Δy.
(2.1)
В этом уравнении (x(t); y(t)) является точкой отрезка, а значение t
пробегает интервал от 0 до L. Значения L,x,y определяются по формулам
L = max(|x0 .. x1|; |y0 .. y1|);
x = x1..x0;
y = y1..y0.
(2.2)
Все числа являются вещественными, и для работы с ними используется
вещественная арифметика. При отрисовке каждого пиксела значения x(t) и
y(t) округляются и дают его целочисленные координаты. Именно поэтому
алгоритм сокращённо называется DDA от английского выражения Digital
Differential Analyzer (цифровой дифференциальный анализатор).






Листинг 2.15. Алгоритм DDA
private void DDA(int x1, int y1, int x2, int y2)
{
float L=Math.Max(Math.Abs(x2-x1),Math.Abs(y2-y1));
float dx=(x2-x1)/L;
float dy = (y2 - y1) / L;
float x = x1;
float y = y1;
for (int i=0; i