3. Domácí úkol: Kulečník
Úvod
V teorii chaosu se studuje chování tzv. dynamických kulečníků (dynamical billiards). Jde o jednoduché modely popisující pohyb kuličky zanedbatelných rozměrů v rovině omezený překážkami, na kterých dochází k dokonale pružnému odrazu. Ve volném prostoru se kulička pohybuje rovnoměrně přímočaře (po přímce) a směr pohybu se mění jenom při odrazu na překážce podle známého zákona odrazu (úhel dopadnu je shodný s úhlem odrazu).
Teoretický background
Odraz na překážkách
V našem simulátoru se zaměříme pouze na dva typy překážek, z kterých bude možné okraj kulečníku sestavit:
- úsečky spojující dva zadané body,
- části kružnice.
Naše kulička bude popsána polohou (bod v rovině) a vektorem rychlosti. Zřejmě si stačí zaznamenávat pouze body, kdy dochází k odrazu (viz níže).
Odraz v obou případech probíhá podobně. Dojde pouze k změně velikosti rychlosti podle následujícího pravidla: je-li vektor udávající směrnici tečny k překážce a odpovídající normálový směr, oba normalizované na jedničku (délky 1), pak nový směr kuličky po odrazu je
kde označuje standardní skalární součin. Vektory a uvedené výše v případě jednotlivých překážek určíme snadno:
- v případě úsečky: směrovým vektorem je směrový vektor přímky, na které úsečka leží, normálový vektor je pak libovolný vektor kolmý na s jednotkovou délkou,
- v případě kružnice: normálový vektor je vektor spojující bod dopadu a střed kružnice, směrový vektor je pak libovolný vektor kolmý na s jednotkovou délkou.
Poincarého řezy
Jedním z vizuálních nástrojů pro pozorování chaosu jsou tzv. Poincarého řezy.
Stav kuličky v našem kulečníku je dán její polohou (bod v rovině) a směrem rychlosti (velikost nehraje roli). Libovolný stav kuličky je proto prvek množiny (tzv. fázový prostor). Prvky této množiny, ale i trajektorie v rovině, sice jde vizualizovat, ale výsledek je značně nepřehledný.
Poincarého myšlenka spočívá v "řezu" této množiny. V našem případě konkrétně zafixujeme úsečku (podél které kulečník rozřízneme) a zaznamenáme si pouze průsečíky trajektorií s touto úsečkou a směr rychlosti. Jsou-li krajní body řezu a a trajektorie prochází bodem ležícím na úsečce spojující tyto dva body, tj. , kde , pak zobrazíme bod o souřadnicích , kde je úhel, který vektor rychlosti svírá s kladným směrem osy , tj. hodnota mezi a . K rozlišení trajektorií použijeme rozdílné barvy (tj. body v řezu odpovídající jedné trajektorii jsou jedné barvy).
Implementační pokyny
V souboru src/billiard.jl
doplňte implementaci modulu Billiard
, který bude umožňovat vytvoření hranice kulečníku z dvou primitivních překážek:
- úsečka zadaná svými krajními body (typ
Segment
, podrobněji níže), - oblouk kružnice zadaný středem a poloměr kružnice a dvěma úhly (typ
Arc
, podrobněji níže).
Celou implementaci pro jednoduchost a rychlost provedeme ve strojových číslech (tj. vektory a různé hodnoty budou uvažovány pouze typu Float64
).
Tento úkol vytvořte jako projekt, tj. bude možné ho aktivovat a doinstalovat závislosti, které použijete na vykreslování.
Typy
Abstraktní typ Obstacle
modeluje libovolnou překážku a má dva podtypy, typ Segment
a typ Arc
.
Typ Segment
představuje úsečku a k vytvoření objektu jednoduše vyžaduje dva body dané úsečky.
Body chápeme jako Vector{Float64}
o dvou složkách.
Nelze vytvořit úsečku mezi body, které jsou u sebe moc blízko nebo jsou dokonce si rovny (blízkost bodů ověřujte pomocí metody isapprox
)
Typ Arc
představuje část oblouku kružnice se středem v bodě (Vector{Float64}
) a poloměrem (Float64
) a dále dvěma úhly (oba Float64
).
První úhel musí být menší než druhý a ukazují (proti směru hodinových ručiček od kladného směru osy ) začátek a konec oblouku.
Tj. pokud bychom měli jednotkovou kružnici, tak s úhly a mluvíme pouze o její části nad osou .
Střed kružnice musí být svousložkový vektor (jsme v rovině), poloměr musí být nezáporný, první úhel musí být menší než druhý a musí být možné je zadat i jako násobky (v Julia existuje abstraktní konstanta pi
, její použití je pohodlné pro uživatele).
Posledním použitým vlastním typem je typ Table
, který jednoduše modeluje kulečník sestavený z překážek z dvou výše uvedených typů.
Tyto překážky jednoduše ukládá/dostává v poli typu Vector{Obstacle}
.
simulate!
Funkce Tato metoda počítá postupně body odrazu na okraji kulečníku, který jí předáme v prvním argumentu (table
).
Druhý argument (path
) obsahuje matici Float64
hodnot rozměru , kde v prvním sloupci jsou uloženy počáteční podmínky: popořadě souřadnice polohy a složky vektoru rychlosti (nemusí být jednotkový).
Metoda z této počáteční podmínky poté vyplní zbývající sloupce pole hodnotami souřadnic dopadů na hranici a novými složkami rychlosti (po odrazu).
Počet odrazů, které algoritmus napočítá je tedy .
Hodnota musí být alespoň .
Matice path
musí mít právě čtyři řádky.
Pokud algoritmus nenajde další dopadu ("děravý" kulečník, nebo špatné počáteční podmínky vně kulečníku), dojde k výjimce RuntimeError
.
draw_path
a draw_poincare
Vizualizační funkce Konečně budou k dispozici dvě vizualizační metody:
draw_path
přijme minimálně kulečníktable
a trajektoriipath
, které vykreslí.draw_poincare
přijme minimálně pole trajektoriípaths
, dva bodyP1
aP2
určující koncové body řezu a vykreslí Poincarého řez popsaný výše.
Testy
Vaši implementaci prověříte spuštěním testů (automaticky se spouštějí i na Gitlabu) příkazem julia --project=@. test/runtests.jl
.
Řešení a odevzdání
Opět vytvořte větev odvozenou z větve assignment/03-billiard
a nezvěte ji solution/03-billiard
.
Do solution/03-billiard
vložte své řešení, což zde znamená vytvoření projektu a primárně editaci src/billiard.jl
. Zdrojový kód ale můžete rozdělit na více souboru, případně přidat testy do složky test
.
Až budete se svým řešením spokojeni, vytvořte MR (to můžete i dříve, aspoň uvidíte výsledek testů, pokud je nespouštíte lokálně) a přiřaďte mě k němu jako assignee
.
Tímto aktem úkol odevzdáte.