Содержание
Содержание. 2
ЗАДАНИЕ 1. Простой алгоритм двумерного отсечения. 3
Листинг программы.. 7
ЗАДАНИЕ 3. Рисование линий по алгоритму Брезенхема. 8
Листинг программы.. 8
Задание 4 Рисование блок-схемы.. 9
ЛИСТИНГ ПРОГРАММЫ РАЗБИЕНИЯ МНОГОУГОЛЬНИКОВ.. 13
Список литературы.. 17
ЗАДАНИЕ 1. Простой алгоритм двумерного отсечения.
Р1 , Р2 - концевые точки отрезка
Р1' , Р2'- концевые точки видимой части отрезка
xл, xп , yв , y н - координаты левой, правой, верхней и нижней сторон окна
Флаг - признак видимости, равный: 0, видимость; - 1, невидимость
вычисление кодов концевых точек
занесение этих кодов в два массива Т1код и Т2код, размерностью 1 х 4 каждый
для первого конца: Р1
if x1 < xл then Т1код(4) = 1 else Т1код(4) = 0
lf x1 > xп then Т1код(3) = 1 else Т1код(3) = 0
If y1 < yн then Т1код(2) = 1 else Т1код(2) = 0
If y1 > yв then Т1код(1) = 1 else Т1код(1) = 0
для второго конца: Р2
if x2 < xл then Т2код(4) = 1 else Т2код(4) = 0
lf x2 > xп then Т2код(3) = 1 else Т2код(3) = 0
If y2 < yн then Т2код(2) = 1 else Т2код(2) = 0
If y2 > yв then Т2код(1) = 1 else Т2код(1) = 0
инициализация признака видимости и видимых концевых точек
инициализация т очень большим числом, имитирующим бесконечный наклон
Флаг = 0
Р1' = Р1
Р2' = Р2'
m = Большое число
проверка полной видимости отрезка
Сумма1 = 0
Сумма2 = 0
for i = 1 to 4
Сумма1 = Сумма1 + Т1код(i)
Сумма2 = Сумма2 + Т2код(i)
next i
if Сумма1 = 0 and Сумма2 = 0 then 7
отрезок не является полностью видимым
проверка случая тривиальной невидимости
вычисление логического произведения (Произвед) кодов концевых точек отрезка
Произвед = 0
for i = 1 to 4
Произвед = Произвед + Целая часть ((Т1код(i)) + Т2код(i)/2)
If Произвед < > 0 then
Флаг = - 1
go to 7
end if
next i
отрезок может быть частично видимым проверка попадания первой точки внутрь окна
if Сумма1 = 0 then
Номер = 1
Р1' = Р1
P = Р2
go to 2
end if
проверка попадания второй точки внутрь окна
if Сумма2 = 0 then
Номер = 2
Р1' = Р2
P = Р1
go to 2
end if
внутри окна нет концов отрезка
инициализация номера конца отрезка
Номер == 0
1 if Номер < > 0 then Р'номер = Р
Номер = Номер + 1
if Номер > 2 then 7
P = Рномер
проверка пересечения с левым краем проверка вертикальности отрезка
2 if (x2 - x1 ) = 0 then 4
m = (y2 - y1 )/ (x2 - x1 )
if xл < Px then 3
у = m * (xл - Px) + Py
if y < yв then 3
if y < yн then 3
обнаружено корректное пересечение
Py = y
Px = xл
gо to 1
проверка пересечения с правым краем
3 if xп > Рx then 4
у = m * (хп - Рx) + Рy
if y < yв then 4
if y < yн then 4
обнаружено корректное пересечение
Py = y
Px = xп
gо to 1
проверка пересечения с верхним краем проверка горизонтальности отрезка
4 if m = 0 then 1
if yв > Рy then 5
x = (1/m) * (ув - Ру) + Рx
if x < xл then 5
if x < xп then 5
обнаружено корректное пересечение
Px = x
Py = yв
gо to 1
проверка пересечения с нижним краем
5 if yн > Рy then ошибка
х = (1/m) * (yн - Ру) + Рx
if x < xл then 6
if x < xп then 6
обнаружено корректное пересечение
Px = x
Py = yн
gо to 1
отрезок невидим
6 Флаг = - 1
завершение работы и вызов процедуры черчения
7 If Флаг = - 1 then 8
Draw P1'P2'
перейти к обработке следующего отрезка
8 finish
Листинг программы
int x1, x2, y1, y2;
void __fastcall TForm1::FormPaint(TObject *Sender)
{
Canvas->Pen->Color = clBlue; // устанавливаем цвет отсеченных отрезков
Canvas->Pen->Width = 1; // устанавливаем ширину отрезков
randomize();
for (int i = 0; i < 100; i++) //рисуем произвольные отрезки
{
Canvas->MoveTo(random(Form1->Width),random(Form1->Height));
Canvas->LineTo(random(Form1->Width),random(Form1->Height));
}
Canvas->Pen->Color = clBlack; // устанавливаем цвет отсекающего окна
Canvas->Rectangle(x1,y1,x2,y2); // рисуем отксекающее окно
}
void __fastcall TForm1::FormCreate(TObject *Sender)
{
x1 = StrToInt(InputBox("Введите координаты","Введите x1 отсекающего окна",0));
x2 = StrToInt(InputBox("Введите координаты","Введите x2 отсекающего окна",0));
y1 = StrToInt(InputBox("Введите координаты","Введите y1 отсекающего окна",0));
y2 = StrToInt(InputBox("Введите координаты","Введите y2 отсекающего окна",0));
}
ЗАДАНИЕ 3. Рисование линий по алгоритму Брезенхема.
Основная идея алгоритма состоит в том, что если угловой коэффициент прямой < 1/2, то следующую точку поставить в позицию (1,0), а если угловой коэффициент > 1/2, то - в позицию (1,1). Для того чтобы принять решение, куда заносить очередной пиксел вводится величина отклонения D точной позиции от середины между двумя возможными растровыми точками в направлении наименьшей относительной координаты. Знак D используется как критерий для выбора ближайшей растровой точки. Если D < 0, то точное Y-значение округляется до меньшего последнего целочисленного значения Y, т.е. Y-координата не меняется по сравнению с предыдущей точкой. В противном случае Y увеличивается на 1.
Листинг программы
dx = abs(x2-x1);
dy = abs(y2-y1);
sx = x2 >= x1 ? 1:-1;
sy = y2 >= y1 ? 1:-1;
if(dy <= dx) //проверка угла наклона линии
{
d=(dy<<1)-dx; //деление на два для определения углового коэффициента
d1=dy<<1;
d2=(dy-dx)<<1;
Canvas->Pixels[x1][y1] = color; //вывод первой точки на экране
for(int x=x1+sx, y=y1, i=1; i<=dx; i++, x+=sx) // цикл вывода линии на экран
{
if(d>0) / * Если d < 0 значение y не меняется по сравнению с предыдущей точкой, иначе y увеличивается * /
{
d+=d2;
y+=sy;
}
else d+=d1;
Canvas->Pixels[x][y]=color; //вывод на экран очередной точки линии
}
}
else
{
d=(dx<<1)-dy;
d1=dx<<1;
d2=(dx-dy)<<1;
Canvas->Pixels[x1][y1] = color;
for(int x=x1,y=y1+sy,i=1;i<=dy;i++,y+=sy)
{
if(d>0)
{
d+=d2;
x+=sx;
}
else d+=d1;
Canvas->Pixels[x][y] = color;
}
Задание 4 Рисование блок-схемы
1. Нарисуйте детальную блок-схему данного алгоритма и реализуйте его на языке программирования. Программа должна выводить исходный многоугольник на экран, а затем, если многоугольник не выпуклый, то при нажатии любой из клавиш он должен разбиваться на n выпуклых многоугольников и результаты разбиения должны выводиться на экран. Координаты исходного многоугольника должны содержаться в файле на диске.
2. Выясните, будет ли работать ваша программа с многоугольником, изображенном на рисунке 3.
3. Скорректируйте вашу программу так, чтобы она работала с любыми невыпуклыми многоугольниками.
Рис. 1
Алгоритм разбиения невыпуклых многоугольников для отдельных случаев может быть представлен в следующей последовательностью:
1. найти вогнутую вершину.
2. соединить вогнутую вершину с предыдущей через одну.
3. проанализировать каждый из вновь образованных многоугольников (п.1,2,3)
Рис. 2 Рис. 3
Для уменьшения размеров алгоритма все последовательные операции были перечислены виде информационных блоков, все выражения и функции подробно указаны в листинге программы.
Данная программа выводит исходный многоугольник, взяв координаты вершин из заранее подготовленного файла, автоматически производит его анализ и построение на экране. Если многоугольник выпуклый, то его разбиения не происходит. В противном случае, программа находит вогнутую вершину и соединяет её с предыдущей через одну. В программе исходный многоугольник отображён красным цветом, а результат его разбиения синим.
Достоинство данной программы заключается в том, что она (программа) позволяет строить многоугольники с произвольным (любым количеством) вершин.
Программа работает с различными видами многоугольников, независимо от их сложности и количества вершин.
ПОРЯДОК РАБОТЫ С ПРОГРАММОЙ
1. Для ввода исходных данных необходимо открыть текстовый файл “text” ввести построчно координаты Х , Y таким образом, чтобы координаты X ,Y одной вершины были расположены на одной строке и разделены пробелом.
2. Закрыть файл, сохранив изменения.
3. Запустить файл Project1.ехе
4. Кликнуть два раза по открывшейся форме.
5. Во вновь появившемся меню выбрать файл “text”.
6. Нажать кнопку «ОТКРЫТЬ» и программа автоматически произведёт построение фигуры с заданными вершинами. Исходный многоугольник отображён красным цветом, а результат его разбиения синим
ЛИСТИНГ ПРОГРАММЫ РАЗБИЕНИЯ МНОГОУГОЛЬНИКОВ
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
OpenDialog1: TOpenDialog;
procedure Image1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure Razb(X,Y:TStringList);
end;
TLine = record //для хранения уравнения линии
K,
B : Real;
end;
var
Form1: TForm1;
X,Y:TStringList;
function GetUrLine(sx1,sy1, sx2,sy2:String):TLine;
function Sravnit(zUrLine:TLine; X,Y:String):Boolean;
implementation
uses StrUtils;
{$R *.dfm}
//------------------------------------------------------------------------------
//Проверяет лежит ли точка выше прямой, задоваемой уравнением
function Sravnit(zUrLine:TLine; X,Y:String):Boolean;
begin
Result:=(zUrLine.K*StrToInt(X)+zUrLine.B)>StrToInt(Y);
end;
//------------------------------------------------------------------------------
//Возвращает уравнение прямой
function GetUrLine(sx1,sy1, sx2,sy2:String):TLine;
var x1,y1, x2,y2:Integer;
begin
x1:=StrToInt(sx1);
y1:=StrToInt(sy1);
x2:=StrToInt(sx2);
y2:=StrToInt(sy2);
if x1=x2 then Result.K:=100000
else Result.K:=(y2-y1)/(x2-x1);
Result.B:=y1-Result.K*x1;
end;
//------------------------------------------------------------------------------
//Процедура разбиения многогранника на выпуклые...
procedure TForm1.Razb(X,Y:TStringList);
var i, j, k, ks, f:Integer;
Pr, PrLine:Boolean;
UrLine:TLine;
X1,Y1 : TStringList;
begin
//поиск точки старта поиска
f:=0;
pr:=True;
while Pr do
begin
if f+1>X.Count-1 then k:=f+1-X.Count else k:=f+1;
UrLine:=GetUrLine(X[f],Y[f], X[k],Y[k]);
if f+2>X.Count-1 then k:=f+2-X.Count else k:=f+2;
PrLine:=Sravnit(UrLine, X[k],Y[k]);
ks:=0;
for j:=2 to X.Count-1 do
begin
if f+j>X.Count-1 then k:=f+j-X.Count else k:=f+j;
if PrLine=Sravnit(UrLine, X[k],Y[k]) then Inc(ks);
end;
pr:=not(ks=X.Count-2);
f:=f+1;
end;
f:=f-1;
//Проверяем выпуклый ли многоугольник....
Pr:=True;
i:=0;
while Pr and (i<X.Count) do
begin
if i+1+f>X.Count-1 then k:=i+1+f-X.Count else k:=i+f+1;
UrLine:=GetUrLine(X[i+f],Y[i+f], X[k],Y[k]);
if i+2+f>X.Count-1 then k:=i+f+2-X.Count else k:=i+f+2;
PrLine:=Sravnit(UrLine, X[k],Y[k]);
ks:=0;
for j:=2 to X.Count-1 do
begin
if i+f+j>X.Count-1 then k:=i+f+j-X.Count else k:=i+f+j;
if PrLine=Sravnit(UrLine, X[k],Y[k]) then Inc(ks);
end;
pr:=(ks=X.Count-2);
i:=i+1;
end;
if not(Pr) then //многоугольник не выпуклый
begin
//Рисуем доп. линию (треугольник)
with Image1.Canvas do
begin
Pen.Color:=clBlue; //синим цветом
Pen.Width:=3; //толщиной 3 пикселя
if i+f>x.Count-1 then k:=i-X.Count+f else k:=i+f;
MoveTo(StrToInt(X[k]), StrToInt(Y[k]));
if i-2+f<0 then k:=X.Count-2+f else k:=i-2+f;
LineTo(StrToInt(X[k]), StrToInt(Y[k]));
end;
X1:=TStringList.Create;
Y1:=TStringList.Create;
if X.Count>4 then
begin
for j:=0 to X.Count-2 do
begin
if i+j+f>X.Count-1 then k:=i+j+f-X.Count else k:=i+f+j;
X1.Add(X[k]);
Y1.Add(Y[k]);
end;
Razb(X1,Y1);
end;
end;
end;
//------------------------------------------------------------------------------
//Открытие файла
procedure TForm1.Image1Click(Sender: TObject);
var zList:TStringList;
i,j:Integer;
begin
if OpenDialog1.Execute then
begin
X:=TStringList.Create;
Y:=TStringList.Create;
zList:=TStringList.Create;
zList.LoadFromFile(OpenDialog1.FileName);
for i:=0 to zList.Count-1 do
begin
j:=PosEx(' ',zList[i]);
X.Add(copy(zList[i],1,j-1));
Y.Add(copy(zList[i],j+1,length(zList[i])-j))
end;
//Нарисовать исходный многогранник
with Image1.Canvas do
begin
Pen.Color:=clRed; //красным цветом
Pen.Width:=4; //ширина линии - 4
MoveTo(StrToInt(X[0]), StrToInt(Y[0]));
for i:=1 to X.Count-1 do
LineTo(StrToInt(X[i]), StrToInt(Y[i]));
LineTo(StrToInt(X[0]), StrToInt(Y[0]));
end;
Razb(X,Y); //процедура разбиения
end;
end;
end.
Список литературы
1. Багриновский К.А., Хрусталев Е.Ю. Программирование на зыках высокого уровня. - М.: “ЭКО”. 2004.
2. Белинов С.В., Зайцев А.А. Современные информационные технологии. – М.: Инфра-М, 2003.
3. Шафрин Ю. А. Программирование на языке С++. - М.: АБФ, 2005.
4. Lavel. Graphics. Растровая и векторная графика: http://win-www.klax.tula.ru/~level/graphics/predgrph.html
5. Векторная графика на языках С++ и Delphi: электронный учебник– http://imped.vgts.ru/polygraph/vektor.html
6. Семенов Р.Ж. О векторной и растровой графике // Компьютера, №3, 2003. http://flashmaker.8m.com/help/html/02basics2.html