Obsah
1. Základní knihovny pro 2D grafiku v jazyku Racket
2. Bitmapy, grafické kontexty a vykreslení (rasterizace) úseček
3. Nastavení vizuálních vlastností vykreslovaných objektů
4. Vykreslení vyplněných 2D objektů
5. Nastavení antialiasingu při vykreslování
6. Styl vykreslovaných úseček, oblouků, křivek a cest
7. Změna tvaru stopy na konci úseček
8. Styl výplně uzavřených objektů
9. Gradientní barvové přechody
11. Vykreslení loga programovacího jazyka Racket
13. Nastavení alfa kanálu (průhlednosti)
16. Použití funkce repeat pro vykreslení složitějších obrazců
17. Další možnosti želví grafiky
18. Repositář s demonstračními příklady
1. Základní knihovny pro 2D grafiku v jazyku Racket
Na rozdíl od předchozích tří článků [1] [2] [3], v nichž jsme se věnovali základním konceptům, na nichž je postaven programovací jazyk Racket, se dnes začneme věnovat praktičtějším příkladům, které se mj. používají i ve výuce (i když je nutné na tomto místě poznamenat, že se Racket do výuky nerozšířil do takové míry, jak jeho tvůrci doufali). Mezi nejvíce názorné metody výuky programování stále patří použití jednoduché 2D grafiky a pro tento účel v Racketu nalezneme hned několik knihoven, zejména pak knihovnu Racket Drawing Toolkit představovanou balíčkem racket/draw.
V první části dnešního článku se budeme zabývat výše zmíněným balíčkem racket/draw, v níž nalezneme většinu standardních funkcí pro vykreslování 2D grafiky. V části druhé si pak ve stručnosti popíšeme knihovnu graphics/turtles, v níž je implementována takzvaná želví grafika neboli turtle graphics.
Balíček racket/draw je určen pro vykreslování 2D grafiky tvořené jak základními geometrickými tvary (úsečka, oblouk, elipsa), tak i textem a popř. i cestami (paths). Většina konceptů, na nichž je tato knihovna postavena, bude mnoha čtenářům připadat známá. Není to samozřejmě náhodou, protože se tvůrci inspirovali PostScriptem [4], z něhož je nepřímo odvozen i jazyk SVG [5]. To mj. znamená, že se setkáme s takovými termíny, jako je pero (pen), štětec (brush), cesta (path) atd. Vzhledem k tomu, že jsou tyto pojmy vysvětleny v odkazovaných článcích, budeme se dnes soustředit především na způsob jejich použití v programovacím jazyku Racket.
2. Bitmapy, grafické kontexty a vykreslení (rasterizace) úseček
Knihovna používá koncepty objektově orientovaného programování, s nimiž jsme se v jazyku Racket prozatím nesetkali, ovšem dnes nám bude stačit pouze vědět, jakým způsobem se vytvoří (zkonstruuje) objekt a jak se tomuto objektu pošle zpráva, resp. (pokud preferujete terminologii C++ či Javy) jak se zavolá metoda objektu. Nový objekt se zkonstruuje pomocí formy new, které se předá výraz typu třída a případné parametry konstruktoru:
(new bitmap-dc% [bitmap target])
Jakmile je objekt zkonstruován, je možné mu poslat zprávou pomocí metody send popř. nějaké další varianty této formy (variant existuje několik, velmi užitečná je forma send*, která objektu postupně pošle více zpráv):
(send objekt metoda argumenty metody) (send* objekt zpráva1 zpráva2 zpráva3 ...)
Znalost těchto dvou forem nám bude pro účely dnešního článku plně dostačovat.
Nyní si ukažme ten nejjednodušší demonstrační příklad, na němž budou vysvětleny dva základní koncepty knihovny racket/draw:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc draw-line 0 0 255 255) (send dc draw-line 0 255 255 0) (send target save-file "01.png" 'png)
Obrázek 1: Výsledek běhu dnešního prvního demonstračního příkladu.
V tomto příkladu se postupně vykonají následující operace:
- Vytvoří se bitmapa (rastrový obrázek), do kterého se bude provádět vykreslování. Povšimněte si, že u bitmapy musíme specifikovat její horizontální i vertikální rozlišení a popř. i další parametry (například to, zda se má používat alfa kanál atd.).
- Vytvoří a inicializuje se takzvaný grafický kontext držící stav vykreslovacího enginu (šířku a barvu pera atd.). U samotných vykreslovacích operací se pouze specifikuje, jaký tvar se má vykreslit a jaký je jeho geometrický tvar (souřadnice). Barva vykreslení či výplně je součástí grafického kontextu.
- Následně přes grafický kontext vykreslíme základní geometrický tvar – úsečku. Souřadnice koncových bodů úsečky jsou specifikovány v souřadném systému bitmapy, v našem případě v souřadném systému, v němž má x-ová i y-ová osa limity 0 až 255 (ve skutečnosti to není zcela pravda, protože je možné provádět lineární transformace souřadnic, ty však prozatím nemáme nastavené).
- Nakonec je bitmapa uložena do rastrového souboru ve formátu PNG, ovšem v případě potřeby je možné zvolit i další formáty, pochopitelně včetně JPEGu.
Ve druhém příkladu navíc bitmapu nejprve „smažeme“ nakreslením bílého obdélníku (viz zvýrazněná část skriptu):
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc draw-rectangle 0 0 256 256) (send dc draw-line 0 0 255 255) (send dc draw-line 0 255 255 0) (send target save-file "02.png" 'png)
Obrázek 2: Výsledek běhu příkladu druhého.
3. Nastavení vizuálních vlastností vykreslovaných objektů
Podobně, jako je tomu například ve vektorovém formátu SVG, PostScriptu či v knihovně OpenVG, se i při použití knihovny racket/draw setkáme se třemi důležitými pojmy:
- Pero (pen) je nástroj použitý při vykreslování obrysu tvarů a samozřejmě i všech liniových tvarů (úsečky, oblouky, …).
- Štětec (brush) je nástroj použitý pro vyplnění uzavřených tvarů (obdélník, polygon, elipsa, cesta).
- Cesta (path) se používá k popisu složitějších tvarů složených z úseček a oblouků. Nad cestami je definováno větší množství operací, například test, zda bod leží uvnitř objektu popsaného cestou atd.
Barva obrysů lze nastavit takto:
(send dc set-pen "red" 3 'solid)
4. Vykreslení vyplněných 2D objektů
Některé objekty jsou „otevřené“ (úsečka, oblouk, spline křivka), další „uzavřené“ (obdélník, elipsa). U uzavřených objektů je možné zvolit, jakým způsobem se vyplní jejich vnitřek. V nejjednodušším případě se vyplnění provede konstantní barvou, což si ukážeme v dalším příkladu. Barva výplně je součástí stavu takzvaného „štětce“ (brush) a nastavuje se metodou set-brush:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "red" 3 'solid) (send dc draw-line 0 0 255 255) (send dc draw-line 0 255 255 0) (send target save-file "03.png" 'png)
Obrázek 3: Třetí demonstrační příklad s vykresleným obdélníkem a dvojicí úseček.
5. Nastavení antialiasingu při vykreslování
Nejrychlejším algoritmem pro vykreslování úseček do bitmapy je slavný Bresenhamův algoritmus. Ovšem klasická podoba tohoto algoritmu má jednu podstatnou nevýhodu, která je navíc ještě zviditelněna kvalitními monitory s pevným rastrem – stopa úsečky tvoří typické „schody“, takže se výsledek někdy označuje „jagged lines“. Existují ovšem i vykreslovací algoritmy, které dokážou úsečky a další tvary vykreslit s využitím antialiasingu. I tyto algoritmy jsou v knihovně racket/draw podporovány a to dokonce ve dvou variantách. První varianta počítá s tím že koncové body úseček a dalších tvarů leží ve středech pixelů, druhá varianta naopak počítá s tím, že koncové body leží na hranicích mezi pixely. Rozdíly mezi všemi třemi vykreslovacími algoritmy jsou ukázány na trojici demonstračních příkladů.
Vykreslení úseček klasickým Bresenhamovým algoritmem se „schody“:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "black" 1 'solid) (for ([i (in-range 0 256 10)]) (send dc draw-line 255 0 i i) (send dc draw-line 0 i i 255)) (send target save-file "04.png" 'png)
Obrázek 4: Vykreslení úseček klasickým Bresenhamovým algoritmem se „schody“.
První algoritmus využívající antialiasing. Zpráva/metoda, která tento algoritmus zapíná, je zvýrazněna tučným písmem:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "black" 1 'solid) (send dc set-smoothing 'smoothed) (for ([i (in-range 0 256 10)]) (send dc draw-line 255 0 i i) (send dc draw-line 0 i i 255)) (send target save-file "05.png" 'png)
Obrázek 5: První algoritmus pro antialiasing.
Druhý algoritmus využívající antialiasing. Zpráva/metoda, která tento algoritmus zapíná, je opět zvýrazněna:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "black" 1 'solid) (send dc set-smoothing 'aligned) (for ([i (in-range 0 256 10)]) (send dc draw-line 255 0 i i) (send dc draw-line 0 i i 255)) (send target save-file "06.png" 'png)
Obrázek 6: Druhý algoritmus pro antialiasing.
Rozdíl mezi oběma algoritmy používajícími antialiasing je ještě více viditelný v případě, že budeme vykreslovat vodorovné či naopak svislé úsečky. Ukažme si rozdíl na příkladu s vodorovnými úsečkami.
První algoritmus využívající antialiasing. Zpráva/metoda, která tento algoritmus zapíná, je zvýrazněna tučným písmem:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "black" 1 'solid) (send dc set-smoothing 'smoothed) (for ([i (in-range 0 256 10)]) (send dc draw-line 0 i 255 i)) (send target save-file "07.png" 'png)
Obrázek 7: První algoritmus využívající antialiasing pro vykreslení vodorovných úseček.
Druhý algoritmus využívající antialiasing. Zpráva/metoda, která tento algoritmus zapíná, je opět zvýrazněna:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "black" 1 'solid) (send dc set-smoothing 'aligned) (for ([i (in-range 0 256 10)]) (send dc draw-line 0 i 255 i)) (send target save-file "08.png" 'png)
Obrázek 8: Druhý algoritmus využívající antialiasing pro vykreslení vodorovných úseček.
6. Styl vykreslovaných úseček, oblouků, křivek a cest
Při kresbě liniových obrazců nebo okrajů plošných obrazců je možné zvolit vzorek (styl) úseček – plná (výchozí nastavení), čárkovaná, čerchovaná, střídavá apod. Tento styl se nastavuje posledním parametrem metody set-pen a jednotlivé možnosti jsou ukázány v dalším demonstračním příkladu (pro větší kvalitu výsledku je povolen antialiasing):
Obrázek 9: Několik úseček s různým stylem vykreslování.
Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-smoothing 'aligned) (send dc set-pen "black" 1 'solid) (send dc draw-line 0 10 255 10) (send dc set-pen "black" 1 'dot) (send dc draw-line 0 20 255 20) (send dc set-pen "black" 1 'long-dash) (send dc draw-line 0 30 255 30) (send dc set-pen "black" 1 'short-dash) (send dc draw-line 0 40 255 40) (send dc set-pen "black" 1 'dot-dash) (send dc draw-line 0 50 255 50) (send dc set-pen "gray" 5 'solid) (send dc draw-line 0 80 255 80) (send dc set-pen "gray" 5 'dot) (send dc draw-line 0 90 255 90) (send dc set-pen "gray" 5 'long-dash) (send dc draw-line 0 100 255 100) (send dc set-pen "gray" 5 'short-dash) (send dc draw-line 0 110 255 110) (send dc set-pen "gray" 5 'dot-dash) (send dc draw-line 0 120 255 120) (send dc set-pen "darkgreen" 15 'solid) (send dc draw-line 0 150 255 150) (send dc set-pen "darkgreen" 15 'dot) (send dc draw-line 0 170 255 170) (send dc set-pen "darkgreen" 15 'long-dash) (send dc draw-line 0 190 255 190) (send dc set-pen "darkgreen" 15 'short-dash) (send dc draw-line 0 210 255 210) (send dc set-pen "darkgreen" 15 'dot-dash) (send dc draw-line 0 230 255 230) (send target save-file "09.png" 'png)
7. Změna tvaru stopy na konci úseček
Konce (zejména) širokých úseček či oblouků mohou být zaobleny, popř. mohou končit přímo na zadaném koncovém bodě (vrcholu) nebo může křivka přesahovat koncový bod tak, aby vzdálenost koncového bodu (vrchol) od vykresleného konce křivky odpovídala polovině jejího průměru. Toto chování vykreslovacího algoritmu nelze nastavit přímo metodou set-pen, ale musíme použít tento postup:
(send dc set-pen (send the-pen-list find-or-create-pen "black" 1 'solid 'butt))
Alternativně můžeme použít metodu set-cap.
Důležitý je poslední parametr metody find-or-create-pen, který může nabývat hodnot:
- 'round (zakulacený konec křivky)
- 'projecting (kolmé ukončení křivky, křivka je prodloužena přes koncový bod)
- 'butt (kolmé ukončení křivky, křivka končí přímo v koncovém bodě)
Podívejme se nyní na úpravu předchozího příkladu tak, aby se změnil způsob vykreslení konců úseček:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-smoothing 'aligned) (send dc set-pen (send the-pen-list find-or-create-pen "black" 1 'solid 'butt)) (send dc draw-line 0 10 255 10) (send dc set-pen (send the-pen-list find-or-create-pen "black" 1 'dot 'butt)) (send dc draw-line 0 20 255 20) (send dc set-pen (send the-pen-list find-or-create-pen "black" 1 'long-dash 'butt)) (send dc draw-line 0 30 255 30) (send dc set-pen (send the-pen-list find-or-create-pen "black" 1 'short-dash 'butt)) (send dc draw-line 0 40 255 40) (send dc set-pen (send the-pen-list find-or-create-pen "black" 1 'dot-dash 'butt)) (send dc draw-line 0 50 255 50) (send dc set-pen (send the-pen-list find-or-create-pen "gray" 5 'solid 'butt)) (send dc draw-line 0 80 255 80) (send dc set-pen (send the-pen-list find-or-create-pen "gray" 5 'dot 'butt)) (send dc draw-line 0 90 255 90) (send dc set-pen (send the-pen-list find-or-create-pen "gray" 5 'long-dash 'butt)) (send dc draw-line 0 100 255 100) (send dc set-pen (send the-pen-list find-or-create-pen "gray" 5 'short-dash 'butt)) (send dc draw-line 0 110 255 110) (send dc set-pen (send the-pen-list find-or-create-pen "gray" 5 'dot-dash 'butt)) (send dc draw-line 0 120 255 120) (send dc set-pen (send the-pen-list find-or-create-pen "darkgreen" 15 'solid 'butt)) (send dc draw-line 0 150 255 150) (send dc set-pen (send the-pen-list find-or-create-pen "darkgreen" 15 'dot 'butt)) (send dc draw-line 0 170 255 170) (send dc set-pen (send the-pen-list find-or-create-pen "darkgreen" 15 'long-dash 'butt)) (send dc draw-line 0 190 255 190) (send dc set-pen (send the-pen-list find-or-create-pen "darkgreen" 15 'short-dash 'butt)) (send dc draw-line 0 210 255 210) (send dc set-pen (send the-pen-list find-or-create-pen "darkgreen" 15 'dot-dash 'butt)) (send dc draw-line 0 230 255 230) (send target save-file "10.png" 'png)
Obrázek 10: Změněné konce úseček.
8. Styl výplně uzavřených objektů
Uzavřené dvourozměrné entity, mezi něž náleží především obdélníky a elipsy (speciálně pak kružnice) mohou být vyplněny, což jsme si již ostatně ukázali ve druhém demonstračním příkladu. Tradičně se může jednat o výplň konstantní barvou, výplň vzorkem (hatch), bitmapou nebo gradientním barvovým přechodem. Nejdříve si ukážeme vyplnění obdélníků vzorkem. V knihovně racket/draw je předpřipraveno několik vzorků, které jsou všechny použity v dalším demonstračním příkladu. Jejich názvy jsou ve zdrojovém kódu tohoto příkladu zvýrazněny tučným písmem:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-brush "black" 'transparent) (send dc draw-rectangle 10 10 50 50) (send dc set-brush "black" 'solid) (send dc draw-rectangle 105 10 50 50) (send dc set-brush "black" 'hilite) (send dc draw-rectangle 200 10 50 50) (send dc set-brush "black" 'horizontal-hatch) (send dc draw-rectangle 10 105 50 50) (send dc set-brush "black" 'vertical-hatch) (send dc draw-rectangle 105 105 50 50) (send dc set-brush "black" 'cross-hatch) (send dc draw-rectangle 200 105 50 50) (send dc set-brush "black" 'bdiagonal-hatch) (send dc draw-rectangle 10 200 50 50) (send dc set-brush "black" 'fdiagonal-hatch) (send dc draw-rectangle 105 200 50 50) (send dc set-brush "black" 'crossdiag-hatch) (send dc draw-rectangle 200 200 50 50) (send target save-file "11.png" 'png)
Výsledek vypadá následovně:
Obrázek 11: Devět čtverců, každý vykreslený s jiným stylem výplně. První čtverec je vykreslen s transparentní výplní a není viditelný, protože i jeho okraj je transparentní.
9. Gradientní barvové přechody
Další demonstrační příklad je poněkud složitější, protože je v něm deklarován a následně použit gradientní barvový přechod, který posloužil jako výplň uzavřeného 2D obrazce, zde konkrétně obdélníku. Povšimněte si, jakým způsobem je gradientní přechod deklarován – zvolí se dva body v ploše a nakonec barvy ležící na spojnici mezi těmito dvěma body. Barev lze zadat libovolné množství, jen je zapotřebí udržovat seznam setříděný podle parametru t rostoucího od 0 do 1:
(new linear-gradient% [x0 0] [y0 100] [x1 100] [y1 0] [stops (list (list 0 (make-object color% 255 0 0)) (list 0.5 (make-object color% 0 255 0)) (list 1 (make-object color% 0 0 255)))])]))
Jeho následné nastavení a použití je zcela jednoduché:
(define rectangle-brush (new brush% [gradient ...])) (send dc set-brush rectangle-brush)
S výsledkem:
Obrázek 12: Obdélník vyplněný s využití barvového gradientního přechodu.
Následuje výpis úplného zdrojového kódu tohoto demonstračního příkladu:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (define rectangle-brush (new brush% [gradient (new linear-gradient% [x0 0] [y0 100] [x1 100] [y1 0] [stops (list (list 0 (make-object color% 255 0 0)) (list 0.5 (make-object color% 0 255 0)) (list 1 (make-object color% 0 0 255)))])])) (send dc set-brush rectangle-brush) (send dc draw-rectangle 0 0 255 255) (send target save-file "12.png" 'png)
10. Cesty
Dalším důležitým konceptem, s nímž se setkáme jak v knihovně , tak i ve výše zmíněném PostScriptu či SVG, jsou takzvané cesty. Jedná se o geometrické tvary vytvořené z úseček, oblouků a křivek. Cesty mohou být uzavřené (potom je lze vyplnit) či otevřené. Samotná cesta je realizována objektem typu dc-path%:
(new dc-path%)
Tomuto objektu se potom posílají zprávy pro přidání nového úsečkového segmentu (line-to), křivkového segmentu (curve-to) či o posunu aktivního bodu na zadané souřadnice (move-to):
(let ([p (new dc-path%)]) (send p move-to 153 44) (send p line-to 161.5 60) (send p curve-to 202.5 49 230 42 245 61) ... ... ...
Podívejme se nyní na příklad, který po svém spuštění vykreslí část loga programovacího jazyka Racket:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (define left-lambda-path (let ([p (new dc-path%)]) (send p move-to 153 44) (send p line-to 161.5 60) (send p curve-to 202.5 49 230 42 245 61) (send p curve-to 280.06 105.41 287.5 141 296.5 186) (send p curve-to 301.12 209.08 299.11 223.38 293.96 244) (send p curve-to 281.34 294.54 259.18 331.61 233.5 375) (send p curve-to 198.21 434.63 164.68 505.6 125.5 564) (send p line-to 135 572) p)) (send dc translate 5 5) (send dc scale 0.4 0.4) (send dc set-smoothing 'smoothed) (send dc set-pen "black" 1 'solid) (send dc draw-path left-lambda-path) (send target save-file "13.png" 'png)
Obrázek 13: Cesta vykreslená předchozím demonstračním příkladem.
11. Vykreslení loga programovacího jazyka Racket
Následující demonstrační příklad byl převzat přímo z dokumentace programovacího jazyka Racket, ovšem byl pro účely dnešního článku zjednodušen. Tento příklad slouží pro vykreslení několika cest, po jejichž vyplnění vznikne logo tohoto programovacího jazyka:
Obrázek 14: Logo programovacího jazyka Racket vykresleného dále vypsaným příkladem.
Úplný zdrojový kód tohoto příkladu vypadá následovně:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (define left-lambda-path (let ([p (new dc-path%)]) (send p move-to 153 44) (send p line-to 161.5 60) (send p curve-to 202.5 49 230 42 245 61) (send p curve-to 280.06 105.41 287.5 141 296.5 186) (send p curve-to 301.12 209.08 299.11 223.38 293.96 244) (send p curve-to 281.34 294.54 259.18 331.61 233.5 375) (send p curve-to 198.21 434.63 164.68 505.6 125.5 564) (send p line-to 135 572) p)) (define left-logo-path (let ([p (new dc-path%)]) (send p append left-lambda-path) (send p arc 0 0 630 630 (* 47/72 2 3.14) (* 121/360 2 3.14) #f) p)) (define bottom-lambda-path (let ([p (new dc-path%)]) (send p move-to 135 572) (send p line-to 188.5 564) (send p curve-to 208.5 517 230.91 465.21 251 420) (send p curve-to 267 384 278.5 348 296.5 312) (send p curve-to 301.01 302.98 318 258 329 274) (send p curve-to 338.89 288.39 351 314 358 332) (send p curve-to 377.28 381.58 395.57 429.61 414 477) (send p curve-to 428 513 436.5 540 449.5 573) (send p line-to 465 580) (send p line-to 529 545) p)) (define bottom-logo-path (let ([p (new dc-path%)]) (send p append bottom-lambda-path) (send p arc 0 0 630 630 (* 157/180 2 3.14) (* 47/72 2 3.14) #f) p)) (define right-lambda-path (let ([p (new dc-path%)]) (send p move-to 153 44) (send p curve-to 192.21 30.69 233.21 14.23 275 20) (send p curve-to 328.6 27.4 350.23 103.08 364 151) (send p curve-to 378.75 202.32 400.5 244 418 294) (send p curve-to 446.56 375.6 494.5 456 530.5 537) (send p line-to 529 545) p)) (define right-logo-path (let ([p (new dc-path%)]) (send p append right-lambda-path) (send p arc 0 0 630 630 (* 157/180 2 3.14) (* 121/360 2 3.14) #t) p)) (define lambda-path (let ([p (new dc-path%)]) (send p append left-lambda-path) (send p append bottom-lambda-path) (let ([t (new dc-path%)]) (send t append right-lambda-path) (send t reverse) (send p append t)) (send p close) p)) (send dc translate 5 5) (send dc scale 0.39 0.39) (send dc set-smoothing 'smoothed) (send dc set-pen "black" 0 'solid) (send dc set-brush "white" 'solid) (send dc draw-path lambda-path) (send dc set-pen "black" 4 'solid) (send dc set-brush "red" 'solid) (send dc draw-path left-logo-path) (send dc draw-path bottom-logo-path) (send dc set-brush "blue" 'solid) (send dc draw-path right-logo-path) (send target save-file "14.png" 'png)
Připomeňme si, že do objektu lze poslat jednu zprávu pomocí formy send, ovšem taktéž můžeme poslat více zpráv metodou pojmenovanou send*. A právě tuto druhou metodu použijeme proto, aby se zdrojový kód příkladu zkrátil a taktéž do jisté míry zjednodušil:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (define left-lambda-path (let ([p (new dc-path%)]) (send* p (move-to 153 44) (line-to 161.5 60) (curve-to 202.5 49 230 42 245 61) (curve-to 280.06 105.41 287.5 141 296.5 186) (curve-to 301.12 209.08 299.11 223.38 293.96 244) (curve-to 281.34 294.54 259.18 331.61 233.5 375) (curve-to 198.21 434.63 164.68 505.6 125.5 564) (line-to 135 572)) p)) (define left-logo-path (let ([p (new dc-path%)]) (send* p (append left-lambda-path) (arc 0 0 630 630 (* 47/72 2 3.14) (* 121/360 2 3.14) #f)) p)) (define bottom-lambda-path (let ([p (new dc-path%)]) (send* p (move-to 135 572) (line-to 188.5 564) (curve-to 208.5 517 230.91 465.21 251 420) (curve-to 267 384 278.5 348 296.5 312) (curve-to 301.01 302.98 318 258 329 274) (curve-to 338.89 288.39 351 314 358 332) (curve-to 377.28 381.58 395.57 429.61 414 477) (curve-to 428 513 436.5 540 449.5 573) (line-to 465 580) (line-to 529 545)) p)) (define bottom-logo-path (let ([p (new dc-path%)]) (send* p (append bottom-lambda-path) (arc 0 0 630 630 (* 157/180 2 3.14) (* 47/72 2 3.14) #f)) p)) (define right-lambda-path (let ([p (new dc-path%)]) (send* p (move-to 153 44) (curve-to 192.21 30.69 233.21 14.23 275 20) (curve-to 328.6 27.4 350.23 103.08 364 151) (curve-to 378.75 202.32 400.5 244 418 294) (curve-to 446.56 375.6 494.5 456 530.5 537) (line-to 529 545)) p)) (define right-logo-path (let ([p (new dc-path%)]) (send* p (append right-lambda-path) (arc 0 0 630 630 (* 157/180 2 3.14) (* 121/360 2 3.14) #t)) p)) (define lambda-path (let ([p (new dc-path%)]) (send* p (append left-lambda-path) (append bottom-lambda-path)) (let ([t (new dc-path%)]) (send t append right-lambda-path) (send t reverse) (send p append t)) (send p close) p)) (send dc translate 5 5) (send dc scale 0.39 0.39) (send dc set-smoothing 'smoothed) (send dc set-pen "black" 0 'solid) (send dc set-brush "white" 'solid) (send dc draw-path lambda-path) (send dc set-pen "black" 4 'solid) (send dc set-brush "red" 'solid) (send dc draw-path left-logo-path) (send dc draw-path bottom-logo-path) (send dc set-brush "blue" 'solid) (send dc draw-path right-logo-path) (send target save-file "15.png" 'png)
Obrázek 15: Logo programovacího jazyka Racket vykresleného výše vypsaným příkladem.
12. Spline křivka
V knihovně je podporována i práce se spline křivkami a taktéž s Bézierovými křivkami. Nejdříve se podívejme na způsob použití spline křivky určené třemi body – dvěma body koncovými a bodem řídicím. Tato křivka se vykreslí metodou draw-spline:
#lang racket/base (require racket/class) (require racket/draw) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-smoothing 'aligned) (send dc set-pen "red" 1 'long-dash) (send dc draw-line 10 128 128 10) (send dc draw-line 128 10 246 128) (send dc set-pen "blue" 1 'solid) (send dc draw-spline 10 130 128 12 246 130) (send target save-file "16.png" 'png)
Obrázek 16: Spline křivka a její řídicí body (spojené úsečkami). Pro větší přehlednost je spline křivka posunuta o dva pixely níže, aby neležela přesně na svých řídicích úsečkách.
13. Nastavení alfa kanálu (průhlednosti)
Knihovna racket/draw plně podporuje alfa kanál, který lze využít jak při kreslení otevřených křivek, tak i (a to zejména) křivek uzavřených. V dalším příkladu je ukázáno, jakým způsobem se nastavuje alfa složka (tedy míra průhlednosti resp. přesněji řečeno neprůhlednosti) při vykreslování čtverců umístěných nad již nakreslený obrazec:
(define alpha 0.0) (for ([y (in-range 0 4)]) (for ([x (in-range 0 4)]) (send dc set-alpha alpha) (set! alpha (+ 0.06 alpha)) (send dc draw-rectangle (+ 10 (* x 60)) (+ 10 (* y 60)) 50 50)))
Obrázek 17: Čtverce vykreslené červenou barvou s různou mírou průhlednosti.
Obrázek 18: Čtverce vykreslené zelenou barvou s různou mírou průhlednosti.
Obrázek 19: Čtverce vykreslené modrou barvou s různou mírou průhlednosti.
Obrázek 20: Čtverce vykreslené černou barvou s různou mírou průhlednosti.
Úplný zdrojový kód tohoto příkladu vypadá následovně:
#lang racket/base (require racket/class) (require racket/draw) (define (draw-example color filename) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "black" 1 'solid) (send dc set-smoothing 'aligned) (for ([i (in-range 0 256 10)]) (send dc draw-line 255 0 i i) (send dc draw-line 0 i i 255)) (send dc set-brush color 'solid) (define alpha 0.0) (for ([y (in-range 0 4)]) (for ([x (in-range 0 4)]) (send dc set-alpha alpha) (set! alpha (+ 0.06 alpha)) (send dc draw-rectangle (+ 10 (* x 60)) (+ 10 (* y 60)) 50 50))) (send target save-file filename 'png)) (draw-example "red" "17A.png") (draw-example "green" "17B.png") (draw-example "blue" "17C.png") (draw-example "black" "17D.png")
14. Vykreslení textu
Do rastrových obrázků lze pochopitelně vykreslovat i text. Nejprve je však vhodné nastavit font (řez písma), jeho velikost, váhu atd.:
(send dc set-font (make-font #:size 60 #:family 'swiss #:weight 'bold))
Následně se text vykreslí stejným způsobem jako ostatní entity:
(send dc set-text-foreground "red") (send dc draw-text "Hello" 16 20) (send dc set-text-foreground "blue") (send dc draw-text "Hello" 16 140)
Výsledek:
Obrázek 21: Text vykreslený do bitmapového obrázku.
Opět pochopitelně následuje výpis zdrojového kódu demonstračního příkladu:
#lang racket/base (require racket/class) (require racket/draw) (define (draw-example filename) (define target (make-bitmap 256 256)) (define dc (new bitmap-dc% [bitmap target])) (send dc set-brush "white" 'solid) (send dc set-pen "white" 1 'transparent) (send dc draw-rectangle 0 0 256 256) (send dc set-pen "black" 1 'solid) (send dc set-smoothing 'aligned) (for ([i (in-range 0 256 10)]) (send dc draw-line 255 0 i i) (send dc draw-line 0 i i 255)) (send dc set-alpha 0.6) (send dc set-font (make-font #:size 60 #:family 'swiss #:weight 'bold)) (send dc set-text-foreground "red") (send dc draw-text "Hello" 16 20) (send dc set-text-foreground "blue") (send dc draw-text "Hello" 16 140) (send target save-file filename 'png)) (draw-example "18.png")
15. Želví grafika
V jazyku Racket existuje i několik knihoven určených pro kreslení s využitím želví grafiky, které jsme se věnovali v samostatném článku. Základní knihovna určená pro tuto oblast se jmenuje graphics/turtles. Podívejme se nyní jen na několik základních příkladů.
Vykreslení čtverce:
#lang racket/base (require graphics/turtles) (turtles) (draw 100) (turn 90) (draw 100) (turn 90) (draw 100) (turn 90) (draw 100) (turn 90) (turtles #f) (save-turtle-bitmap "19.png" 'png)
Obrázek 22: Čtverec vykreslený pomocí želví grafiky.
Vykreslení mnohoúhelníku se 72 hranami (takže se podobá kružnici):
#lang racket/base (require graphics/turtles) (turtles) (define (repeat count function) (for ((i (in-range count))) (function))) (repeat 72 (lambda () (turn 5) (draw 15))) (turtles #f) (save-turtle-bitmap "20.png" 'png)
Obrázek 23: Mnohoúhelník se 72 hranami.
Stejný příklad, ovšem želva byla posunuta o 100 pixelů ve vertikálním směru (na obrázku to není patrné, ale při zobrazení GUI se celý mnohoúhelník/kružnice posune do středu okna:
#lang racket/base (require graphics/turtles) (turtles) (move-offset 0 100) (define (repeat count function) (for ((i (in-range count))) (function))) (repeat 72 (lambda () (turn 5) (draw 15))) (turtles #f) (save-turtle-bitmap "21.png" 'png)
Obrázek 24: Mnohoúhelník se 72 hranami.
16. Použití funkce repeat pro vykreslení složitějších obrazců
V programovacím jazyku Logo se velmi často používá příkaz repeat pro opakované volání stejného kódu, v němž se ovšem mění stav samotné želvy (viz například příklad uvedený zde nebo zde, popř. popis uvedený v tomto článku). Tento příkaz můžeme odsimulovat i v jazyku Racket:
(define (repeat count function) (for ((i (in-range count))) (function)))
Příklad použití, v němž je repeat třikrát zanořen:
#lang racket/base (require graphics/turtles) (turtles) (define (repeat count function) (for ((i (in-range count))) (function))) (repeat 36 (lambda () (turn 10) (repeat 10 (lambda () (turn 36) (draw 80) (repeat 3 (lambda () (draw 30) (turn 120))))))) (turtles #f) (save-turtle-bitmap "22.png" 'png)
Obrázek 25: Obrazec vytvořený pomocí opakování příkazů s využitím repeat.
17. Další možnosti želví grafiky
S využitím funkce repeat můžeme začít vytvářet i složitější obrazce:
#lang racket/base (require graphics/turtles) (turtles) (define (repeat count function) (for ((i (in-range count))) (function))) (repeat 36 (lambda () (turn 10) (repeat 36 (lambda () (turn 10) (draw 20))))) (turtles #f) (save-turtle-bitmap "23.png" 'png)
Obrázek 26: Obrazec vytvořený pomocí opakování příkazů s využitím repeat.
Některé knihovny a systémy pro práci s želví grafikou umožňují použít větší množství želv (tento koncept se objevil například i ve stařičkém Atari Logu pro osmibitové mikropočítače Atari, kde pro tento účel sloužila funkce TELL). Jakmile je vytvořena další želva (či želvy), budou všechny želvy reagovat na další příkazy pro posun, kreslení, otočení atd. Vytvoření želvy se provádí funkcí:
(split ...)
Důležité je, že se této funkci může přidat příkaz pro posun či pro otočení želvy. Nová želva tedy nebude zcela totožná s původní želvou nebo želvami. Ukažme si nyní použití několika želv, které budou postupně vytvářeny a budou postupně kreslit části výsledného obrazce:
#lang racket/base (require graphics/turtles) (turtles) (define (repeat count function) (for ((i (in-range count))) (function))) (repeat 6 (lambda () (turn 60) (split (move 10)) (repeat 36 (lambda () (turn 10) (draw 20))))) (turtles #f) (save-turtle-bitmap "24.png" 'png)
Obrázek 27: Obrazec vykreslený několika želvami.
V dnešním posledním demonstračním příkladu použijeme pomocnou funkci nazvanou radial-turtles, kterou nalezneme v knihovně graphics/turtle-examples. Tato funkce slouží pro vytvoření stanoveného počtu želv, které jsou rozmístěny po kružnici. Poté, co všem těmto želvám zadáme vykreslení hvězdy, vznikne následující obrazec:
Obrázek 28: Obrazec vykreslený několika želvami.
Zdrojový kód příkladu, v němž je použita výše zmíněná funkce , vypadá následovně:
#lang racket/base (require graphics/turtles) (require graphics/turtle-examples) (turtles) (define (repeat count function) (for ((i (in-range count))) (function))) (radial-turtles 5) (move 120) (repeat 6 (lambda () (draw 30) (turn 144))) (turtles #f) (save-turtle-bitmap "25.png" 'png)
18. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/lisp-families.git (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
19. Literatura
- Peter Seibel
„Practical Common Lisp“
2009 - Paul Graham
„ANSI Common Lisp“
1995 - Gerald Gazdar
„Natural Language Processing in Lisp: An Introduction to Computational Linguistics“
1989 - Peter Norvig
„Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp“
1991 - Alex Mileler et.al.
„Clojure Applied: From Practice to Practitioner“
2015 - „Living Clojure: An Introduction and Training Plan for Developers“
2015 - Dmitri Sotnikov
„Web Development with Clojure: Build Bulletproof Web Apps with Less Code“
2016 - McCarthy
„Recursive functions of symbolic expressions and their computation by machine, part I“
1960 - R. Kent Dybvig
„The Scheme Programming Language“
2009 - Max Hailperin
„Concrete Abstractions“
1998 - Guy L. Steele
„History of Scheme“
2006, Sun Microsystems Laboratories - Kolář J., Muller K.:
„Speciální programovací jazyky“
Praha 1981 - „AutoLISP Release 9, Programmer's reference“
Autodesk Ltd., October 1987 - „AutoLISP Release 10, Programmer's reference“
Autodesk Ltd., September 1988 - McCarthy, John; Abrahams, Paul W.; Edwards, Daniel J.; Hart, Timothy P.; Levin, Michael I.
„LISP 1.5 Programmer's Manual“
MIT Press. ISBN 0 262 130 1 1 4 - Carl Hewitt; Peter Bishop and Richard Steiger
„A Universal Modular Actor Formalism for Artificial Intelligence“
1973 - Feiman, J.
„The Gartner Programming Language Survey (October 2001)“
Gartner Advisory - Harold Abelson, Gerald Jay Sussman, Julie Sussman:
Structure and Interpretation of Computer Programs
MIT Press. 1985, 1996 (a možná vyšel i další přetisk) - Paul Graham
On Lisp
Prentice Hall, 1993
Dostupné online na stránce http://www.paulgraham.com/onlisptext.html - David S. Touretzky
Common LISP: A Gentle Introduction to Symbolic Computation (Dover Books on Engineering)
- Peter Norvig
Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp - Patrick Winston, Berthold Horn
Lisp (3rd Edition)
ISBN-13: 978–0201083194, ISBN-10: 0201083191 - Matthias Felleisen, David Van Horn, Dr. Conrad Barski
Realm of Racket: Learn to Program, One Game at a Time!
ISBN-13: 978–1593274917, ISBN-10: 1593274912 - Graham Hutton
A tutorial on the universality andexpressiveness of fold
http://www.cs.nott.ac.uk/~pszgmh/fold.pdf
20. Odkazy na Internetu
- Racket: programovací jazyk a současně i platforma pro vývoj nových jazyků
https://www.root.cz/clanky/racket-programovaci-jazyk-a-soucasne-i-platforma-pro-vyvoj-novych-jazyku/ - Makra v Racketu i v dalších lispovských jazycích
https://www.root.cz/clanky/makra-v-racketu-i-v-dalsich-lispovskych-jazycich/ - Základní knihovna jazyka Racket
https://www.root.cz/clanky/zakladni-knihovna-jazyka-racket/ - Grafický metaformát PostScript
https://www.root.cz/clanky/graficky-metaformat-postscript/ - Vektorový grafický formát SVG
https://www.root.cz/clanky/vektorovy-graficky-format-svg/ - The Racket Drawing Toolkit
https://docs.racket-lang.org/draw/index.html - Traditional Turtles
https://docs.racket-lang.org/turtles/Traditional_Turtles.html - [racket] How best to repeat a function call n times?
https://lists.racket-lang.org/users/archive/2014-September/064203.html - Racket: Macros
https://www.it.uu.se/edu/course/homepage/avfunpro/ht13/lectures/Racket-3-Macros.pdf - Beautiful Racket / explainers: Macros
https://beautifulracket.com/explainer/macros.html - Macros (dokumentace k Racketu)
https://docs.racket-lang.org/guide/macros.html - Model syntaxe jazyka Racket
https://docs.racket-lang.org/reference/syntax-model.html - Syntax Objects
https://docs.racket-lang.org/guide/stx-obj.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Beautiful Racket: an introduction to language-oriented programming using Racket
https://beautifulracket.com/ - Stránky projektu Racket
https://racket-lang.org/ - Dokumentace k projektu Racket
https://docs.racket-lang.org/index.html - Seznam dostupných balíčků pro Racket
https://pkgs.racket-lang.org/ - Racket na Wikipedii
https://en.wikipedia.org/wiki/Racket_(programming_language) - Blogy o Racketu a navazujících technologiích
https://blog.racket-lang.org/ - Prográmky psané v Racketu na RosettaCode
http://rosettacode.org/wiki/Category:Racket - Fear of Macros
https://www.greghendershott.com/fear-of-macros/ - Rackjure
https://github.com/greghendershott/rackjure - Matthew Flatt’s proposal to change Racket’s s-expressions based syntax to infix representation creates a stir in the community
https://hub.packtpub.com/matthew-flatts-proposal-to-change-rackets-s-expressions-based-syntax-to-infix-representation-creates-a-stir-in-the-community/ - Racket News
https://racket-news.com/ - Racket: Lisp for learning
https://lwn.net/Articles/795385/ - Future of Racket
https://www.greghendershott.com/2019/07/future-of-racket.html - Kawa: Compiling Scheme to Java
https://www.mit.edu/afs.new/sipb/project/kawa/doc/kawa-tour.html - Kawa in Languages shootout
http://per.bothner.com/blog/2010/Kawa-in-shootout/ - Kawa 2.0 Supports Scheme R7RS
https://developers.slashdot.org/story/14/12/13/2259225/kawa-20-supports-scheme-r7rs/ - Kawa — fast scripting on the Java platform
https://lwn.net/Articles/623349/ - Tail call (a její optimalizace)
https://en.wikipedia.org/wiki/Tail_call - SLIME (Wikipedia)
http://en.wikipedia.org/wiki/SLIME - slime.vim
http://s3.amazonaws.com/mps/slime.vim - What are the best scheme implementations?
https://www.slant.co/topics/5282/~scheme-implementations - Bigloo homepage
http://www-sop.inria.fr/mimosa/fp/Bigloo/ - FTP s tarbally Bigloo
ftp://ftp-sop.inria.fr/indes/fp/Bigloo - GOTO 2018 • Functional Programming in 40 Minutes • Russ Olsen
https://www.youtube.com/watch?v=0if71HOyVjY - TinyScheme (stránka na Sourceforge)
http://tinyscheme.sourceforge.net/home.html - Embedding Tiny Scheme in a Game
http://www.silicondelight.com/embedding-tiny-scheme-in-a-game/ - Embedding Scheme for a game mission scripting DSL
http://carloscarrasco.com/embedding-scheme-for-a-game-mission-scripting-dsl.html - Všechny verze TinyScheme na SourceForge
https://sourceforge.net/projects/tinyscheme/files/tinyscheme/ - Fork TinyScheme na GitHubu
https://github.com/yawnt/tinyscheme - Ackermannova funkce
https://cs.wikipedia.org/wiki/Ackermannova_funkce - Ackermann function na Rosetta Code
https://rosettacode.org/wiki/Ackermann_function#Scheme - Success Stories (lisp.org)
https://lisp-lang.org/success/ - Allegro Common Lisp Success Stories
https://franz.com/success/ - Clojure Success Stories
https://clojure.org/community/success_stories - Scheme Quick Reference
https://www.st.cs.uni-saarland.de/edu/config-ss04/scheme-quickref.pdf - Slajdy o Scheme (od slajdu číslo 15)
https://docs.google.com/presentation/d/1abmDnKjrq1tcjGvvRNAKhOiSTSE2lyagtcEPal07Gbo/edit - Scheme Cheat Sheet
https://github.com/smythp/scheme-cheat-sheet - Embedding Lua, embedding Guile
http://puntoblogspot.blogspot.com/2013/04/embedding-lua-embedding-guile.html - Lambda Papers
https://en.wikisource.org/wiki/Lambda_Papers - Revised7Report on the Algorithmic Language Scheme
https://small.r7rs.org/attachment/r7rs.pdf - Video Lectures (MIT, SICP 2005)
https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6–001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/ - Why is Scheme my first language in university?
https://softwareengineering.stackexchange.com/questions/115252/why-is-scheme-my-first-language-in-university - The Perils of JavaSchools
https://www.joelonsoftware.com/2005/12/29/the-perils-of-javaschools-2/ - How to Design Programs, Second Edition
https://htdp.org/2019–02–24/index.html - LilyPond
http://lilypond.org/ - LilyPond — Extending (přes Scheme)
http://lilypond.org/doc/v2.18/Documentation/extending/scheme-tutorial - Scheme in LilyPond
http://lilypond.org/doc/v2.18/Documentation/extending/scheme-in-lilypond - GnuCash
http://www.gnucash.org/ - Custom Reports (in GNU Cash)
https://wiki.gnucash.org/wiki/Custom_Reports - Program by Design
https://programbydesign.org/ - SchemePy
https://pypi.org/project/SchemePy/ - LISP FQA: Section – [1–5] What is the „minimal“ set of primitives needed for a Lisp interpreter?
http://www.faqs.org/faqs/lisp-faq/part1/section-6.html - femtolisp
https://github.com/JeffBezanson/femtolisp - (How to Write a (Lisp) Interpreter (in Python))
http://norvig.com/lispy.html - Repositář s Guile Emacsem
http://git.hcoop.net/?p=bpt/guile.git - Interacting with Guile Compound Data Types in C
http://www.lonelycactus.com/guilebook/x1555.html - Calling Guile functions from C
http://www.lonelycactus.com/guilebook/c1204.html#SECCALLGUILEFUNC - Arrays, and other compound data types
http://www.lonelycactus.com/guilebook/charrays.html - Interacting with Guile Compound Data Types in C
http://www.lonelycactus.com/guilebook/x1555.html - Guile Reference Manual
https://www.gnu.org/software/guile/manual/html_node/index.html - Scheme: Summary of Common Syntax
https://www.gnu.org/software/guile/manual/html_node/Syntax-Summary.html#Syntax-Summary - Scripting with Guile: Extension language enhances C and Scheme
https://www.ibm.com/developerworks/library/l-guile/index.html - Having fun with Guile: a tutorial
http://dustycloud.org/misc/guile-tutorial.html - Guile: Loading Readline Support
https://www.gnu.org/software/guile/manual/html_node/Loading-Readline-Support.html#Loading-Readline-Support - lispy
https://pypi.org/project/lispy/ - Lython
https://pypi.org/project/Lython/ - Lizpop
https://pypi.org/project/lizpop/ - Budoucnost programovacích jazyků
http://www.knesl.com/budoucnost-programovacich-jazyku - LISP Prolog and Evolution
http://blog.samibadawi.com/2013/05/lisp-prolog-and-evolution.html - List of Lisp-family programming languages
https://en.wikipedia.org/wiki/List_of_Lisp-family_programming_languages - clojure_py na indexu PyPi
https://pypi.python.org/pypi/clojure_py - PyClojure
https://github.com/eigenhombre/PyClojure - Hy na GitHubu
https://github.com/hylang/hy - Hy: The survival guide
https://notes.pault.ag/hy-survival-guide/ - Hy běžící na monitoru terminálu společnosti Symbolics
http://try-hy.appspot.com/ - Welcome to Hy’s documentation!
http://docs.hylang.org/en/stable/ - Hy na PyPi
https://pypi.org/project/hy/#description - Getting Hy on Python
https://lwn.net/Articles/596626/ - Programming Can Be Fun with Hy
https://opensourceforu.com/2014/02/programming-can-fun-hy/ - Přednáška o projektu Hy (pětiminutový lighttalk)
http://blog.pault.ag/day/2013/04/02 - Hy (Wikipedia)
https://en.wikipedia.org/wiki/Hy - GNU Emacs Lisp Reference Manual: Point
https://www.gnu.org/software/emacs/manual/html_node/elisp/Point.html - GNU Emacs Lisp Reference Manual: Narrowing
https://www.gnu.org/software/emacs/manual/html_node/elisp/Narrowing.html - GNU Emacs Lisp Reference Manual: Functions that Create Markers
https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Markers.html - GNU Emacs Lisp Reference Manual: Motion
https://www.gnu.org/software/emacs/manual/html_node/elisp/Motion.html#Motion - GNU Emacs Lisp Reference Manual: Basic Char Syntax
https://www.gnu.org/software/emacs/manual/html_node/elisp/Basic-Char-Syntax.html - Elisp: Sequence: List, Array
http://ergoemacs.org/emacs/elisp_list_vs_vector.html - Elisp: Property List
http://ergoemacs.org/emacs/elisp_property_list.html - Elisp: Hash Table
http://ergoemacs.org/emacs/elisp_hash_table.html - Elisp: Association List
http://ergoemacs.org/emacs/elisp_association_list.html - The mapcar Function (An Introduction to Programming in Emacs Lisp)
https://www.gnu.org/software/emacs/manual/html_node/eintr/mapcar.html - Anaphoric macro
https://en.wikipedia.org/wiki/Anaphoric_macro - Some Common Lisp Loop Macro Examples
https://www.youtube.com/watch?v=3yl8o6r_omw - A Guided Tour of Emacs
https://www.gnu.org/software/emacs/tour/ - The Roots of Lisp
http://www.paulgraham.com/rootsoflisp.html - Evil (Emacs Wiki)
https://www.emacswiki.org/emacs/Evil - Evil (na GitHubu)
https://github.com/emacs-evil/evil - Evil (na stránkách repositáře MELPA)
https://melpa.org/#/evil - Evil Mode: How I Switched From VIM to Emacs
https://blog.jakuba.net/2014/06/23/evil-mode-how-to-switch-from-vim-to-emacs.html - GNU Emacs (home page)
https://www.gnu.org/software/emacs/ - GNU Emacs (texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?GnuEmacs - An Introduction To Using GDB Under Emacs
http://tedlab.mit.edu/~dr/gdbintro.html - An Introduction to Programming in Emacs Lisp
https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html - 27.6 Running Debuggers Under Emacs
https://www.gnu.org/software/emacs/manual/html_node/emacs/Debuggers.html - GdbMode
http://www.emacswiki.org/emacs/GdbMode - Emacs (Wikipedia)
https://en.wikipedia.org/wiki/Emacs - Emacs timeline
http://www.jwz.org/doc/emacs-timeline.html - Emacs Text Editors Family
http://texteditors.org/cgi-bin/wiki.pl?EmacsFamily - Vrapper aneb spojení možností Vimu a Eclipse
https://mojefedora.cz/vrapper-aneb-spojeni-moznosti-vimu-a-eclipse/ - Vrapper aneb spojení možností Vimu a Eclipse (část 2: vyhledávání a nahrazování textu)
https://mojefedora.cz/vrapper-aneb-spojeni-moznosti-vimu-a-eclipse-cast-2-vyhledavani-a-nahrazovani-textu/ - Emacs/Evil-mode – A basic reference to using evil mode in Emacs
http://www.aakarshnair.com/posts/emacs-evil-mode-cheatsheet - From Vim to Emacs+Evil chaotic migration guide
https://juanjoalvarez.net/es/detail/2014/sep/19/vim-emacsevil-chaotic-migration-guide/ - Introduction to evil-mode {video)
https://www.youtube.com/watch?v=PeVQwYUxYEg - EINE (Emacs Wiki)
http://www.emacswiki.org/emacs/EINE - EINE (Texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?EINE - ZWEI (Emacs Wiki)
http://www.emacswiki.org/emacs/ZWEI - ZWEI (Texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?ZWEI - Zmacs (Wikipedia)
https://en.wikipedia.org/wiki/Zmacs - Zmacs (Texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?Zmacs - TecoEmacs (Emacs Wiki)
http://www.emacswiki.org/emacs/TecoEmacs - Micro Emacs
http://www.emacswiki.org/emacs/MicroEmacs - Micro Emacs (Wikipedia)
https://en.wikipedia.org/wiki/MicroEMACS - EmacsHistory
http://www.emacswiki.org/emacs/EmacsHistory - Seznam editorů s ovládáním podobným Emacsu či kompatibilních s příkazy Emacsu
http://www.finseth.com/emacs.html - evil-numbers
https://github.com/cofi/evil-numbers - Debuggery a jejich nadstavby v Linuxu (1.část)
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2.část)
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
https://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Org mode
https://orgmode.org/ - The Org Manual
https://orgmode.org/manual/index.html - Kakoune (modální textový editor)
http://kakoune.org/ - Vim-style keybinding in Emacs/Evil-mode
https://gist.github.com/troyp/6b4c9e1c8670200c04c16036805773d8 - Emacs – jak začít
http://www.abclinuxu.cz/clanky/navody/emacs-jak-zacit - Programovací jazyk LISP a LISP machines
https://www.root.cz/clanky/programovaci-jazyk-lisp-a-lisp-machines/ - Evil-surround
https://github.com/emacs-evil/evil-surround - Spacemacs
http://spacemacs.org/ - Lisp: Common Lisp, Racket, Clojure, Emacs Lisp
http://hyperpolyglot.org/lisp - Common Lisp, Scheme, Clojure, And Elisp Compared
http://irreal.org/blog/?p=725 - Does Elisp Suck?
http://irreal.org/blog/?p=675 - Emacs pro mírně pokročilé (9): Elisp
https://www.root.cz/clanky/emacs-elisp/ - If I want to learn lisp, are emacs and elisp a good choice?
https://www.reddit.com/r/emacs/comments/2m141y/if_i_want_to_learn_lisp_are_emacs_and_elisp_a/ - Clojure(Script) Interactive Development Environment that Rocks!
https://github.com/clojure-emacs/cider - An Introduction to Emacs Lisp
https://harryrschwartz.com/2014/04/08/an-introduction-to-emacs-lisp.html - Emergency Elisp
http://steve-yegge.blogspot.com/2008/01/emergency-elisp.html - Lambda calculus
https://en.wikipedia.org/wiki/Lambda_calculus - John McCarthy's original LISP paper from 1959
https://www.reddit.com/r/programming/comments/17lpz4/john_mccarthys_original_lisp_paper_from_1959/ - Micro Manual LISP
https://www.scribd.com/document/54050141/Micro-Manual-LISP - How Lisp Became God's Own Programming Language
https://twobithistory.org/2018/10/14/lisp.html - History of Lisp
http://jmc.stanford.edu/articles/lisp/lisp.pdf - The Roots of Lisp
http://languagelog.ldc.upenn.edu/myl/llog/jmc.pdf - Racket
https://racket-lang.org/ - The Racket Manifesto
http://felleisen.org/matthias/manifesto/ - MIT replaces Scheme with Python
https://www.johndcook.com/blog/2009/03/26/mit-replaces-scheme-with-python/ - Adventures in Advanced Symbolic Programming
http://groups.csail.mit.edu/mac/users/gjs/6.945/ - Why MIT Switched from Scheme to Python (2009)
https://news.ycombinator.com/item?id=14167453 - Starodávná stránka XLispu
http://www.xlisp.org/ - AutoLISP
https://en.wikipedia.org/wiki/AutoLISP - Seriál PicoLisp: minimalistický a výkonný interpret Lispu
https://www.root.cz/serialy/picolisp-minimalisticky-a-vykonny-interpret-lispu/ - Common Lisp
https://common-lisp.net/ - Getting Going with Common Lisp
https://cliki.net/Getting%20Started - Online Tutorial (Common Lisp)
https://cliki.net/online%20tutorial - Guile Emacs
https://www.emacswiki.org/emacs/GuileEmacs - Guile Emacs History
https://www.emacswiki.org/emacs/GuileEmacsHistory - Guile is a programming language
https://www.gnu.org/software/guile/ - MIT Scheme
http://groups.csail.mit.edu/mac/projects/scheme/ - SIOD: Scheme in One Defun
http://people.delphiforums.com/gjc//siod.html - CommonLispForEmacs
https://www.emacswiki.org/emacs/CommonLispForEmacs - Elisp: print, princ, prin1, format, message
http://ergoemacs.org/emacs/elisp_printing.html - Special Forms in Lisp
http://www.nhplace.com/kent/Papers/Special-Forms.html - Basic Building Blocks in LISP
https://www.tutorialspoint.com/lisp/lisp_basic_syntax.htm - Introduction to LISP – University of Pittsburgh
https://people.cs.pitt.edu/~milos/courses/cs2740/Lectures/LispTutorial.pdf - Why don't people use LISP
https://forums.freebsd.org/threads/why-dont-people-use-lisp.24572/ - Structured program theorem
https://en.wikipedia.org/wiki/Structured_program_theorem - Clojure: API Documentation
https://clojure.org/api/api - Tutorial for the Common Lisp Loop Macro
http://www.ai.sri.com/pkarp/loop.html - Common Lisp's Loop Macro Examples for Beginners
http://www.unixuser.org/~euske/doc/cl/loop.html - A modern list api for Emacs. No 'cl required.
https://github.com/magnars/dash.el - The LOOP Facility
http://www.lispworks.com/documentation/HyperSpec/Body/06_a.htm - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - Transient Data Structureshttp://clojure.org/transients
- Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Jazyky Hy a Clojure-py: moderní dialekty LISPu určené pro Python VM
https://www.root.cz/clanky/jazyky-hy-a-clojure-py-moderni-dialekty-lispu-urcene-pro-python-vm/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/ - Stránka projektu Jython
http://www.jython.org/ - Jython (Wikipedia)
https://en.wikipedia.org/wiki/Jython - Scripting for the Java Platform (Wikipedia)
https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - JSR 223: Scripting for the JavaTM Platform
https://jcp.org/en/jsr/detail?id=223 - List of JVM languages
https://en.wikipedia.org/wiki/List_of_JVM_languages - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354