<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="/cjs/screen.xsl" media="screen"?>
<lecture>

<meta>
  <maintitle>Python</maintitle>
  <author>Jiří Znamenáček</author>
  <title>„Želví“ grafika – rekurzivní obrazce</title>
  <date>2015-10-06</date>
  <link><!--a href="http://vyuka.ookami.cz" rel="external">http://vyuka.ookami.cz</a--></link>
</meta>
<!--
  „“–…
  ←→ ↑↓ ↔↕
  ↵ aneb &#x21B5; aneb \r aneb CR aneb CarriageReturn
-->


<slide title="Úvod">

    <p>
        Jedním z velmi zábavných (a navíc ještě užitečných :-) použití želví grafiky je kreslení fraktálních obrazců pomocí rekurze (nebo smyček). V této přednášce si na příkladu stromu rozebereme základní principy, a pak se je pokusíme ještě trochu vylepšit.
    </p>
    <p>
        PS: Mimochodem existují i rozšíření želví grafiky do tří rozměrů, která se používají kupříkladu pro reálně vypadající imitace rostlin.
    </p>

</slide>
<slide title="Zadání příkladu">

    <p>
        Naším úkolem je nakreslit přibližně následující „stromeček“:
    </p>
    <img src="_files/stromecek_0.png" width="319" height="245" alt="" title="Fraktální stromeček" />
    <p>
        Na první pohled to vypadá asi skoro nemožně, leč už na ten druhý je jasné, že stromeček je tvořen vždy dvěma zmenšenými kopiemi svého kmene na jeho konci, a to tak dále na každé kopii až po nějakou mez.
    </p>

</slide>
<slide title="Rozbor zadání I">

    <p>
        Co musí naše „želva“ udělat, aby požadovaný stromeček nakreslila? Následující:
    </p>
    <ul>
        <li>
            z výchozího místa nakreslit kmen zadané délky;
        </li>
        <li>
            na jeho konci nakreslit větev (= kmen kratší délky) pod jistým úhlem doleva;
        </li>
        <li>
            na jeho konci nakreslit větev (= kmen kratší délky) pod jistým úhlem doprava;
        </li>
        <li>
            na koncích obou větví zopakovat úplně to samé.
        </li>
    </ul>

</slide>
<slide title="Rozbor zadání II – invariantní funkce">

    <p>
        Rekurzivní krok je asi celkem jasný – na konci každého kmene/větve s želvou otočenou příslušným směrem ji necháme nakreslit kopii předchozí práce ve zmenšeném měřítku. A to hned dvakrát – jednou směrem vlevo, podruhé vpravo.
    </p>
    <p>
        Zároveň je asi také jasné, že aby to mohlo fungovat, musí „želva“ po dokončení práce na příslušné (zmenšené) kopii stát opět na konci předchozí větve, jinak by pokus o vykreslení kopie druhým směrem začal na úplně špatném místě.
    </p>
    <note>
        Což mimochodem znamená, že po dokončení kreslení stromu bude „želva“ stát ve výchozí pozici otočená stejným směrem jako na začátku!
    </note>
    <p>
        Odborně se tomu říká, že (příslušná rekurzivní) funkce musí být <strong>stavovým invariantem</strong> (<em>state invariant</em>) – jejím voláním se sice něco stalo (nakreslily se další části stromu), nicméně po jejím ukončení se „želva“ nachází ve stejném stavu jako na jejím začátku.
    </p>

</slide>
<slide title="Náčrt bez rekurze">

    <p>
        Ukažme si vykreslení do druhé úrovně (tedy pouze kmen a první dvojce větví) procedurálním kódem bez jakékoliv rekurze:
    </p>
    <img src="_files/stromecek_1.png" width="151" height="179" alt="" title="Fraktální stromeček – náčrt" />
    <example lang="python" src="_files/stromecek_1.py" />

</slide>
<slide title="A nyní s rekurzí">

    <p>
        Zkusme to nyní celé zapsat rekurzivně:
    </p>
    <example lang="python" src="_files/stromecek_2.py" />
    <p>
        Tohle pochopitelně ještě nebude fungovat, protože rekurze se bude donekonečna zanořovat pořád na levou část stromu. Ale už je aspoň vidět, jak to celé vypadá.
    </p>

</slide>
<slide title="Ukončení rekurze">

    <p>
        Jelikož rekurze se musí někdy zarazit, nemá-li býti nekonečná, náš program se kapku zesložití o ukončovací podmínku (tou může být třebas jako zde vykreslovaná délka větví nebo počet zanoření do rekurze). Zároveň jsem přesunul spočítání délky nových větví do vlastní proměnné:
    </p>
    <img src="_files/stromecek_3.png" width="365" height="266" alt="" title="Fraktální stromeček" />
    <example lang="python" src="_files/stromecek_3.py" />

</slide>
<slide title="Reálněji vypadající strom I">

    <p>
        Ačkoli jsem v předchozím příkladu trochu upravil úhly a vzdálenosti, výsledek je stejně takový nemastný neslaný – je totiž až příliš symetrický. A má málo listů ^_^ Ale nikdo nám vlastně nenakázal, že oba rekurzivní kroky musí být úplně stejné. Nebo že musí být právě jenom dva. A už vůbec ne, že všechny „větve“ musí vycházet ze stejného místa:
    </p>
    <img src="_files/stromecek_4.png" width="210" height="264" alt="" title="Fraktální stromeček" />
    <example lang="python" src="_files/stromecek_4.py" />
    <note>
        Upraveno podle: <a href="https://www.cs.berkeley.edu/~bh/v1ch10/turtle.html" class="external"><em>Computer Science Logo Style -- Volume 1: Symbolic Computing</em></a>
    </note>

</slide>
<slide title="Reálněji vypadající strom II">

    <p>
        Když už jsme v tom, přihodíme ještě i barvu. Jen nesmíme zapomenout dodržovat invarianci i pro ni:
    </p>
    <img src="_files/stromecek_4c.png" width="206" height="261" alt="" title="Fraktální stromeček barevně" />
    <example lang="python" src="_files/stromecek_4c.py" />

</slide>
<slide title="L-systémy – simulace (nejen) růstu organismů">

    <p>
        Po posledním příkladě asi nepřekvapí, že už dávno někoho napadlo použít želví grafiku, rekurzi a fraktály k simulaci skutečných rostlin, respektive obecně k simulaci růstu organismů. Konkrétně to byl Aristid Lindenmayer v roce 1968, který vymyslel tzv. <strong>L-systémy</strong> (aka <em>Lindenmayerovy systémy</em>). O těch ale <a href="/materialy/techs/L-systems/overview.xml">až jinde</a>.
    </p>

</slide>


</lecture>
