Processing/Geometria

Z Wikibooks, biblioteki wolnych podręczników.

Bez matematyki ani rusz[edytuj]

Na szczęście matematyka, o której tu mowa nie jest skomplikowana i w praktyce okazuje się łatwa do stosowania. W tym rozdziale mówić będziemy jedynie o podstawowych operacjach, a w przyszłych więcej o trygonometrii i podobnych wynalazkach. Teraz jednak powróćmy do podstaw - w programowaniu nawet dodawanie ma kilka postaci.


Operacje przypisania... i dodawanie[edytuj]

Zacznijmy od tzw. operacji przypisania, czyli nadawania zmiennej jakiejś wartości. Rzecz wydaje się prosta, ale przyjrzyjmy się poniższemu kodowi - czy wszystkie operacje są oczywiste?


int x = 3;
int y = 0;

y = x + 6;
y = y + 1;

println( "Wartość zmiennej y to " + y );


Na pewno pojawi się pytanie, co to za funkcja na końcu i co oznacza tam dodawanie. Wyjaśnijmy to od razu. Funkcja println wypisuje w dolnej, czarnej częsci okna Processingu wszystko, o co ją poprosimy. W naszym przypadku chcielibyśmy, żeby wypisała na ekranie wartość zmiennej y. W tym celu dodajemy napis "Wartość zmiennej y to " do zmiennej y. Co Processing z tym zrobi? odczyta, jaka jest wartość zmiennej y i doklei ją do tego napisu. W ten sposób dostaniemy:


Wartość zmiennej y to 10


Do tego tematu wrócimy jeszcze w dalszych rozdziałach. W tym momencie warto pamiętać, że jeśli chcialibyśmy podejrzeć, jakie wartości znajdują się w naszym programie to możemy wypisać je w oknie konsoli (czarny obszar na dole okna Processingu) za pomocą funckji println.

Wracamy do dodawania i przypisywania. Dwie pierwsze linie kodu są proste. Tworzymy zmienną typu całkowitego i nadajemy jej nową wartość. Co dzieje się w liniach 4 i 5?


x = x + 1 to nie to samo, co x = x + 1[edytuj]

Na lekcjach matematyki uczyliśmy się, że:


x = x + 1
x - x = 1
0 = 1

Równianie sprzeczne


W programowaniu jest trochę inaczej - tutaj prawa i lewa strona nie są wymienne. Processing wie, że najpierw ma wykonać wszystkie działania po prawej stronie znaku równości, a następnie przekazać ich wartość temu, co znajduje się po lewej stronie znaku równości. W poprzednim przykładzie (linie 4-5) mieliśmy zatem taką kolejność wykonuwania kodu:


// Linia numer 4: y = x + 6;
Liczę wartość wyrażenia po prawej stronie --> x + 6
    zmienna x --> 3
    3 + 6 --> 9
Przypisuję zmiennej y (obojętnie jaką wartość miała wcześniej) wartość 9

// Linia numer 5: y = y + 1;
Liczę wartość wyrażenia po prawej stronie --> y + 1
    zmienna y --> 9
    9 + 1 --> 10
Przypisuję zmiennej y (obojętnie jaką wartość miała wcześniej) wartość 10


Można zatem powiedzieć, że - w odróżnieniu od matematyki - w programowaniu znak = oznacza: temu, co znajduje się po lewej stronie znaku, przypisz (nadaj) wartość wyrażenia znajdującego się po prawej stronie znaku. Znaczy to, że Processing widząc linię kodu zawierającą znak = czyta ją od znaku = do końca w prawo, a następnie cofa się jeden krok w lewo. W sumie to proste.


Matematyka dla leniwych[edytuj]

Jeśli w programowaniu można napisać coś skrótem, to pewnie da się napisać to skrótem. Często jest tak, jak w ostatnim przykładzie - chcielibyśmy dodać do zmiennej jakąś wartość:


int x = 8;

// jakis kod

// zwieksz wartosc zmiennej x o 5
x = x + 5;


Taką operację można zapisać następującym skrótem:


// dodaj 5 do aktualnej wartosci zmiennej x
x += 5;


Co więcej - takie skróty dotyczą wszytkich podstawowych operacji matematycznych.


int x = 2;

// dodaj 3 do aktualnej wartosci zmiennej x
x += 3;

// odejmij 1 od aktualnej wartosci zmiennej x
x -= 1;

// pomnóż aktualną wartość zmiennej x przez 3
x *= 3;

// podziel aktualną wartość zmiennej x przez 2
x /= 2;

println( "Wartość zmiennej x to " + x );


Wartość zmiennej powinna wynosić 6.


Skrót skrótu[edytuj]

Wyobraźmy sobie taką sytuację. Piszemy program, który odtwarza plik filmowy (a będziemy taki pisać w dalszej części podręcznika). Naciskamy play i klatka po klatce film wyświetlany jest na ekranie. Żeby wiedzieć, czy znajdujemy się już w połowie, czy dopiero na początku filmu, mamy zmienną frameCounter (licznik klatek), która zwiększa się o jeden po każdej wyświetlonej klatce filmu. Nasz algorytm mógłby wyglądać tak:


wyświetl nową klatkę filmu

frameCounter += 1;


I tak w kółko. Programiści wynaleźli na taką operację specjalną nazwę i bardzo przydatny skrót, który ma dwie wersje*:


frameCounter++;  // to jest inkrementacja
frameCounter--;  // a to jest dekrementacja


W pierwszym przypadku dodajemu 1 do wartości zmiennej frameCount, w drugim przypadku 1 od niej odejmujemy. W pewnym sensie efekt działania jest identyczny dla poniższych lini kodu:


frameCounter++;
frameCounter += 1;


Wbrew pozorom inkrementacja to bardzo przydatna sprawa i od następnego rozdziału korzystać z niej będziemy bezustannie!!


* - tak naprawdę instnieją cztery wersje, a nie dwie. Pozostałe dwie poznamy jednak później, bo w chwili obecnej nie mają one dla nas większego znaczenia.

Trzy przez dwa[edytuj]

Dzielenie to nie fizyka kwantowa - trzy przez dwa to przecież półtora.


int result = 3 / 2;

println( "Trzy przez dwa to " + result );


Jak to 1?! Czyżby się Processing pomylił?! Przyjrzyjmy się dokładnie powyższemu fragmentowi kodu. Jak widać dzielimy liczby całkowite i w dodatku zapisujemy wynik w zmiennej cełkowitej. Processing nie miał szansy pokazania nam tego, co po przecinku - prosimy o liczbę całkowitą, dostajemy całkowitą! Spróbujmy zatem zmienić zmienną result na liczbę z przecinkiem:


float result = 3 / 2;

println( "Trzy przez dwa to " + result );


1.0?! O co chodzi?! Znów jednak przyjrzyjmy się dokładniej przykładowi i zastanówmy, jak Processing wykonuje pierwszą linię kodu - krok po kroku:


// float result = 3 / 2;
Widzę operację przypisania (=) - zaczynam od prawej strony znaku =
    3 / 2 --> dzielenie:
        3 to liczba całkowita
        2 to też liczba całkowita
    wynik jest zatem liczbą całkowitą --> 1
Cofam się o krok i wykonuję operację przypisania:
    result --> zmienna z przecinkiem
    1 --> liczba całkowita
        przekonwertuj liczbę całkowitą na z przecinkiem, żeby pasowała do zmiennej result
        1 --> 1.0
    result --> 1.0


Uff... Trochę to pogmatwane. Lekcja jednak z tego taka, że jeśli wykonujemy dowolną operację matematyczną na liczbach całkowitych, wynik tej operacji będzie całkowity - nawet jeśli w ten sposób stracimy dokładność obliczeń. Jak się później okaże czasami bywa to bardzo przydatne. Pamiętajmy bowiem, że działamy na monitorze podzielonym na piksele i nie ma piksela numer 2.4 ani współrzędnej (24.7, 61.9).

Jak jednak poradzić sobie z naszym prostym dzieleniem? Rozwiązanie jest następujące: z obu stron znaku przypisania (=) musimy mieć liczbę z przecinkiem.


float result = 3.0 / 2.0;

println( "Trzy przez dwa to tak naprawdę " + result );


Udało się!! Processing policzył z przecinkami wynik i przypisał go zmiennej przecinkowej wartość tych obliczeń. Czy to znaczy, że musimy wszystkie operacje z przecinkiem pisać z zerami? I tak i nie. Można wykorzystać taką cechę Processingu, że gdy w operacji matematycznej pojawia się choćby jedna liczba z przecinkiem, Processing automatycznie zamienia tę drugą na przecinkową. Należy jednak na to uważać, bo...


Kto pierwszy, kto drugi[edytuj]

Processing liczy proste wyrażenia tak jak my robimy to na lekcjach matematyki: najpierw to, co w nawiasach, później mnożenie i dzielenie, a na końcu dodawania i odejmowanie. Zmiany z liczb całkowitych na przecinkowe dokonuje się z zachowaniem tych zasad, co w praktyce oznacza, że:


float result = 3 / 2 + 0.1;

println( "Coś tu chyba nie gra: " + result );


Wyszło 1.1 zamiast 1.6. Dlaczego? Dlatego, że Processing najpierw podzielił dwie liczby całkowite i dostał całkowity wynik (1), po czym dodał ten wynik do liczby z przecinkiem. W tymc celu zamienił 1 na 1.0 i dodał 0.1. Wszystko gra. Tylko, że nie o to nam chodziło. Należałoby zatem napisać tak:


float result = 3 / 2.0 + 0.1;

println( "Teraz chyba gra: + " result );


Łatwo tu o pomyłki. Często będzie tak, że nasz program będzie działał, ale to, co zobaczymy na ekranie nie będzie odpowiadało naszym oczekiwaniom. W wielu przypadkach okaże się, że miało być 1.5 * 2, a wyszło 1 * 2, bo gdzieś wcześniej wykonaliśmy operacje na liczbach całkowitych, a nie przecinkowych.


A co z resztą?=[edytuj]