czwartek, 13 sierpień 2020
 
Strona główna Języki programowania Grafika żółwia

Grafika żółwia - przykład realizacji w Delphi

Grafika żółwia jest charakterystyczna dla języka LOGO, przeznaczonego do nauki programowania dla dzieci. Jej podstawową zaletą jest podobieństwo do "ręcznego rysowania". Łatwiej jest projektować rysunek przesuwając odpowiednio pisak (w LOGO nazywany żółwiem) zamiast obliczać współrzędne każdej kreski, jak to jest w klasycznej grafice Pascala.
Poniżej prezentuję przykład realizacji grafiki żółwia w Delphi z wykorzystaniem obiektu bazującego na TImage.

program demonstracyjny zolw.zip (237kB)

    Opis programu

  1. Ogólne założenia programu
  2. Opis możliwości żółwia
  3. Deklaracja klasy TZolw
  4. Utworzenie obiektu p typu TZolw

    Definicje metod

  5. liniado, skokdo - procedury pomocnicze
  6. cs - czyszczenie ekranu
  7. upoz, ukat - ustawienie położenia żółwia
  8. dom - żółw do położenia startowego
  9. pod, opu - wyłączanie / włączanie pisaka
  10. np, ws - naprzód / wstecz
  11. pr, lw - w lewo / w prawo

    Dodatki

  12. Rysowanie wielokątów
  13. Możliwości rozwoju klasy TZolw
do góry
  1. Ogólne założenia programu
  2. Aplikacja posiada elementy sterujące umieszczone na pasku narzędziowym ToolBar1. Pozostały obszar zajmuje ekran żółwia tworzony dynamicznie.
    Przycisk Button1 służy do kasowania ekranu, pozostałe służą do testowania różnych możliwości żółwia (rysowanie figur, fraktale itp).

    Deklaracja formularza
    type
      TForm1 = class(TForm)
        ToolBar1: TToolBar;
        Button1: TButton;
        Button2: TButton;
    //   ... itd
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
    //   ... itd
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    do góry
  3. Opis możliwości żółwia
  4. Żółw jest rodzajem pisaka, który możemy ustawić w określonym punkcie ekranu, przesuwać po ekranie oraz ustawiać i zmieniać kierunek ruchu. Żółw, poruszając się, może za sobą zostawiać kreskę lub przemieszczać się bez rysowania.
    Położeniem startowym żółwia jest środek ekranu (współrzędne x=0,y=0), żółw skierowany do góry (kąt=0).

    ekran.gif

    Stan żółwia określają cztery pola:

    Pola stanu żółwia
      xb:    Extended;   // bieżąca współrzędna pozioma
      yb:    Extended;   // bieżąca współrzędna pionowa
      kat:   Extended;   // bieżący kąt (azymut) ruchu
      pioro: Boolean;    // stan pisaka (true-rysuje, false-nie rysuje)
    

    Dodatkowo należy określić współrzędne środka ekranu w pikselach

    Pola stanu ekranu
      x0:    Integer;    // współrzędne pikselowe środka ekranu
      y0:    Integer;
    
    do góry
  5. Deklaracja klasy TZolw
  6. Klasa TZolw dziedziczy po klasie TImage rozszerzając ją o metody charakterystyczne dla grafiki żółwia. Ich opis znajduje się w dalszej części strony.
    Należy dopisać w sekcji uses moduł ExtCtrls.

    klasa TZolw
    type
      TZolw = class(TImage)
        procedure cs;                 // czyszczenie ekranu
        procedure upoz(x,y:extended); // ustaw żółwia na pozycji
        procedure ukat(k:extended);   // ustaw kąt żółwia
        procedure dom;                // żółw na środek, skierowany do góry
        procedure pod;                // podnieś pisak żółwia
        procedure opu;                // opuść pisak żółwia
        procedure np(d:extended);     // naprzód o n kroków
        procedure ws(d:extended);     // wstecz o n kroków
        procedure pr(k:extended);     // obróć o k stopni w prawo
        procedure lw(k:extended);     // obróć o k stopni w lewo
      private
        xb:    Extended;
        yb:    Extended;
        kat:   Extended;
        pioro: Boolean;
        x0,y0: Integer;
        procedure liniado(x,y:extended);// pomocnicze procedury wykorzystujące
        procedure skokdo(x,y:extended); // "Pascal-owskie" procedury LineTo i MoveTo
      end;
    
    do góry
  7. Utworzenie obiektu p typu TZolw
  8. zmienna p
    var   p:  TZolw;
    

    Fizyczne utworzenie obiektu należy zrealizować zaraz po utworzeniu formularza (onCreate). Ponadto należy ustawić właściwości ekranu:

    Utworzenie obiektu p i konfiguracja ekranu
    procedure TForm1.FormCreate(Sender: TObject);
    begin   align:=alClient;        //formularz na cały ekran
            Width:=Screen.Width;    //ustawienie rozmiarów formularza
            Height:=Screen.Height;
            p:=TZolw.Create(self);  //utworzenie obiektu (self=Form1)
            p.Parent:=self;         //włączenie obiektu do formularza
            p.Align:=alClient;      //obszar rysowania na cały formularz
            p.x0:=p.Width div 2;    //ustalenie współrzędnych środka ekranu
            p.y0:=p.Height div 2;
            p.cs;                   //czyszczenie ekranu
    end;
    

    Obiekt p należy usunąć przed zamknięciem aplikacji:

    Likwidacja obiektu p
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
            p.Free;
    end;
    
    do góry
  9. liniado, skokdo - procedury pomocnicze
  10. Są to jedyne procedury bezpośrednio wykorzystujące pikselową grafikę "Pascalowską". Są wykorzystywane wszędzie tam, gdzie zmienia się położenie żółwia. Sposób przeliczania współrzędnych, a zwłaszcza pionowej wynika z różnic między współrzędnymi ekranowymi a "żółwiowymi". Ilustruje to rysunek:

    ekran.gif
    liniado, skokdo
    procedure TZolw.liniado(x,y:extended);
    begin    Canvas.LineTo(Round(x0+x),Round(y0-y));
    end;
    
    procedure TZolw.skokdo(x,y:extended);
    begin    Canvas.MoveTo(Round(x0+x),Round(y0-y));
    end;
    
    do góry
  11. cs - czyszczenie ekranu
  12. Zrealizowano przez narysowanie prostokąta o rozmiarach całego obrazu. Po oczyszczeniu żółw wraca do położenia startowego.

    cs
    procedure TZolw.cs;
    begin   canvas.Rectangle(0,0,Width,Height);
            pod;
            dom;
            opu;
    end;
    
    do góry
  13. upoz, ukat - ustawienie położenia żółwia
  14. Procedura upoz ustawia kursor w podanym punkcie ekranu bez zmiany kąta, przy czym uwzględniany jest stan pióra.
    Procedura ukat ustawia kąt żółwia, przeprowadzając jednocześnie normalizację tak, aby sprowadzić go do przedziału <0-360).

    upoz, ukat
    procedure TZolw.upoz(x,y:Extended);
    begin   xb:=x;
            yb:=y;
            case pioro of
              true:  liniado(x,y);
              false: skokdo(x,y);
            end;
    end;
    
    procedure TZolw.ukat(k:Extended);
    begin   while k>=360 do k:=k-360;
            while k<0 do k:=k+360;
            kat:=k;
    end;
    
    do góry
  15. dom - żółw do położenia startowego
  16. Żółw przechodzi na środek ekranu (ewentualnie ciągnąc za sobą ślad) i ustawia kąt 0 (pionowo do góry):

    dom
    procedure TZolw.dom;
    begin   upoz(0,0);
            ukat(0);
    end;
    
    do góry
  17. pod, opu - wyłączanie / włączanie pisaka
  18. Polega to na modyfikacji pola logicznego pioro:

    pod, opu
    procedure TZolw.pod;
    begin   pioro:=false;
    end;
    
    procedure TZolw.opu;
    begin   pioro:=true;
    end;
    
    do góry
  19. np, ws - naprzód / wstecz
  20. Metody przestawiają żółwia o podaną liczbę kroków w aktualnym kierunku naprzód (np) lub wstecz (ws). Działanie np polega na odpowiednim zastosowaniu metody upoz, ws wykorzystuje np:

    np, ws
    procedure TZolw.np(d:extended);
    begin   upoz( xb+d*sin(pi/180*kat),
                  yb+d*cos(pi/180*kat));
    end;
    
    procedure TZolw.ws(d:extended);
    begin   np(-d);
    end;
    
    do góry
  21. pr, lw - w lewo / w prawo
  22. Wykorzystano metodę ukat obliczając odpowiedni kąt:

    pr, lw
    procedure TZolw.pr(k:extended);
    begin   ukat(kat+k);
    end;
    
    procedure TZolw.lw(k:extended);
    begin   ukat(kat-k);
    end;
    
    do góry
  23. Rysowanie wielokątów
  24. Poniższe procedury rysują podstawowe figury foremne.
    Dla obydwu procedur punktem startowym i końcowym jest środek ekranu.
    Procedura nkatop rysuje wielokąt o n bokach opisany na okręgu o promieniu r.

    procedure nkatop(r:Extended;n:integer);
    var     a:Extended;
            i:integer;
    begin   a:=2*r*sin(pi/n)/cos(pi/n);    // długość boku n-kąta
            with p do
            begin   pod; np(r);            // przesunięcie początkowe żółwia
                         pr(90);
                         ws(a/2);
                    opu;
                    for i:=1 to n do       // pętla główna
                    begin   np(a);
                            pr(360/n);
                    end;
                    pod; np(a/2);          // powrót żółwia
                         lw(90);
                         ws(r);
                    opu;
            end;
    end;
    

    Procedura nkatwp rysuje wielokąt o n bokach wpisany w okrąg o promieniu r.

    procedure nkatwp(r:Extended;n:integer);
    var     a:Extended;
            i:integer;
    begin   a:=2*r*sin(pi/n);              // długość boku n-kąta
            with p do
            begin   pod; np(r);            // przesunięcie początkowe żółwia
                         pr(90+180/n);
                    opu;
                    for i:=1 to n do       // pętla główna
                    begin   np(a);
                            pr(360/n);
                    end;
                    pod; lw(90+180/n);     // powrót żółwia
                         ws(r);
                    opu;
            end;
    end;
    

    Aby narysować okrąg wystarczy wywołać jedną z powyższych procedur dla dużej wartości n (np. n=50).

    procedure okrag(r:extended);
    begin   nkatop(r,50);
    end;
    
    do góry
  25. Możliwości rozwoju klasy TZolw
  26. Rozbudowa klasy jest dość prosta. W zasadzie można zrealizować wszystkie polecenia grafiki żółwia programu LOGO.

    do góry
© mgr inż. Piotr Kotarski, Kalety