Chyba prędzej czy później każdy, kto choć trochę programuje ma ochotę/musi/powinien narysować coś na ekranie: może to być wykres funkcji matematycznej, czy też jakieś dane do zobrazowania. Siadamy do komputera, zaczynamy pisać kod, dochodzimy do fragmentu, w którym należy wskazać współrzędne punktu do postawienia na formie naszego projektu i ... zatrzymujemy się.
W tym właśnie momencie uświadamiamy sobie, że mamy kilka problemów do rozwiązania:
Wszystkie te kwestie sprowadzają się do pytania : jak zmieścić obszar matematyczny na obszarze fizycznym naszego ekranu? Domyślamy się, że trzeba jakoś ‘przetłumaczyć’ współrzędne ze świata naszej funkcji na ekranowe. Często spotykam w źródłach, że autor mnoży współrzędne przez jakąś liczbę, a potem cos jeszcze dodaje i nie wiadomo, dlaczego akurat takie liczby dobrał . W prostych przypadkach można je ustalić metodą prób i błędów. Ja chciałem natomiast mieć rozwiązanie uniwersalne – sprawdzające się w możliwie największej liczbie przypadków i wydaje się, że cel zostal osiągnięty.
Kilka słów niezbędnej teorii
Jeśli chcemy przeskalować przedzial X=[x1,x2] na X’= [x3,x4], to musimy ten pierwszy rozciągnąć/ścisnąć i/lub przesunąć w lewo/prawo – ujmuje to wzór: x’= A x+ B, gdzie współczynnik A wyraża zmianę ‘szerokości’ przedziału, a B – przesunięcie.
Współczynniki A i B znajdziemy z dwóch naturalnych warunków:
Lewy koniec (x1) przedziału X ma przejść na lewy koniec (x3) przedzialu X’ i analogicznie prawe końce.
Zapisując ogólną zależność x’=Ax+B dla tych szczególnych przypadków dostajemy układ równań:
x3=A x1+B x4=A x2+B
którego rozwiązaniem jest
A= -(x4-x3)/(x1-x2) B= -(x2x3-x1x4)/(x1-x2)
Mam nadzieję, że teraz będzie jasne nasze postępowanie w przypadku 2-wymiarowym. Przekształcamy parę punktów (xr,yr) na (xs,ys) zgodnie ze wzorem:
xs=A xr+B ys=C yr+D

Podobnie jak poprzednio – A,B,C i D wyliczamy z żądań, by odpowiednie boki obszarów przechodziły na siebie:
- lewy bok przestrzeni matematycznej na lewy przestrzeni ekranowej:
xs0=A xrmin+B
xs0+swidth=A xrmax+B
ys0=C yrmax+D
ys0+sheight=C yrmin+D
Rozwiązując układ tych 4 równań (leniwce mogą użyć darmowego oprogramowania w rodzaju wxMaxima czy też komercyjnego Mathematica) otrzymujemy:
A= swidth/(-xrmax+xrmin) B= -(swidth xrmin-xrmax xs0+xrmin xs0)/(xrmax-xrmin) C= -sheight/(yrmax-yrmin) D= (sheight yrmax)/(yrmax-yrmin)
Analogicznie obliczamy współczynniki przy przechodzeniu z przestrzeni ekranu do przestrzeni matematycznej:
xr=E xs+F yr=G ys+H
otrzymując:
E = -((-xrmax + xrmin) / swidth); F = -((-swidth * xrmin + xrmax * xs0 - xrmin * xs0) / swidth); G = -((yrmax - yrmin) / sheight); H = -((-sheight * yrmax - yrmax * ys0 + yrmin * ys0) / sheight);
Implementacja
Pora teraz odnieść jakieś praktyczne korzyści z naszych obliczeń. Napisałem małą klasę Scaling, która ma za zadanie realizować opisane wyżej przekształcenia ekran<->przesteń matematyczna.
Użycie jej we własnym projekcie wymaga dodania odpowiedniej referencji.
W konstruktorze:
Scaling(double xrmin, double xrmax, double yrmin, double yrmax,int xs0, int ys0, int swidth, int sheight)
ustalamy obszary:
Metody:
int getScreenX(double xr) int getScreenY(double yr)
double getRealX(int xs) double getRealY(int ys)
Ponieważ polecenia graficzne .NET często wymagają podania rozpiętości poziomej i pionowej jakiegoś obiektu (np. elipsy) - pomocne mogą być metody:
int getScreenDX(double x0, double x1) int getScreenDY(double y0, double y1)
Na koniec, żeby ewentualnym niedowiarkom udowodnić działanie tego wszystkiego, zrzut ekranu z aplikacji, której kod źródłowy można ściągnąc stąd.

|
|