MFF UK / Ústav teoretické fyziky / Tomáš Ledvinka
Přednášky
. . . . . . . . . . . . . . . . . . . . . . . . . .
Programování pro fyziky (1.r)
  Úvod
  Programy a algoritmy
  Píšeme program
  Píšeme program II
  Procedury a funkce
  Malujeme funkce
  Chyby. Typy I.
  Typy II. Pole a Záznamy
  Pole II.Řetězce.Soubory.
  Gnuplot.Interpolace...
    Funkce v tabule
    Interpolace
    Polynomy
  Matice. Velké O...
  Fronta,Zásobník. Postscript
  Bin. soubory, ...
  Ukazatele,Objekty, ...
Maple pro fyziky (3.r)
Klasická elektrodynamika (2.r)
Vybrané partie OTR

Cvičení
. . . . . . . . . . . . . . . . . . . . . . . . . .
Programování pro fyziky (1.r)
Teoretická mechanika (2.r)
Klasická elektrodynamika (2.r)


Věda
. . . . . . . . . . . . . . . . . . . . . . . . . .
Diskové zdroje v OTR
Hyperbolické systémy v OTR


Kontakt
. . . . . . . . . . . . . . . . . . . . . . . . . .
Email
Konzultační hodiny


Ostatní
. . . . . . . . . . . . . . . . . . . . . . . . .
Mallorca
Ze společnosti

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.

.