Вычисления площади произвольного многоугольникаРефераты >> Программирование и компьютеры >> Вычисления площади произвольного многоугольника
Учитывая все вышеприведенное, составляем процедуру вычисления внутренних углов.
procedure Angles;
var
al1,al2,
dx, dy, dxp, dyp,
s_in, s_out, a: real;
i,j: integer;
function ArcCos(a: real): real;
var res: real;
begin
if abs(a)<1.0E-30 then res:=pi/2
else res:=ArcTan(sqrt(1-a*a)/a);
if dx<0 then
if dy>=0 then res:=pi+res
else res:=-pi-res
else
if dy<0 then res:=-res;
ArcCos:=res
end;
begin
dxp:=sd[1].x-sd[n].x;
dyp:=sd[1].y-sd[n].y;
a:=sqrt(dxp*dxp+dyp*dyp);
dxp:=dxp/a;
dyp:=dyp/a;
i:=1;
while i<=(n-1) do
begin
dx:=sd[i+1].x-sd[i].x;
dy:=sd[i+1].y-sd[i].y;
a:=sqrt(dx*dx+dy*dy);
dx:=dx/a;
dy:=dy/a;
if (dx=dxp) and (dy=dyp) then
begin
dec(n);
for j:=i to n do sd[j]:=sd[j+1];
end;
dxp:=dx; dyp:=dy;
inc(i)
end;
dx:=sd[1].x-sd[n].x;
dy:=sd[1].y-sd[n].y;
al1:=ArcCos(dx/sqrt(dx*dx+dy*dy));
for i:=1 to n-1 do
begin
dx:=sd[i+1].x-sd[i].x;
dy:=sd[i+1].y-sd[i].y;
al2:=ArcCos(dx/sqrt(dx*dx+dy*dy));
sd[i].angle:=pi-al1+al2;
if sd[i].angle>2*pi then sd[i].angle:=sd[i].angle-2*pi
else
if sd[i].angle<0 then sd[i].angle:=2*pi+sd[i].angle;
al1:=al2
end;
dx:=sd[1].x-sd[n].x;
dy:=sd[1].y-sd[n].y;
al2:=ArcCos(dx/sqrt(dx*dx+dy*dy));
sd[n].angle:=pi-al1+al2;
if sd[n].angle>2*pi then sd[n].angle:=sd[n].angle-2*pi
else
if sd[n].angle<0 then sd[n].angle:=2*pi+sd[n].angle;
s_in:=0;
s_out:=0;
for i:=1 to n do
begin
if sd[i].angle<0 then sd[i].angle:=2*pi+sd[i].angle;
S_in:=S_in+sd[i].angle;
S_out:=S_out+(2*pi-sd[i].angle);
end;
if S_out<S_in then
for i:=1 to n do sd[i].angle:=2*pi-sd[i].angle;
end;
3) Нахождение выпуклых вершин.
Как было сказано выше, внутренний угол выпуклой вершины меньше 1800. Но не всякую выпуклую вершину можно "отрезать", т.к. линия "отреза" может пересекать стороны многоугольника. Например, вершину А "отрезать" нельзя:
Эта задача сводится к задаче о пересечении двух отрезков. Пусть отрезки заданы координатами своих концов. Первый отрезок A1(X1A, Y1A) и
A2(X2A, Y2A). Второй – B1(X1B, Y1B) и B2(X2B, Y2B).
1) Запишем уравнения прямой, проходящей через точки A1 и A2.
Преобразуем его в форму вида:
где , ,
Из геометрии известно, что если две точки находятся по одну сторону от прямой, то при подстановке их координат в полином левой части получим значения одного знака. Таким образом, если точки B1 и B2 располагаются по разные стороны от прямой, то
(AX1B+BY1B+C)(AX2B+BY2B+C)<0
Но пересечение прямых не является достаточным для пересечения отрезков, например:
Эти отрезки не пересекаются.
Для достаточного доказательства пересечения отрезков необходимо произвести все вышеприведенные операции над точками B1 и B2, т.е. провести через них прямую и выяснить расположение точек A1 и A2 относительно ее.
Таким образом определяем возможность отсечения вершины многоугольника с количеством вершин, больше четырех.
Для некоторых видов четырехугольника это условие не несправедливо, например:
Здесь вершину A отсечь нельзя. Для четырехугольника определяем расположение отсекаемой вершины и вершины, несмежной с ней (через оставшиеся проходит "линия отреза"). Если они расположены по одну сторону, как на рисунке, то отсекать нельзя. Приведенный алгоритм контроля реализуем в следующей функции:
function cross(c: integer): boolean;
var a, b, i: integer;
AA, BB, CC,
AA1, BB1, CC1: real;
function Mline(x,y: real): real;
begin
Mline:=AA*x+BB*y+CC
end;
function Sline(x,y: real): real;
begin
Sline:=AA1*x+BB1*y+CC1
end;
begin
if c=1 then
begin
a:=n;
b:=2;
end
else if c=n then
begin
a:=n-1;
b:=1;
end
else
begin
a:=c-1;
b:=c+1;
end;
cross:=true;
AA:=sd[b].y-sd[a].y;
BB:=-(sd[b].x-sd[a].x);
CC:=sd[a].y*(sd[b].x-sd[a].x)-sd[a].x*(sd[b].y-sd[a].y);
if n=4 then
begin
for i:=1 to n do
if (Mline(sd[i].x, sd[i].y)*Mline(sd[c].x, sd[c].y)>0) and (i<>c)
then exit;
cross:=false;
exit
end;
for i:=1 to n-1 do
begin
AA1:=sd[i+1].y-sd[i].y;
BB1:=-(sd[i+1].x-sd[i].x);
CC1:=sd[i].y*(sd[i+1].x-sd[i].x)-sd[i].x*(sd[i+1].y-sd[i].y);
if Mline(sd[i].x, sd[i].y)*Mline(sd[i+1].x,sd[i+1].y)<0 then
if Sline(sd[a].x, sd[a].y)*Sline(sd[b].x,sd[b].y)<0 then exit;
end;
AA1:=sd[1].y-sd[n].y;
BB1:=-(sd[1].x-sd[n].x);
CC1:=sd[n].y*(sd[1].x-sd[n].x)-sd[n].x*(sd[1].y-sd[n].y);
if Mline(sd[n].x, sd[n].y)*Mline(sd[1].x,sd[1].y)<0 then
if Sline(sd[a].x, sd[a].y)*Sline(sd[b].x,sd[b].y)<0 then exit;
cross:=false;
end;
4) Вычисление площадей отсеченных треугольников будем по формуле Герона
где .
function St(x1,y1, x2,y2, x3,y3: real): real;
var a, b, c, p: real;
begin
a:=sqrt(sqr(x1-x2)+sqr(y1-y2));
b:=sqrt(sqr(x1-x3)+sqr(y1-y3));
c:=sqrt(sqr(x3-x2)+sqr(y3-y2));
p:=(a+b+c)/2;
St:=sqrt(p*(p-a)*(p-b)*(p-c));
end;
5) Отсечение i-той вершины
dec(n);
for j:=i to n do sd[j]:=sd[j+1];
После отсечения какой-либо вершины необходимо заново рассчитать внутренние углы многоугольника, т.е. вызвать процедуру Angles.
После вычисления площади, выводим ее на экран и ожидаем нажатия любой клавиши.