Nadesłany przez Michał Knasiecki, 03 sierpnia 2005 01:00
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
polygon_d/Unit1.pas:
{
Algorytm sprawdzający, czy punkt p należy do wielokąta W
Program pobrano ze strony www.algorytm.org
Opracował: Michał Knasiecki
Format zapisu danych wejściowych znajduje się w pliku "!FormatDanych.txt"
}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,math;
type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
vertex=record //Współrzędne
x,y:integer;
end;
var
Form1: TForm1;
polygon:array[0..20] of vertex; //Tablica wierzchołków wielokąta, max 20
p:vertex; //Dany punkt - pierwszy koniec odcinka
r:vertex; //Drugi koniec odcinka
n:byte; //liczba wierzchołków wielokąta
k:integer;
tmp:vertex;
implementation
{$R *.DFM}
function przynaleznosc(x,y,z:vertex):boolean; //Ta procedura sprawdza, czy punkt z należy do odcinka |xy|
var det:byte;
begin
det:=x.x*y.y+y.x*z.y+z.x*x.y-z.x*y.y-x.x*z.y-y.x*x.y;
if det<>0 then result:=false else
begin
if (min(x.x,y.x)<=z.x)and(z.x<=max(x.x,y.x)) and (min(x.y,y.y)<=z.y)and(z.y<=max(x.y,y.y)) then
result:=true else
result:=false;
end;
end;
function det(x,y,z:vertex):integer; //Wyznacznik macierzy kwadratowej stopnia 3.
begin
result:=x.x*y.y+y.x*z.y+z.x*x.y-z.x*y.y-x.x*z.y-y.x*x.y;
end;
function sgn(a:integer):integer;
begin
if a = 0 then result := 0
else if a < 0 then result := -1
else result := 1;
end;
function przecinanie(a,b:vertex):boolean; //Funkcja sprawdza czy odcinki |AB| i |PR| się przecinają
begin
result:=false;
if (przynaleznosc(p,r,a)=false)and(przynaleznosc(p,r,b)=false) then
begin //półprosta nie przecina odcinka |AB| w końcach
if (sgn(det(p,r,a)) <> sgn(det(p,r,b))) and
(sgn(det(a,b,p)) <> sgn(det(a,b,r))) then result:=true else
result:=false;
end else //do półprostej należy przynajmniej jeden koniec odcinka |AB|
begin
if (przynaleznosc(p,r,a))and(przynaleznosc(p,r,b)) then
begin
if (sgn(det(p,r,polygon[(k-1+n) mod n])) = sgn(det(p,r,polygon[(k+2) mod n]))) and
(sgn(det(p,r,polygon[(k-1+n) mod n])) <> 0) then result:=false
else result:=true;
end else
if (przynaleznosc(p,r,polygon[(k-1+n) mod n]))or(przynaleznosc(p,r,polygon[(k+2) mod n]))then
result:=false else
begin //półprosta zawiera tylko wierzchołek
if przynaleznosc(p,r,b) then
begin
tmp:=a;
result:=false;
end;
if przynaleznosc(p,r,a) then
begin
if (sgn(det(p,r,tmp)) = sgn (det(p,r,b))) and
(sgn(det(p,r,tmp)) <> 0) then result:=false
else result:=true;
end;
end;
end;
end;
function oblicz:boolean; //Funkcja zwraca True, gdy liczba przecięć jest nieparzysta
var
l:byte; //liczba przecięć
i:integer;
begin
l:=0;
for i:=0 to n-1 do //pętla po wszystkich wierzchołkach wielokąta
begin
k:=i;
if przynaleznosc(polygon[i], polygon[(i+1)mod n], p)=true then
begin
result:=true;
showmessage('Punkt nalezy do krawedzi wielokata');
exit;
end;
if przecinanie(polygon[i],polygon[(i+1) mod n]) then inc(l);
end;
if (l mod 2)=0 then result:=false else result:=true;
showmessage('Liczba przecięć: '+inttostr(l));
end;
procedure TForm1.Button1Click(Sender: TObject);
var f:textfile;
j:integer;
max_X:integer;
begin
if fileexists('dane.txt') then
begin
assignfile(f,'dane.txt');
reset(f);
//Wczytywanie współrzędnych punktu
readln(f,p.x);
readln(f,p.y);
j:=0;
n:=0;
max_X:=0;
while not(eof(f)) do
begin
readln(f,polygon[j].x);
if polygon[j].x>max_X then max_X:=polygon[j].x;
readln(f,polygon[j].y);
inc(j);
end;
n:=j;
closefile(f);
//Wyznaczanie współrzędnych drugiego końca odcinka
r.x:=max_X+1;
r.y:=p.y;
//Punkt r na pewno znajduje się poza wielokątem
//Wypisywanie danych wejściowych
memo1.lines.add('p=('+inttostr(p.x)+','+inttostr(p.y)+')');
memo1.lines.add('r=('+inttostr(r.x)+','+inttostr(r.y)+')');
for j:=0 to n-1 do
memo1.lines.add('Wierzchołek #'+inttostr(j)+'=('+inttostr(polygon[j].x)+','+inttostr(polygon[j].y)+')');
if oblicz=true then showmessage('Punkt p należy do zadanego wielokąta') else
showmessage('Punkt p NIE należy do zadanego wielokąta')
end else showmessage('Plik z danymi nie istnieje');
end;
end.


Druga, poważniejsza jeszcze rzecz - zarówno tu (w 106 i 107)jak i w programie w Javie mamy odwołanie to punktu tmp, który może być niezainicjowany