Strona główna » Algorytmy » Artykuły » Konsolowe Skalowanie
 

Konsolowe Skalowanie

Zadanie

Napisz program, który wczyta od użytkownika pewien wzór złożony z znaków alfanumerycznych oraz skalę s. Następnie wypisz na konsolę ten sam wzór zeskalowany o wczytaną wcześniej wartość. Wczytana wartość skalowanie może być dowolną liczbą rzeczywistą większą od 0.

Przykład

Przypuśćmy, że użytkownik wpisze następujący wzór:

  1. ab
  2. cd

Zadana skala wynosi 2, a więc wzór zostanie powiększony dokładnie 2 razy:

  1. aabb
  2. aabb
  3. ccdd
  4. ccdd

Analiza zadania

Do powiększania wzoru zostanie zastosowana technika najbliższego sąsiada. Metoda ta polega na kopiowaniu sąsiednich wartości w przypadku zwiększania, a jeśli wzór będzie zmniejszany to analogicznie pewne wartości zaczną znikać. W celu rozszerzenia / skrócenia linijki danych należy wyliczyć stosunek starej szerokości do nowej mn, a następnie dla każdej nowej pozycji pobrać wartość pod indeksem, który jest iloczynem aktualna pozycji oraz wyliczonej wartości mn.

Przykładowo rozszerzamy dwukrotnie linijkę ab. W tym celu wyliczamy nową szerokość czyli 4, a następnie przechodzimy do wyliczania wartości. Mnożnik mn wynosi 1/2=0.5. W tabelce zebrano potrzebne informacje:

Nowa pozycja0123
Wyliczona wartość00.511.5
Stara pozycja0011
Znakaabb

Wyliczonej wartości na podstawie indeksu nowej pozycji należy obciąć część ułamkową. Dzięki temu możliwe będzie pobranie wartości z starej linijki. Na koniec obliczona wartość wskazuje indeks pozycji do pobrania z danych.

Implementacja

Poniższa funkcja SkalujWzor() jest rozwiązaniem omawianego problemu. Przyjmuje ona tablicę łańcuchów znaku, gdzie przechowywany jest wzór oraz skalę - liczbę rzeczywistą.

  1. void SkalujWzor(vector<string> dane, double skala) {
  2.   int szer_glowna = dane[0].size();
  3.   int wys_glowna = dane.size();
  4.   double szer_nowa = szer_glowna * skala;
  5.   double wys_nowa = wys_glowna * skala;
  6.   for (int y = 0; y < wys_nowa; y++) {
  7.     double mn_y = wys_glowna / wys_nowa;
  8.     for (int x = 0; x < szer_nowa; x++) {
  9.       double mn_x = szer_glowna / szer_nowa;
  10.       cout << dane[(int)(y*mn_y)][(int)(x*mn_x)];
  11.     }
  12.     cout << endl;
  13.   }
  14. }

Na początku pobierana jest akualna szerokość oraz wysokość, a następnie wyliczana nowa szerokość i wysokość. Dla każdej nowej pozycji zeskalowanego obiektu: należy obliczyć, którą wartość należy przepisać z danych. Warto pamiętać, że interpolację przeprowadzamy zarówno wzdłuż szerokości jak i wysokości, a więc potrzebny jest inny mnożnik dla każdej współrzędnej. (W przypadku równomiernego skalowania i kwadratowego obrazka wystarczyłby jeden mnożnik.)

Testowanie funkcji

Test kodu można przeprowadzić używając poniższego fragmentu kodu, który wczyta potrzebne dane, a następnie wypisz wynik na ekran.

  1. int main() {
  2.   int w, h;
  3.   double skala;
  4.   cout << "Podaj rozmiar wzoru\n w x h = ";
  5.   cin >> w >> h;
  6.   cout << "Podaj wzor:" << endl;
  7.   vector<string> dane;
  8.   string line;
  9.   cin.ignore();
  10.   while (h > 0) {
  11.     getline(cin, line);
  12.     dane.push_back(line);
  13.     h--;
  14.   }
  15.   cout << "Podaj skale\n s = ";
  16.   cin >> skala;
  17.   SkalujWzor(dane, skala);
  18.   system("pause");
  19.   return 0;
  20. }