Zanim przystąpisz do tej lekcji, zapoznaj się z poprzednimi lekcjami:

Wstęp do grafiki - biblioteki SDL i newgfx
Opis biblioteki newgfx
Grafika - wielokąty


 

Grafika SLD - tworzenie wykresów dowolnych funkcji

Na tych zajęciach pokażemy, iż stworzenie prostej aplikacji rysującej wykresy dowolnych funkcji matematycznych nie jest wcale rzeczą trudną.

Postępujemy wg następującej metody:

 

Określamy przedział argumentów, w którym będzie tworzony wykres. Dla prostoty oznaczmy ten przedział za pomocą xp i xk:

 

obrazek

 

Przedział <xp,xk> dzielimy na n równoodległych punktów x0,x1,...,xn-1:

 

obrazek

 

Odległość pomiędzy dwoma sąsiednimi punktami wynosi dx. Łatwo zauważysz, że n punktów dzieli przedział na n-1 części o długości dx, zatem:

 

obrazek

 

Poszczególne punkty podziałowe wyznaczymy wg wzorów:

 

obrazek

 

Dla każdego punktu xi wyznaczymy i zapamiętamy wartość funkcji w tym punkcie:

 

obrazek

 

Otrzymane punkty (xi,yi) posłużą nam jako końce odcinków, z których będzie zbudowany wykres funkcji. W trakcie wyznaczania współrzędnych yi wyszukamy wśród nich wartości:

 

ymin - najmniejsza wartość yi
ymax - największa wartość yi.

 

Cały wykres funkcji mieści się teraz w prostokącie:

 

obrazek

 

Lewy górny narożnik tego prostokąta ma współrzędne xp,ymax, prawy dolny narożnik ma współrzędne xk,ymin.  Prostokąt ten należy odwzorować na ekranie graficznym w prostokąt ekranowy:

 

obrazek

 

xep,yep - to współrzędne lewego górnego narożnika prostokąta. Pamiętaj, że na powierzchni graficznej początek układu współrzędnych rozpoczyna się w lewym górnym narożniku - wyprowadzone przez nas wzory przeliczeniowe będą to odzwierciedlać.

w - szerokość prostokąta w pikselach

h - wysokość prostokąta w pikselach.

x,y - współrzędne dowolnego punktu wewnątrz prostokąta

xe,ye - odpowiednik ekranowy współrzędnych x,y.

 

Zadanie nasze polega na znalezieniu wzorów na xe i ye w zależności od x i y.

 

Na pierwszy rzut oka zadanie wydaje się trudne, jednakże skorzystajmy z prostych proporcji:

 

obrazek

 

Ponieważ prostokąt ekranowy odwzorowuje prostokąt wykresu funkcji, to w obu muszą być spełnione proporcje:

 

obrazek

 

Z kolei możemy zapisać:

 

obrazek

 

Wstawiamy to do proporcji i otrzymujemy:

 

obrazek

 

Te wzory pozwalają nam wyznaczyć bezpośrednio xe oraz ye:

 

obrazek

 

Teraz wystarczy wyliczone wcześniej punkty xi,yi przeliczyć na punkty ekranowe xe,ye, które następnie łączymy odcinkami i wykres będzie gotowy.

Pozostaje problem dorysowania osi współrzędnych. Oś OX wpada w prostokąt wykresu funkcji, jeśli ymax i ymin posiadają różne znaki. Jeśli tak, to rysujemy na prostokącie ekranowym linię poziomą o szerokości okna. Początek linii jest na współrzędnej xep. Współrzędną ye obliczymy wg wcześniejszego wzoru wstawiając y = 0.

Podobnie z osią OY - oś ta znajdzie się w prostokącie ekranowym, jeśli xp i xk mają różne znaki. W takim przypadku w prostokącie ekranowym rysujemy pionową linię o wysokości prostokąta ekranowego. Współrzędną xe początku tej linii znajdziemy wg wzoru, wstawiając x=0. Współrzędna pionowa to yep.

 

Uruchom Code::Blocks, utwórz nowy projekt SDL i wpisz poniższy kod:

 

// Rysowanie wykresów funkcji
// (C)2011 Koło Informatyczne
// I LO w Tarnowie
//-------------------------------

#include "newgfx.h"
#include <cmath>

// Tutaj umieszczamy przepis funkcji
//----------------------------------

double f(double x)
{
    return x*cos(x)*sin(x*x);
}

int main(int argc, char *argv[])
{

  if(!SDL_Init(SDL_INIT_VIDEO))
  {
    atexit(SDL_Quit);

    SDL_Surface * screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE);

    // najpierw definiujemy wszystkie stałe

    const int n = 200;               // liczba punktów wykresu funkcji
    const double xp = -2;            // początek przedziału argumentów
    const double xk = 5;             // koniec przedziału argumentów
    const Sint32 xep = 4;            // współrzędne lewego górnego narożnika prostokąta
    const Sint32 yep = 4;            // ekranowego
    const Uint32 w   = screen->w-10; // szerokość prostokąta ekranowego
    const Uint32 h   = screen->h-10; // wysokość prostokąta ekranowego

    // teraz zmienne

    double x[n],y[n],dx,ymax,ymin;
    Sint32 xe,ye,i;

    // wyliczamy odległość pomiędzy dwoma punktami podziałowymi

    dx = (xk - xp) / (n - 1);

    // wyliczamy współrzędne punktów wykresu funkcji oraz ymax i ymin

    for(i = 0; i < n; i++)
    {
        x[i] = xp + i * dx;
        y[i] = f(x[i]);

        if(!i) ymax = ymin = y[0];
        else
        {
            if(y[i] > ymax) ymax = y[i];
            if(y[i] < ymin) ymin = y[i];
        }
    }

    if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);

    // Ekran graficzny wypełniamy kolorem białym:

    SDL_Rect r;

    r.x = r.y = 0;
    r.w = screen->w;
    r.h = screen->h;
    SDL_FillRect(screen,&r,0xffffff);

    // rysujemy osie, jeśli wpadają w prostokąt ekranowy

    if(ymin * ymax <= 0)  // oś OX
    {
        ye = yep + ymax * (h - 1) / (ymax - ymin);
        gfxHLine(screen,xep,ye,0x000000,w);
    }

    if(xp * xk <=0)  // oś OY
    {
        xe = xep - xp * (w - 1) / (xk - xp);
        gfxVLine(screen,xe,yep,0x000000,h);
    }

    // rysujemy wykres funkcji

    for(i = 0; i < n; i++)
    {
        xe = xep + (x[i] - xp) * (w - 1) / (xk - xp);
        ye = yep + (ymax - y[i]) * (h - 1) / (ymax - ymin);
        if(!i) gfxMoveTo(xe,ye);
        else   gfxWuLineTo(screen,xe,ye,0xff0000);
    }

    if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);

    SDL_UpdateRect(screen, 0, 0, 0, 0);

    // oczekujemy klawisza ESC

    int waiting = 0;

    do
    {
      SDL_Event event;

      while (SDL_PollEvent(&event))
        if ((event.type == SDL_QUIT) ||
           ((event.type == SDL_KEYDOWN) &&
            (event.key.keysym.sym == SDLK_ESCAPE))) waiting = 1;
    } while(!waiting);
  }
  return 0;
}

 

obrazek

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe