5.2.3. Примеры фрагментов отчета по
Пример 1.
Условие задачи: Выпуклый многоугольник задан координатами своих вершин. Необходимо его закрасить не пользуясь процедурой FloodFill.
Идея решения: Процедура типа floodfill для своей работы нуждается в одной точке, находящейся точно внутри многоугольника. Поэтому задача распадается на две:
Поиск точки внутри многоугольника.
Закраска многоугольника с использованием найденной точки.
Как найти точку внутри многоугольника? Точку внутри многоугольника можно найти следующим образом:
построим точку, находящуюся на середине отрезка, соединяющего две соседние вершины, обозначим эту точку через А.
Возьмём любую другую вершину, кроме использованных для построения точки А.
Построим точку, находящуюся на середине отрезка, соединяющего точку А и выбранную вершину.
Эта точка будет гарантировано находится внутри многоугольника.
Как закрасить многоугольник зная внутреннюю точку. Если от точки (находящейся внутри многоугольника ) провести горизонтальную линию вправо и влево, то она обязательно пересечёт границы многоугольника. Таким образом, мы можем найти левую и правую точку границы. Затем, мы можем провести линию. Далее, перемещаем точку вверх на 1 пиксель, после чего опять определяем точку границы слева и справа и проводим еще одну линию. Таким образом, наша точка (о которой, мы точно знаем, что она внутри многоугольника) будет ползти вверх и на каждом шаге её смещения, будет проводится одна закрашивающая линия от левой границы до правой границы многоугольника.
Чтобы многоугольник оказался полностью закрашенным, точка должна дойти до самой верхней вершины, чтобы это обеспечить, её координаты достаточно на каждом шаге пересчитывать как среднее арифметическое координат найденных точек левых и правых границ. Если этого не делать, то внутренняя точка в своём движении вверх скорее всего упрётся в одну из сторон многоугольника.
Описанный выше процесс закрасит контур от внутренней точки и вверх. Затем следует повторить эти же действия, но для движения точки вниз.
Примечание:
Вычисленная нами внутренняя точка, нужна дважды: для закраски вверх и закраски вниз. Однако, после того, как точка начала двигаться вверх, её исходные координаты будут забыты. Следовательно, о их запоминании надлежит позаботится особо.
В алгоритме предполагается, что многоугольник вводимый пользователем – выпуклый, и это его свойство не проверяется.
Алгоритм главной программы:
Задать многоугольник и нарисовать его.
Определить внутреннюю точку.
Выполнить закраску вверх от внутренней точки.
Выполнить закраску вниз от внутренней точки.
Описание процедур:
Многоугольник определяется множеством своих вершин. Каждая из вершин имеет две координаты, поэтому для определения многоугольника требуется ввести количество вершин и, затем, для каждой вершины два числа - координаты.
Для вычисления координат внутренней точки удобно использовать три первых точки.
Процедура Выполнить закраску.
Данные, передаваемые в процедуру: координаты точки начала (n,m), направление.
Повторять пока цвет точки начала <> 15
Начало:
Найти расстояние от точки начала до левой стороны многоугольника (ix).
Найти расстояние от точки начала до правой стороны многоугольника (kx).
Провести линию от точки начало на ix влево и на kx-вправо.
Вычислить абциссу точки начала, как среднее арифметическое от абцисс правой и левой точки.
Сместить ординату точки начала на 1 вверх или на 1 вниз.
Конец
Примечания:
Данная процедура осуществляет закраску как вниз, так и вверх, в зависимости от переданного в неё направления.
Предполагается, что цвет многоугольника белый (номер цвета - 15).
Описание переменных используемых в программе:
x, y - массивы координат вершин многоугольника.
xc, yc - координаты внутренней точки многоугольника.
program example;
uses crt,graph;
var
dr,md,i,a,xc,yc:integer;
x,y:array [1..10] of integer;
procedure fil(n,m,b:integer);
var
ix,kx:integer;
begin
while getpixel(n,m)<>15 do
begin
ix:=0;kx:=0;
while getpixel(n-ix,m)<>15 do ix:=ix+1;
while getpixel(n+kx,m)<>15 do kx:=kx+1;
line(n-ix,m,n+kx,m);
n:=round((n-ix+n+kx)/2);
m:=m+b;
end;
end;
begin
clrscr;
write('Введите число вершин вашей фигуры:');read(a);
clrscr;
for i:=1 to a do
begin
write('Введите Х координату:');read(x[i]);
write('Введите Y координату:');read(y[i]);
end;
clrscr;
dr:=detect; initgraph(dr,md,'');
for i:=1 to a-1 do line(x[i],y[i],x[i+1],y[i+1]);line(x[a],y[a],x[1],y[1]);
xc:=round((x[1]+x[2]+2*x[3])/4); yc:=round((y[1]+y[2]+2*y[3])/4);
putpixel(xc,yc,6);
fil(xc,yc-1,-1); fil(xc,yc,1);
while not keypressed do;
end.
Примечание:
Процедура закраски вызывается один раз от точки xc,yc, а второй раз от точки xc,yc-1. Это делается для того, чтобы не закрашивать дважды одну и ту же линию.
Пример 2.
{ Программа вращения куба вокруг своей оси.
Автор: Hестеренкова Яна.
-----------------------------------------------------------------
Цель: графически изобразить вращение куба вокруг своей оси, соединяющей центры верхней и нижней граней куба, и закрасить его видимые грани.
-----------------------------------------------------------------
Алгоритм:
1. Ввод цветов граней куба.
2. Расположение куба в начальной позиции ( начальный угол ).
3. Основная часть :
1) Вычисление координат верхних вершин куба.
2) Определение видимости вершин куба.
3) Изображение видимых ребер куба.
4) Закраска видимых граней.
5) Изменение угла.
6) Очистка экрана.
------------------------------------------------------------------
1. Вводятся числовые обозначения цветов боковых сторон (4), и в последнюю очередь числовое обозначение цвета верхней грани куба.
------------------------------------------------------------------
2. Верхние вершины (они пронумерованы: 1,2,3,4 ) вращаются относительно начала координат - В, расположенного в центре верхней грани (система координат - В также принадлежит плоскости верхней грани). Расположение куба в начальной позиции подразумевает собой расположение вершины номер 1 под углом поворота в 135 градусов.
-----------------------------------------------------------------
3. Основная часть представляет собой цикл, продолжающийся пока не будет нажата любая клавиша.
3.1 В процессе вращения куба основную роль играет вращение его вершин ( в данном случае верхних ), т.к. верхняя и нижняя вершины, которые будут иметь общее ребро, также будут иметь общую координату на оси абсцисс и координаты их на оси ординат будут отличатся на длину ребра куба, поэтому не составит труда вычислить координаты нижних вершин, если знаешь верхние, и провести соответствующие линии между ними.
Вращение вершин происходит по окружности через вычисление координат с помощью sin и cos угла поворота, создать видимость трехмерного пространства помогает уменьшение радиуса в два раза при вычислении координаты по оси ординат (возникновение мнимой системы координат -В, с совпадающим началом координат с началом координат действительной системы).
Изменяя ( увеличивая ) угол поворота на угол a 1-ой вершины мы находим ее новые координаты, а ,т.к. между собой вершины отличаются на угол поворота в 90 градусов ( правда, все углы здесь вычисляются в радианах, но я не нашла способа это записать ), то, следовательно, угол поворота 2 угла будет равен углу поворота 1 угла плюс 90 градусов и т.д.
Информацию о координатах верхних вершин содержит массив, но заполнение его ведется несколько странным способом: в первую ячейку координаты 4 вершины, за ней 1, потом 2, следом 3, за ними опять 4 , а заканчивается заполнение координатами 1. Зачем это происходит будет рассказано дальше.
3.2 Если нижняя вершина находится в III и IV координатных углахили лежит на оси абсцисс ; или если вершина расположена во II к.у. и ее координата по оси абсцисс ниже, чем у предыдущей ( для этого нужна информация о координатах 4 вершины перед 1),расположенной в III к.у.; или если вершина расположена во I к.у. и ее координата по оси абсцисс выше, чем у последующей ( для этого нужна информация о координатах 1 вершины после 4),расположенной в IV к.у. - то эта вершина видима. Информация о видимости также записана в массив аналогично с координатами.
3.3 Ребро будет видимым, если будут видимы его вершины (поэтому информация о видимости записана аналогично с координатами (соед.4 и 1 вершины), т.е. если вершины ребра видны, то оно изображается, также учитывается перенос действительной системы координат в центр экрана.
3.4 Закраска грани происходит в том случае, если образующие его ребра видимы. Точки закраски определились методом научного «тыка», но начальной точкой поиска была верхняя вершина с соответствующим номером.
3.5 Увеличение угла поворота на 0.05 рад.
3.6 Закраска всего экрана в черный цвет.
====================================================================}
program pp;
uses crt, graph;
var
dri,mode,z:integer;
x,y,c,s:array [0..6] of integer;
i:real;
begin
clrscr;
{Ввод цветов граней куба}
for z:=1 to 5 do
readln(c[z]);
dri:=detect;
initgraph(dri,mode,'');
{Расположение куба в начальной позиции}
i:=0.785398163;
{Основная часть}
while not keypressed do
begin
{Вычисление координат верхних вершин куба}
for z:=1 to 6 do
begin
x[z]:=round(100*cos(i+1.570796327*(z-1)));
y[z]:=round(50*sin(i+1.570796327*(z-1)));
end;
{Определение видимости вершин куба}
for z:=2 to 6 do
if (y[z]<=0)or((x[z-1]>0)and(x[z]>x[z-1]))or((x[z+1]<0)and(x[z]<x[z+1]))
then s[z]:=1
else s[z]:=0;
{Изображение видимых ребер куба}
for z:=2 to 5 do
begin
if s[z]=1 then
line(320+x[z],190-y[z],320+x[z],290-y[z]);
if (s[z]=1)and(s[z+1]=1) then
line(320+x[z],290-y[z],320+x[z+1],290-y[z+1]);
line(320+x[z],190-y[z],320+x[z+1],190-y[z+1]);
end;
{Закраска видимых граней}
for z:=2 to 5 do
begin
if (s[z]=1)and(s[z+1]=1) then
begin
setfillstyle(1,c[z-1]);
floodfill(321+x[z],240-y[z],15);
end;
end;
setfillstyle(1,c[5]);
floodfill(320,190,15);
{Изменение угла}
i:=i+0.05;
{Очистка экрана}
setfillstyle(1,16);
floodfill(1,1,7);
end;
end.
