Dziś jest piątek, 3 lipca 2009 roku (z kalendarza...)

Maptool

Zgodnie z wczorajszą zapowiedzią, dzisiaj o tym, jak działa program maptool potrafiący obliczać z dużą dokładnością powierzchnie różnych terytoriów z uwzględnieniem kulistego kształtu Ziemi. Danymi wejściowymi są dwa pliki: obraz PNG, w którym jednolitym kolorem zaznaczony jest obszar do obliczenia, oraz plik tekstowy zawierający parametry pozwalające odpowiednio umiejscowić obraz na powierzchni kuli. Przyjmujemy, że mapa zrobiona jest w odwzorowaniu walcowym równoodległościowym.

Samo policzenie powierzchni zakolorowanego kształtu jest trywialne. Puszczamy dwie pętle i jeśli dany piksel ma określony kolor, dodajemy go do rachunku. Rzecz w tym, że jeżeli obraz rozciągnięty jest na kuli, to w takim odwzorowaniu piksele na różnej wysokości reprezentują inną powierzchnię i naszym zadaniem jest odnalezienie wzoru, na nią. Aby program działał jak najszybciej, dobrze jest obliczyć sobie powierzchnie pikseli na każdej wysokości przed startem właściwego algorytmu i zapisać je do jakiegoś bufora. Dzięki temu nie będziemy musieli setki tysięcy razy powtarzać tych samych obliczeń.

Przyjmując, że nasza sfera składa się z bardzo malutkich, płaskich prostokącików (jak w grafice 3D) odpowiadających wielkością pikselom na obrazie, można stosunkowo łatwo wyprowadzić sobie ów wzór, wykorzystując wiadomości o liczeniu powierzchni prostokątów i wzory na długość łuku. Po dokonaniu odpowiednich przekształceń wychodzi nam, że powierzchnia pikseli na zadanej wysokości to pewien stały współczynnik k pomnożony przez cosinus szerokości geograficznej, jakiej dana wysokość na obrazku odpowiada. Sposób obliczenia k oraz pola danego piksela pokazują załączone poniżej wzory:

wzory

dx i dy odpowiadają rozpiętości geograficznej (w stopniach) podanego obrazka - wczytujemy ją z pliku tekstowego. mx i my to wysokość i szerokość obrazka w pikselach, a r to promień kuli. Kod C++ obliczający tablicę powierzchni jest następujący:

int calculate_pixel_area(m_map_info *m)
{
  m -> pixel_area = new float[m->y];
  
  float k = pow(M_PI*m->radius/180, 2)*((m->dsx*m->dsy)/(m->x*m->y));
  float deg_y = m -> dsy / m -> y;
  float di = m -> dpy;
  
  for(int i = 0; i < m -> y; i++, di -= deg_y)
  {
    m -> pixel_area[i] = k * cos(deg2rad(di));
  }
  return 0;
} // end calculate_pixel_area(); 

Teraz wystarczy tylko zmodyfikować nasze dwie pętle - ustaliwszy, ile na danej wysokości jest pikseli w danym kolorze, mnożymy tę ilość przez wartość z tablicy powierzchni i wynik dodajemy do ogólnego areału. To wszystko :).

Podany tu problem ma charakter stricte matematyczny. Wczytanie pliku PNG do pamięci, wykonanie dwóch pętli, można zrealizować w kilkanaście minut, jednak bez wyprowadzenia odpowiedniego wzoru program nie jest gotowy do żadnego działania.

Powrót

Skomentuj

NickInformacja
E-mailNa wypadek potrzeby kontaktu z autorem (niepublikowany)
BlogNie zapomnij o http://
LayoutNapisz tu, czy widzisz dzienny czy nocny layout.
WpisFormatowanie wiki
Internauto, pamiętaj! Wolność to nie samowola - dbaj o kulturę wypowiedzi oraz dyskusji w sieci.

Na Zyxist.com panuje swoboda wyrażania opinii oraz krytyki pod dowolnym adresem. Jedyny warunek: musi być ona kulturalna i rzeczowa. Na chamstwo, prostactwo lub jawne obrażanie kogokolwiek nie ma tu miejsca i takie komentarze są bardzo szybko usuwane. Jeśli zamierzasz polemizować z treścią wpisu, wpierw uważnie ją przeczytaj.

© Tomasz "Zyx" Jędrzejewski 2005 - 2009 | Wykonanych zapytań: 1 | Serwer wirtualny zapewnia