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. static void SkalujWzor(string[] dane, double skala)
  2. {
  3. int szer_glowna = dane[0].Length;
  4. int wys_glowna = dane.Length;
  5. double szer_nowa = szer_glowna * skala;
  6. double wys_nowa = wys_glowna * skala;
  7. for (int y = 0; y < wys_nowa; y++)
  8. {
  9. double mn_y = wys_glowna / wys_nowa;
  10. for (int x = 0; x < szer_nowa; x++)
  11. {
  12. double mn_x = szer_glowna / szer_nowa;
  13. Console.Write(dane[(int)(y * mn_y)][(int)(x * mn_x)]);
  14. }
  15. Console.WriteLine();
  16. }
  17. }

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. static void Main(string[] args)
  2. {
  3. Console.Write("Podaj rozmiar wzoru\n w x h = ");
  4. string[] poz = Console.ReadLine().Split();
  5. int w = Convert.ToInt32(poz[0]);
  6. int h = Convert.ToInt32(poz[1]);
  7. Console.WriteLine("Podaj wzór:");
  8. string[] dane = new string[h];
  9. for(int i = 0; i < h; i++)
  10. {
  11. dane[i] = Console.ReadLine();
  12. }
  13. Console.Write("Podaj skalę\n s = ");
  14. double skala = Convert.ToDouble(Console.ReadLine());
  15. SkalujWzor(dane, skala);
  16. Console.ReadKey();
  17. }