Давайте поговорим о процедурах SetPixel(x, y, c) и PutPixel(x, y, c), которые выполняют одну и ту ж работу – закрашивают пиксель с координатами (x, y) цветом c. Но зачем это надо – закрашивать точки в разные цвета? Дело в том, что любое изображение состоит из точек (пикселей), каждая из которых имеет определенный цвет и свои координаты графическом окне Pascal. Во второй части статьи (см. внизу) мы покажем, как с помощью закрашивания пикселей нарисовать прямоугольник в Паскале, отрезок линии, круг и даже эллипс. А пока немного поговорим о геометрии.
Простейшим геометрическим объектом в математике является точка – нечто такое, не имеющее никакого размера, ни объема, ни площади. Правда, чтобы точку нарисовать, придется придать ей хоть какой-то размер (иначе её изобразить невозможно). Из точек построены все линии и фигуры, поверхности и тела – как на плоскости, так и в пространстве.
Чем отличается фигура от линии? Замкнутая линия на плоскости – это только граница, край, а фигура – часть плоскости, находящаяся внутри замкнутой линии. Примером линии является окружность, а соответствующая ей фигура – круг (часть плоскости).
Геометрическим телом называется множество точек в пространстве. Только не любое множество, а вся совокупность точек, отделенная от остального пространства какой-то границей, называемой поверхностью. Тело – это уже геометрическая фигура в пространстве. Примеры геометрического тела: куб, тетраэдр, шар, параллелепипед и др.
Создание изображения в Паскале реализуются с помощью растровой графики (точечной графики). Это значит, что наименьшим элементом рисунка является точка, называемая пикселем, которых представляют обычно в виде маленьких кружков или квадратиков. Если взять любое растровое изображение и сильно его увеличить, то можно увидеть отдельные области, из которых и состоит всё изображение – пиксели. Каждый пиксель имеет один цвет, и его уже нельзя разделить на меньшие части.
Другой важной характеристикой пикселя является его координаты в графическом окне, которые отсчитываются с левого верхнего угла вправо (ось OX) и вниз (ось OY). Раз так, то есть природная необходимость в подпрограммах, которые бы задавали цвет и координаты пикселя. Или, наоборот, при наличии рисунка в графическом окне было бы интересно узнать цвет пикселя с данными координатами.
Причем первые две процедуры – SetPixel и PutPixel – являются равнозначными, и вы можете использовать любую из них. Чтобы продемонстрировать действие данных процедур, давайте напишем несколько простых программ. А вот функцией GetPixel(x,y) мы займемся на следующей странице. Но сначала укажем некоторые цветовые константы – названия стандартных цветов в PascalABC.Net:
Есть многие другие цветовые константы, но нам пока этого хватит.
Итак, попробуем нарисовать точку в PascalABC.Net с координатами, например, (300, 200), окрашенную в красный цвет. Чтобы мы её увидели, напишем возле неё слово «точка». Для этого создадим простую программу, подключив к ней модуль GraphABC:
Program my_Point;
uses
GraphABC; //подключенный модуль для работы с графикой
begin
{ Красная точка с координатой (300,200): }
SetPixel(300, 200, clRed);
{ Надпись возле точки: }
TextOut(301, 200, 'точка')
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**procedure** SetPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clRed
- красный**procedure** TextOut(x,y: integer; s: string);
: Выводит строку s в прямоугольник к координатами левого верхнего угла (x,y) Запустите приложение и в открывшемся графическом окне попробуйте найти маленькую красную точку чуть выше слева слова «точка». Это и есть пиксель с координатами (300, 200). Но точки создавать не интересно. Если бы мы нарисовали совокупность точек, идущих друг за другом, например, в горизонтальном направлении, то получили бы уже линию. Давайте так и сделаем.
Как построить линию в PascalABC.Net с помощью точек? Строить линию точками, каждый раз записывая процедуру SetPixel (или PutPixel), это не правильно, поскольку для этого пришлось бы записывать SetPixel огромное количество раз. Вместо этого построение можно организовать в цикле, в котором, шаг за шагом, точки сами будут выстраиваться в прямую линию.
Нарисуем линию от точки с координатами (100, 200) до точки (400, 200). Как видим, эта прямая будет параллельна оси OX (горизонтальна в нашем понимании), поскольку начало и конец отрезка имеют одинаковую координату y = 200. Таким образом, изменять придется только координату x – от 100 до 400, а для этого мы используем цикл for (с параметром) и процедуру SetPixel. Вот какая программа у нас вышла:
Program my_Line;
uses
GraphABC;
var
x: integer;
begin
for x := 100 to 400 do
SetPixel(x, 200, clRed)
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**type** integer;
: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647**procedure** SetPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clRed
- красный Созданная нами линия имеет толщину 1 пиксель. А чтобы нарисовать жирную линию, нужно, естественно, построить несколько линий рядом, накладывая их как бы одну на другую столько раз, какова толщина линии. Поскольку мы будем менять не только x, но и y, то здесь не обойтись без вложенного двойного цикла. Во внешнем цикле будем изменять y, а во внутреннем – координату x. Результат наших размышлений:
Program my_Line2;
uses
GraphABC;
var
i, x, x1, x2, y, d: integer;
begin
d := 3; //толщина отрезка
x1 := 100; x2 := 400; //абсцисса начала и конца отрезка
y := 200; //ордината отрезка
for i := 0 to d - 1 do //наращиваем толщину отрезка
for x := x1 to x2 do
PutPixel(x, y + i, clBlue)
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**type** integer;
: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647**procedure** PutPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clBlue
- синий
Как создать прямоугольник в PascalABC.Net с помощью точек? Поскольку рисовать отрезки мы уже научились, то для создания прямоугольника придется начертить всего четыре отрезка. Для этой цели достаточно задать координаты двух противоположных вершин прямоугольника – (x1, y1) и (x2, y2), где x2 > x1, y2 > y1, – а потом нарисовать четыре стороны (линии). Вот сам код с комментариями:
Program my_Rectangle;
uses
GraphABC;
var
x, y, x1, y1, x2, y2: integer; //координаты вершин прямоугольника
begin
x1 := 100; y1 := 150; //координаты левого верхнего угла
x2 := 400; y2 := 300; //координаты правого нижнего угла
{ Нижняя и верхняя сторона: }
for x := x1 to x2 do begin //здесь изменяется x
PutPixel(x, y1, clRed);
PutPixel(x, y2, clRed)
end;
{ Левая и правая сторона: }
for y := y1 to y2 do begin //здесь изменяется y
PutPixel(x1, y, clRed);
PutPixel(x2, y, clRed)
end
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**type** integer;
: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647**procedure** PutPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clRed
- красный**procedure** PutPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clRed
- красный**procedure** PutPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clRed
- красный**procedure** PutPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clRed
- красный
А как закрасить прямоугольник в PascalABC.Net с помощью процедуры SetPixel или PutPixel? Для заливки прямоугольника каким-либо цветом используется тот же способ, что и при создании жирной линии: рисуются отрезки толщиной в 1 пиксель один за другим, пока их общая толщина не составит длину какой-то из сторон прямоугольника. Немного переформатировав код программы жирная линия, получим:
Program my_FillRectangle;
uses
GraphABC;
var
x, y, x1, y1, x2, y2: integer; //координаты вершин прямоугольника
begin
x1 := 100; y1 := 150; //координаты левого верхнего угла
x2 := 400; y2 := 300; //координаты правого нижнего угла
for y := y1 to y2 do
for x := x1 to x2 do
PutPixel(x, y, clBrown) //точки коричневого цвета
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**type** integer;
: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647**procedure** PutPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clBrown
- коричневый
Как нарисовать круг в PascalABC.Net с помощью точек? Можно закрасить не весь прямоугольник, а какую-то его часть, например, круг, находящийся в середине квадрата с координатами противоположных вершин (x0 - r, y0 - r) и (x0 + r, y0 + r). Мы знаем, что уравнение окружности с центром в точке (x0, y0) и радиусом r выглядит так:
(x – x<sub>0</sub>)<sup>2</sup> + (y – y<sub>0</sub>)<sup>2</sup> = r<sup>2</sup>
.
Но нам нужна не окружность, а круг, то есть «внутренность» окружности. Это вся совокупность точек (x, y), для которых расстояние до центра (x0, y0) не больше r:
(x – x<sub>0</sub>)<sup>2</sup> + (y – y<sub>0</sub>)<sup>2</sup> ≤ r<sup>2</sup>
.
Таким образом, чтобы закрасить круг в квадрате, необходимо его точки проверять на выполнение вышеуказанного неравенства: если оно истинно, то точки (x, y) закрашиваются. Вот соответствующая программа:
program my_circle;
uses
GraphABC;
var
x, y, x0, y0, r: integer;
bln: boolean; { bln = true, если точка (x,y) находится внутри
круга, bln = false - в противном случае }
begin
x0 := 250; y0 := 200; //координаты центра круга
r := 110; //радиус круга
{ Проверяем все точки прямоугольника с координатами
противоположных вершин (x0 - r, y0 - r) и (x0 + r, y0 + r): }
for x := x0 - r to x0 + r do
for y := y0 - r to y0 + r do begin
{ Выражение, означающее, что точка с координатами (x, y)
находится внутри круга радиуса r и центром (x0, y0): }
bln := sqr(x - x0) + sqr(y - y0) <= sqr(r);
{ Если точка (x, y) попадает внутрь данного круга,
то закрашиваем её цветом clGreen: }
if bln then SetPixel(x, y, clGreen)
end
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**type** integer;
: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647**type** boolean;
: Представляет логическое значение.**function** Sqr(x: integer): integer;
: Возвращает квадрат числа x.**function** Sqr(x: integer): integer;
: Возвращает квадрат числа x.**function** Sqr(x: integer): integer;
: Возвращает квадрат числа x.**procedure** SetPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clGreen
- зеленый
А как нарисовать закрашенный эллипс в PascalABC.Net с помощью точек? Для этого используем эллипс, вписанный в прямоугольник с координатами противоположных вершин (x1, y1) и (x2, y2), для которых x2 > x1, y2 > y1. Сначала укажем, что уравнение эллипса с центром в начале координат и полуосями a и b выглядит так:
(x/a)<sup>2</sup> + (y/b)<sup>2</sup> = 1
.
Но поскольку нам необходимо закрасить внутреннюю часть эллипса, то уравнение превратится в неравенство заполненного эллипса:
(x/a)<sup>2</sup> + (y/b)<sup>2</sup> ≤ 1
.
Стороны прямоугольника параллельны осям координат. Это означает, что координаты его центра равны полусумме координат противоположных вершин: x0 = (x1 + x2)/2, y0 = (y1 + y2)/2. А как найти a и b? Это стороны прямоугольника, разделенные на 2 (поэтому они называются полуосями): a = (x2 – x1)/2, b = (y2 – y1)/2. С учетом этого, неравенство заполненного эллипса приобретает вид:
(x – x<sub>0</sub>)<sup>2</sup>/a<sup>2</sup> + (y – y<sub>0</sub>)<sup>2</sup>/b<sup>2</sup> ≤ 1
.
Program my_FillEllipse;
uses
GraphABC;
var
x, y, x1, y1, x2, y2, x0, y0, a, b: integer;
bln: boolean; { bln = true, если точка (x,y) находится внутри
эллипса, bln = false - в противном случае }
begin
x1 := 100; y1 := 150; { <== Координаты левого верхнего угла }
x2 := 400; y2 := 300; { <== Координаты правого нижнего угла }
{ Координаты центра эллипса: }
x0 := (x1 + x2) div 2;
y0 := (y1 + y2) div 2;
{ Полуоси эллипса: }
a := (x2 - x1) div 2;
b := (y2 - y1) div 2;
{ Проверяем все точки прямоугольника с координатами
противоположных вершин (x1, y1) и (x2, y2): }
for x := x1 to x2 do
for y := y1 to y2 do begin
{ Выражение, означающее, что точка (x, y) находится внутри
эллипса с полуосями a и b и центром в точке (x0, y0): }
bln := sqr((x - x0) / a) + sqr((y - y0) / b) <= 1;
{ Если точка (x, y) попадает внутрь данного эллипса,
то закрашиваем её цветом RGB(250, 100, 200): }
if bln then SetPixel(x, y, RGB(250, 150, 250))
end
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**type** integer;
: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647**type** boolean;
: Представляет логическое значение.A **div** B
- целочисленное деление А на ВA **div** B
- целочисленное деление А на ВA **div** B
- целочисленное деление А на ВA **div** B
- целочисленное деление А на В**function** Sqr(x: integer): integer;
: Возвращает квадрат числа x.**function** Sqr(x: integer): integer;
: Возвращает квадрат числа x.**procedure** SetPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c**function** RGB(r,g,b: byte): Color;
: Возвращает цвет, который содержит красную (r), зеленую (g) и синюю (b) составляющие (r,g и b - в диапазоне от 0 до 255)
Как видно на рисунках эллипса и круга, создание изображений с помощью закрашивания пикселей имеет существенный недостаток: границы рисунков выглядят не совсем плавными, как бы ступенчатыми. Оно и понятно: ведь пиксели – не точки в геометрическом понимании, которые не имеют размера, а все-таки небольшие квадратики или кружки. Тогда почему на всех фотографиях и рисунках нет ступенек? – спросите вы. Да потому, что там используется так называемое сглаживание. Суть этого метода в основном состоит в том, чтобы ближайшие к границе точки заменять более светлыми, или точнее, наиболее близкими по цвету с фоном, из-за чего создается эффект плавного перехода.
Бывает и обратная ситуация, когда нужно не сгладить изображение, сделав границы плавными (особенно это касается геометрических фигур), а как бы размыть. Делается это так: берем несколько соседних пикселей изображения, имеющих обычно разный цвет, и заменяем на пиксели одинакового цвета, совпадающем с цветом одного из пикселей. Получается картинка с очень увеличенными пикселями.
То же касается и видео: бывает необходимость закрыть лицо персонажа такими же увеличенными пикселями, или часть области заменить одним цветом. В специализированных программах для работы с графикой типа Gimp, Photoshop или Movavi показывается замена пикселей одного цвета на пиксели другого цвета.