|
|
|
|
|
|
Reálná funkce v tabulce
Budeme se zbývat situací, kdy z nějakého
důvodu musíme mít funkci v počítači uloženou jako tabulku
hodnot. Bohužel ještě pár let nebude možné psát array[real]
of real a tak budeme graf
funkce parametrizovat celočíselným parametrem z
nějakého intervalu. To už v Pascalu jde
type tIndexTabulky = 0 .. 12;
tPolicko = array[tIndexTabulky] of real;
const HodnotyX : tPolicko = (-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5);
HodnotyY : tPolicko = (-1.3734008, -1.3258177, -1.2490458, -1.1071487, -0.78539816, 0, 0.78539816, 1.1071487, 1.2490458, 1.3258177, 1.3734008);
Pokud bychom jedno z polí nahradili explicitní funkcí
indexu,
stále bychom mluvili o určení funkce pomocí tabulky.
Malujeme funkci z tabulky
Již víme, že pokud vytvoříme přesměrováním standardního výstupu (kam
píše
běžně Writeln) soubor se dvěma sloupečky čísel, můžeme program gnuplot
požádat, aby za nás namaloval pěkné obrázky. V minulé přednášce jsme se
ale
naučili pracovat se soubory, řetězci a dokonce spouštět jiné programy a
tak
můžeme všechnu tuto práci automatizovat.
Následující program nám pomocí
dvou funkcí umožní malovat
grafy. Funkce MalujPole vypíše do souboru hodnoty z obou
tabulek a, případně, jejím
posledním, nepovinným, parametrem určíme, zda se místo lomené čáry nemá
malovat třeba
pomocí puntíků či třeba zaoblených křivek (splines).
Fukce ZobrazGraf pak zobrazí
okénko s grafem funkce. Program je záměrně co nejkratší, aby bylo jeho
funkci možno vysvětlit na přednášce.
program FcePole; uses Windows;
type tIndexTabulky = 1 .. 11; tPolicko = array[tIndexTabulky] of real; const HodnotyX : tPolicko = (-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); HodnotyY : tPolicko = (-1.3734, -1.3258, -1.2490, -1.1071, -0.78540, 0, 0.78540, 1.1071, 1.2490, 1.3258, 1.3734);
const GnuPlotExe = 'C:\Program Files\gnuplot\bin\wgnuplot.exe'; Procedure MalujPole(const x,y : array of real; const Jmeno:string; const format:string = 'notitle with lines'); var T : text; nxy,i : integer; begin nxy := High(X); assert( nxy = High(Y) ,'MalujPole: Pole museji byt stejne dlouha!');
{Nejdrive prikaz pro vykresleni} Assign(T,Jmeno+'.plt'); Rewrite(T); Writeln(T,'plot "'+Jmeno+'.dat" index 0 '+format); Close(T);
{Potom otevrit soubor pro vystup dat} Assign(T,Jmeno+'.dat'); Rewrite(T); for i := 0 to nxy do Writeln(T,x[i],#9,y[i]); Close(T); Assert( IOResult=0 ,'MalujPole: Chyba pri zapisu do souboru'); end;
Procedure ZobrazGraf(const Jmeno : String);
var CmdStr : string; T : Text;
begin CmdStr := GnuPlotExe + ' ' + Jmeno + '.plt -';
// !! Trik !! // 1. Delphi umeji prevest String na (ukazatel na) PoleZnakuSeZarazkou napiseme-li tam PChar // 2. SW_NORMAL pripadne SW_MAXIMIZE rikaji jak ma vypadat okenko grafu WinExec(PChar(CmdStr),SW_NORMAL);
end;
begin MalujPole(HodnotyX,HodnotyY,'Priklad','title "Data" with points pointtype 2 pointsize 2'); ZobrazGraf('Priklad');
MalujPole(HodnotyX,HodnotyY,'Priklad2','smooth csplines title "Splajny"'); ZobrazGraf('Priklad2'); Writeln('Skoncil jsem, cekam na <Enter>'); ReadLn; end.
Triky použité v kódu byly probrány na přednášce a jsou v kódu
komentovány. Následně jsme program rozdělili na modul exportující obě
funkce a program, který modul importuje pomocí uses. Podrobně
byla probrána i struktura
modulu a to, jak vyčlenit z hotového programu recyklováníhodné kusy a
jak z nich vytvořit modul rozdělením na veřejné rozhraní a
privátní implementační část. Čtenáře poznámek odkazuji na
[Satrapa], kapitola 20. Doporučuji
vyzkoušet. Pro praktické použití v následujících přednáškách je vhodná
vylepšená verse modulu, která umožnuje malovat více křivek do jednoho
grafu a případně zobrazit jen výřez z daného grafu.
Unit GNUPlot01;
Interface
Procedure MalujPole(const x,y : array of real; const Jmeno:string; const format:string = 'notitle with lines'); Procedure ZobrazGraf(const Jmeno : String; const Rozsah: String = '');
Implementation USES windows; {$IOCHECKS OFF}
const GnuPlotExe = 'C:\Program Files\gnuplot\bin\wgnuplot.exe'; var ZobrazeneGrafy :string; PoradiGrafu:integer=10;
Procedure MalujPole(const x,y : array of real; const Jmeno:string; const format:string = 'notitle with lines'); var T : text; S,PP : String; nxy,i,index,j,ipos : integer; const Big = 100000; begin nxy := High(X); assert( nxy = High(Y) ,'MalujPole: Pole museji byt stejne dlouha!');
i:=1; while (i<=length(Jmeno)) and (Jmeno[i]='>') do i:=i+1;
S := copy(Jmeno,i,Big); if pos('*'+S+'*',ZobrazeneGrafy)>0 then begin PP:='MalujPole: Pokus o modifikaci jiz zobrazeneho grafu ('+S+')'; MessageBox(0, PChar(PP),'Chyba',MB_OK); exit; end; if i<=2 then begin {Pripad 'Soubor' nebo '>Soubor'} {Nejdrive prikaz pro vykresleni} Assign(T,S+'.plt'); Rewrite(T); Writeln(T,'plot "'+S+'.dat" index 0 '+format); Close(T); {Potom otevrit soubor pro vystup dat} Assign(T,S+'.dat'); Rewrite(T);
end else begin {pripad '>>Soubor'} {nactu Predchozi Prikaz do PP} Assign(T,S+'.plt'); Reset(T); if IOResult=0 then begin Readln(T,PP); Close(T); end else PP:='';
Rewrite(T); if PP='' then {Ted vyrobim prikaz pro vykresleni} Writeln(T,'plot "'+S+'.dat" index 0 '+format) else begin {Tady vylepsim prikaz pro vykresleni} j:=1;index := -1; repeat //zjistit posledni index ipos := pos(' index ',copy(PP,j,Big)); index := index+1; j := j+ipos+7; until ipos=0; Writeln(T,PP,',"',S,'.dat" index ',index,' ',format); end;
Close(T); {Potom otevrit soubor pro vystup dat} Assign(T,S+'.dat'); Append(T); if IOResult>0 then Rewrite(T); //velmi hrube.... Writeln(T); Writeln(T); //Pred data pridam dva radky aby to byl dalsi blok pro gnuPlot end;
for i := 0 to nxy do Writeln(T,x[i],#9,y[i]); Close(T); if IOResult<>0 then MessageBox(0, 'MalujPole: Chyba pri zapisu do souboru','Chyba',MB_OK); end;
Procedure ZobrazGraf(const Jmeno : String; const Rozsah: String = ''); const WinExecMaxKodChyby = 31; var CmdStr,NoveJmeno : string; T : Text;
begin CmdStr := GnuPlotExe + ' ' + Jmeno + '.plt -';
if Rozsah<>'' then begin { musim prikaz >plot "soubor" with ... zmenit na >plot [Range] "soubor" with ...} Assign(T,Jmeno + '.plt'); //Soubor s puvodnim prikazem Plot Reset(T);Readln(T,CmdStr);Close(T);//Nacti puvodni prikaz pro gnuplot
if Copy(CmdStr,1,5)='plot ' then //Zkontroluj ze tam je Plot begin Insert(Rozsah,CmdStr,5); //Prepis na Plot [Rozsah]} Str(PoradiGrafu,NoveJmeno); PoradiGrafu:=PoradiGrafu+1; NoveJmeno:=Jmeno+NoveJmeno+'.plt'; Assign(T,NoveJmeno); Rewrite(T); Writeln(T,CmdStr); Close(T); CmdStr := GnuplotExe + ' ' + NoveJmeno + ' -'; end; if IOResult<>0 then MessageBox(0, 'ZobrazGraf: Chyba pri cteni nebo zapisu do souboru','Chyba',MB_OK); end;
ZobrazeneGrafy:=ZobrazeneGrafy+'*'+Jmeno+'*';
// !! Trik !! // 1. Delphi umeji prevest String na (ukazatel na) PoleZnakuSeZarazkou napiseme-li tam PChar // 2. SW_NORMAL pripadne SW_MAXIMIZE rikaji jak ma vypadat okenko grafu if WinExec(PChar(CmdStr),SW_NORMAL) <= WinExecMaxKodChyby then MessageBox(0, 'MalujPole: Nenalezen WGnuPl32.exe','Chyba',MB_OK);
end;
{ ToDo: - kontrola spravnosti poradi formatu - moznost nastavit styl car - etc. chybi sposta veci jde zamerne o jednoduchy kod } end.
Význam obou funkcí nejlépe objasní Příklady použití
begin
MalujPole(HodnotyX,HodnotyY,'Priklad','title "Data" with points
pointtype 2 pointsize 2');
MalujPole(HodnotyX,HodnotyY,'>>Priklad','title "Lomene
cary" with lines');
MalujPole(HodnotyY,HodnotyX,'>>Priklad','title "Inversni
fce" with lines');
ZobrazGraf('Priklad');
MalujPole(HodnotyX,HodnotyY,'Priklad2','title "Data" with points
pointtype 2 pointsize 2');
MalujPole(HodnotyX,HodnotyY,'>>Priklad2','smooth csplines
title "Splajny"');
ZobrazGraf('Priklad2','[0:]');
Writeln('Skoncil jsem, cekam na <Enter>');
ReadLn;
end.
Význam kontrolních slovíček
with points atp. je v povídání o gnuplotu, příkaz "smooth csplines" je
uveden jen jako reklama na gnuplot.
|
.
|