Obsah
1. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
3. Funkce vnoise, vsnoise a Perlinův šum
4. Úplný zdrojový kód demonstračního příkladu clisktest4
5. Podpora pro vykreslování fraktálů
7. Kubická Mandelbrotova množina
8. Úplný zdrojový kód demonstračního příkladu clisktest5
9. Repositář s demonstračními příklady
10. Odkazy na předchozí části seriálu
1. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
V dnešní části seriálu, v němž se zabýváme různými obvyklými i poněkud neobvyklými aspekty programovacího jazyka Clojure a taktéž knihovnami, které mohou programátoři pracující v jazyku Clojure použít, dokončíme popis knihovny Clisk. Tato knihovna mj. podporuje tvorbu textur s využitím takzvané Perlinovy šumové funkce, která má v počítačové grafice široké možnosti využití, a to jak pro tvorbu běžných dvourozměrných textur, tak i textur trojrozměrných (volumetrických) či čtyřrozměrných (animované mraky atd.). Ve druhé kapitole si popíšeme princip této funkce, její konkrétní využití je naznačeno v kapitole třetí. V navazujících kapitolách bude zmíněna možnost využití fraktálů pro tvorbu textur, následně (ale až v příští části) si popíšeme již existující (předdefinované) textury a nakonec si ukážeme jeden ze způsobů využití Voroného diagramů při vytváření uživatelsky definovaných textur.
Obrázek 1: Perlinova šumová funkce použitá při generování dvourozměrných textur. Pro vytvoření tohoto obrázku byla použita barvová paleta mapující výsledné hodnoty z rozsahu 0 až 1 na vybraných 256 barev.
2. Perlinova šumová funkce
Perlinova šumová funkce (Perlin noise (function)) byla s velkým úspěchem použita v mnoha aplikacích počítačové grafiky; například prakticky každý film, ve kterém je využita renderovaná grafika (CG), tuto funkci nějakým způsobem použil. Její úspěch spočívá v tom, že se pomocí ní dají do původně přesných a „počítačově chladných“ modelů vnést náhodné prvky, takže se model či celá vytvářená scéna více přiblíží realitě. Podobný princip vnesení náhodnosti ostatně umožňují i fraktály, zejména ty vytvářené na stochastickém základě (plasma, stochastické L-systémy apod.). Ken Perlin svoji šumovou funkci navrhl už v roce 1983, v roce 1985 o její aplikaci vznikl článek prezentovaný na SIGGRAPHu (jedna z nejvýznamnějších konferencí počítačové grafiky) a v letech 1986 až 1988 tuto funkci s některými modifikacemi používaly takové firmy, jako Pixar, Alias, SoftImage apod. Dnes ji mj. najdeme například i v raytraceru POVRay.
Obrázek 2: Aplikace Perlinovy šumové funkce při tvorbě trojrozměrných (volumetrických) textur. Povšimněte si, že nikde nedochází k tvorbě „polů“, které by byly při použití běžné dvourozměrné textury jasně viditelné.
Při tvorbě textur, které by měly reprezentovat přírodní vzorky jako je mramor, dřevo či mraky, není možné použít ani klasický generátor pseudonáhodných čísel RNG (tím je myšlena například funkce rand() ze standardní céčkové knihovny), ale ani základní matematické funkce. V minulosti byly prováděny pokusy o využití goniometrických funkcí, které posléze vyústily v úspěšnou metodu generování plasmy pomocí Fourierovy syntézy. Při přímé aplikaci generátorů pseudonáhodných čísel sice získáme šum, ten je však příliš náhodný a vůbec se nehodí pro generování textur, a to ani po své filtraci. Perlin pro účely vytváření přírodních textur navrhl výpočet, který sice využívá generátor pseudonáhodných čísel, ale mezi jednotlivými vypočtenými náhodnými hodnotami je prováděna interpolace, která výsledný průběh funkce vyhladí, takže se již nebude jednat o zcela náhodný šum. Pro vyhlazení je možné použít velké množství matematických funkcí, od jednoduché lineární interpolace přes kvadratické a kubické funkce až po funkce goniometrické a jejich vzájemné kombinace.
Obrázek 3: Jednorozměrná Perlinova šumová funkce s parametry alpha=2, beta=2, n=10. Změnou těchto parametrů je možné řídit vyhlazování průběhu, četnost změn apod.
Dvourozměrný Perlinův šum je vypočten prakticky stejným způsobem jako šum jednorozměrný. Jediný podstatný rozdíl spočívá v tom, že se interpolace provádí ve dvou směrech a výsledek této interpolace je sečten. V praxi se opět používá součet několika šumových funkcí s klesající amplitudou a rostoucí „frekvencí“. Dvourozměrné textury však mají pro použití v praxi několik vážných nevýhod, z nichž největší nevýhoda spočívá v obtížném mapování na nerovné povrchy. Například mapování obdélníkové dvourozměrné textury na kouli vede k tomu, že se textura na pólech smrští a naopak na rovníku příliš roztáhne. Výsledek je většinou neuspokojivý, zvláště při aplikaci šumové funkce (ta by měla být směrově invariantní). Přechodem k výpočtům 3D (volumetrických) textur se tohoto problému zbavíme (viz obrázek číslo 2, protože pro každý bod v prostoru je možné zjistit hodnotu šumu bez nutnosti mapování.
Obrázek 4: Aplikace dvourozměrné Perlinovy šumové funkce s parametry alpha=2, beta=2, n=10. Opět je použita barevná paleta.
3. Funkce vnoise, vsnoise a Perlinův šum
V knihovně Clisk je Perlinova šumová funkce implementována ve funkcích nazvaných vnoise a vsnoise. Počáteční písmeno těchto funkcí naznačuje, že výsledkem výpočtu je vektor, a to konkrétně čtyřrozměrný vektor. V případě funkce vnoise mohou jednotlivé složky vektoru nabývat hodnot z rozsahu 0 až 1, u funkce vsnoise je pak rozsah rozšířen na –1 až 1 (což zjednodušuje některé výpočty). To znamená, že funkce vnoise a vsnoise je možné použít jak pro generování dvourozměrných textur (což si ukážeme v demonstračním příkladu), tak i pro tvorbu trojrozměrných (volumetrických) textur. V případě dvourozměrných textur je návratová hodnota použita pro určení barvových složek red, green a blue, pro vytvoření monochromatické textury lze použít funkci monochrome. Podívejme se na jednoduchý příklad použití Perlinovy funkce v praxi:
(defn noise-patterns-test "Otestování funkce vnoise a vsnoise." [noise-function filename-prefix] (let [patterns [noise-function (monochrome noise-function) (scale 1/10 noise-function) (monochrome (scale 1/10 noise-function)) (v- (v* 5 noise-function) 1) (scale 1/4 (offset noise-function (checker yellow blue))) (scale 1/4 (offset (v* 1/5 noise-function) (checker yellow blue))) (scale 1/4 (offset (v* 1/2 noise-function) (checker yellow blue))) (scale 1/4 (offset (v* 2 noise-function) (checker yellow blue))) (scale 1/4 (offset (v* 5 noise-function) (checker yellow blue))) (scale 1/4 (rotate (v* 5 noise-function) (checker yellow blue))) (scale 1/4 (rotate (v* 5 noise-function) (offset (v* 5 noise-function) (checker yellow blue)))) ]] ; postupně projít všemi prvky vektoru "patterns", vytvořit ; dvouprvkový vektor [index+patter], vytvořit jméno výstupního ; souboru a následně zavolat funkci write-pattern (doseq [ [i pattern] (map-indexed vector patterns)] (write-pattern pattern (construct-filename filename-prefix i))))) (println "Vnoise test...") (noise-patterns-test vnoise "vnoise") (println "Done") (println "Vsnoise test...") (noise-patterns-test vsnoise "vsnoise")
Obrázek 5: Textura vytvořená s využitím výrazu vnoise-function. Pro každý pixel textury je vypočten vektor převedený na barvu (složky vektoru odpovídají barvovým složkám red, green a blue).
Obrázek 6: Textura vytvořená s využitím výrazu (monochrome vnoise-function). Funkce monochrome slouží k převodu z prostoru RGB na stupně šedi (monochromatický obrázek).
Obrázek 7: Textura vytvořená s využitím výrazu (scale 1/10 vnoise-function). Funkce scale zde provádí změnu měřítka (samozřejmě bez ztráty kvality).
Obrázek 8: Textura vytvořená s využitím výrazu (monochrome (scale 1/10 vnoise-function)).
Obrázek 9: Textura vytvořená s využitím výrazu (v- (v* 5 vnoise-function) 1).
Obrázek 10: Textura vytvořená s využitím výrazu (scale 1/4 (offset vnoise-function (checker yellow blue))). Perlinův šum je zde použit nepřímo pro změnu souřadnic bodů, které tvoří vstup do funkce checker).
Obrázek 11: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 1/5 vnoise-function) (checker yellow blue))). Zmenšení amplitudy posunu bodů.
Obrázek 12: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 1/2 vnoise-function) (checker yellow blue))).
Obrázek 13: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 2 vnoise-function) (checker yellow blue))). Zvětšení amplitudy posunu bodů.
Obrázek 14: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 5 vnoise-function) (checker yellow blue))). Zvětšení amplitudy posunu bodů.
Obrázek 15: Textura vytvořená s využitím výrazu (scale 1/4 (rotate (v* 5 vnoise-function) (checker yellow blue))). 3D rotace v RGB prostoru.
Obrázek 16: Textura vytvořená s využitím výrazu (scale 1/4 (rotate (v* 5 vnoise-function) (offset (v* 5 vnoise-function) (checker yellow blue))))
Obrázek 17: Textura vytvořená s využitím výrazu vsnoise-function.
Obrázek 18: Textura vytvořená s využitím výrazu (monochrome vsnoise-function).
Obrázek 19: Textura vytvořená s využitím výrazu (scale 1/10 vsnoise-function).
Obrázek 20: Textura vytvořená s využitím výrazu (monochrome (scale 1/10 vsnoise-function)).
Obrázek 21: Textura vytvořená s využitím výrazu (v- (v* 5 vsnoise-function) 1).
Obrázek 22: Textura vytvořená s využitím výrazu (scale 1/4 (offset vsnoise-function (checker yellow blue))).
Obrázek 23: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 1/5 vsnoise-function) (checker yellow blue))).
Obrázek 24: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 1/2 vsnoise-function) (checker yellow blue))).
Obrázek 25: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 2 vsnoise-function) (checker yellow blue))).
Obrázek 26: Textura vytvořená s využitím výrazu (scale 1/4 (offset (v* 5 vsnoise-function) (checker yellow blue))).
Obrázek 27: Textura vytvořená s využitím výrazu (scale 1/4 (rotate (v* 5 vsnoise-function) (checker yellow blue))).
Obrázek 28: Textura vytvořená s využitím výrazu (scale 1/4 (rotate (v* 5 vsnoise-function) (offset (v* 5 vsnoise-function) (checker yellow blue)))).
4. Úplný zdrojový kód demonstračního příkladu clisktest4
V této kapitole bude uveden výpis úplného zdrojového kódu dnešního prvního demonstračního příkladu nazvaného clisktest4, z něhož jsme používali úryvky a ukázky v předchozí kapitole:
Obsah souboru project.clj:
(defproject clisktest2 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] [net.mikera/clisk "0.10.0"]] :main ^:skip-aot clisktest4.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Obsah souboru core.clj:
(ns clisktest4.core (:gen-class) (:use clisk.live)) (import java.io.File) (import javax.imageio.ImageIO) (defn write-image "Uložení rastrového obrázku typu BufferedImage do souboru." [image file-name] (ImageIO/write image "png" (File. file-name))) (defn write-pattern "Vytvoření rastrového obrázku na základě předaného patternu." [pattern file-name] (write-image (image pattern) file-name)) (defn construct-filename [filename-prefix index] (format "%s_%02d.png" filename-prefix index)) (defn noise-patterns-test "Otestování funkce vnoise a vsnoise." [noise-function filename-prefix] (let [patterns [noise-function (monochrome noise-function) (scale 1/10 noise-function) (monochrome (scale 1/10 noise-function)) (v- (v* 5 noise-function) 1) (scale 1/4 (offset noise-function (checker yellow blue))) (scale 1/4 (offset (v* 1/5 noise-function) (checker yellow blue))) (scale 1/4 (offset (v* 1/2 noise-function) (checker yellow blue))) (scale 1/4 (offset (v* 2 noise-function) (checker yellow blue))) (scale 1/4 (offset (v* 5 noise-function) (checker yellow blue))) (scale 1/4 (rotate (v* 5 noise-function) (checker yellow blue))) (scale 1/4 (rotate (v* 5 noise-function) (offset (v* 5 noise-function) (checker yellow blue)))) ]] ; postupně projít všemi prvky vektoru "patterns", vytvořit ; dvouprvkový vektor [index+patter], vytvořit jméno výstupního ; souboru a následně zavolat funkci write-pattern (doseq [ [i pattern] (map-indexed vector patterns)] (write-pattern pattern (construct-filename filename-prefix i))))) (defn -main [& args] (try (println "Vnoise test...") (noise-patterns-test vnoise "vnoise") (println "Done") (println "Vsnoise test...") (noise-patterns-test vsnoise "vsnoise") (println "Done") (catch Throwable e (println (.toString e))) (finally ; jistota, že program vždy korektně skončí (System/exit 0))))
5. Podpora pro vykreslování fraktálů
V knihovně Clisk je podporováno i generování textur s využitím fraktálů, přesněji řečeno takových fraktálů, které lze vykreslit v rovině takovým způsobem, že se každému bodu (popř. pixelu) přiřadí barva na základě počtu iterací nutných pro splnění nějaké podmínky, přičemž vstupními informacemi pro výpočet je pozice bodu v rovině nebo v prostoru, maximální počet iterací, podmínka pro ukončení výpočtu a taktéž funkce použitá pro obarvení bodu. Do této kategorie fraktálů spadají prakticky všechny známé fraktály vykreslované v komplexní rovině, především pak Mandelbrotova množina, Newtonova množina, fraktály typu Phonenix, Magnet apod. V navazujících dvou kapitolách si ukážeme použití knihovny Clisk pro vykreslení klasické Mandelbrotovy množiny i kubické Mandelbrotovy množiny.
Obrázek 29: Mandelbrotova množina (zvětšeno).
Obrázek 30: Newtonova množina.
Obrázek 31: Fraktál typu Magnet.
Obrázek 32: Fraktál typu Magnet (odlišný způsob zobrazení).
6. Mandelbrotova množina
Mandelbrotova množina je vytvořena pomocí jednoduchého dynamického systému, který je založený na iteraci funkce komplexní paraboly:
zn+1=zn2+c
kde proměnné z a c leží v komplexní rovině.
V průběhu výpočtu se hodnota z postupně mění, zatímco hodnota c zůstává konstantní – tato se mění pouze při přesunu výpočtu na nový bod. Celý iterační proces začíná s určitou startovní hodnotou z0, takže systém postupně generuje sekvenci hodnot zk, které nazýváme orbit. Postup si ukážeme na prvních čtyřech iteracích:
z1=(z0)2+c
z2=((z0)2+c)2+c
z3=(((z0)2+c)2+c)2+c
z4=((((z0)2+c)2+c)2+c)2+c
Při práci se systémem popsaným v předchozím textu nás zajímá, zda pro danou startovní hodnotu z0 a konstantu c posloupnost zk konverguje či diverguje. Ukazuje se, že pro některé počáteční hodnoty nastává také oscilace – hodnoty zk se opakují s určitou periodou, to znamená, že platí rovnost zk=zk+i, kde i je perioda oscilace. Bližším studiem vlivu počátečních podmínek na budoucí stav systému se zabýval právě Benoit B. Mandelbrot a před ním i Fatou.
Mandelbrot se omezit na případ, kdy počáteční hodnota z0 je nulová a pro každý počítaný bod se mění pouze konstanta c. Iterativním výpočtem vzniknou pouze orbity nuly. Orbity nuly lze podle jejich vlastností rozdělit do dvou kategorií:
- Pro některé hodnoty c je orbit konečný, tzn. všechny hodnoty zk jsou konečné. Do této kategorie spadají také hodnoty, které oscilují.
- Pro další hodnoty c je orbit nekonečný, tzn. po určité době rostou hodnoty zk nade všechny meze.
Mandelbrotova množina je poté definována jako množina všech komplexních čísel c, které produkují konečný orbit nuly.
Obrázek 33: Mandelbrotova množina vytvořená funkcí mandelbrot-fractal. Střed obdélníku je nastaven na souřadnice [-1/2 0], zvětšení na hodnotu 3/4 a maximální počet iterací na 1000. Vnitřek Mandelbrotovy množiny má černou barvu.
Podívejme se nyní na způsob, jakým je v knihovně Clisk možné vykreslit Mandelbrotovu množinu. K tomu musíme použít dvě funkce nazvané viewport a fractal. První z těchto funkcí slouží (poněkud zjednodušeně řečeno) k nastavení umístění a rozměrů obdélníku v rovině. Všechny body tvořící vstupní parametry pro výpočet fraktálu jsou pravidelně rozmístěny právě v tomto obdélníku (leží v pravidelné mřížce). V mnoha případech je však zadávání rozměrů a umístění obdélníku v rovině poněkud pracné, proto jsem použil odlišný a v praxi i používanější způsob – do funkce pro výpočet fraktálu nazvané jednoduše mandelbrot-fractal vstupují informace o středu obdélníku center-x, center-y a třetí informace o požadovaném zvětšení fraktálu scale. Z těchto tří parametrů se vypočítají rozměry zmíněného obdélníku xmin, xmax, ymin a ymax, které jsou předány do funkce viewport.
Obrázek 34: Mandelbrotova množina vytvořená funkcí mandelbrot-fractal. Střed obdélníku je nastaven na souřadnice [0 1], zvětšení na hodnotu 4 a maximální počet iterací na 1000. Vnitřek Mandelbrotovy množiny má černou barvu.
Mnohem zajímavější je funkce nazvaná fractal, která je taktéž uživatelům v knihovně Clisk nabízena. Této funkci lze předat větší počet parametrů uvozených klíči :init, :while, :update, :result, :bailout-result a :max-iterations. Význam jednotlivých parametrů shrnuje tabulka:
Parametr uvozený klíčem | Význam |
---|---|
:init | inicializace pomocných lokálních proměnných atd. |
:while | podmínka pro ukončení iterační smyčky |
:update | výraz zavolaný v průběhu každé iterace, právě zde se provádí výpočet |
:result | jaká hodnota se má vrátit, pokud se splní podmínka pro ukončení iterační smyčky |
:bailout-result | hodnota (většinou barva) vrácená ve chvíli, kdy se překročí maximální počet iterací |
:max-iterations | maximální počet iterací, pokud dojde k překročení, vrátí se hodnota :bailout-result |
Obrázek 35: Mandelbrotova množina vytvořená funkcí mandelbrot-fractal. Střed obdélníku je nastaven na souřadnice [0 1], zvětšení na hodnotu 10 a maximální počet iterací na 1000. Vnitřek Mandelbrotovy množiny má černou barvu.
Iterační vzorec pro výpočet Mandelbrotovy množiny známe, stejně tak známe podmínku pro ukončení iterační smyčky. Nyní je „pouze“ nutné tyto vztahy (používající komplexní čísla) přepsat takovým způsobem, aby se používaly vektorové operace. Podívejme se na řešení, kde se explicitně používají lokální proměnné x a y a vektorové operace v-, v+, v* a length:
(defn mandelbrot-fractal "Výpočet Mandelbrotovy množiny." [center-x center-y scale maxiter] (let [xmin (- center-x (/ 1.0 scale)) xmax (+ center-x (/ 1.0 scale)) ymin (- center-y (/ 1.0 scale)) ymax (+ center-y (/ 1.0 scale))] (viewport [xmin ymin] [xmax ymax] (fractal ; podmínka pro ukončení iterační smyčky :while (v- 2 (length [x y])) ; výpočet z=z^2+c převedený na operace nad vektory :update (v+ c [(v- (v* x x) (v* y y)) ; zx^2-zy^2 + cx (v* 2 x y)]) ; 2*zx*zy + cy ; výpočet barvy výsledného vzorku :result (v* 'i 0.01) ; barva, která se vrátí ve chvíli, ; kdy se dosáhne maximálního počtu iterací :bailout-result black ; maximální počet iterací :max-iterations maxiter))))
Obrázek 36: Mandelbrotova množina vytvořená funkcí mandelbrot-fractal.
Tuto funkci lze snadno otestovat, zde s použitím „tabulky“ (vektoru vektorů), v níž jsou zaznamenány středy fraktálu v komplexní rovině, zvětšení, maximální počet iterací a jméno výsledného souboru s texturou:
(defn mandelbrot-rendering-test [] ; x0 y0 scale maxiter filename (let [mandel-params [[-1/2 0 3/4 1000 "mandelbrot1.png"] [ 0 -1 4 1000 "mandelbrot2.png"] [ 0 -1 10 1000 "mandelbrot3.png"] [-1.74809088500000000 0.00069335009900000 110116 1000 "mandelbrot4.png"] [-0.80594802749999990 0.20140617800000000 50 10000 "mandelbrot5.png"]]] (doseq [mandel-param mandel-params] (-> (mandelbrot-fractal (nth mandel-param 0) (nth mandel-param 1) (nth mandel-param 2) (nth mandel-param 3)) (write-pattern (nth mandel-param 4))))))
Obrázek 37: Mandelbrotova množina vytvořená funkcí mandelbrot-fractal.
7. Kubická Mandelbrotova množina
Pro ilustraci možností funkce fractal popsané v předchozí kaptitole si ukažme, jakým způsobem je možné vykreslit kubickou Mandelbrotovu množinu, u níž se namísto iteračního vztahu:
zn+1=zn2+c
používá vztah:
zn+1=zn3+c
kde proměnné z a c opět leží v komplexní rovině.
Převod tohoto vztahu na „vektorovou“ podobu v parametru :update je poněkud složitější, ale snadno pochopitelný, když si uvědomíme, jak se počítá zn3 v komplexní rovině:
(defn cubic-mandelbrot-fractal "Výpočet kubické Mandelbrotovy množiny." [center-x center-y scale maxiter] (let [xmin (- center-x (/ 1.0 scale)) xmax (+ center-x (/ 1.0 scale)) ymin (- center-y (/ 1.0 scale)) ymax (+ center-y (/ 1.0 scale))] (viewport [xmin ymin] [xmax ymax] (fractal ; podmínka pro ukončení iterační smyčky :while (v- 2 (length [x y])) ; výpočet z=z^2+c převedený na operace nad vektory :update (v+ c [(v- (v* x x x) (v* 3 x y y)) ; zxn= zx*zx*zx-3.0*zx*zy*zy+cx; (v- (v* 3 x x y) (v* y y y))]) ; zyn=-zy*zy*zy+3.0*zx*zx*zy+cy; ; výpočet barvy výsledného vzorku :result (v* 'i 0.01) ; barva, která se vrátí ve chvíli, ; kdy se dosáhne maximálního počtu iterací :bailout-result black ; maximální počet iterací :max-iterations maxiter))))
Obrázek 38: Kubická Mandelbrotova množina vytvořená funkcí cubic-mandelbrot-fractal.
8. Úplný zdrojový kód demonstračního příkladu clisktest5
V této kapitole bude uveden výpis úplného zdrojového kódu dnešního druhého a současně i posledního demonstračního příkladu nazvaného clisktest5, z něhož jsme používali úryvky a ukázky v předchozích dvou kapitolách:
Obsah souboru project.clj:
(defproject clisktest5 "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] [net.mikera/clisk "0.10.0"]] :main ^:skip-aot clisktest5.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
Obsah souboru core.clj:
(ns clisktest5.core (:gen-class) (:use clisk.live)) (import java.io.File) (import javax.imageio.ImageIO) (defn write-image "Uložení rastrového obrázku typu BufferedImage do souboru." [image file-name] (ImageIO/write image "png" (File. file-name))) (defn write-pattern "Vytvoření rastrového obrázku na základě předaného patternu." [pattern file-name] (write-image (image pattern) file-name)) (defn mandelbrot-fractal "Výpočet Mandelbrotovy množiny." [center-x center-y scale maxiter] (let [xmin (- center-x (/ 1.0 scale)) xmax (+ center-x (/ 1.0 scale)) ymin (- center-y (/ 1.0 scale)) ymax (+ center-y (/ 1.0 scale))] (viewport [xmin ymin] [xmax ymax] (fractal ; podmínka pro ukončení iterační smyčky :while (v- 2 (length [x y])) ; výpočet z=z^2+c převedený na operace nad vektory :update (v+ c [(v- (v* x x) (v* y y)) ; zx^2-zy^2 + cx (v* 2 x y)]) ; 2*zx*zy + cy ; výpočet barvy výsledného vzorku :result (v* 'i 0.01) ; barva, která se vrátí ve chvíli, ; kdy se dosáhne maximálního počtu iterací :bailout-result black ; maximální počet iterací :max-iterations maxiter)))) (defn cubic-mandelbrot-fractal "Výpočet kubické Mandelbrotovy množiny." [center-x center-y scale maxiter] (let [xmin (- center-x (/ 1.0 scale)) xmax (+ center-x (/ 1.0 scale)) ymin (- center-y (/ 1.0 scale)) ymax (+ center-y (/ 1.0 scale))] (viewport [xmin ymin] [xmax ymax] (fractal ; podmínka pro ukončení iterační smyčky :while (v- 2 (length [x y])) ; výpočet z=z^2+c převedený na operace nad vektory :update (v+ c [(v- (v* x x x) (v* 3 x y y)) ; zxn= zx*zx*zx-3.0*zx*zy*zy+cx; (v- (v* 3 x x y) (v* y y y))]) ; zyn=-zy*zy*zy+3.0*zx*zx*zy+cy; ; výpočet barvy výsledného vzorku :result (v* 'i 0.01) ; barva, která se vrátí ve chvíli, ; kdy se dosáhne maximálního počtu iterací :bailout-result black ; maximální počet iterací :max-iterations maxiter)))) (defn mandelbrot-rendering-test [] ; x0 y0 scale maxiter filename (let [mandel-params [[-1/2 0 3/4 1000 "mandelbrot1.png"] [ 0 -1 4 1000 "mandelbrot2.png"] [ 0 -1 10 1000 "mandelbrot3.png"] [-1.74809088500000000 0.00069335009900000 110116 1000 "mandelbrot4.png"] [-0.80594802749999990 0.20140617800000000 50 10000 "mandelbrot5.png"]]] (doseq [mandel-param mandel-params] (-> (mandelbrot-fractal (nth mandel-param 0) (nth mandel-param 1) (nth mandel-param 2) (nth mandel-param 3)) (write-pattern (nth mandel-param 4)))))) (defn fractal-rendering-test [] (mandelbrot-rendering-test) (-> (cubic-mandelbrot-fractal 0 0 3/4 1000) (write-pattern "mandelbrot6.png"))) (defn -main [& args] (try (println "fractal rendering test...") (fractal-rendering-test) (println "Done") (catch Throwable e (println (.toString e))) (finally ; jistota, že program vždy korektně skončí (System/exit 0))))
9. Repositář s demonstračními příklady
Oba dva dnes popsané demonstrační příklady byly, podobně jako v předchozích částech tohoto seriálu, uloženy do GIT repositáře dostupného na adrese https://github.com/tisnik/clojure-examples. V tabulce zobrazené pod tímto odstavcem naleznete na jednotlivé příklady přímé odkazy:
# | Příklad | Github |
---|---|---|
1 | clisktest4 | https://github.com/tisnik/clojure-examples/tree/master/clisktest4 |
2 | clisktest5 | https://github.com/tisnik/clojure-examples/tree/master/clisktest5 |
10. Odkazy na předchozí části seriálu
- Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/
11. Odkazy na Internetu
- Clisk
https://github.com/mikera/clisk - clojars: net.mikera/clisk
https://clojars.org/net.mikera/clisk - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - Clisk: wiki
https://github.com/mikera/clisk/wiki - Dokumentace vygenerovaná pro knihovnu core.matrix
https://cloojure.github.io/doc/core.matrix/index.html - Size and Dimensionality
https://groups.google.com/forum/#!topic/numerical-clojure/zebBCa68eTw/discussion - Towards core.matrix for Clojure?
https://clojurefun.wordpress.com/2013/01/05/towards-core-matrix-for-clojure/ - The Clojure Toolbox
http://www.clojure-toolbox.com/ - Neanderthal
http://neanderthal.uncomplicate.org/ - Hello world project
https://github.com/uncomplicate/neanderthal/blob/master/examples/hello-world/project.clj - vectorz-clj
https://github.com/mikera/vectorz-clj - vectorz – Examples
https://github.com/mikera/vectorz-clj/wiki/Examples - gloss
https://github.com/ztellman/gloss - HTTP client/server for Clojure
http://www.http-kit.org/ - Array Programming
https://en.wikipedia.org/wiki/Array_programming - Discovering Array Languages
http://archive.vector.org.uk/art10008110 - no stinking loops – Kalothi
http://www.nsl.com/ - Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
http://www.vector.org.uk/ - APL Interpreters
http://www.vector.org.uk/?area=interpreters - APL_(programming_language
http://en.wikipedia.org/wiki/APL_(programming_language - APL FAQ
http://www.faqs.org/faqs/apl-faq/ - APL FAQ (nejnovější verze)
http://home.earthlink.net/~swsirlin/apl.faq.html - A+
http://www.aplusdev.org/ - APLX
http://www.microapl.co.uk/ - FreeAPL
http://www.pyr.fi/apl/index.htm - J: a modern, high-level, general-purpose, high-performance programming language
http://www.jsoftware.com/ - K, Kdb: an APL derivative for Solaris, Linux, Windows
http://www.kx.com - openAPL (GPL)
http://sourceforge.net/projects/openapl - Parrot APL (GPL)
http://www.parrotcode.org/ - Learning J (Roger Stokes)
http://www.jsoftware.com/help/learning/contents.htm - Rosetta Code
http://rosettacode.org/wiki/Main_Page - Why APL
http://www.acm.org/sigapl/whyapl.htm - java.jdbc API Reference
https://clojure.github.io/java.jdbc/ - Hiccup
https://github.com/weavejester/hiccup - Clojure Ring na GitHubu
https://github.com/ring-clojure/ring - A brief overview of the Clojure web stack
https://brehaut.net/blog/2011/ring_introduction - Getting Started with Ring
http://www.learningclojure.com/2013/01/getting-started-with-ring.html - Getting Started with Ring and Compojure – Clojure Web Programming
http://www.myclojureadventure.com/2011/03/getting-started-with-ring-and-compojure.html - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II
2) http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/