Napisałem program oparty na ONP, który wyświetla wykres funkcji opisanej wzorem podanym przez użytkownika. Większość funkcji rysuje dobrze, ale jest problem z funkcją secans(odwrotność cosinusa).
Miałem problem z określaniem dziedziny funkcji. Otóż wykres powinien wyglądać tak:
http://img25.imageshack.us/my.php?image=wykresi.jpg
a wyglądał tak
http://img27.imageshack.us/my.php?image=wykres2q.jpg
Sposób określania, czy dany argument należy do dziedziny polegał na wykorzystaniu wyjątków:
if ONP.el[i]='sec' then
begin
try
a:=zamien(StrToFloat(zdejmij));
n:=1/cos(a);
except
niedziedzina:=True;
exit;
end;
dodaj(FloatToStr(sec(a)),0);
end
ONP to record, w którym tablica ONP.el zawiera elementy zapisu w ONP
Zamien to funkcja, która zamienia jednostki kątów, w zależności od wyboru użytkownika(stopnie, radiany, gradusy)
Zdejmij, to funkcja, która zdejmuje najwyższy element ze stosu i zwraca jego zawartość
Niedziedzina zwraca True, jeśli dany argument nie należy do dziedziny
Procedura dodaj dodaje wybrany element do stosu(pierwszy argument to wartosc, drugi to priorytet operatora - ten sam stos jest wykorzystywany do konwersji na ONP)
Teoretycznie, okresowo powinien pojawiać się błąd polegający na próbie dzielenia przez zero. W części odpowiedzialnej za rysowanie, jeśli obliczany jest pierwszy argument lub jeśli poprzedni argument nie należy do dziedziny, to kursor jest przesuwany do wyliczonego punktu. Jeśli argument nie należy do dziedziny, to nic się nie dzieje. Jeśli do niej należy, to rysowana jest linia do tego punktu.
Niestety nie działało to jak powinno, prawdopodobnie ze względu na to, że dokładność wykresu jest skończona i cos(x) zawsze trochę różnił się od zera. Dodałem więc następujący kod:
for j := P to K do
if (Round(1/d*a)*d)=(Round(1/d*(Pi/2+j*Pi))*d) then
begin
niedziedzina:=True;
exit;
end
gdzie:
P to początek układu współrzędnych
K to koniec układu współrzędnych
d = (K-P)/Image1.Width
W radianach, x=Pi/2+k*Pi <=> cos(x)=0(k jest dowolną liczbą całkowitą).
Na pierwszy rzut oka działało, ale pojawił się nowy problem.
Przy odpowiednim przybliżeniu wykres wyglądał poprawnie:
http://img25.imageshack.us/my.php?image=secans.png
ale po oddaleniu już nie:
http://img25.imageshack.us/my.php?image=secans2.png
Ramiona powinny dążyć do nieskończoności. Wydaje mi się, że problem znów polega na przybliżaniu wartości. Zamieszczam kod odpowiedzialny za rysowanie, może to coś pomoże.
ostatni:=False;
if funkcje.il<>0 then
for m := 1 to funkcje.il do
begin
Poczatek:=True;
Image1.Canvas.Pen.Color:=funkcje.item[m].kolor;
Image1.Canvas.Pen.Width:=funkcje.item[m].grubosc;
ostatni:=True;
blad:=False;
for x := 0 to Image1.Width do
if not(blad) then
begin
konwersja(funkcje.item[m].wzor);
y:=oblicz(True,d*(x-sx));
if Poczatek or ostatni then
begin
Image1.Canvas.MoveTo(x,-Round((1/d)*(y))+sy);
Poczatek:=False;
end else
if not(niedziedzina) then Image1.Canvas.LineTo(x,-Round((1/d)*(y))+sy);
ostatni:=niedziedzina;
end;
Ostatni określa czy poprzedni argument należał do dziedziny.
Jednocześnie można wyświetlać wiele różnych funkcji. Funkcje to record, w którym funkcje.il określa ilość zapisanych funkcji, funkcje.item to tablica, która przechowywuje wzory funkcji.
Blad zwraca true, jeśli wystąpi jakiś błąd niezwiązany z wyznaczaniem dziedziny funkcji.
Konwersja to funkcja, która konwertuje wyrażenie na zapis ONP i zapisuje je do recordu ONP.
Oblicz to funkcja, która oblicza wartość wyrażenia z recordu ONP. Pierwszy argument określa, czy wyrażenie jest funkcją, drugi to wartość argumentu.
Poczatek zwraca True, jeśli obliczana jest wartość dla pierwszego argumentu.
sx to współrzędna x środka układu(sx=Image1.Width div 2)
sy to współrzędna y środka układu(sy=Image1.Height div 2)
Czy ktoś wie jak można to rozwiązać?