18. Polymorfné korytnačky


Posledná zmena: 24.11.2002

Banner Text 21.11.2002

    čo sme sa doteraz naučili

    • ako funguje polymorfizmus, čo sú to virtuálne metódy

    čo sa budeme dnes učiť

    • ako funguje polymorfizmus pre korytnačky, ako ho môžeme využiť, ako pracujeme s polymorfným poľom korytnačiek (trieda TVelaKor)
    • indexované vlastnosti (property)
    • pretypovanie, resp. zisťovanie, či je daná inštancia nejakého typu

Virtuálne metódy triedy TKor

Definícia triedy TKor má skoro všetky metódy virtuálne. To znamená, že budeme môcť v našich programoch využívať polymorfizmus. Okrem toho niektoré metódy triedy TKor využívajú iné korytnačie metódy a teda ich predefinovanie má za následok zmenu správania aj týchto metód. Napr. ak opravíme ZmenXY, potom to bude mať vplyv aj na metódu Dopredu.

malý príklad:

type
  TKor1=class(TKor)
    procedure ZmenXY(nx,ny:real); override;
  end;

  TKor2=class(TKor)
    procedure ZmenXY(nx,ny:real); override;
  end;

procedure TKor1.ZmenXY(nx,ny:real);
begin
  inherited ZmenXY(X,ny);
end;

procedure TKor2.ZmenXY(nx,ny:real);
begin
  inherited ZmenXY(nx,Y);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  k,k1,k2:TKor;
  u:integer;
begin
  k:= TKor.Create;  k.HP:=5;  k.FP:=clRed;
  k1:=TKor1.Create; k1.HP:=5; k1.FP:=clBlue;
  k2:=TKor2.Create; k2.HP:=5; k2.FP:=clGreen;
  repeat
    // zmaz;
    k.dopredu(5); k1.dopredu(5); k2.dopredu(5);
    cakaj(10);
    u:=random(10);
    k.vpravo(u); k1.vpravo(u); k2.vpravo(u);
  until false;
end;
  • v tomto prvom príklade sa 3 korytnačky pohybujú úplne rovnakým spôsobom - ak by boli všetky tri rovnakej tiedy TKor, tak by sme videli kresbu len jednej z nich (poslednej - zelenej)
  • k1 a k2 majú zmenené správanie tak, že k1 mení iba Y-ovú súradnicu a k2 mení len X-ovú
  • ak odkomentujete príkaz zmaz na priebežné zmazávanie plochy, tak korytnačky nebudú kresliť čiary, ale budú sa zobrazovať krátkymi "paličkami"
  • v nasledujúcom príklade zatiaľ nevyužívame žiadne predefinovanie metód - pomocou dvoch korytnačiek kreslíme myšou do plochy

"obyčajné" kreslenie myšou:

var
  k1,k2:TKor;

procedure TForm1.FormCreate(Sender: TObject);
begin
  k1:=TKor.Create; k1.PH; k1.FP:=clLtGray; k1.HP:=7;
  k2:=TKor.Create; k2.PH;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  k1.PH; k1.ZmenXY(X,Y); k1.PD;
  k2.PH; k2.ZmenXY(X,Y); k2.PD;
end;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  u,v:real;
begin
  if Shift=[ssLeft] then begin
    u:=k1.Smerom(X,Y); v:=k1.Vzd(X,Y);
    k1.Smer:=u; k1.Dopredu(v);
    k2.Smer:=u; k2.Dopredu(v);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  k1.Free; k2.Free;
end;
  • dodefinujeme novú triedu, ktorej poopravíme metódu ZmenSmer, aby nastavovala uhol na opačný:

trieda TMojaKor má zmenený ZmenSmer:

type
  TMojaKor = class(TKor)
    procedure ZmenSmer(uhol:real); override;
  end;

procedure TMojaKor.ZmenSmer(uhol:real);
begin
  inherited ZmenSmer(-uhol);
end;

...

procedure TForm1.FormCreate(Sender: TObject);
begin
  k1:=TKor.Create; k1.PH; k1.FP:=clLtGray; k1.HP:=7;
  k2:=TMojaKor.Create; k2.PH;
end;
  • teraz sa bude 2. korytnačka správať veľmi čudne
  • zaujímavý efekt vznikne aj vtedy, keď v Image1MouseDown vyhodíme príkaz k1.PD;
  • v ďalšej sérii príkladov demonštrujeme rôzne pozmenené dopredu
  • najprv základná verzia bez pozmenenej korytnačky - na kliknutie do plochy sa na tom mieste nakreslí domček:

domčeky:

procedure domcek(k:TKor; d:real);
var
  i:integer;
begin
  for i:=1 to 4 do begin
    k.Dopredu(d);
    k.Vpravo(90);
  end;
  k.Vlavo(60);
  for i:=1 to 2 do begin
    k.Dopredu(d);
    k.Vpravo(120);
  end;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  k:TKor;
begin
  randomize;
  k:=TKor.Create(X,Y,90); k.FP:=random(256*256*256);
  domcek(k,70);
  k.Free;
end;
  • ak korytnačka nedokáže robiť úsečky presnej dĺžky, ale s nejakou pravdepodobnosťou sa "mýli" o -10%..10%, môžu vznikať zaujímavé kresby

nepresná dĺžka:

type
  TKor1 = class(TKor)
    procedure Dopredu(dlzka:real); override;
  end;

procedure TKor1.Dopredu(dlzka:real);
begin
  inherited Dopredu(dlzka*(0.9+random(20)/100));
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  k:TKor;
begin
  randomize;
  k:=TKor1.Create(X,Y,90); k.FP:=random(256*256*256);
  domcek(k,70);
  k.Free;
end;
  • trieda TKor2 má metódu Dopredu v poriadku (je odvodená z Tkor), ale otáčanie Vpravo nechodí presne, ale korytnačka sa mýli o -10%..10% - otestujte to na príklade s domčekom

nepresné otáčanie vpravo:

type
  TKor2 = class(TKor)
    procedure Vpravo(u:real); override;
  end;

procedure TKor2.Vpravo(u:real);
begin
  inherited Vpravo(u*(0.9+random(20)/100));
end;

...

  k:=TKor2.Create(X,Y,90);
  • ak by sme odvodili triedu TKor2 z TKor1, dostali by sme korytnačku, ktorá nevie robiť ani presné Dopredu ani presné Vpravo

kombinovaná trieda - preberá vlastnosti z TKor1:

type
  TKor2 = class(TKor1)
    ...
  • ďalšie dve triedy ilustrujú iné varianty zmenenej metódy Dopredu:

iné verzie Dopredu:

type
  TKor3 = class(TKor)
    procedure Dopredu(d:real); override;
  end;

  TKor4 = class(TKor)
    procedure Dopredu(d:real); override;
  end;

procedure TKor3.Dopredu(d:real);
begin
  Vlavo(random(41)/10-2);
  inherited;               // to je to isté, ako inherited Dopredu(d);
  Vlavo(180+random(41)/10-2);
  inherited;
  Vlavo(180+random(41)/10-2);
  inherited;
end;

procedure TKor4.Dopredu(d:real);
begin
  Vlavo(60);
  while d>=5 do begin
    inherited Dopredu(5);
    Vpravo(120);
    inherited Dopredu(5);
    Vlavo(120);
    d:=d-5;
  end;
  Vpravo(60);
  inherited Dopredu(d);
end;
  • otestujte kreslenie domčeka korytnačkou, ktorá je inštanciou týchto tried
  • poexperimentujte s tým, ak TKor3, resp. TKor4 bude odvodená nie z TKor ale z TKor1 alebo TKor2
  • nasledujúci jednoduchý príklad ilustruje pole 10 korytnačiek, ktoré sa pohybujú po rôzne veľkých kružniciach

10 korytnačiek:

procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
  k:array [1..10] of TKor;
begin
  for i:=1 to 10 do begin
    k[i]:=TKor.Create; k[i].HP:=7;
  end;
  repeat
    zmaz;
    for i:=1 to 10 do begin
      k[i].Dopredu(i); k[i].Vpravo(3);
    end;
    cakaj(100);
  until false;
end;
  • ak týmto korytnačkám opravíme metódu ZmenXY, tak budeme vidieť tento pohyb po kružniciach "zboku"

predefinujeme ZmenXY:

type
  TKor0 = class(TKor)
    procedure ZmenXY(xx,yy:real); override;
  end;

procedure TKor0.ZmenXY(xx,yy:real);
begin
  Inherited ZmenXY(X,yy);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
  k:array [1..10] of TKor;
begin
  for i:=1 to 10 do begin
    k[i]:=TKor0.Create; k[i].HP:=7;
  end;
  ...
  • iných 10 korytnačiek bude kresliť 10 rovnako veľkých kružníc, ktoré ale budú rôzne veľké:

10 rovnako vľkých kružníc:

type
  TMojaKor = class(TKor)
    procedure Dopredu(d:real); override;
  end;

procedure TMojaKor.Dopredu(d:real);
begin
  inherited Dopredu(d*1.5);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  k:array [1..10] of TKor;
  i,j:integer;
begin
  for i:=1 to 10 do
    if random(5)=0 then
      k[i]:=TMojaKor.Create(50+i*10,200)
    else
      k[i]:=TKor.Create(50+i*10,200);

  for i:=1 to 10 do k[i].HP:=3;
  for i:=1 to 10 do
    if k[i] is TMojaKor then k[i].FP:=clRed;

  for j:=1 to 120 do begin       // tu sa kreslia kružnice
    for i:=1 to 10 do k[i].Dopredu(3);
    for i:=1 to 10 do k[i].Vpravo(3);
    cakaj(10);
  end;

  for i:=1 to 10 do
    k[i].Free;
end;
  • všimnite si riadok, v ktorom sme zafarbili tie korytnačky, ktoré sú odvodené z TMojaKor - použili sme na to operátor as, ktorý otestuje, či je inštancia danej triedy (alebo triedy, ktorá je potomkom tejto triedy)
    • častou začiatočníckou chybou je test if k[i] is TKor then - totiž všetky prvky k[i] sú odvodené z TKor - aj keď sú odvodené z nejakých tried, ktoré sú potomkami TKor - teda tento test je splnený vždy
  • v tomto príklade sa niektoré korytnačie metódy často volajú pre všetky existujúce korytnačky - asi by sa nám tu hodila nejaká trieda, ktorá "zapúzdri" pole korytnačiek a hromadné metódy pre toto pole

Trieda na obsluhu viac korytnačiek - TVelaKor

Do programovej jednotky (unitu) VelaKorUnit zadefinujeme novú triedu TVelaKor. Táto trieda sa bude starať o dynamické (polymorfné) pole korytnačiek: umožní pridávať a vyhadzovať korytnačky a tiež paralelne vykonávať všetky korytnačie príkazy (metódy). Definícia triedy obsahuje:

  • súkromné dynamické pole Fk korytnačiek a ich počet Fpk (pomocou vlastností - property umožníme čítať tieto stavové premenné - ale nie modifikovať);
  • metódy na pridávanie do tohoto poľa:
    • metóda UrobKor je definovaná v troch rôznych verziách: verzia bez parametrov, verzia s troma číselnými parametrami x, y, a u; a verzia s polymorfnou korytnačkou - podľa typu volaných parametrov sa Delphi rozhodnú, ktorú z týchto verzií naozaj zavolajú (použijeme špecifikátor overload)
  • stavové premenné - vlastnosti, pomocou ktorých povolíme čítanie súkromných (a teda chránených) stavových premenných
    • vlastnosť k, ktorá sprístupní pole Fk je "indexovaná" stavová premenná, to znamená, že metóda dajKor musí mať jeden parameter typu index a musí to byť funkcia, ktorá vracia príslušnú hodnotu stavovej premennej

deklarácie triedy:

type
  TVelaKor = class
  private
    Fk:array of TKor;
    Fpk:integer;
    function dajKor(i:integer):TKor;
  public
    constructor Create;
    destructor Destroy; override;
    procedure UrobKor; overload;
    procedure UrobKor(x,y:real; u:real = 0); overload;
    procedure UrobKor(nk:TKor); overload;
    procedure ZrusKor(i:integer); overload;
    procedure ZrusKor(nk:TKor); overload;
    procedure Uprac;
    procedure Dopredu(d:real);
    ...
    procedure Vypln(fv:TColor);
    function  Blizko(x,y:real):TKor;

    property  k[i:integer]:TKor read dajKor;
    property  pk:integer read Fpk;
  end;

realizácia kľúčových metód:

constructor TVelaKor.Create;
begin
  Fpk:=0;
end;

destructor TVelaKor.Destroy;
var
  i:integer;
begin
  for i:=0 to Fpk-1 do Fk[i].Free;
end;

function TVelaKor.dajKor(i:integer):TKor;
begin
  if (i<0) or (i>=Fpk) then Result:=nil
  else Result:=Fk[i];
end;

procedure TVelaKor.UrobKor;
begin
  UrobKor(TKor.Create);          // toto nie je rekurzia
end;

procedure TVelaKor.UrobKor(x,y,u:real);
begin
  UrobKor(TKor.Create(x,y,u));   // toto nie je rekurzia
end;

procedure TVelaKor.UrobKor(nk:TKor);
begin
  if Fpk>high(Fk) then SetLength(Fk,Length(Fk)+10);
  Fk[Fpk]:=nk;
  inc(Fpk);
end;

procedure TVelaKor.ZrusKor(i:integer);
begin
  if (i>=0) and (i<Fpk) then begin
    Fk[i].Free; Fk[i]:=nil;
  end;
end;

procedure TVelaKor.ZrusKor(nk:TKor);
var
  i:integer;
begin
  i:=0; while (i<Fpk) and (Fk[i]<>nk) do inc(i);
  ZrusKor(i);                     // ani toto nie je rekurzia
end;

procedure TVelaKor.Uprac;         // vyhodí nil korytnačky z poľa
var
  i,j:integer;
begin
  j:=0;
  for i:=0 to Fpk-1 do
    if Fk[i]<>nil then begin
      Fk[j]:=Fk[i]; inc(j);
    end;
  Fpk:=j;
end;

metóda Dopredu posunie všetky korytnačky

procedure TVelaKor.Dopredu(d:real);
var
  i:integer;
begin
  for i:=0 to Fpk-1 do
    if Fk[i]<>nil then
      Fk[i].Dopredu(d);
end;
  • na rovnakom princípe ako metóda Dopredu pracujú skoro všetky ostatné metódy

metóda Blízko - vráti korytnačku, ktorá je dostatočne blízko od bodu (x,y):

function TVelaKor.Blizko(x,y:real):TKor;
var
  i:integer;
begin
  i:=Fpk-1;
  while (i>=0) and ((Fk[i]=nil) or not Fk[i].Blizko(x,y)) do dec(i);
  if i<0 then Result:=nil else Result:=Fk[i];
end;

Príklad

  • teraz môžeme prepísať príklad s 10 kružnicami s použitím triedy TVelaKor

použitie triedy TVelaKor:

uses
  KorUnit, VelaKorUnit;

...

procedure TForm1.Button1Click(Sender: TObject);
var
  v:TVelaKor;
  i,j:integer;
begin
  v:=TVelaKor.Create;
  for i:=1 to 10 do
    if random(5)=0 then
      v.UrobKor(TMojaKor.Create(50+i*10,200))
    else
      v.UrobKor(50+i*10,200);
  v.HP:=3;
  for i:=0 to v.pk-1 do
    if v.k[i] is TMojaKor then v.k[i].FP:=clRed;
  for j:=1 to 120 do begin
    v.Dopredu(3);
    v.Vpravo(3);
    cakaj(10);
  end;
  v.Free;
end;

zápis pomocou príkazu with:

procedure TForm1.Button1Click(Sender: TObject);
var
  i,j:integer;
begin
  with TVelaKor.Create do begin
    for i:=1 to 100 do
      if random(5)=0 then
        UrobKor(TMojaKor.Create(50+i*10,200))
      else
        UrobKor(50+i*10,200);
    HP:=3;
    for i:=0 to pk-1 do
      if not (k[i] is TMojaKor) then k[i].FP:=clRed;
    for j:=1 to 120 do begin
      //zmaz; Dopredu(23); Dopredu(-20);
      Dopredu(3);
      Vpravo(3);
      cakaj(10);
    end;
    Free;
  end;
end;
  • v tomto riešení sme nepotrebovali premennú v typu TVelaKor - tento objekt existoval len počas platnosti with
  • príkaz if not (k[i] is TMojaKor) then ... testuje tie korytnačky, ktoré nie sú triedy TMojaKor a teda sú to všetky ostatné

Príklad

  • nasledujúci príklad demonštruje nutnosť pretypovať inštanciu, ak potrebujeme vyvolať metódu (alebo aj použiť stavovú premennú), ktorú nepozná predok (základná trieda) ale iba potomok

korytnačky nakreslia sínus:

type
  TMojaKor = class(TKor)
  private
    k:real;
  public
    constructor Create(x,y:real; u:real = 0);
    procedure Koef(kk:real);
    procedure Dopredu(d:real); override;
  end;

constructor TMojaKor.Create(x,y,u:real);
begin
  inherited; k:=1;
end;

procedure TMojaKor.Koef(kk:real);
begin
  k:=kk;
end;

procedure TMojaKor.Dopredu(d:real);
begin
  inherited Dopredu(d*k);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
begin
  with TVelaKor.Create do begin
    for i:=1 to Image1.Width div 2 do begin
      UrobKor(TMojaKor.Create(2*i,250));
      TMojaKor(k[pk-1]).koef(sin(2*rad*i));      // posledne urobená korytnačka
    end;
    Dopredu(200);
    Free;         // uvoľní inštanciu TVelaKor - pole korytnačiek
  end;
end;

"sinusové" korytnačky kmitajú:

...

procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
begin
  with TVelaKor.Create do begin
    for i:=1 to Image1.Width div 2 do begin
      UrobKor(TMojaKor.Create(2*i,250));
      (k[pk-1] as TMojaKor).koef(sin(2*rad*i));
    end;
    HP:=3;
    Dopredu(200);
    repeat
      vpravo(180);
      for i:=1 to 100 do begin
        zmaz;
        Dopredu(4);
        cakaj(1);
      end;
    until false;
  end;
end;
  • v druhom príklade môžeme vidieť iný variant pretypovania - použili sme operátor as, ktorým sa "pozrieme" na nejakú inštanciu (korytnačku) akoby bola inej triedy (svoj potomok)

Projekt, ktorý bol na skúške v 1996:

zadanie:

Napíšte program, ktorý bude riešiť nasledovnú úlohu: textový súbor subor.txt obsahuje postupnosť príkazov pre korytnačku, ktorá popisuje nejaký obrázok. Najprv zadefinujete triedu TKor0 potomka triedy TKor, ktorá bude obsahovať jedinú metódu

    procedure kresli(var f:TextFile);

Táto metóda sa nastaví na začiatok súboru f, korytnačke zdvihne pero a zinterpretuje príkazy v súbore. Nakoľko takto kreslený obrázok môže byť buď príliš veľký alebo malý alebo môže presahovať okraje grafickej obrazovky, bude ho treba zmenšiť alebo zväčšiť, resp. pri inicializovaní korytnačky nezačať kresliť v strede plochy, ale zvoliť si domovskú pozíciu vhodnejšie a to tak, aby na šírku alebo výšku bol maximálne možne veľký.

Na riešenie tejto úlohy zadefinujete ešte dve podtriedy triedy TKor0: trieda TKor1 bude slúžiť na zistenie rozmerov obrázka pomocou zdedenej metódy kresli pričom na obrazovke sa bude pohybovať so zdvihnutým perom. Trieda TKor2 (tiež podtrieda triedy TKor0) bude vedieť nakresliť daný obrázok (zdedenou metódou kresli) pričom prekryje virtuálnu metódu Dopredu tak, že obrázok bude požadovanej veľkosti.

Textový súbor subor.txt sa skladá z takýchto "viet": prvé číslo každej vety je typu ordinálna hodnota z

    type TPrik = (pdo,pvl,pvp,pfp,pph,ppd);

a reprezentuje postupne príkazy (Dopredu, Vlavo, Vpravo, ZmenFP, PH, PD). Pre hodnoty pdo, pvl, pvp a pfp za týmto číslom nasleduje parameter príslušného príkazu - jedno celé číslo (integer). Pre hodnoty pph a ppd veta už neobsahuje ďalšie čísla. Predpokladajte, že vstupný súbor je zadaný korektne (obrázok nemá nulovú ani výšku ani šírku).

Váš program teda najprv popíše tri triedy TKor0, TKor1 a TKor2. Potom pomocou inštancie triedy TKor1 (s domovskou pozíciou v (0,0)) zistí rozmery obrázka (použijeme na to stavové premenné minX, minY, maxX a maxY) - zrejme predefinujete virtuálne metódy Dopredu, PH a PD. Nakoniec, pomocou inštancie triedy TKor2, ktorú zinicializuje v nejakej novej domovskej pozícii, vykreslí daný obrázok správnej veľkosti. Obe korytnačky majú rovnaký počiatočný smer zadaný konštantou programu, napr.

    const U = 30;

Na testovanie programu môžete použiť súbory subor.txt alebo subor1.txt.

Riešenie:

najprv len vykreslíme súbor pomocou inštancie Kor0, aby sme mohli vidieť, momentálny obsah súboru:

type
  TKor0 = class(TKor)
    procedure kresli(var t:TextFile);
  end;

procedure TKor0.kresli(var t:TextFile);
type
  TPrik = (pdo,pvl,pvp,pfp,pph,ppd);
var
  p:TPrik;
  i:integer;
begin
  PH; Reset(t);
  while not seekEof(t) do begin
    read(t,i); p:=TPrik(i);
    if p<=pfp then read(t,i);
    case p of
      pdo: Dopredu(i);
      pvl: Vlavo(i);
      pvp: Vpravo(i);
      pfp: ZmenFP(i);
      pph: PH;
      ppd: PD;
    end;
  end;
end;

const
  u = -45;
  subor = 'subor.txt';

// toto slúži len na otestovanie metódy kresli

procedure TForm1.FormCreate(Sender: TObject);
var
  t:TextFile;
begin
  AssignFile(t,subor);
  with TKor0.Create do begin  // nepotrebujeme premennú typu TKor0
    Smer:=u;
    kresli(t);
    Free;
  end;
  CloseFile(t);
end;

teraz dodefinujeme Kor1 a Kor2:

type
  TKor1 = class(TKor0)
    b,p:boolean;
    minx,miny,maxx,maxy:real;
    procedure Dopredu(d:real); override;
    procedure PH; override;
    procedure PD; override;
  end;

procedure TKor1.PH;
begin
  inherited; p:=false;
end;

procedure TKor1.PD;
begin
  p:=true;
end;

procedure TKor1.Dopredu(d:real);

  procedure xy;
  begin
    if not p then exit;     // ak je pero hore
    if b or (X<minx) then minx:=X;
    if b or (X>maxx) then maxx:=X;
    if b or (Y<miny) then miny:=Y;
    if b or (Y>maxy) then maxy:=Y;
    b:=false;
  end;

begin
  xy; inherited; xy;
end;

trieda TKor2:

type
  TKor2 = class(TKor0)
    r:real;
    procedure Dopredu(d:real); override;
  end;

procedure TKor2.Dopredu(d:real);
begin
  inherited Dopredu(d*r);
end

tlačidlo Button1 naštartuje celý algoritmus:

procedure TForm1.Button1Click(Sender: TObject);
var
  t:TextFile;
  rr,r1,r2:real;
begin
  AssignFile(t,subor);
  with TKor1.Create(0,0,u) do begin
    b:=true;        // bude treba inicializovať minx, maxx, miny, maxy
    kresli(t);      // TKor1 naozaj nekreslí - len zisťuje oblasť
    r1:=sirka/(maxx-minx+1);    // sirka a vyska sú premenne z KorUnit
    r2:=vyska/(maxy-miny+1);
    if r1<r2 then rr:=r1 else rr:=r2;
    with TKor2.Create(-rr*minx,-rr*miny,u) do begin
      r:=rr;        // nastaví mierku pre Dopredu
      kresli(t);
      Free;
    end;
    Free;
  end;
  CloseFile(t);
end;


© 2002 AB, KVI
blaho@fmph.uniba.sk