Состав и структура программы
В состав программы входят следующие модули:
– пользовательский интерфейс;
– модуль создания линий;
– модуль определения положения точки;
– модуль определения положения фигуры;
– модуль определения топологического отношения;
В модуле создания линий по заданным точкам высчитываются коэффициенты k и b для прямых заданных уравнением и записываются в динамический массив lines типа TMas_L, определенного программистом.
В модуле определения положения точки используется функция «figure_vo», которая определяет количество точек одной фигуры, принадлежащих другой фигуре и функция «figure_nr», определяющая количество точек одной фигуры принадлежащих ребрам другой фигуры.
В модуле определения положения фигуры используется функция «proverka», которая определяет положение каждой фигуры относительно другой
В модуле определения топологического отношения используется функция «res», определяющая конечный результат, основываясь на том, какой результат получился при выполнении модуля определения положения фигуры.
После запуска приложения появляется основная форма, содержащая меню, Radiogroup для выбора фигуры, кнопку «Добавить точку», кнопку «Показать результат» и поле для отображения введенных точек.
При нажатии на кнопку «Добавить точку», появляется форма с полями для ввода координат и кнопкой «Добавить».
При нажатии на кнопку «Показать результат» (при введенных значениях), появляется форма с графиком и полем с результатом.
Кнопка «Очистить» из Меню удаляет информацию о введенных точках.
Кнопка «О программе» показывает форму с информацией о программном продукте и его разработчиках.
Кнопка «Выход» закрывает приложение.
Используемые технические средства
- PC
- Мышь
- Клавиатура
Вызов и загрузка
Вызов программы осуществляется выполнением приложения PrgTopology, которое находится в папке «Основной проект»
Входные данные:
Координаты точек каждой из фигур (Вводятся в StringGrid). Координаты должны быть целочисленные. Хотя пользователь при вводе координат точки, не сможет ввести вещественные и отрицательные числа, так как сработает защита от «дураков», с помощью которой возможно избежать некоторые ошибки.
Инструкция пользователя
1. После запуска приложения, пользователь видит основную форму для ввода данных
Пользователь выбирает координаты точек, какой фигуры он собирается задать и нажимает на кнопку «Добавить точку»
2.
Пользователь видит перед собой форму с полями для ввода координат и кнопкой «Добавить»
3. Пользователь вводит координаты для необходимого количества точек, используя символы от 0 до 9, строго в той последовательности, в которой они должны будут соединяться (возможен ввод по часовой и против, результат одинаковый).
4.
После того, как пользователь ввел координаты точек первой фигуры, он выбирает вторую фигуру и таким же образом добавляет точки для нее.
5. После того, как все точки добавлены, пользователь нажимает на кнопку «Просмотр результата»
6.
И видит перед собой форму, на которой выведен результат и его визуальное представление в виде графика с фигурами в соответствующем масштабе
7. После получения результата пользователь закрывает окно с графиком и возвращается к основной форме. Далее он может очистить поля для ввода значений точек (Файл – очистить или же комбинация «горячих» клавиш: Ctrl+A) и проверить другие фигуры.
8.
Так же пользователь имеет возможность подробнее узнать о программе и её разработчиках, нажав «О программе»
9. Пользователь может закрыть программу несколькими способами:
1) Нажав на «крестик» в правом верхнем углу
2) Нажав «Выход» (Файл – Выход)
3) Нажав комбинацию «горячих» клавиш: Ctrl+Q
Выходные данные:
Результат проверки, в виде текста («Наложение», «Вложена», «Примыкает», «Не пересекаются)
Визуальное представление результата в виде контуров заданных фигур, изображенных в первой четверти координатных осей.
Приложение
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Menus, Grids, XPMan, Math;
type
TForm1 = class(TForm)
select_figure: TRadioGroup;
StringGrid1: TStringGrid;
StringGrid2: TStringGrid;
Label1: TLabel;
Label2: TLabel;
MainMenu1: TMainMenu;
N1: TMenuItem;
N2: TMenuItem;
Button_addpoint: TButton;
XPManifest1: TXPManifest;
ButtonStart: TButton;
N3: TMenuItem;
N4: TMenuItem;
procedure Button_addpointClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure ButtonStartClick(Sender: TObject);
procedure N4Click(Sender: TObject);
procedure N3Click(Sender: TObject);
procedure N2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Unit2, Unit3, Unit4;
{$R *.dfm}
type
//параметры каждой прямой!
TLine = record
x0,x1 :double; //промежуток, на котором задана прямая
k,b: double; //коэффициенты прямой
end;
//координаты точки
TPoints = record //запись для точки
x,y:double;
end;
TMas_L=array of TLine; //типы данных определенные программистом
TMas_P=array of TPoints;
const
eps=-10;
var
lines: TMas_L; //основной массив прямых
points: TMas_P; //массив для входных точек
num1, num2:integer; //количество точек (прямых)
teta:double;//угол поворота
procedure CreateLine (points:TMas_P; n1,n2:integer); //создание прямых по точкам
var
i:integer; //переменные для циклов
begin
SetLength(lines,n1+n2); //определение количества прямых
for i:=0 to n1-1 do
if i<>n1-1 then
begin
if points[i].x < points[i+1].x then
begin
lines[i].x0:=points[i].x;
lines[i].x1:=points[i+1].x;
end
else
begin
lines[i].x0:=points[i+1].x;
lines[i].x1:=points[i].x;
end;
lines[i].k:=(points[i+1].y-points[i].y)/(points[i+1].x-points[i].x);
lines[i].b:=points[i].y - points[i].x*lines[i].k;
end
else
begin
if points[i].x > points[0].x then
begin
lines[i].x0:=points[0].x;
lines[i].x1:=points[i].x;
end
else
begin
lines[i].x0:=points[i].x;
lines[i].x1:=points[0].x;
end;
lines[i].k:=(points[0].y-points[i].y)/(points[0].x-points[i].x);
lines[i].b:=points[i].y - points[i].x*lines[i].k;
end;
for i:=n1 to n1+n2-1 do
if i<>n1+n2-1 then
begin
if points[i].x < points[i+1].x then
begin
lines[i].x0:=points[i].x;
lines[i].x1:=points[i+1].x;
end
else
begin
lines[i].x0:=points[i+1].x;
lines[i].x1:=points[i].x;
end;
lines[i].k:=(points[i+1].y-points[i].y)/(points[i+1].x-points[i].x);
lines[i].b:=points[i].y - points[i].x*lines[i].k;
end
else
begin
if points[i].x > points[n1].x then
begin
lines[i].x0:=points[n1].x;
lines[i].x1:=points[i].x;
end
else
begin
lines[i].x0:=points[i].x;
lines[i].x1:=points[n1].x;
end;
lines[i].k:=(points[n1].y-points[i].y)/(points[n1].x-points[i].x);
lines[i].b:=points[i].y - points[i].x*lines[i].k;
end;
end;
//*************************************************************************************************
function figure_vo(lines:TMas_L; n1, n2: integer; x,y:double):boolean; //функция проверки есть ли нужное пересечение
var
i:integer;
fx,fi:boolean;
begin
figure_vo:=false;
fx:=false;
fi:=false;
for i:=n1 to n2-1 do
begin
if i<>n2-1 then
begin
if simpleroundto(lines[i].x1,eps)=simpleroundto(lines[i+1].x0,eps) then
if (simpleroundto(x,eps) <= simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x1,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
if simpleroundto(lines[i].x0,eps)=simpleroundto(lines[i+1].x1,eps) then
if (simpleroundto(x,eps) < simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >=simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x0,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
if simpleroundto(lines[i].x1,eps)=simpleroundto(lines[i+1].x1,eps) then
if (simpleroundto(x,eps) <= simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x1,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
if simpleroundto(lines[i].x0,eps)=simpleroundto(lines[i+1].x0,eps) then
if (simpleroundto(x,eps) < simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >=simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x0,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
end
else
begin
if simpleroundto(lines[i].x1,eps)=simpleroundto(lines[n1].x0,eps) then
if (simpleroundto(x,eps) <= simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x1,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
if simpleroundto(lines[i].x0,eps)=simpleroundto(lines[n1].x1,eps) then
if (simpleroundto(x,eps) < simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >=simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x0,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
if simpleroundto(lines[i].x1,eps)=simpleroundto(lines[n1].x1,eps) then
if (simpleroundto(x,eps) <= simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x1,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
if simpleroundto(lines[i].x0,eps)=simpleroundto(lines[n1].x0,eps) then
if (simpleroundto(x,eps) < simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >=simpleroundto(lines[i].x0,eps)) then
begin
if (simpleroundto(y,eps) < simpleroundto(lines[i].k*x + lines[i].b,eps)) then fx:=not(fx);
if (simpleroundto(y,eps) > simpleroundto(lines[i].k*x + lines[i].b,eps)) and (simpleroundto(x,eps)<>simpleroundto(lines[i].x0,eps)) then fi:=not(fi);
if fx and fi then begin figure_vo:=true; exit; end;
end;
end;
end;
end;
function figure_nr(lines:TMas_L; n1, n2: integer; x,y:double):boolean; //функция проверки есть ли нужное пересечение
var
i:integer;
begin
figure_nr:=false;
for i:=n1 to n2-1 do
if (simpleroundto(x,eps) <= simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps) >= simpleroundto(lines[i].x0,eps)) and (simpleroundto(y,eps) = simpleroundto((lines[i].k*x + lines[i].b),eps)) then begin figure_nr:=true; exit; end;
end;
function proverka(nl,vo,nr:integer;flag,flagindex:boolean):string;
begin
//условия, при выполнении которых можно сделать вывод
proverka:='';
if (nl>0) and (nr>=0) and (vo>=0) and (flag) then proverka:='Н';
if (nl>0) and ((nr>0) or (flagindex)) and (vo=0) and (flag=false) then proverka:='П';
if (nl=0) and ((vo>0) or (nr>0) or flagindex) and (flag=false) then proverka:='В';
if (nl>0) and (vo=0) and (nr=0) and (flag=false) and (flagindex=false) then proverka:='НП';
end;
function res(nl1,nl2,vo1,vo2,nr1,nr2:integer; flag, flagindex:boolean):string;
var str1,str2:string;
begin
str1:=proverka(nl1,vo1,nr1,flag,flagindex);
str2:=proverka(nl2,vo2,nr2,flag,flagindex);
if (str1='Н') or (str2='Н') then res:='Наложение';
if ((str1='В') or (str2='В')) and ((str1='П') or (str2='НП') or (str1='НП') or (str2='П') ) then res:='Вложена';
if (str1='НП') and (str2='НП') then res:='Не пересекаются';
if ((str1='П') and (str2='П')) then res:='Примыкает';
end;
//******************************************************************************
procedure TForm1.Button_addpointClick(Sender: TObject); //открытие формы для добавления точки
begin
Form2.Show;
end;
procedure TForm1.FormActivate(Sender: TObject); //нанесение поясительных записей в stringgrid
begin
stringgrid1.Cells[0,0]:='Имя';
stringgrid1.cells[1,0]:='X';
stringgrid1.Cells[2,0]:='Y';
stringgrid2.cells[0,0]:='Имя';
stringgrid2.cells[1,0]:='X';
stringgrid2.Cells[2,0]:='Y';
end;
procedure TForm1.ButtonStartClick(Sender: TObject);//запуск основной процедуры
var
i,j:integer;//переменная для цикла
vo1, nr1, nl1,vo2,nl2,nr2:integer; //счетчки для определения положения фигуры
x:double;//икс для дополнительного условия
flag,flagindex,flagvn:boolean; //флаг нахождения пересечения для дополнительного условия
fl1,fl2:integer;//флаги возможного положения прямой внутри фигуры
begin
teta:=20;//коэффициент для афинного преобразования
form2.Close;//закрытие формы ввода
form3.show;//показ формы с графиком
//флажки пересечения
flag:=false;
flagindex:=false;
//обнуление счетчиков
vo1:=0;
nr1:=0;
nl1:=0;
vo2:=0;
nr2:=0;
nl2:=0;
//присвоение точек в массив**************************************************
num1:=Stringgrid1.rowcount-1;
num2:=Stringgrid2.rowcount-1;
SetLength(points,num1+num2);
//преобразование и ввод координат точек
for i:=0 to num1-1 do
begin
points[i].x:=StrToFloat(stringgrid1.Cells[1,i+1]) + teta*StrToFloat(stringgrid1.Cells[2,i+1]);
points[i].y:=StrToFloat(stringgrid1.Cells[2,i+1]);
end;
for i:=num1 to (num1+num2)-1 do
begin
points[i].x:=StrToFloat(stringgrid2.Cells[1,i+1-num1]) + teta*StrToFloat(stringgrid2.Cells[2,i+1-num1]);
points[i].y:=StrToFloat(stringgrid2.Cells[2,i+1-num1]);
end;
//******************************************************************************
CreateLine(points,num1,num2);//создание прямых по точкам
for i:=0 to num1-1 do //используется для проверки пересечения прямых. Тем самым выполняется ли условие наложенности
begin
for j:=num1 to num1+num2-1 do
begin
if simpleroundto(lines[i].k,eps)<>simpleroundto(lines[j].k,eps) then
begin
x:=(lines[i].b-lines[j].b)/(lines[j].k-lines[i].k); //решение уравнения
if (simpleroundto(x,eps)<simpleroundto(lines[i].x1,eps)) and (simpleroundto(x,eps)>simpleroundto(lines[i].x0,eps)) and (simpleroundto(x,eps)<simpleroundto(lines[j].x1,eps)) and (simpleroundto(x,eps)>simpleroundto(lines[j].x0,eps))then flag:=true;
end;
//линия лежит на линии другой фигуры
if ((simpleroundto(lines[i].k,eps)=simpleroundto(lines[j].k,eps)) and (simpleroundto(lines[i].b,eps)=simpleroundto(lines[j].b,eps))) and (((simpleroundto(lines[i].x0,eps)>=simpleroundto(lines[j].x0,eps)) and (simpleroundto(lines[i].x1,eps)<=simpleroundto(lines[j].x1,eps))) or ((simpleroundto(lines[i].x0,eps)<=simpleroundto(lines[j].x0,eps)) and (simpleroundto(lines[i].x1,eps)>=simpleroundto(lines[j].x1,eps)))) then flagindex:=true;
end;
end;
for i:=0 to num1-1 do //проверка расположения второй относительно точек первой
begin
if figure_nr(lines,num1,num1+num2,points[i].x,points[i].y) then nr1:=nr1+1
else if figure_vo(lines,num1,num1+num2,points[i].x,points[i].y) then vo1:=vo1+1
else nl1:=nl1+1;
end;
for i:=num1 to num1+num2-1 do //проверка первой относительно точек второй
begin
if figure_nr(lines,0,num1,points[i].x,points[i].y) then nr2:=nr2+1
else if figure_vo(lines,0,num1,points[i].x,points[i].y) then vo2:=vo2+1
else nl2:=nl2+1;
end;
form3.Label1.caption:=res(nl1,nl2,vo1,vo2,nr1,nr2,flag,flagindex);//вывод окнчательного вердикта о расположении
end;
[1] Код программы на алгоритмическом языке находится в разделе Приложение