uses crt, graph;
const n=5; {Кол-во точек. n>1 иначе задача не имеет смысла}
Rad2Grad=180/pi; {Если не нужно преобразовывать радианы в
градусы заменяем 180/pi на 1}
BGI_path='c:\bp\bgi'; {путь к каталогу графических драйверов, при несовпадении указанного и реального его расположения, работа в графическом режиме невозможна}
var
zoom,drive,mode,i,j:integer;
x,y:real;
points:array [1..n,1..4] of real; {здесь хранятся координаты}
P_order:array [1..n] of integer; {Вспомогательный массив. Хранит индексы
точек в основном массиве. Определяет порядок обхода точек}
Function CalcZoom:integer; {определение коэф-та увеличения при построении линии}
var
max_X, max_Y:real;
begin
max_X:=abs(points[1,1]); {находим макс. по модулю значение Х и Y}
max_Y:=abs(points[1,2]); {простым сравнением}
for i:=2 to n do
begin
if abs(points[i,1])>max_X then max_X:=abs(points[i,1]);
if abs(points[i,2])>max_Y then max_Y:=abs(points[i,2]);
end;
if (GetMaxX-10) div round(2*max_X) < (GetMaxY-10) div round(2*max_Y) then
CalcZoom:=(GetMaxX-10) div round(2*max_X) else
CalcZoom:=(GetMaxY-10) div round(2*max_Y);
{оставляем поля по 5 пикселов по краям экрана, 5+5=10, поэтому вместо
GetMaxX и GetMaxY используем GetMaxX-10 и GetMaxY-10 соответственно
Т.к. каждая четверть построенной координатной плоскости равна половине ширины и половине
высоты экрана, делим макс. широту и высоту (за вычетом полей) на 2, и затем на max_Y или max_Х
соответственно. А потом выбираем меньшее из значений. Таким образом избавляемся от
возможности выскочить за пределы экрана и одновременно получаем автоматическое
масштабирование построенной линии}
end;
procedure XY2Polar(t:integer); {Перевод декартовых координат в полярные}
{Обозначим буквами r и ф полярные координаты
(расстояние до объекта от начала координат и
угол направления на объект соответственно)}
var
r,phi:real;
begin
x:=points[t,1]; {в принципе, переменные х и у вводить необязательно}
y:=points[t,2]; {однако это повышает наглядность}
r:=sqrt(sqr(x)+sqr(y));{вычисляем r по т.Пифагора, как гипотенузу
треугольника с катетами x и y}
{т.к. x = r*cosф, y = r*sinф, -> y/x = sinф/cosф = tgф}
phi:=arctan(y/x); {а из tgф, через arctg(tgф) получим угол ф}
points[t,3]:=r; {и занесем преобразованные координаты}
points[t,4]:=phi; {в ту же строку массива точек}
end;
function ComparePoints(a,b:integer):boolean;
{Функция сравнивает две точки по их координатам.
"Больше" та точка, угол которой больше,
а при одинаковом значении угла -
сравнивает по расстоянию. Возвращает True,
если первая точка "больше" второй}
var t1,t2:integer;
begin
t1:=P_order[a];
t2:=P_order[b];
ComparePoints:=(points[t1,4]>points[t2,4])
or
((points[t1,4]=points[t2,4]) and (points[t1,3]>points[t2,3]));
end;
procedure Swap(a,b:integer);
{Процедура меняет местами индексы двух точек в массиве,
изменяя тем самым порядок их обхода}
var
t:integer;
begin
t:=P_order[a];
P_order[a]:=P_order[b];
P_order[b]:=t;
end;
begin
For i:=1 to n do {вводим координаты n точек}
begin
Write('Точка ');
Write(i);
Writeln(' - X:');
readln(points[i,1]);
Write('Точка ');
Write(i);
Writeln(' - Y:');
readln(points[i,2]);
P_order[i]:=i; {заносим индекс очередной точки в массив}
XY2Polar(i); {и преобразуем введенные координаты в полярные}
end;
For i:=1 to n-1 do {сортируем массив введенных координат
(а точнее - его индекс) методом простого выбора}
begin
For j:=i+1 to n do
begin
if ComparePoints(i,j) then
Swap(i,j);
end;
end;
WriteLn('Порядок обхода точек:'); {начинаем вывод результатов}
For i:=1 to n do
begin
Write('Точка N:');
Write((P_order[i]):3);
Write(', Угол Ф:');
Write((points[P_order[i],4]*Rad2Grad):6:2);
Write(', Расстояние R:');
Write(points[P_order[i],3]:6:2);
Write(', X:');
Write(points[P_order[i],1]:6:2);
Write(', Y:');
WriteLn(points[P_order[i],2]:6:2);
end;
WriteLn('Нажмите Enter...'); {Делаем паузу, чтобы можно было увидеть}
ReadLn; {результаты работы программы}
{а теперь строим замкнутую ломаную в графическом режиме}
drive:=detect;
initgraph(drive,mode,BGI_path);
zoom:=CalcZoom; {вычисляем масштаб}
line(10,240,630,240); {Проводим ось Х}
line(320,10,320,470); {и ось Y}
line(630,240,610,235); {Стрелка на оси Х}
line(630,240,610,245);
line(320,10,315,30); {Стрелка на оси Y}
line(320,10,325,30);
For i:=1 to n do
begin
x:=points[P_order[i],1]*zoom + (GetMaxX div 2);
y:=(GetMaxY div 2) - points[P_order[i],2]*zoom;
{ставим точки, взяв за начало координат середину экрана, в масштабе 1:zoom
Т.к. на экране ось Y идет сверху вниз, координата по оси у берется с
противоположным знаком, или, проще говоря, отнимается от начала координат}
if i>1 then LineTo(round(x),round(y));
{если точка не первая - проводим к ней линию от предыдущей}
Circle(round(x),round(y),1);
{обводим точку маленьким кружком для заметности}
end;
x:=points[P_order[1],1]*zoom + (GetMaxX div 2);
y:=(GetMaxY div 2) - points[P_order[1],2]*zoom;
LineTo(round(x),round(y)); {замыкаем линию}
repeat until keypressed; {и ждем нажатия клавиши для завершения работы}
closegraph;
end.