Univerzita Karlova v Praze Matematicko-fyzikální fakulta
BAKALÁŘSKÁ PRÁCE
Martin Chytil Automatický dispečer železničního provozu Katedra aplikované matematiky
Vedoucí bakalářské práce: Mgr. Robert Babilon Studijní program: Informatika, programování
2009
Děkuji panu Mgr. Robertu Babilonovi za odborné vedení mé práce, za rady a za čas, který mi během vypracování této práce věnoval.
Prohlašuji, že jsem svou bakalářskou práci napsal samostatně a výhradně s použitím citovaných pramenů. Souhlasím se zapůjčováním práce. V Praze dne 28.5.2009
Martin Chytil
-2-
Obsah 1
Úvod ......................................................................................................................... 6
2
Požadavky na program .......................................................................................... 7 2.1 Požadavky na editor.......................................................................................... 7 2.2 Notace diagramu kolejiště ................................................................................ 7 2.3 Požadavky na simulátor .................................................................................... 8
3
Uživatelská dokumentace....................................................................................... 9 3.1 Instalace programu............................................................................................ 9 3.2 Spuštění programu ............................................................................................ 9 3.3 Editace modelu ................................................................................................. 9 3.3.1 Vytvoření tratě .......................................................................................... 9 3.3.2 Označování objektů................................................................................. 10 3.3.3 Editace objektů na trati........................................................................... 11 3.3.4 Vytvoření a editace vlaku........................................................................ 13 3.3.5 Generování jízdního řádu ....................................................................... 14 3.4 Ukládání a načítání ......................................................................................... 15 3.5 Kontrola tratě .................................................................................................. 16 3.6 Spuštění simulace ........................................................................................... 17 3.7 Ovládání simulace........................................................................................... 17 3.8 Podrobný popis pracovního prostředí ............................................................. 18 3.8.1 Rozložení hlavní aplikace ....................................................................... 18 3.8.2 Menu a toolbar........................................................................................ 18 3.8.3 Boční panel ............................................................................................. 20 3.8.4 Spodní panel ........................................................................................... 20 3.8.5 Stavový řádek.......................................................................................... 20 3.8.6 Ovládání.................................................................................................. 20 3.8.7 Nastavení simulace ................................................................................. 20 3.9 Doporučení pro ovládání ................................................................................ 21
4
Problémy spojené s tvorbou GUI ........................................................................ 23 4.1 Uspořádání aplikace........................................................................................ 23 4.2 Zobrazení diagramu kolejiště.......................................................................... 23 4.3 Vykreslení diagramu....................................................................................... 24 4.4 Zpracování požadavků myši ........................................................................... 24 4.5 Ukládání a otevírání souborů .......................................................................... 26 4.5.1 Uložení do souboru................................................................................. 26 4.5.2 Načtení souboru...................................................................................... 26 4.5.3 Kontrola souboru.................................................................................... 26 4.5.4 Struktura RTS souboru............................................................................ 26 4.6 Undo / Redo .................................................................................................... 27 4.7 Kopírování, vkládání ...................................................................................... 28
5
Kolejiště, vlaky, jízdní řády ................................................................................. 30 5.1 Reprezentace kolejiště v programu................................................................. 30 5.2 Sestavení tratě ................................................................................................. 30 5.3 Kontrola tratě .................................................................................................. 31 5.3.1 Spojení tratě............................................................................................ 31 -3-
5.3.2 Test souvislosti tratě ............................................................................... 31 5.3.3 Validační test .......................................................................................... 32 5.4 Reprezentace vlaků v programu ..................................................................... 32 5.5 Hledání cest vlaků........................................................................................... 32 5.6 Reprezentace jízdních řádů v programu ......................................................... 34 5.7 Generování jízdních řádů................................................................................ 34 6
Simulace................................................................................................................. 36 6.1 Spuštění a běh simulace.................................................................................. 36 6.2 Kolizní cesta a kolizní body............................................................................ 36 6.2.1 Kolizní body ............................................................................................ 36 6.2.2 Kolizní cesta............................................................................................ 37 6.3 Plánovač úloh.................................................................................................. 38 6.4 Řízení simulace............................................................................................... 39 6.4.1 Inicializace.............................................................................................. 39 6.4.2 Procesní fáze........................................................................................... 39 6.4.3 Fáze ukončení ......................................................................................... 39 6.5 Pohyb vlaků .................................................................................................... 40 6.6 Krokování pohybu vlaků ................................................................................ 41 6.6.1 Vlastnosti pohybu.................................................................................... 41 6.6.2 Anomálie při použití průměrného přírůstku ........................................... 41 6.6.3 Krokování................................................................................................ 41 6.6.4 Generování výchozích přírůstků ............................................................. 42 6.6.5 Zaokrouhlovací chyby............................................................................. 43
7
Automatické řízení provozu................................................................................. 44 7.1 Úloha dispečera............................................................................................... 44 7.2 Stavění cest ..................................................................................................... 44 7.3 Řízení provozu................................................................................................ 44 7.3.1 Postavení nového úseku cesty ................................................................. 45 7.3.2 Uvolnění nepoužívaného úseku cesty...................................................... 46 7.3.3 Hledání nejvhodnějšího čekajícího vlaku ............................................... 46
8
Závěr ...................................................................................................................... 47 8.1 Budoucnost programu RTS ............................................................................ 47
Literatura ...................................................................................................................... 48 Přílohy............................................................................................................................ 49 Instalační CD .............................................................................................................. 49
-4-
Název práce:Automatický dispečer železničního provozu Autor: Martin Chytil Katedra: Katedra aplikované matematiky Vedoucí práce: Mgr. Robert Babilon E-mail vedoucího:
[email protected] Abstrakt: Cílem práce je vytvořit prostředí, ve kterém bude možno simulovat provoz železnice za nečekaných událostí. Z toho důvodu je důležité rozdělit vytvářený program do dvou samostatných částí, které spolu budou úzce spolupracovat – editoru a simulátoru. V editoru si uživatel nejdříve vytvoří svůj model železnice, vytvoří si vlaky a jízdní řád. Simulátor mu pak jeho model odsimuluje s tím, že do simulace uživatel bude moci zasahovat a vnášet do ní mimořádnosti. Automatický dispečer se pak pokusí situaci vyhodnotit a vyřešit pokud možno s co nejmenším dopadem na provoz. Klíčová slova: modelování tratě, řízení provozu, zpoždění
Title: Automatic Rail Traffic Controller Author: Martin Chytil Department: Department of Applied Mathematics Supervisor: Mgr. Robert Babilon Supervisor’s e-mail address:
[email protected] Abstract: The goal of this work is to create program environment which is simulating railway activity during unexpected situations. For that reason it is important to separate creating program into two separated parts which are cooperating with each other – editor and simulator. At first user makes his own railway model, creates trains and generates traffic order. Then simulator starts simulating and user can create exceptionalities on it. Automatic Controller solves these special situations to minimalize consequences of railway activity. Keywords: railway modelling, traffic controlling, overdues
-5-
1 Úvod Snad každý již ve svém životě někdy jel vlakem, ale málokdo se u toho zamýšlel nad tím, proč vlaky jezdí, kudy jezdí, proč přejíždí z jedné koleje na druhou a jestli a jak je vůbec železniční doprava řízena. Běžně vlaky slouží pro přepravu osob, ale musíme si být vědomi, že existují i nákladní vlaky na přepravu materiálu a zboží, dokonce se někdy na trati objeví i například vlaky historické, které slouží jako exhibice. Když se nad tím trochu zamyslíme, tak zjistíme, že většina těchto speciálních vlaků nejezdí pravidelně, tudíž s nimi nelze počítat jako s vlaky pravidelnými. Jistěže mají i takové speciální vlaky své jízdní řády, ale například u nákladní dopravy dochází k tak velkým zpožděním, že v důsledku jako by jízdní řád vůbec nebyl. Nikoho pak ale už moc nezajímá, jaký dopad může takový mimořádný vlak mít na samotný pravidelný provoz. Stejně tak nikomu nepřijde zvláštní, že při opravě železnice vlaky jezdí v obou směrech například jen po jedné koleji a přitom vlak nabírá pouze minimální zpoždění, nebo dokonce žádné. To vše je dáno právě dobrým řízením dopravy. Dispečeři na drahách řídí cesty vlaků tak, aby při nějakých mimořádnostech, i mimo ně, docházelo k minimálnímu zpoždění. A právě cílem této práce je vytvořit program, který dokáže zautomatizovat činnost dispečera na trati s několika stanicemi. Součástí programu bude editor železničních tratí a grafický simulátor, ve kterém bude provoz znázorněn. Do průběhu simulace musí mít uživatel možnost vnášet různé mimořádnosti. Výsledkem práce je program RTS, což je zkratka z anglického označení Railway Traffic Supervisor. Nedílnou součástí programu je pokročilý editor železničních tratí, pomocí kterého uživatel dokáže vytvořit téměř libovolnou trať spolu s vlaky, které se budou po trati pohybovat. Po spuštění simulace může uživatel přerušit trať v některém místě, stejně tak může náhodně vpouštět do tratě mimořádné vlaky a provoz tak narušovat. Ve druhé kapitole práce jsou shrnuty požadavky na samotný program a též vysvětlena notace, která se při modelování použila. Třetí kapitola obsahuje uživatelskou dokumentaci, která slouží jak pro orientaci při užívání programu, tak jako přehled funkcí programu. Na ni navazuje čtvrtá kapitola, kde jsou popsány některé zajímavé problémy, které se při implementaci vyskytly a jak byly vyřešeny. Pátá a šestá kapitola se zaměřují na vlastní programovou reprezentaci tratě, vlaků, jízdních řádů a následné řešení simulace. A konečně sedmá kapitola se zabývá vlastním automatizovaným řízením.
-6-
2 Požadavky na program Úlohou programu je vytvořit prostředí, ve kterém bude možno simulovat provoz železnice za nečekaných událostí. Z toho důvodu je nutné program rozdělit do dvou samostatných částí, které spolu budou úzce spolupracovat – editoru a simulátoru. V editoru si uživatel nejdříve vytvoří svůj model železnice, vytvoří si vlaky a jízdní řád. Simulátor mu pak jeho model odsimuluje s tím, že do simulace uživatel bude moci zasahovat a vnášet do ní problémy. Automatický dispečer se pak pokusí situaci vyhodnotit a vyřešit pokud možno s co nejmenším dopadem na zpoždění vlaků.
2.1 Požadavky na editor Za hlavní cíl editorové části programu RTS byla kladena jednoduchost. Editor programu RTS je navržen tak, aby co nejvíce zpříjemnil a zjednodušil uživateli práci při tvorbě kolejiště, ale zároveň poskytuje plnohodnotné prostředí pro tvorbu libovolně složitých kolejišť. Navíc díky možnostem různého natočení kolejových bloků umožňuje vytvářet modely realisticky, tj. umožňuje zobrazit prvky v poloze odpovídající skutečnosti. Klasický lineární model, používaný mj. také na železnici je podporován samozřejmě také. Oba modely zobrazení je možno navzájem kombinovat. Zároveň editor RTS obsahuje také kontrolní mechanismy, které nedovolí uživateli spustit simulaci provozu na kolejišti, které není správně nastaveno.
2.2 Notace diagramu kolejiště Protože program RTS modeluje železnici, vychází se z notace podobné notaci používané přímo na drahách. Podobné zobrazení prvků využívá též program Multikon [1], ze kterého původně program RTS vychází. Notace vypadá takto: •
Kolej je zobrazena jako plná čára. Speciálním případem koleje je tzv. úsek jednokolejné trati. Zde je pouze jedna samostatná kolej, a tedy nelze vést současně provoz v obou směrech. Jednokolejný úsek trati se od klasické koleje vzhledově nijak neodlišuje, programu se tato informace zadává zvlášť prostřednictvím dialogového okna (viz kapitola 3.3.3 Editace objektů na trati). Tato informace je podstatná pro správný chod simulátoru.
•
Návěstidla jsou vyznačena černým trojúhelníkem směřujícím ven z koleje, na které leží.
•
Jednoduchá výhybka je zobrazena rovnou kolejí, z níž vychází pod úhlem 45° kolej druhá.
•
Složená výhybka je zobrazena jako dvě koleje, které jsou uprostřed křížově spojeny.
•
Stanice (zastávka) je zobrazena modrým obdélníkem, s modrým popiskem.
•
Slepá kolej je zobrazena symbolem ve tvaru T.
-7-
•
Externí zdroj je místo, odkud do modelovaného úseku přichází vlaky z jiných úseků. Je zobrazen jako žlutý čtverec s šedým širokým rámem.
•
Spojení úseků je prvek, který uživatel použije v lineárním modelu. Určuje druhou stranu, tj. kde se zobrazí vlak, který na místo přijede. V editoru je zobrazen přerušovanou slabě šedou barvou, zakončenou na obou koncích černým bodem. V režimu simulace je tento prvek jako jediný skrytý před zraky uživatele.
Obrázek 2.1 Ukázka rozpracovaného modelu tratě s uvedenou notací
2.3 Požadavky na simulátor Úlohou simulátoru je simulovat provoz na trati. Uživatel může do simulace zasahovat a samotný provoz tak narušovat a ovlivňovat. Díky dvěma nástrojům, Přerušení koleje a Mimořádný vlak, lze provoz narušit opravdu maximálně. Opět je i zde kladen důraz na jednoduchost, uživatel vše zařídí během několika kliků myší. Samotný simulátor je koncipován tak, aby bylo možno provoz najednou odsimulovat a zjistit, jaký dopad na provoz může mít určité omezení tratě. Z toho důvodu je podporováno několik rychlostí simulace. Vhodným nastavením parametrů lze dosáhnout i simulace v reálném čase.
-8-
3 Uživatelská dokumentace 3.1 Instalace programu Program RTS je napsán pro operační systémy Windows. Pro svůj běh nevyžaduje žádné speciální prostředí, vystačí si plně se svou vlastní instalací. Měl by tedy bez problémů fungovat na všech operačních systémech Windows, od verze Windows 98. Program je dodáván v podobě instalačního balíku s názvem RTSSetup.exe. Vše potřebné provede průvodce instalací. Jediné, co musíte udělat, je zvolit, kam chcete program nainstalovat. K běhu programu je potřeba utilita xmllint.exe, která je uložena v podadresáři xmllint. Ve stejném podadresáři jsou též uloženy knihovny libxml2.dll, zlib1.dll a iconv.dll, které utilita xmllint využívá. Pro správnou funkčnost programu prosím ponechte všechny tyto soubory v uvedeném podadresáři.
3.2 Spuštění programu Program se spouští souborem RTS.exe, který se nachází v instalačním adresáři. Po spuštění se otevře hlavní okno aplikace (obr. 3.1 na následující stránce). Program umožňuje v jeden okamžik mít otevřen pouze jeden diagram kolejiště, případně jednu simulaci. Ovšem počet najednou otevřených instancí programu omezen není. Jednotlivé prvky diagramu kolejiště a vlaky lze jednoduše předávat mezi jednotlivými instancemi prostřednictvím schránky Windows. Pokud uvedete při spuštění parametr s názvem uloženého souboru, ten se vám po spuštění ihned otevře. Pokud navíc uvedete parametr –s, uložený soubor se vám spustí rovnou v režimu simulace. K vyzkoušení programu je v podadresáři Examples ukázkový příklad priklad.rts. Ten se otevře v pracovní části okna. Pokud velikost okna přesáhne, je možné ho posouvat pomocí posuvných lišt, nebo kolečkem myši. Pod menu hlavní aplikace se nachází nástrojová lišta, která obsahuje tlačítka pro rychlý přístup k nejčastěji používaným položkám menu. V podadresáři Help najdete referenční příručku RTSHelp.chm.
3.3 Editace modelu Při editaci se používá notace popsaná v kapitole 2.2 této práce.
3.3.1 Vytvoření tratě Po spuštění aplikace se zobrazí čistá pracovní plocha pro tvorbu tratě. Nový soubor lze taktéž vytvořit pomocí menu Soubor, položka Nový, případně také pomocí příslušného tlačítka v nástrojové liště. Pokud ve stávajícím souboru byly provedeny nějaké změny, RTS se vás dotáže, zda chcete změny uložit. Nyní je možno začít vytvářet novou trať. Prvky, pomocí kterých budete trať modelovat jsou umístěný vlevo na bočním panelu v části Editor. Příslušný prvek vyberete stiskem
-9-
odpovídajícího tlačítka. Po té je možné kurzor myši přesunout nad pracovní plochu a zde začít tvořit trať. Všechny prvky, vyjma koleje a spojení úseků budou zobrazeny jako stín u kurzoru kdekoliv myší pohnete a budou vám ukazovat, na kterém místě se daný prvek objeví, pokud byste ho vložili do tratě.
Obrázek 3.1 Hlavní okno aplikace RTS
Některým prvkům lze změnit jejich orientaci ještě před tím, než se vloží do tratě. To lze provést stiskem pravého tlačítka myši. Změnu směru uživatel vidí přímo právě pomocí zobrazeného stínu u kurzoru. Nelze měnit orientaci prvků Stanice, Externí zdroj, Kolej a Spojení úseků.
3.3.2 Označování objektů V editoru nejde samozřejmě pouze o přidávání prvků, ale především o editaci jako takovou, tedy změnu pozice, mazání, případně úpravu jiných vlastností. Ani o tyto schopnosti není editor RTS ochuzen. K tomu, abyste mohli nějaký prvek měnit, musíte ho nejdříve označit. K označení jsou v RTS dvě možnosti - označení jednoho prvku pomocí nástroje Kurzor nebo označení skupiny prvků pomocí nástroje Výběr.
3.3.2.1 Mód výběru jednoho prvku Mód výběru jednoho prvku aktivujete tlačítkem Kurzor na bočním panelu. Po kliknutí na libovolný prvek diagramu bude prvek aktivován. Označení se projeví zčervenáním prvku. Takto aktivovaný prvek je možno následně modifikovat. Držením levého tlačítka myši a tažením můžete tento prvek přesouvat po pracovní ploše. U prvků, kterých se týká změna orientace, lze tuto orientaci změnit, a to tak, že držíte levé tlačítko myši a pravým tlačítkem myši klikáte a hledáte pro vás nejlepší vhodnou
- 10 -
orientaci. Změna orientace se provádí okamžitě, takže je hned vidět a můžete si tedy zrovna vybrat tu, která se vám nejvíce hodí. Stejným způsobem lze u prvku Kolej měnit typ koleje podle toho, kde chcete mít umístěna návěstidla. Máte čtyři možnosti - žádné návěstidlo, jedno návěstidlo na jedné straně, jedno návěstidlo na druhé straně a návěstidla na obou stranách koleje. Dvojitým klikem nad objektem aktivujete příslušný dialog, ve kterém nastavíte potřebné údaje pro každý prvek, viz další část 3.3.3 Editace objektů na trati. Označený objekt je možno také smazat a to pomocí tlačítka Guma na panelu vlevo nebo pomocí klávesy Delete. Často se vám může stát, že se vám některé bloky navzájem překrývají, např. že prvek Spojení úseků vám kříží Kolej. Pokud vyberete levým tlačítkem myši nějaký prvek, ten, který leží pod ním, tímto způsobem nevyberete. Pokud ale přesto chcete tento spodní prvek vybrat, RTS to umožňuje. Stačí kliknout pravým tlačítkem myši a označí se prvek další v pořadí. Stejný trik můžete používat stále dokola a dostat se tak ke všem prvkům, které leží nad sebou, pokud jich tak máte více.
3.3.2.2 Mód výběru skupiny prvků Druhý mód výběru - výběr skupiny prvků, se aktivuje tlačítkem s přerušovaným obdélníkem na obrázku. Objekty, které chcete mít označeny, označíte stejným způsobem, jako jste zvyklí ve Windows. Klikněte levým tlačítkem myši a myší táhněte. Pod myší by se měl vykreslovat obdélník určující výběr. Jestliže máte vybranou celou oblast, kterou chcete, tlačítko myši pusťte. Už v průběhu tahu myši se prvky, které spadají do označované oblasti, označují červenou barvou, stejně jako v prvním módu výběru. Při označování si dávejte ovšem pozor - do označení spadnou pouze ty prvky, které jsou při tahu myši označeny celé, nestačí pouze jejich část. S takto označenými prvky lze provádět v zásadě tři operace. První z nich je přesun. To provedete tak, že nejdříve stisknete klávesu SHIFT, poté kliknete levým tlačítkem někam do označené oblasti a tahem tuto celou označenou oblast přesunete. Druhou možností je smazání celé skupiny. To lze provést stejným způsobem jako v předešlém výběrovém módu, tj. tlačítkem Guma na bočním panelu nebo stiskem klávesy Delete. Třetí možností je uložení označené skupiny objektů do schránky Windows a její přenesení do jiné instance programu RTS, případně uschování ve schránce pro pozdější použití. To lze provést klávesovou zkratkou CTRL + c, případně pomocí menu Úpravy, položky Kopírovat. Opětovné vložení se provede klávesovou zkratkou CTRL + v nebo pomocí menu Úpravy, položky Vložit. Je možno též vybírat i navzájem nesourodé skupiny prvků, tj. takové, které spolu přímo nesousedí. Pokud takto chcete k nějaké skupině prvků přidat skupinu jinou, stiskněte klávesu CTRL a úplně stejným způsobem jako v prvním případě vyberte skupinu jinou. Pokud chcete naopak zrušit výběr nějaké podskupiny objektů, přidržte ke stisknuté klávese CTRL navíc klávesu SHIFT a opět úplně stejným způsobem vyberte skupinu, u které chcete označení zrušit.
3.3.3 Editace objektů na trati Jak již bylo zmíněno v souvislosti s dvojitým klikem nad prvkem tratě, je nutné projít všechny prvky kolejiště a nastavit jim vlastnosti. Nastavení vlastností prvků probíhá formou dialogových oken, která se liší podle prvku, kterému se vlastnosti právě nastavují. U všech prvků kromě Spojení úseků, Externí zdroj a Stanice se nastavuje reálná délka a maximální možná průjezdná rychlost.
- 11 -
V prvku Spojení úseků se nenastavuje nic. Je to pouze vizualizační pomocný prvek, takže není nutné nic nastavit. Prvek Externí zdroj musí mít nastaveno pouze číslo externího zdroje. Toto číslo je pouze orientační pro uživatele, aby uživatel věděl, o jaký prvek se jedná, nicméně editor RTS požaduje, aby bylo vyplněno. Viz obrázek 3.2. RTS navíc kontroluje unikátnost označení, tedy nedovolí uživateli zadat dvakrát stejné číslo.
Obrázek 3.2 Editace externího zdroje
Prvek Kolej kromě základních vlastností nastavuje také číslo koleje a informaci o tom, zda se jedná o úsek jednokolejné trati či nikoliv. Zatímco první ze zmíněných vlastností slouží uživateli pro rozlišení, druhá vlastnost pomáhá dispečerovi správně se rozhodovat při některých situacích. Viz obrázek 3.3.
Obrázek 3.3 Editace koleje
Prvek Stanice nastavuje pouze název stanice a počet kolejí stanice. Je zde omezení na počet kolejí v rozsahu 1 – 20. Pokud zaškrtneme v tomto dialogovém okně volbu Upravit pouze jméno, upraví se pouze název stanice. V opačném případě budou koleje, které patří k dané stanici, smazány a nahrazeny novými, i když počet zůstane zachován. Nové koleje bude nutné opět postupně projít a nastavit jim vlastnosti. Také u tohoto prvku je kontrolována unikátnost názvu, a tedy nelze mít dvě stanice se stejným názvem.
Obrázek 3.4 Editace stanice
Ostatním prvkům se nastavují pouze stejné výše zmíněné dvě vlastnosti. Mají tedy dialogové okno společné.
- 12 -
Obrázek 3.5 Editace ostatních prvků
3.3.4 Vytvoření a editace vlaku Dalším krokem, co musí uživatel zadat, jsou vlaky. Bez nich by byla trať prázdná. Vlaky se vytváří pomocí dialogového okna Nový vlak (obr. 3.6). Zde si vyplníte veškeré důležité informace o vlaku. V případě, že se vám podaří na některou zapomenout, budete systémem upozorněni, abyste chybu napravili. Stanice, ve kterých vlak zastaví, se vybírají jednotlivým klikáním na názvy stanic v mutli-výběrovém prvku (Multiple Select box).
Obrázek 3.6 Nový vlak
Ovšem pozor! V současné verzi programu není možno vlaku pevně říci, kudy má jet. Tedy to, že označení stanice v seznamu ještě neznamená, že vlak tady skutečně zastaví, resp. že tudy vůbec pojede. Daná stanice musí ležet na nejkratší cestě mezi počáteční a cílovou stanicí. Dispečeři drah mají typicky na starosti lineární úseky trati s odbočkami (tj. grafový strom), a tedy omezení na vlaky jedoucí nejkratší cestou nevadí. Pokud budete chtít během simulace do trati pouštět také nějaké mimořádné vlaky, musíte si je nadefinovat také pomocí tohoto dialogového okna. Jen musíte vybrat typ Mimořádný.
- 13 -
Seznam dostupných vlaků je uveden dole na levém bočním panelu v ovládacím prvku typu Seznam (listbox). Označením vlaku a stiskem tlačítka Smazat, které leží pod tímto seznamem, vlak smažete. Stejným způsobem, avšak stisknutím tlačítka Kopírovat, lze vlak zkopírovat do schránky a pomocí CTRL + v, případně v menu Úpravy, položky Vložit, přenést vlak do jiné instance programu RTS. Dvojitým klikem na označení vlaku se otevře dialogové okno pro úpravu vlaku, které je úplně stejné jako to pro tvorbu vlaku nového.
3.3.5 Generování jízdního řádu Ke každému vlaku je ještě nutné vytvořit jízdní řád. Abyste nemuseli zadávat jízdní řád pro každý vlak ručně, je v RTS k dispozici mechanismus, který dle zadané tratě jízdní řád vygeneruje. Tento mechanismus se aktivuje stiskem tlačítka Generovat jízdní řád v dialogovém okně Nový vlak (Úprava vlaku). Po stisku tohoto tlačítka se otevře nové dialogové okno s vygenerovaným jízdním řádem, který je možno ručně doladit (obrázek 3.7). Ke stejnému oknu se lze dostat i přímo z hlavního okna stiskem tlačítka Zobrazit jízdní řády na nástrojové liště, případně v menu Vlaky, položka Zobrazit jízdní řády. Zde si v malém dialogu dvojitým kliknutím vyberete jízdní řád vlaku, který chcete. Abyste nemuseli postupně klikat na každý vlak zvlášť, umožňuje RTS vygenerovat všechny jízdní řády současně najednou. To se dělá pomocí menu Vlaky, položkou Generovat jízdní řády. Stejným tlačítkem také na nástrojové liště (ikona s obrázkem „Ge“). Upozornění: V případě, že máte hodně vlaků nebo jste vytvořili rozsáhlý model kolejiště, může generování jízdních řádů zabrat nějaký čas. O skončení generování budete informováni formou informační hlášky programu RTS. Samotný průběh generování jízdních řádů je zobrazen v hlavním okně v dolním panelu úplně vpravo v prvku ProgressBar – zobrazení průběhu operace. Název právě zpracovávaného vlaku je též zobrazen v jedné z částí stavového řádku aplikace. Jak je vidět z obrázku 3.7 na následující straně, časy příjezdu se editovat nedají, protože jsou automaticky spočítány z dob odjezdu, jež editovat lze. Po editaci časů odjezdu můžete stiskem tlačítka Přepočítat zjistit, jak vypadá upravený jízdní řád. Po stisku tlačítka OK bude též provedeno přepočítání, změna se uloží a dialogové okno se zavře. Časy odjezdu vlaku musí být vždy alespoň jednu minutu od času příjezdu. Tuto hodnotu lze změnit v nastavení simulace (viz 3.8.7 Nastavení simulace). Jedná se o minimální dobu strávenou ve stanici, která se použije, pokud má vlak zpoždění, proto je zde omezení, že pod tuto hodnotu jít nelze. Pokud zadáte čas pod touto hranicí, hodnota se ignoruje a odjezd bude nastaven na dvě minuty. Také tuto hodnotu lze nastavit, a to pomocí dialogového okna Nastavení standardní doby, které otevřete pomocí menu Vlaky, položky Nastavení standardní doby. Jinak bude hodnota ignorována a odjezd bude nastaven dvě minuty (tato hodnota se dá také nastavit) od času příjezdu.
- 14 -
Obrázek 3.7 Editace jízdního řádu
3.4 Ukládání a načítání Jako každý editor, také RTS poskytuje možnost rozpracovanou trať uložit a pak se k ní někdy vrátit. Pomocí menu Soubor, volby Uložit nebo Uložit jako lze kolejiště se všemi náležitostmi uložit. Při volbě Uložit jako vám RTS vždy nabídne možnost zvolit si cílovou cestu a název souboru. Volba Uložit tuto možnost poskytuje pouze poprvé, pokud není soubor ještě uložený. Pokud je již soubor uložený, případně se edituje již existující soubor, RTS se znovu ptát nebude a případné požadavky o uložení budou již směřovat vždy na tento soubor. Pomocí menu Soubor, položky Otevřít lze otevřít již existující soubor. V případě, že je již otevřený nějaký soubor a byla v něm provedena nějaká změna, RTS se nejdříve zeptá, jestli chcete změny uložit, pak až zobrazí dialogové okno pro výběr souboru. Dialogová okna Otevřít a Uložit jsou standardní dialogová okna pro výběr souboru ve Windows. Uživatelům proto nebude jejich ovládání dělat problém. Uložené soubory jsou soubory s příponou RTS. Jejich struktura je postavená na technologii XML. Zkušenější uživatelé mohou proto do souboru nahlédnout v libovolném XML editoru a soubor upravit přímo. Kontrola načtení tratě se provádí pomocí utility xmllint validací proti XML schématu, které je možno k nahlédnutí nalézt v podadresáři xmllint, v souboru rts.xsd, případně také zvlášť jako příloha na CD.
- 15 -
3.5 Kontrola tratě To, že si naklikáte nějaký model tratě ještě neznamená, že model je vytvořený správně a že jste na nic nezapomněli. RTS obsahuje několik kontrolních mechanismů a pomocných funkcí, které umožní odladit spoustu detailů tak, abyste byli s modelem maximálně spokojeni a zároveň nebyla narušena konzistence dat potřebných pro simulaci. Prvním a zároveň základním testem, který se provádí je spojení tratě. Jednotlivé kolejové bloky, ačkoliv se jeví vedle sebe jako spojené, RTS jako spojené nepovažuje, minimálně do doby, dokud mu to nepovíte. Spojení tratě se děje automaticky před spouštěním simulace, kdy se nejdříve provádí všechny testy. Ovšem testem Spojení tratě si můžete zkontrolovat trať ještě před tím, než simulaci budete chtít spustit, a to pomocí položky menu Kontrola, volby Spojení tratě. Alternativně také přes nástrojovou lištu tlačítkem s černým zaměřovačem, symbolizujícím spojení tratě. Pokud vše proběhne v pořádku, RTS oznámí uživateli počet spojení. V opačném případě oznámí uživateli počet nepřipojených míst. S připojenými a nepřipojenými místy se pojí dvě pomocné funkce, které najdeme opět v menu Kontrola, Ukázat spojená místa a Ukázat nespojená místa. Opět lze využít alternativu nástrojové lišty pomocí tlačítek se zeleným a červeným kolečkem. Červeným kolečkem se aktivuje mód zobrazení, ve kterém je v každém nepřipojeném bodě zobrazen červený puntík. Účel zeleného kolečka je opačný, aktivuje mód, kde každý připojený bod je zobrazen jako zelený puntík. Oba módy lze kombinovat dohromady. Druhým testem je tzv. validační test, který kontroluje správnost vyplnění všech údajů všech kolejových prvků. Test lze spustit opět z nástrojové lišty tlačítkem se symbolem fajfky nebo z menu Kontrola, položka Validace kolejových bloků. V případě chyby je uživateli oznámeno kolik prvků je vyplněno špatně a jejich seznam je zobrazen do informačního logu v dolním panelu. Prvky jsou zde identifikovány typem prvku a souřadnicí, na které tento prvek najdete. Aktuální souřadnice myši vzhledem k pracovní ploše vidíte ve třetí části stavového řádku. Pomocí těchto informací lze nevalidní prvky snadno najít a chyby opravit. Třetí test je test souvislosti kolejiště. Nelze mít kolejiště rozdělené do více různých úseků, ani kdyby jednotlivé úseky spolu vůbec nesouvisely. Program RTS na to není stavěn, proto pokud uživatel bude chtít simulovat najednou provoz na více nesouvislých částech, bude muset vytvořit více modelů kolejiště a simulovat každý zvlášť ve vlastní instanci programu. Ověřování souvislosti je součástí hned prvního testu. Ověřuje se ale pouze za předpokladu, že je kolejiště správně spojeno. Pokud kolejiště souvislé není, RTS vám to oznámí. Poslední test, nebo spíše pomocná funkce, se týká vlaků. Pomocí menu Vlaky, položky Zobrazit cesty, stejně tak z nástrojové lišty tlačítkem s modrým pětiúhelníkem lze zobrazit cesty, po kterých vlak pojede. Cesta se zobrazí barvou vlaku, takže se dá rozlišit, kudy který vlak pojede. Navíc jsou cesty kvůli rozlišení označeny popiskem stejné barvy. V této funkci probíhá hledání nejkratších cest pro vlaky. V případě, že je vlaků hodně, může operace nějakou dobu trvat. Průběh operace je možno shlédnout v dolním panelu v prvku Průběh operace. Označení právě zpracovávaného vlaku je též možno vidět ve čtvrté části stavového řádku. Po dokončení operace hledání cesty se - 16 -
zobrazí prázdná stránka a dialogové okno, ve kterém je uveden seznam vlaků, pro které byla cesta nalezena (viz obrázek 3.8 na následující straně) . Označením názvu vlaku danou cestu zobrazíte. Odznačením se cesta opět skryje. Je možné označit více vlaků současně.
Ukázka zobrazení cest 3.8
Do módu editace se přepnete opětovným stiskem stejného tlačítka. Současně s tímto stiskem se též zavře dialogové okno Filtr zobrazení cest vlaků, jenž normálně zavřít nelze.
3.6 Spuštění simulace Samotnou simulaci lze spustit z menu Simulace, položka Start. Po vybrání této volby jsou provedeny všechny kontroly zmíněné v předchozí sekci. V případě chyby samotná simulace vůbec nezačne. Po spuštění simulace přebírá řízení provozu Manažer Simulátoru a uživatel může začít do simulace zanášet problémy. Aktuální čas simulace je zobrazen v bočním levém panelu pod nadpisem Simulátor.
3.7 Ovládání simulace Režim simulace nabízí uživateli pouze dva nástroje. Prvním je Přerušení tratě, druhým jsou Mimořádné vlaky. Nástroj Přerušení tratě slouží, jak již název napovídá, k přerušení tratě. Je možné přerušovat koleje a všechny druhy výhybek. Ostatní prvky přerušit nelze. Dvojitým klikem do trati je identifikován prvek pod kurzorem a pokud se jedná o výše zmíněné
- 17 -
prvky, je trať v daném místě přerušena a kolejový blok nelze použít pro jízdu. Přerušení tratě poznáte podle červeného symbolu křížku, který se objeví přes kolejový blok. Opětovným dvojitým klikem na přerušený blok se tento blok znovu uvolní.
Po kliknutí na tlačítko Mimořádné vlaky se otevře dialogové okno, které obsahuje seznam mimořádných vlaků. Dvojitým klikem na libovolný název mimořádného vlaku se vlak vpustí do tratě. Toto dialogové okno je poměrně malé, ale kdyby vám překáželo, můžete jej zavírat a znovu otevírat podle toho, jak se vám to zrovna hodí. Jak již bylo zmíněno, Mimořádné vlaky se od klasickým vlaků liší pouze typem. Zadávají se již v režimu simulace stejným způsobem jako vlaky ostatní. Po spuštění simulace je uživateli přímo vybrán nástroj Přerušení tratě. Tento nástroj má své vlastní tlačítko v bočním panelu i přesto, že je to jediný nástroj svého druhu v režimu simulace. Je to z důvodu budoucího rozšíření simulace o další nástroje.
3.8 Podrobný popis pracovního prostředí 3.8.1 Rozložení hlavní aplikace V horní části hlavního okna aplikace se nachází menu. Pod menu se nachází nástrojová lišta, která slouží především k rychlému přístupu k nejčastěji používaným položkám menu. Samotná klientská část okna je rozdělena na tři části. Vlevo se nachází boční panel, který zaujímá celou výšku okna a šířku 134 pixelů. Největší částí okna je samotná pracovní plocha, která zaujímá cca 80 % zbytku okna. Začíná nahoře pod nástrojovou lištou a končí 125 pixelů pod spodním okrajem okna nezávisle na jeho velikosti. Zbylou část tvoří spodní panel. Ten tvoří výplň celého zbytku okna. Poslední částí je stavový řádek, rozdělený na čtyři části, ve kterých je zobrazeno několik informací. Pracovní plocha slouží pouze jako plátno, do kterého se kreslí vlastní diagram kolejiště. Ostatním částem okna se věnuje několik následujících sekcí.
3.8.2 Menu a toolbar V horní části okna se nachází menu, které obsahuje všechny funkce programu. Nástrojová lišta (toolbar), která leží pod ním, umožňuje rychlý přístup k nejčastěji používaným volbám menu.
Obrázek 3.9 Menu a nástrojová lišta
Nabídka Soubor obsahuje následující položky: •
Nový – vytvoří nový soubor modelu kolejiště. V případě provedených změn v již otevřeném souboru se RTS nejdříve dotáže uživatele na uložení rozpracovaného souboru.
- 18 -
•
Otevřít – otevře standardní dialog Windows pro otevření souboru. V případě změny v právě editovaném souboru se nejdříve dotáže na možnost uložení.
•
Uložit – uloží rozpracované kolejiště do souboru. V případě ještě neuloženého souboru nejdříve zobrazí dialog pro uložení souboru. V opačném případě ukládá do stejného, již existujícího souboru.
•
Uložit jako – vždy zobrazí standardní dialog pro uložení souboru. V případě změn se dotáže na uložení rozpracovaného díla.
•
Konec - ukončí aplikaci. RTS hlídá uživatele, aby si práci uložil, než program ukončí.
Nabídka Úpravy obsahuje tyto možnosti: •
Zpět – vrátí se o jeden krok zpět v provádění akcí (Undo).
•
Vpřed - znovu provede vrácenou akci (Redo).
•
Kopírovat – v případě že je vybrána skupina objektů, zkopíruje je do schránky.
•
Vložit – vloží ze schránky skupinu objektů.
Nabídka Kontrola obsahuje tyto funkce: •
Spojit prvky – spustí test na spojení prvků.
•
Ukázat spojená místa – zobrazí v místě spoje dvou bloků zelený puntík.
•
Ukázat nespojená místa – zobrazí v místě, kde chybí spoj, červený puntík.
•
Validace kolejových bloků – spustí validační test (viz výše 3.5).
Nabídka Vlaky obsahuje tyto položky: •
Nový vlak – zobrazí dialogové okno pro přidání nového vlaku.
•
Zobrazit jízdní řády – zobrazí dialogové okno se seznamem dostupných jízdních řádů.
•
Generovat jízdní řády – spustí generování jízdních řádů.
•
Zobrazit cesty – aktivuje hledání a zobrazení cest vlaků.
Nabídka Simulace obsahuje tyto položky: •
Start – spustí simulaci.
•
Stop – zastaví simulaci.
•
Nastavení simulace – zobrazí dialogové okno pro nastavení parametrů simulace.
- 19 -
3.8.3 Boční panel V bočním levém panelu jsou umístěny prvky pro editaci, tzn. kurzor, výběr, guma, zvětšení, zmenšení a také všechny kolejové prvky. Pod těmito prvky jsou dále také prvky pro simulaci a zobrazení aktuálního času simulace. Pod nimi je umístěn seznam vlaků a tlačítka pro smazání vlaku a zkopírování do schránky.
3.8.4 Spodní panel Tento spodní panel obsahuje pouze 2 prvky. Prvním prvkem je tzv. informační log. Do tohoto logu RTS uživateli vpisuje hlášky, chyby a varování. Jedná se pouze o element typu editační pole (editbox), kterému je zakázáno měnit obsah. Druhý prvek zobrazuje průběh operace. Jedná se o Progress bar, který využívají generátor jízdních řádů a zobrazovač cest vlaků, aby informovali uživatele o tom, že program nezatuhl, jenom neúprosně pracuje a hledá cesty nebo generuje jízdní řády.
3.8.5 Stavový řádek Stavový řádek je rozdělen na čtyři části. V první části je zobrazen počet použitých kolejových bloků. Druhá část je analogická, zobrazuje počet vlaků, které jsou v modelu k dispozici. Třetí blok zobrazuje aktuální souřadnice myši na pracovní ploše. Do výsledné souřadnice je započítán i posun posuvných lišt. Poslední čtvrtá část slouží pouze jako informační panel. V průběhu generování jízdních řádů nebo hledání cest se do této části stavového řádku zobrazuje informace, co se právě odehrává a nad kterým vlakem.
3.8.6 Ovládání Program vyžaduje ovládání zejména pomocí myši. Ke zvládnutí programu stačí základní gramotnost práce s myší. Práce se dá urychlit použitím klávesových zkratek. Spousta položek menu má klávesovou zkratku přiřazenou. Odpovídající zkratky jsou v menu uvedeny vedle názvu položky. V současné verzi programu RTS je velikost pracovní plochy omezena na velikost 3000 x 2000 pixelů. Program není určen pro tvorbu velkých kolejišť ve smyslu železniční mapa ČR. Vychází z reálného provozu na železnici, kde dispečer řídí pouze určitou malou část kolejiště. Proto ani nebyl stavěn pro neomezenou velikost pracovní plochy. Plocha je i tak dostatečně velká, aby zvládla pojmout i poměrně velký kus kolejiště. Pomocí dvou tlačítek se symbolem lupy si lze celý model prohlédnout najednou tím, že ho zmenším. Nebo naopak ho lze zvětšit. Ovšem jedná se pouze o náhled, tedy nelze ve zmenšeném režimu editovat. Režim lupy se přepne automaticky do normálního zobrazení po stisku nějakého jiného tlačítka, takže není nutný přechod zpět do normálního zobrazení provádět explicitně. Lupu lze využít také v režimu simulace, a to i ve spojení s nástrojem Přerušení koleje.
3.8.7 Nastavení simulace Průběh simulace není jednoznačný, lze jej ještě před vlastním spuštěním parametrizovat nastavením několika následujících vlastností: •
Minimální doba strávená ve stanici
- 20 -
•
Časový posun
•
Rychlost simulace
•
Začátek simulace
Minimální doba strávená ve stanici je doba, kterou vlak stráví ve stanici, pokud má zpoždění. Bývá obvykle menší, než je Standardní doba strávená ve stanici (viz 3.3.5 Generování jízdního řádu). Časový posun uvádí, o kolik vteřin se posune čas simulace během jednoho simulačního cyklu. Možnosti jsou jedna, tři, pět a deset vteřin. Rychlost simulace uvádí počet simulačních cyklů na jednu vteřinu skutečného času. Možnosti jsou jeden, dva, pět a deset cyklů za vteřinu. Předchozí dvě vlastnosti spolu úzce souvisí, a utvářejí spolu skutečnou rychlost simulace. Pokud budou obě hodnoty nastaveny na jedna, bude simulace probíhat v reálném čase. Pokud bude například Časový posun nastaven na pět vteřin a rychlost nastavena na dva cykly za vteřinu, během jedné vteřiny skutečného času odběhne deset vteřin času simulovaného. Toto nastavení pak ovlivňuje programový časovač, který je zdrojovým elementem simulace.
Obrázek 3.8 Ukázka nastavení simulace
Začátek simulace uvádí, od kdy má simulace probíhat. Jsou zde jen dvě možnosti, od půlnoci a od prvního vlaku. První možnost zahajuje simulaci v čase 00:00:00. Druhá možnost začíná simulaci pět minut před výjezdem prvního vlaku, nejdříve však o půlnoci.
3.9 Doporučení pro ovládání Samotná tvorba modelů nemá žádná omezení, proto lze v RTS věrohodně namodelovat poměrně hodně tratí. Vzhledem k omezení pro trasování vlaků je ale doporučeno
- 21 -
simulovat pouze lineární úseky tratí s případnými odbočkami. Do kolejiště obsahujícího okruhy bude velmi obtížné nadefinovat vlaky tak, aby jezdily podle představ. Při vytváření vlaků je důležité dát pozor na to, kudy chcete vlak vést. Jak již bylo zmíněno, nelze cestu vlaku určit. Ta je programem hledána automaticky a je brána cesta nejkratší. Po spuštění simulace je nutné dávat pozor, kam kladete přerušení tratě. V případě přerušení koleje je občas nutné přerušit též některé bloky před ní, a to z toho důvodu, že simulátor staví cesty vlakům jen do vzdálenosti 2. V případě delšího úseku před přerušeným úsekem, kde není výhybka na druhou kolej, se vlak může dát po špatné koleji směrem k přerušenému úseku, což jistě nechceme.
- 22 -
4 Problémy spojené s tvorbou GUI Grafické uživatelské rozhraní (GUI) je u aplikací obdobného typu, jako je program RTS, stěžejní součástí. K zajištění pohodlného ovládání pro uživatele je nutné naimplementovat řadu funkčnosti, což s sebou přináší určité problémy. S některými problémy nám pomůže dobré vývojové prostředí, které nám nabídne řešení minimálně klasických, pro programátory otravných problémů, jako je právě např. návrh GUI. Právě prostředí Microsoft Visual Studio 2008, ve kterém byl program RTS vyvíjen pomáhá programátorovi na opravdu velké úrovni. Zvolení C++ a Win32API jako programovacího jazyka nebyla zrovna nejlepší volba, protože většinu složitějších, avšak klasických řešení si programátor musí implementovat sám. Na rozdíl od C# a prostředí .NET, kde jsou typické funkčnosti už naimplementované a připravené pro programátora k okamžitému použití. Avšak vzhledem k nemalé zkušenosti s programování právě pro Win32API a poměrně malé zkušenosti s prostředím .NETu a C# zvítězilo právě Win32API v kombinaci s C++.
4.1 Uspořádání aplikace Program RTS svým charakterem více méně jasně předurčuje, jak bude vzhled aplikace vypadat. Většinu plochy aplikace zabírá tzv. pracovní část, tedy okno, které bude obsahovat samotný diagram kolejiště. To je pro pohodlí uživatele zobrazeno tak, aby zabíralo co možná největší část okna aplikace. V levé části okna je boční panel, na kterém se nachází všechny ovládací prvky, pomocí nichž uživatel vytváří diagram kolejiště a vytváří vlaky. V dolní části se nachází jakýsi informační panel, ve kterém se nachází informační okno, do kterého RTS vypisuje uživateli chybové a jiné hlášky, a prvek Zobrazení průběhu zobrazuje průběh déle trvajících operací. Jak vypadá program RTS si můžete prohlédnout na obrázku 3.1. Současná verze programu RTS nepodporuje mít najednou více otevřených souborů (MDI – Multiple Document Interface). Nic ovšem nebrání uživateli spustit najednou více instancí programu RTS a pomocí mechanismu kopírování přenášet diagramy kolejiště mezi sebou.
4.2 Zobrazení diagramu kolejiště Jednou ze základních návrhových záležitostí bylo rozhodnout, jakým způsobem bude zobrazeno samotné kolejiště. Při návrhu jsem se snažil zohlednit fakt, že na nakresleném kolejišti bude nutné naimplementovat vlastní simulaci pohybu, proto jsem se snažil o co nejjednodušší způsob zobrazení, který by vyhovoval uživateli i simulátoru. Také jsem musel zohlednit jeden z požadavků právě na zobrazení diagramu kolejiště, a sice aby diagram odpovídal skutečnosti. Především na základě těchto faktů jsem se rozhodl, že celý diagram bude zobrazen pouze pomocí úseček. Jednotlivé úsečky budou moci být natočeny do čtyř směrů pod úhly 0°, 45°, 90° a 135°. Další důležitým faktem je základní jednotka délky kolejových bloků. Po několika testech jsem usoudil, že nejlepší velikostí pro základní jednotku je délka 25 pixelů (dále px). Celá pracovní plocha je tedy rozdělena do malých čtverečků velikosti 25 × 25px a každá čárá, která bude v diagramu zobrazena, bude umístěna do rohů těchto čtverečků. - 23 -
Tím jsem docílil toho, že uživatel velmi jednoduše bude moci spojovat bloky k sobě a nikdy se mu tak nestane, že by se netrefil. Pokud se klikne myší kamkoliv na pracovní plochu, souřadnice kliku myši je zaokrouhlena právě na celé základní jednotky délky. Tím se může stát, že ačkoliv klikneme myší do určitého místa, prvek se zobrazí o kousek dále. To je způsobeno právě zaokrouhlením. Délka jednotlivých prvků diagramu kolejiště je určena v počtu základních jednotek délky kolejových bloků. Velikost prvků ovšem nemá žádné pevné měřítko vzhledem ke skutečným délkám kolejových bloků. Skutečnou délku musí uživatel nastavit povinně u každého kolejového prvku, neboť ta hraje důležitou roli při generování jízdních řádů, a pak hlavně také v samotné simulaci.
4.3 Vykreslení diagramu Diagram kolejiště je vykreslen do pracovní části okna. Po každé provedené změně je nutné vlastní diagramu překreslit. Diagram se vykresluje vždy celý. Aby se předešlo blikání, ke kterému dochází při překreslování pouze změněné části okna, je použita technika Dvojitého překreslení (angl. Double Buffering). Kreslený diagram se nejdříve vykreslí do bitmapy. Po té se celý obrázek překopíruje do paměti okna a najednou zobrazí uživateli. Uživatel tak vidí přímo hotový obrázek a samotná změna mu zůstane skryta někde uvnitř paměti. Z důvodu ušetření kopírování velké části paměti není nutné při každé změně kopírovat paměť pro celou obrazovku. Stačí překopírovat pouze zneplatněnou oblast okna, což se následně projeví na rychlosti překreslování. U rychlých počítačů to problém není, u těch starších to problém je a změna je skutečně viditelná na první pohled.
4.4 Zpracování požadavků myši Jelikož se editor ovládá zejména pomocí myši, nelze se spokojit pouze s jednoduchým klikáním, ale je nutné různě implementovat kliknutí myši podle toho, jaký má uživatel právě vybraný aktivní nástroj. Správu těchto stavů zajišťuje multifunkční třída SelectionControl, která neobsahuje jenom informaci o aktuálně vybraném prvku, ale také zajišťuje na žádost přepínání orientace u prvků, které s orientací pracují. U každého takového prvku si pamatuje počet orientací a v případě změny orientace tuto orientaci cyklicky mění. V případě nástrojů pro výběr prvků (Kurzor a Výběr) musíme navíc také rozeznávat, jestli jsme při kliknutí myši na pracovní plochu neklikli na nějaký objekt a podle toho se zachovat. Vlastní logiku přepínání stavů nejlépe vystihuje obrázek 4.1 na následující straně. Jelikož uživatel může z libovolného prvku kdykoliv přejít do libovolného jiného prvku, jedná se o úplný graf. Kreslením všech vazeb by obrázek ztratil na přehlednosti. Místo toho je zde znázorněn uživatel jako zprostředkovatel, změny aktivního prvku. Tato volba je v obrázku znázorněna plnou čarou. Přechody mezi různými stavy v rámci jednotlivých vybraných možností jsou znázorněny přerušovaně. Šipky směřující samy na sebe znázorňují změnu orientace.
- 24 -
Slepá kolej
Jednoduchá výhybka
Uživatel
Dvojitá výhybka
Stanice
Externí zdroj
Kolej
Kurzor
Výběr
Koncový bod
Druhý bod
Změna orientace
Přesun prvku
Další prvek
Spojení úseků
Přidání do skupiny
Přesun skupiny
Odebrání ze skupiny
Obrázek 4.1 Diagram přepínání stavů myši
Do všech stavů zobrazených na obrázku 4.1 kurzívou se uživatel dostane kliknutím na příslušné tlačítko v bočním panelu. Následně lze klikáním do pracovní plochy přidávat nové prvky. Při stisku levého tlačítka myši ve stavu Kolej je vytvořen počáteční bod prvku Kolej v místě kliknutí. Pohybem myši lze sledovat, kudy kolej povede. Po druhém kliknutí se koncový bod koleje ukotví v místě kliku. Obdobná situace je u stavu Spojení úseků. Uživatel ale zpravidla už dopředu ví, kam chce spojení vlastně umístit, proto uživatel po prvním kliknutí nevidí, kudy spojení povede. Po druhém kliknutí myši se opět pouze ukotví koncový bod spojení. Stavy Kurzor a Výběr slouží k vybírání prvků. Stav Kurzor umožňuje po kliknutí na objekt tento objekt vybrat, zaktivnit. V případě následného kliknutí na jiný objekt, bude tento aktivní objekt deaktivován a aktivován objekt nový. Aktivní objekt lze tažením myši přesunout na jinou pozici. Stisknutím pravého tlačítka na aktivní objekt lze vybrat objekt, který se nachází pod ním, tzn. pokud se objekty částečně nebo úplně překrývají. Při stisknutém levém tlačítku myši a následným stisknutí pravého tlačítka lze měnit orientaci některých prvků.
- 25 -
Stav Výběr slouží k označení skupiny objektů. Při současném stisku klávesy CTRL lze do vybrané skupiny přidávat další prvky. Při stisku kláves CTRL a SHIFT lze naopak objekty z vybrané skupiny odstranit. Při stisku klávesy SHIFT lze objekty tahem myši přesouvat.
4.5 Ukládání a otevírání souborů Možnost uložení a následné načítání souborů je samozřejmostí i u těch nejjednodušších editorů. Existuje spoustu možností, jak realizovat ukládání souborů a jejich následné načítání. Data mohou být do souboru zapsána textově, binárně, nebo například v nějakém strukturovaném souboru. Přes dlouhé rozhodování jsem se nakonec uchýlil k technologii XML [2]. Ta umožňuje velice elegantním způsobem uložit data do souboru tak, že jsou pak velmi dobře čitelná i mimo program, pro který je soubor určen. Zkušenější uživatelé jej mohou editovat přímo, pokud dodrží jeho schéma. Druhým důvodem proč jsem si vybral právě XML technologii pro uložení je ten, že lze poměrně snadno ověřit, zda jsou data v souboru v pořádku a v konzistentním stavu.
4.5.1 Uložení do souboru Diagram kolejiště spolu s vlaky a jízdními řády se ukládá do souboru s příponou rts, který, má strukturu XML souboru. Samotné uložení obstarává rozhraní SaveAble, které implementují všechny třídy, které chtějí být uloženy. Při požadavku o uložení po vybrání souboru ze standardního dialogu Windows je otevřen stream do nového souboru. Následně se volá metoda save rozhraní SaveAble na všechny dostupné prvky, které mají být uloženy. Ty jsou následně zapsány do streamu a po uzavření uloženy na disk.
4.5.2 Načtení souboru Přečtení a zpracování XML souboru je poměrně snadnou záležitostí, pokud máme k dispozici dobrý XML parser. V případě mnou vybraného programovacího jazyka C++ byla situace poněkud ztížena, protože C++ nativně XML nepodporuje, na rozdíl od jiných programovacích jazyků jako například Java nebo C#, a proto bylo potřeba sehnat nějaký externí parser, pokud možno jako hotovou knihovnu. Pomohla mi knihovna C++ XML Parser [3]. Ta umožňuje pomocí C++ opravdu elegantně brouzdat XML souborem a získávat z něj data.
4.5.3 Kontrola souboru Jak jsem již zmiňoval, XML soubory je možno efektivně kontrolovat, jestli struktura v souboru popsaná je ta pravá pro náš program. Kontrola v RTS se provádí pomocí utility xmllint v podadresáři xmllint validací načítaného souboru proti XSD schématu uloženém v souboru rts.xsd ve stejném podadresáři.
4.5.4 Struktura RTS souboru Strukturu uloženého souboru nejlépe popisují schémata RTS souboru, která jsou uložena na přiloženém CD v adresáři Prilohy/xml nebo též v podadresáři xmllint instalačního adresáře v souborech rts.xsd nebo rts.dtd.
- 26 -
4.6 Undo / Redo Někdy se stane, že provedeme operaci, kterou chceme vrátit zpět. A když už se vrátíme zpět, chceme se třeba z nějakého důvodu posunout zase zpět vpřed do původního stavu. Díky konstrukci Undo / Redo to uděláme jedním klikem myši. RTS navíc neklade žádné omezení na počet operací, které lze vrátit zpět, a tedy by všechny změny měly jít v rámci dostupné paměti vrátit zpět. Operace, které podléhají změnám a které lze vrátit zpět, ukazuje následující seznam: • přidání nového prvku • odebrání prvku z diagramu • změna pozice prvku v diagramu • změna atributů prvku • přesun skupiny prvků • změna pozice skupiny prvků • smazání skupiny prvků • přidání nového vlaku • smazání vlaku • změna atributů vlaku Každou takovou operaci zastupuje instance třídy URCommand (z angličtiny Undo – Redo Command). Jednotlivé instance už při instanciaci vytvoří požadavek, který se má v případě vrácení zpět (opětovného zopakování) provést. Tento požadavek má strukturu XML dokumentu, který ovšem není uložen na disku, nýbrž si ho jednotlivé instance programu RTS drží samy u sebe v paměti. Pro samotné provádění změn se použije stejný parser [3], který zpracovává načítání existujících souborů, ovšem v trochu pozměněné variantě. Jako triviální pozorování můžeme vidět, že některé operace jsou navzájem opačné – například přidání a odebrání prvku. Na tomto jednoduchém pozorování je postaven v podstatě celý algoritmus, který Undo / Redo ovládá. Při každé výše zmíněné operaci je vytvořena konkrétní instance třídy URCommand, která určuje operaci opačnou. Když např. uživatel prvek smaže, těsně před smazáním se vytvoří požadavek na přidání nového prvku identického podle toho, který je právě mazán, aby se v případě undo mohl tento prvek vložit zpět. Nová instance se předá instanci třídy ChangesRepository, která zastřešuje funkčnost Undo / Redo. Ta obsahuje dva zásobníky instancí URCommand, jeden pro Undo, druhý pro Redo. Po dokončení každé výše zmíněné operace se na vrchol zásobníku Undo vloží konkrétní vytvořený požadavek a smaže se obsah zásobníku Redo pro případ, že se uživatel vrátil zpět a udělal novou operaci. V tom případě už nelze chodit vpřed a zásobník Redo se musí vyčistit. Když si uživatel usmyslí, že se chce vrátit zpět, je z vrcholu Undo odebrána instance a ta je předána XML parseru, který zpracuje požadavek. V průběhu zpracování parser na základě typu požadavku vytvoří požadavek opačný, který se v případě v pořádku provedené operace Undo uloží na vrchol zásobníku Redo (obrázek 4.2 na následující straně). Situace v případě provádění operace Redo je úplně stejná s tím rozdílem, že při přehazování požadavku na vrchol zásobníku Undo se zásobník Redo smazat nesmí. A to z toho důvodu, že by se mohli smazat ještě nějaké další použitelné Redo kroky.
- 27 -
Samotné zpracování požadavku Redo pak probíhá úplně stejně. Skutečnost, ze kterého zásobníku jsme odebrali požadavek na změnu, nehraje při zpracování žádnou roli. Požadavek se provede úplně stejně.
4.2 Ukázka operace Undo
4.7 Kopírování, vkládání Při kopírování a vkládání částí diagramu, případně vlaků je použita schránka Windows. Kopírovat části diagramu lze pouze objekty, které jsou označeny skupinově, tzn. pomocí nástroje Výběr. Zkopírování se v případě prvků diagramu provede klávesovou zkratkou CTRL + c nebo pomocí menu Úpravy, položky Kopírovat. Kopírovat vlak lze příslušným tlačítkem na bočním panelu pod seznamem vlaků. Vložení se pak provede jednotným způsobem - buď klávesovou zkratkou CTRL + v, nebo pomocí menu Úpravy, položky Vložit. Při žádosti o kopírování se vytvoří podobný požadavek jako v případě Undo / Redo s tím rozdílem, že je vždy vytvořen požadavek pro vložení nového prvku (nového vlaku). Tento požadavek je opět strukturován jako XML soubor. Tím je ulehčeno programování, protože opět můžeme použít při vkládání stejný XML parser [3]. Tento XML požadavek je do schránky Windows nakopírován přímo jako XML text. Před provedením operace Vložit je ještě požadavek kontrolován, zda má správnou strukturu. Protože se lehce může stát, že do schránky bude, byť omylem, nakopírován nežádoucí text. Kontrola se realizuje zapsáním požadavku do temporálního souboru v podadresáři tmp a pomocí utility xmllint ověřením proti stejnému již zmiňovanému XSD schématu.
- 28 -
V případě kopírování vlaků se nekopírují kompletní informace o vlaku, ale vynechávají se informace o cílové a výchozí stanici. Také se vynechávají zastávky, protože zmíněné parametry jsou vázány na konkrétní diagram a nelze bezpečně zaručit, že stejné prvky (zastávky, externí zdroje) budou i v nové diagramu, kam vlaky vkládáme. Vložení prvků diagramu kolejiště se provede standardním způsobem vkládáním prvků do kolejiště. Po vložení vlaku se automaticky otevře dialog pro úpravu vlaku, ve kterém si musím nově vložený vlak nastavit. U standardních aplikací pro Windows, které podporují kopírování a vkládání bývá ještě funkce Vyjmout. Tuto funkčnost editor RTS nepodporuje z důvodu ochrany uživatele před nekonzistencí schématu v případě vyjmutí zastávky nebo externího zdroje, které jsou spojeny s určitými vlaky.
- 29 -
5 Kolejiště, vlaky, jízdní řády 5.1 Reprezentace kolejiště v programu Samotné kolejiště je složeno z menších prvků - Kolej, Jednoduchá výhybka, atd. Proto je kolejiště jako celek vytvořeno jako složenina všech použitých prvků. Základem je abstraktní třída RailBlock, která zastřešuje nad každým blokem všechny základní vlastnosti a funkce, jako je např. pozice, skutečná délka bloku, maximální průjezdná rychlost, označení bloku jako vybraný, otočení bloku do jiného úhlu apod. Od této abstraktní třídy jsou pak přímo odvozeny konkrétní třídy jednotlivých kolejových prvků. Výjimku mají pouze třídy Jednoduché výhybky, které mají mezi třídou RailBlock a vlastní třídou ještě jednu abstraktní třídu, která představuje abstrakci jednoduché výhybky, protože jednoduchých výhybek máme čtyři druhy podle natočení připojené koleje. Třída RailBlock navíc implementuje rozhraní SaveAble, takže bloky samy o sobě se umí uložit do souboru. Kvůli implementačním problémům, ale také kvůli snadnému ladění, má každý blok skrytě přiřazeno interní kladné celé číslo, pomocí kterého je v programu každý blok dohledatelný. Toto označení slouží dále především pro vytváření grafu kolejiště, pro hledání cest vlaků a pro tvorbu kolizních cest (viz dále, kapitola 6.2). Uživateli je toto číslo skryto. Celé kolejiště pak zpracovává třída Railway, která slouží jako skladiště těchto jednoduchých malých objektů. Ty si skrytě ukládá do seznamu a v případě potřeby k nim tedy může přistupovat. Ať už jednotlivě nebo, a to ve většině případů, ke všem prvkům najednou. Většinou je právě potřeba zpracovat požadavek na všech prvcích kolejiště - vykreslit všechny prvky, vytvořit z kolejiště graf, zjistit, které prvky se nachází ve výběrovém obdélníku k označení, uložení kolejiště do souboru a další. Navíc tato třída též obsahuje všechny testy, které se týkají kolejiště a jejímž prostřednictvím se testy spouští. Jelikož se v programu nachází pouze jediná instance této třídy a navíc ani není žádoucí, aby existovalo více takových tříd, je třída implementována jako Singleton [4].
5.2 Sestavení tratě Vlastní kolejiště ve své podstatě vytváří graf. Grafy mají dobré vlastnosti a dají se na nich používat různé algoritmy, např. pro hledání cest. Toho jsem ve velké míře využil a proto pokročilé vlastnosti editoru, a především hlavně simulátor, využívají graf jako základní stavební kámen své funkčnosti. Pro účely tvorby grafu má každý blok přetíženou metodu toGraph(), která vrátí graf bloku. Takovýto graf má vrcholy v bodech, kde končí blok a napojuje se další, u výhybek také v bodech, kde se kolej vyhýbá do jiného směru. Hrany pak pouze kopírují nakreslení bloku a jejich ohodnocení je odvozeno od skutečné délky kolejového bloku. Samotný proces spojení tratě do grafu G = (V, E) se řídí následujícím algoritmem: 1. Vytvoř prázdný graf G, tj. V a E jsou prázdné množiny. 2. Procházej postupně všechny bloky v kolejišti a získej jejich graf H.
- 30 -
•
Do grafu G přidej vrcholy z grafu H.
•
Do grafu G přidej hrany z grafu H.
3. Proveď kompletaci grafu: •
Každé 2 různé vrcholy se stejným umístěním spoj hranou s ohodnocením 0.
4. Vrať počet spojení při kompletaci. Počet spojení slouží jako orientační hodnota pro uživatele. Lze si všimnout, že v místě spojení se vždy nachází dva vrcholy spojené nulovou hranou. Je to z důvodu, že jednotlivé vrcholy grafu jsou asociovány s konkrétním kolejovým blokem pomocí interního čísla kolejového bloku. Z toho důvodu jsou zachovány oba dva vrcholy na téže pozici. Tuto vlastnost odstraňuje element Kolizní bod, který je popsán v kapitole 6.2.
5.3 Kontrola tratě Jak již bylo zmíněno v kapitole 3.5, proces tvorby tratě prochází před spuštěním simulace řadou kontrol, které zajistí, že uživatel vytvořil model kolejiště alespoň trochu rozumně. Proto bylo nutné navrhnout model tříd tak, aby bylo možné tyto kontroly provádět.
5.3.1 Spojení tratě Tato kontrola slouží k tomu, aby upozornila uživatele, že jednotlivé prvky nejsou spojeny správně, resp. že chybí zakončení k některým prvkům. Ke správně realizaci simulace je zapotřebí, aby kolejiště bylo kompletní. Základem kontroly spojení tratě je struktura JOINPOINT, která obsahuje pozici bodu a ukazatel na prvek, se kterým je bod spojen. Každý kolejový blok obsahuje pole těchto struktur, jehož délka je rovna počtu míst připojitelných k jiným blokům. Kolej má dva body, jednoduchá výhybka tři, dvojitá čtyři, atd.. Pozice těchto bodů přímo odpovídá aktuální pozici daného kolejového bloku, musí se tedy měnit s měnící se polohou bloku. Při každé žádosti o test spojení se nejdříve zavolá metoda join třídy Railway, která pro každé dva kolejové bloky najde všechny společné body, tj. body spojení. Pokud nějaké takové body najde, pak provede vzájemné propojení těchto bloků tak, že odpovídajícím JOINPOINTům nastaví vzájemnou provázanost. Zároveň se počítá počet takovýchto spojení. Druhá fáze testu prochází všechny kolejové bloky a počítá, kolik z nich nemá připojený konec. Tento celkový počet je pak vrácen jako výsledek testu. Pokud je výsledek nula, je kolejiště v pořádku spojitelné. V případě, že test neproběhne v pořádku, je možné nechat uživateli zobrazit body, ve kterých nedošlo ke správnému spojení vizuálně. V takovém případě se nastaví příznak vykreslení bodů spojení a metoda drawJointPoints třídy RailBlock vykreslí v patřičných bodech červené kolečko (zelené, pokud si uživatel nechá vykreslit body spojení).
5.3.2 Test souvislosti tratě Co je cílem tohoto testu je zřejmé z jeho názvu. Zjišťuje, jestli model kolejiště vytváří souvislý graf nebo nesouvislý. Pro správnou funkčnost programu je důležité mít model - 31 -
souvislý. V opačném případě nelze například hledat cesty pro vlaky. Proto je tento test velmi důležitý. Test spouští třída Railway, která ho spouští jako součást testu spojení tratě. Tento test nelze spouštět odděleně, protože uživatel většinou vidí, že kolejiště je nesouvislé. Kontrola je pouze ochrana RTS před nekonzistencí ze strany uživatele pro případ, že by nesouvislé kolejiště udělal úmyslně. Samotný test pak provádí metoda componentTest třídy Graph. V testu se nejdříve provede Dijkstrův algoritmus z náhodného počátečního vrcholu. Pak se projdou všechny vrcholy grafu a pokud se narazí na první, který má vzdálenost od počátku NIL, pak vrátí neúspěch. V opačném případě po projití všech vrcholů vrátí úspěch.
5.3.3 Validační test Tento test slouží ke zjištění, jestli byly všechny údaje o jednotlivých blocích vyplněny správně, pokud tedy vůbec byly vyplněny. Každý kolejový blok obsahuje svou virtuální metodu isValid, která kontroluje jeho správnost. Při spuštění tohoto testu se postupně procházejí všechny prvky. Pokud prvek není validní, zaznamená se do seznamu nevalidních prvků, jenž je na konci testu vrácen jako výsledek. Pokud seznam obsahuje nějaké nevalidní prvky, jsou vypsány do informačního logu, kde jsou jak jejich názvy, tak souřadnice, na kterých lze prvek najít.
5.4 Reprezentace vlaků v programu Vlaky jsou v programu reprezentovány pomocí třídy Train. Tato třída zastřešuje základní vlastnosti vlaků, jako jsou rychlost vlaku, typ vlaku, výchozí a cílová stanice, zastávky a další. Navíc obsahuje spoustu metod, které slouží především simulátoru, jako například určovaní polohy vlaku, vykreslení vlaku, změna směru jízdy vlaku, nastavení rychlosti, zastavení a znovu rozjetí vlaku a další. Co se týče části editoru, tak tato třída obsahuje metodu drawWay, která vykreslí nalezenou cestu vlaku, dále pak také metodu generateTrafficOrder, která pro daný vlak vygeneruje jízdní řád. Třída Train také implementuje rozhraní SaveAble, takže také vlaky se umí uložit do souboru. Všechny vlaky jsou uloženy ve třídě TrainStorage, která funguje obdobným způsobem jako třída Railway pro kolejové bloky. Ukládá vlaky do seznamu a vyřizuje na ně jednotlivé požadavky. Základní funkce, které třída zpracovává jsou vygenerování jízdních řádů, hledání cest vlaků a vykreslení jejich cest. Stejně jako u třídy Railway, i u třídy TrainStorage, není žádoucí větší počet instancí, proto i tato třída je implementována jako Singleton [4].
5.5 Hledání cest vlaků Každý vlak musí dopředu znát, kudy pojede. Protože vlaky v simulátoru jezdí po nejkratších cestách, bylo by dobré vytvořit z kolejiště graf. Existuje totiž celá řada algoritmů pro hledání nejkratších cest v grafech. Program RTS využívá pro hledání cest pravděpodobně ten nejznámější, Dijkstrův algoritmus. Dijkstrův algoritmus byl od začátku jasná volba mezi grafovými algoritmy na hledání cesty, jelikož mě nezajímá pouze výsledná minimální vzdálenost, ale potřebuji také nejkratší cestu zpětně zkonstruovat, což se např. u Floyd-Warshallova algoritmu tak snadno nepodaří.
- 32 -
Minimální cesta je u Dijkstrova algoritmu konstruována již v průběhu, je potřeba ji jen z výsledného grafu vyextrahovat. Podmínky Dijkstrova algoritmu jsou splněny již typem úlohy, jelikož kolejové bloky (hrany) nemají záporné vzdálenosti (ohodnocení hran) a tedy nemají ani záporné cykly. Použití tohoto algoritmu už tedy nestojí v cestě žádná překážka. Proces tohoto algoritmu se spouští ve startovním vrcholu, který odpovídá startovnímu bodu vlaku. Po skončení procesu se z grafu extrahuje minimální cesta. Vlastní algoritmus implementuje třída Graph a jeho postup vypadá následovně: 1. Inicializace grafu •
Všem vrcholům nastav vzdálenost na NIL, předchůdce vrcholu smaž a označ všechny vrcholy jako nenavštívené.
•
Startovnímu vrcholu nastav vzdálenosti na 0.
2. Prováděj tolikrát, kolik je počet vrcholů: •
Najdi nenavštívený vrchol u takový, který má nejmenší vzdálenost.
•
Označ u jako navštívený.
•
Najdi všechny sousedy nalezeného vrcholu.
•
Pro každého souseda v vrcholu u proveď relaxaci po hraně e = (u, v): o Pokud je vzdálenost v NIL nebo je větší než vzdálenost u + délka hrany e, nastav v vzdálenost u + délka e a nastav předchůdce vrcholu v na vrchol u
3. Extrahování výsledné minimální cesty •
Vytvoř prázdný graf W
•
v := cílový vrchol, přidej vrchol v do grafu W
•
Dokud v není počáteční vrchol prováděj: o Označ v pořadovým číslem o Označ v jako extrahovaný o u := předchůdce v o pokud je u NULL nebo je u již extrahovaný, ukonči proces extrahování cesty a vymaž graf W o e := hrana (u,v) o přidej vrchol u do grafu W o přidej hranu e do grafu W o v := u
- 33 -
Jelikož je celkový graf kolejiště souvislý (ověřeno testem souvislosti grafu kolejiště), vždy existuje cesta z cílového vrcholu do vrcholu počátečního. Výjimku mají pouze grafy simulátoru, kde může být uživatelem přerušena cesta a graf se tak může stát nesouvislým. Z toho důvodu je do procesu extrakce cesty vložena podmínka na existenci předchůdce vrcholu u. Označení pořadovým číslem není běžná součást Dijkstrova algoritmu. Jak již bylo zmíněno, v místě spoje dvou sousedních kolejových bloků se nacházejí dva vrcholy spojené hranou nulové délky. A protože chceme, aby bylo možno vrcholy ve výsledném grafu setřídit postupně podle pořadí navštívení vlakem, nelze vrcholy setřídit pouze podle vzdálenosti od počátku. Proto se vrcholy při extrakci označí pořadovým číslem, podle kterého jsou pak sestupně setříděny.
5.6 Reprezentace jízdních řádů v programu Jízdní řády se nejlépe uchovávají v podobě tabulky příjezdů a odjezdů. Stejným způsobem jsou jízdní řády reprezentovány i v programu RTS. Jízdní řád, který se váže na konkrétní vlak je uložen ve třídě TrafficOrder, která obsahuje dva seznamy, jeden pro příjezdy, druhý pro odjezdy. Prvkem obou těchto seznamů je třída TrafficOrderUnit, která pouze obsahuje informace o bloku a čase, ve kterém má mít vlak příjezd, resp. odjezd. Také třída TrafficOrder implementuje rozhraní SaveAble, takže i jízdní řády mají implementovaný způsob, jakým se zapsat do souboru. Správcem jízdních řádů je třída TrafficOrderStorage, opět díky svým vlastnostem implementovaná jako Singleton [4]. Její funkce jsou pouze starat se o jízdní řády, ukládat a mazat, případně na žádost vracet.
5.7 Generování jízdních řádů Každý vlak musí mít jízdní řád, podle kterého jezdí. Aby uživatel nemusel zadávat celý jízdní řád postupně, stačí zadat pro každý vlak výchozí čas a RTS dokáže sám vygenerovat zbytek jízdního řádu. Samotný generátor bohužel není moc dokonalý, nedokáže například řešit nejrůznější kolize v jízdním řádu. Program na to ani nebyl stavěn. Cílem RTS je řídit provoz, ne generovat dokonalé jízdní řády. Tomu se věnují jiné práce. RTS je nicméně poměrně otevřen změnám a není vyloučeno, že do budoucna bude RTS obsahovat také právě nějaký pěkný a sofistikovaný generátor jízdních řádů. Nicméně i samotný proces tvorby jízdních řádů v RTS není úplně jednoduchý a má svá úskalí. Generování jízdního řádu má na starosti metoda generateTrafficOrder třídy Train, o níž už zmínka byla. Jelikož se při generování používá kolizní cesta a kolizní body, které budou probírány až v kapitole 6.2 Kolizní cesta, kolizní body, zmíním se jen velmi stručně k čemu slouží. Kolizní bod je speciální třída, který se používá pro potřeby simulace. Obsahuje interní informace pro vlak, co má udělat když do takového bodu vjede, tzn. jestli má např. změnit směr, změnit rychlost, apod. Odpovídá vrcholu grafu, avšak v místě spoje je vytvořen pouze jeden kolizní bod, nikoliv dva. Kolizní cesta je posloupnost takových bodů, které dokáží dovést vlak z výchozího bodu do cílového. Kolizní cesta se vytváří
- 34 -
z grafu, který je vytvořen hledáním nejkratší cesty vlaku. Zde se redukuje počet vrcholů, které graf původně má. Samotný algoritmus generování jízdního řádu je stejný pro generování prvního jízdního řádu i pro přepočítání jízdního řádu podle úprav uživatele, jen s malou odlišností seznamem aktualizovaných hodnot. Průběh celého algoritmu pak vypadá takto: 1. Vytvoř prázdný jízdní řád 2. Vytvoř kolizní cestu pro vlak 3. Inicializuj počáteční čas •
Pokud provádíme přegenerování, nastav počáteční čas na první hodnotu ze seznamu odjezdů.
•
Jinak nastav na startovní čas vlaku.
4. Pro každý kolizní bod kolizní cesty proveď: •
Pokud kolizní bod není bodem zastávky: o Získej z kolizního bodu jeho vzdálenost od předchozího o Získej maximální průjezdnou rychlost jako minimum rychlosti vlaku a průjezdné rychlosti. o Připočítej dobu jízdy.
•
Pokud kolizní bod je bodem zastávky: o Spočítej čas a připočítej k aktuálnímu času. o Zaznamenej čas jako čas příjezdu do jízdního řádu. o Pokud provádíme přegenerování:
Pokud máme zpoždění oproti plánovanému jízdnímu řádu, připočítej k aktuálnímu času konstantní přírůstek jako dobu strávenou ve stanici. Zaokrouhli aktuální čas na minuty.
Jinak nastav aktuální čas na hodnotu odjezdu ze stanice.
o Pokud přegenerování neprovádíme, připočítej k aktuálnímu času konstantní přírůstek jako dobu strávenou ve stanici a zaokrouhli aktuální čas na minuty. o V obou případech ulož aktuální čas jako čas odjezdu ze stanice. o Vynuluj dobu jízdy mezi zastávkami.
- 35 -
6 Simulace 6.1 Spuštění a běh simulace Druhá část programu RTS se zabývá simulací provozu. Simulace je spuštěna pomocí menu Simulace, položky Start. Ukončit ji lze pomocí položky Stop. Alternativně lze použít klávesové zkratky F5 pro start a F6 pro ukončení. Před spuštěním simulace je nutné zkontrolovat, zda trať navržená uživatelem neobsahuje nějaké chyby. Proto jsou před spuštěním simulace postupně provedeny všechny testy. V případě chyby je simulace ukončena ještě před tím, než vůbec mohla začít. Spustit simulaci lze tedy pouze na zkontrolované trati, která je v pořádku. Po provedení všech testů a pokud vše dopadne správně, je řízení předáno řídicí třídě SimulatorManager, která samotnou simulaci spustí a následně ovládá. Po skončení simulace je činnost Manažera Simulátoru zastavena a RTS se přepne do režimu editace, kde ovládání programu plně leží v rukou uživatele. Pokud uživatel simulaci neukončí předčasně, je zastavena automaticky přechodem na další den, tj. po překročení půlnoci. Klíčem ke správnému vedení simulace je programový časovač, který v pravidelných okamžicích dle nastavení simulace (viz kapitola 3.8.7 Nastavení simulace) zasílá zprávy, na které manažer simulátoru reaguje a zpracovává. V jeho pravidelnosti se pak odráží samotný proces simulace. V případě, že je tento časovač narušován, např. nějakým cizím procesem zvenčí, nemusí být simulace plynulá. Bohužel tuto menší závadu nelze odstranit bez netriviálního zásahu do činnosti operačního systému, proto je nutné počítat s možností ztráty plynulosti v případě vytíženosti systému. Okno, ve kterém probíhá simulace je totožné s oknem editoru. Samotné vykreslení se opět děje pomocí techniky Dvojitého překreslení, ovšem manažer simulátoru obsahuje vlastní paměť pro uložení obrazovky. Také se opět vykresluje pouze viditelná část obrazovky. Samotným simulovaným pohybem vlaků se zabývá kapitola 6.5 Pohyb vlaků. Způsobu jejich řízení po trati se věnuje celá sedmá kapitola.
6.2 Kolizní cesta a kolizní body 6.2.1 Kolizní body Kolizní bod je speciální třída reprezentující místo na trati, kde se pohybující se vlak dozví, co má v případě střetu s tímto místem dělat. V podstatě se dá říct, že slouží pro uložení interních informací pro potřeby simulace pohybu vlaků. V případě kolize vlaku s tímto bodem (odtud kolizní bod) vlak např. zjistí, jestli má změnit směr, zrychlit nebo zpomalit. Co přesně se odehrává bude vysvětleno v kapitole 6.5 Pohyb vlaků. Třída těchto bodů je programově řešena třídou CollisionPoint. Každý kolizní bod odpovídá vrcholu grafu. Z grafu cesty vlaku také kolizní body vznikají. Ovšem je zde oproti grafu jedna výjimka. Ne z každého vrcholu grafu vzniká kolizní bod. Kolizní body odstraňují duplicity ve vrcholech se stejnou pozicí. Kolizní body vytvářejí rozhraní, odkud kam vede cesta. Každý takový bod, který leží na rozhraní dvou - 36 -
kolejových bloků je tvořen dvěma vrcholy grafu - jedním příchozím a druhým odchozím. Pamatuje si tedy, z kterého bloku do kterého vede cesta. Pokud je kolizní bod vytvořen z vrcholu, který leží uvnitř nějakého kolejového bloku (bloky výhybek), je kolizní bod vytvořen pouze z jednoho vrcholu grafu a toto rozhraní má nastavenu stejnou hodnotu na příchozí i odchozí blok. Startovní a cílové body jsou vedeny jako speciální případy, protože nemají buďto příchozí nebo odchozí část. Každý kolizní bod obsahuje ještě navíc odkaz na předchozí a následující kolizní bod, takže tak vytváří celou cestu, kterou označujeme kolizní cesta.
6.2.2 Kolizní cesta Kolizní cestou rozumíme posloupnost kolizních bodů, která dokáže dovést vlak z výchozího bodu do cílového, přičemž výchozí bod je v prvotním okamžiku startovní bod vlaku – externí zdroj, nebo stanice. Jak již bylo zmíněno, kolizní cesta je vytvořena z grafu. Kolizní cesta není určena jednoznačně. Je sice vygenerovována celá již při spouštění simulace, nicméně se může v průběhu simulace změnit. V tom případě je za výchozí bod považován kolizní bod, ve kterém se aktuálně nachází vlak. Cílový bod je vždy stejný. Je to cíl vlaku, tedy externí zdroj, nebo stanice. Kolizní cesta je implementována třídou CollisionPath. Mezi základní úkoly kolizní cesty patří testování na kolizi vlaku s jejími body, získání startovních informací pro každý vlak, tzn. kterým směrem vlak pojede, rychlost v prvním úseku a startovní pozici vlaku, a pak také sebe postavení. Testování na kolizi spočívá pouze v projití celé cesty a v případě, že existuje kolize s některým bodem, je zavolána metoda makeChange, která zpracuje kolizi a její výsledek je vrácen jako výsledek celé operace testování kolize. Startovní informace vlaku se získávají z prvních dvou kolizních bodů na cestě. Podle jejich polohy je určen směr, podle jejich vzdálenosti je stejným způsobem jako v metodě makeChange spočítána rychlost (viz 6.4 Pohyb vlaků). Algoritmus sebe postavení není úplně triviální, vypadá následovně: 1. Získej vrcholy grafu cesty a setřiď je (využívá se interní pořadové číslo při extrahování cesty), P := odkaz na předchozí kolizní bod nastav na NULL. 2. Pro každý vrchol prováděj: •
Pokud je vrchol asociován s kolejovým blokem Spojení úseků, pokračuj dalším vrcholem.
•
Získej pozici vrcholu.
•
Pokud pozice je již pozicí nějakého kolizního bodu (jsme na rozhraní dvou bloků), nastav P odchozí blok na blok, se kterým je asociován aktuální vrchol. Pokud je rychlost v P nebo maximální průjezdná rychlost v aktuálním vrcholu 0, nastavíme rychlost P na maximum z těchto dvou
- 37 -
hodnot. Jinak nastavíme rychlost P na rychlost v aktuálním vrcholu. Pokračujeme dalším vrcholem. •
C := nový kolizní bod daný pozicí aktuálního vcholu.
•
Nastavíme příchozí blok na blok asociovaný s aktuálním vrcholem, stejně tak rychlost. Předchozí blok nastavíme na P.
•
Pokud P <> NULL, následník P nastavíme na C. Vzdálenost P nastavíme na rozdíl vzdálenosti C a P. C nastavíme vzdálenost podle vzdálenosti vrcholu. Odchozí blok P nastavíme na blok asociovaný s aktuálním vrcholem.
•
Jinak nastavíme vzdálenost C na 0.
•
Uložíme C jako nový bod kolizní cesty.
•
P := C
Ačkoliv algoritmus může být poněkud složitější na pochopení, vlastní myšlenka je jednoduchá. Základem je držení odkazu na předchozí kolizní bod. Postupně vytváříme kolizní body z vrcholů grafu, rychlost v kolizním bodě se odvíjí od maximální průjezdné rychlosti přes daný blok, který je asociovaný s aktuálně procházeným vrcholem. Pro úplně první kolizní bod je vzdálenost nastavena na 0, jinak je vzdálenost nastavena na rozdíl vzdáleností aktuálního a předchozího bodu, z čehož dostáváme, že vzdálenost kolizního bodu neurčuje vzdálenost od začátku cesty, ale vzdálenost od předchozího kolizního bodu. Pokud narazíme na vrchol, který už svůj kolizní bod má (vrchol na rozhraní dvou bloků), využijeme odkaz na předchozí kolizní bod a upravíme rychlost podle rychlosti v novém vrcholu a změníme odchozí blok. A to je celý princip.
6.3 Plánovač úloh Plánovač úloh je pomocná datová struktura, která ukládá požadavky, o kterých víme, v jakém čase je potřeba je vykonat, tzn. jsou časově závislé. Takovými požadavky jsou zařazení vlaku do simulace, odstranění vlaku ze simulace a spuštění pohybu vlaku. Při vytváření kolizních cest jsou do plánovače vždy zařazeny první úlohy - úloha pro vytvoření daného vlaku a též zařazení úlohy pro první start. Po dojetí do cíle je zařazena úloha pro vyřazení vlaku z procesu simulace. Když vlak zastaví ve stanici, je zařazena úloha spuštění pohybu. Plánovač je implementován třídou Scheduler. Jedná se pouze o datovou strukturu, úložiště, do kterého se jednotlivé úlohy vkládají. Nejdůležitější metodou této třídy je metoda getTasks, která podle času předaného jako parametr vrátí seznam úloh, které je v daném čase potřeba vyřídit. O samotné zpracování požadavků se pak již stará hlavní třída SimulatorManager.
- 38 -
6.4 Řízení simulace Celý proces simulace řídí jediná třída SimulatorManager. Jelikož není žádoucí, aby bylo v programu více instancí této třídy, hlavně pro to, aby nefungovaly všechny najednou, je opět využit již několikrát zmiňovaný Singleton [4] jako základ této třídy. Proces činnosti lze rozdělit časově do tří fází – inicializace, procesní fáze a fáze ukončení. Je zřejmé, že procesní fáze bude zabírat nejvíce času běhu manažera simulace.
6.4.1 Inicializace V této fázi se provádí nastavení Manažera Simulátoru. Musí se nastavit časový přírůstek podle nastavení simulace. Ten si manažer uloží a jeho hodnotu dále poskytuje pomocným třídám. Dále se nastavují vlaky, které do simulace vstupují. Pro každý vlak se postaví kolizní cesta, která slouží jako výchozí cesta daného vlaku. Tuto cestu si pak manažer uloží do svého seznamu cest. Nakonec se ještě inicializuje bitmapa, do které se vykresluje simulace.
6.4.2 Procesní fáze Tato fáze zabírá 99.98% času řízení simulace. Je to výkonná část simulátoru. Jejím základem je metoda cycle třídy SimulatorManager. Tuto metodu volá opakovaně časovač v časovém intervalu, který je určen nastavením rychlosti simulace. Princip této metody lze shrnout do následující posloupnosti úkonů: •
Proveď úlohy plánovače.
•
Přesuň vlaky, které momentálně nestojí na další pozici.
•
Proveď test na kolize s kolizními body.
•
Proveď výměnu kolizních cest.
•
Vykresli aktuální situaci.
Přesun vlaku na další pozici je řízen tzv. krokovačem, třídou Stepper, která řídí pohyb vlaků (viz 6.6 Krokování pohybu vlaků). Krokovač vrátí posun, o který se má změnit poloha vlaku, a tento posun je přičten k aktuální pozici vlaku na novou pozici. Test na kolize se řídí průchodem všech kolizních cest u vlaků, které jsou aktuálně na trati, kde je zavolána jejich metoda testCollision a následně zpracován výsledek této metody. Výměna kolizních cest se děje tehdy, když po střetu vlaku s kolizním bodem dispečer zjistí, že nelze pokračovat započatou cestou a je možnost jet cestou jinou. Tuto cestu dispečer vytvoří a zařadí do seznamu nových kolizních cest. Po skončení testování kolizí jsou odpovídající staré cesty nahrazeny cestami novými.
6.4.3 Fáze ukončení V této závěrečné fázi probíhá čištění struktur použitých pro simulaci, aby bylo možno je opětovně použít pro znovu spuštění simulace. Víceméně se jedná pouze o vyčištění kontejnerů. Po skončení úklidu se smaže buffer určený pro kreslení simulace, a tím samotný proces simulace končí.
- 39 -
6.5 Pohyb vlaků Jak již bylo zmíněno, vlaky se pohybují po kolizních cestách. Při střetu s kolizním bodem, je zavolána metoda makeChange třídy CollisionPoint, ve které proběhnou operace, které nasměrují vlak dalším správným směrem. Výsledek této metody je předán metodě executeResult třídy SimulatorManager, která zajistí dodatečné operace při speciálních případech jako je např. zastavení ve stanici. Díky tomu, jakým způsobem je trať zobrazována, mohou jezdit vlaky pouze v osmi směrech, jenž odpovídají světovým stranám. Objekt třídy Train, který reprezentuje konkrétní vlak obsahuje odkaz na instanci aktuálního směru pohybu. Při změně směru je volána metoda changeDirection třídy Train, která požadavek deleguje právě na instanci aktuálního směru. Ta v závislosti na poloze následujícího bodu rozhodne, kterým novým směrem vlak pojede a přepne vlak do nového směru. Vlak se dokáže z libovolného směru přepnout do libovolného jiného směru. Při implementaci směru pohybu bylo využito návrhového vzoru State [4], který se touto problematikou zabývá. V celém algoritmu často vystupuje pojem „dispečer“. Jedná se o třídu BuiltPathStorage, která funkci dispečera zastřešuje. Problematice dispečera je věnována celá následující 7. kapitola, proto je zde pouze zmínka. Co tedy přesně probíhá při kolizi s kolizním bodem popíšeme následujícím algoritmem: 1. Pokud existuje následník následníka aktuálního kolizního bodu, pak je předán dispečerovi k zařazení do aktuální postavené cesty. Pokud navíc existuje ještě následující bod, je i ten předán dispečerovi k zařazení. 2. Pokud existuje předchůdce aktuálního kolizního bodu a vlak zrovna nestojí, je předchůdce předán dispečerovi k odstranění z aktuální postavené cesty. 3. Pokud existuje následník aktuálního kolizního bodu, proveď: •
v := menší ze dvou rychlostí, rychlosti vlaku a maximální průjezdné rychlosti aktuálním kolizním bodem.
•
Nastav parametry s, realPosition a realPosition2 podle toho, jestli je aktuální kolizní bod bodem bloku Spojení úseků.
•
distance := vzdálenost realPosition a realPosition2 na obrazovce v pixelech
•
Vypočítej čas pohybu t mezi dvěma kolizními body, t := s / (v / 3.6)
•
vygeneruj vektor přírůstků rychlostí velocities z parametrů t a distance (viz další kapitola 6.6 Krokování pohybu vlaků)
•
změň směr jízdy vlaku
4. Pokud neexistuje, znamená to, že jsme u konce jízdy. Oznámíme dispečerovi příjezd na určitou kolej do stanice a vrátíme jako výsledek konec jízdy.
- 40 -
5. Pokud se vlak nachází v kolizním bodě, který reprezentuje zastávku, oznámíme dispečerovi příjezd na určitou kolej ve stanici a vrátíme jako výsledek zastavení ve stanici. Zpracování výsledku metodou executeResult není nikterak složité. Existují pouze tři možnosti, co se může odehrát. První možností je, že vlak zastaví ve stanici. V takovém případě manažer simulátoru zastaví patřičný vlak a do plánovače naplánuje úlohu na znovu spuštění vlaku. Druhou možností je ukončení jízdy vlaku. Vlak se opět zastaví a do plánovače je přidána úloha na odstranění vlaku ze simulačního procesu. Třetí možnost je prázdná. To znamená, že vlak daným kolizním bodem jenom projede a pokračuje dál. V takovém případě není potřeba provádět žádné dodatečné operace.
6.6 Krokování pohybu vlaků 6.6.1 Vlastnosti pohybu Celou dobu se zde hovoří o pohybu vlaků, ale ani jednou zde nebylo vysvětleno, jakým způsobem se vlaky vlastně pohybují. Jak si pozorný čtenář jistě všiml, není při přepočítání času mezi dvěma kolizními body vůbec zohledněno žádné zrychlení, pokud se vlak rozjíždí. Pohyb, který v simulace probíhá, je v jednotlivých blocích rovnoměrný přímočarý. Rychlost se mění pouze v kolizních bodech, pokud je nutné v následujícím bloku rychlost omezit, případně je možné zrychlit. Při simulaci je nutné držet vlak na kolizní cestě mezi dvěma kolizními body po celou dobu jízdy mezi těmito dvěma body. Navíc je nutné pravidelně vlakem pohybovat správným směrem. Pohyb vlaku se realizuje tak, že k aktuální pozici vlaku je připočítán přírůstek vzdálenosti ve směru osy x i osy y podle směru, kterým vlak jede. Tento přírůstek určuje vzdálenost, kterou při dané rychlosti urazí vlak za nastavenou jednotku časového posunu. A tím se tedy vlak pohne.
6.6.2 Anomálie při použití průměrného přírůstku Je zřejmé, že nelze uvažovat tento přírůstek jako průměr. Proč, to si ukážeme na následujícím příkladu. Není těžké vytvořit takový model, ve kterém by průměrný přírůstek byl v intervalu (0, 1). Stačí namodelovat krátkou trať (zobrazeno na obrazovce), její skutečnou hodnotu nastavit na velké číslo a rychlost vlaku, který tudy pojede nastavit na malou hodnotu. Pak bude přírůstek v uvedeném intervalu. Jenže přírůstek z pohledu simulace musí být celé číslo, protože pozice musí být uváděna v celých pixelech. Kdybychom tedy zkusili hodnotu zaokrouhlit, narazili bychom. Zaokrouhlením dolů dostaneme přírůstek 0, což nám nezmění pozici vlaku. Pokud zaokrouhlíme nahoru, dostaneme 1. To znamená, že vlak se sice bude pohybovat, jenže se bude pohybovat větší rychlostí než jsme chtěli, tedy nejenže dorazí do stanice vždy dříve, což by nám ani nevadilo, ale také skrytě porušuje předpisy, protože se pohybuje větší rychlostí, než mu dovoluje trať nebo výkon lokomotivy.
6.6.3 Krokování Řešením je právě krokování pohybu vlaků. Jedná se o postup, který přírůstky pohybu vlaku rozdělí, tak aby nedocházelo k anomáliím uvedeným výše.
- 41 -
Krokování pohybu zajišťuje třída Stepper, na jejíž instanci má odkaz právě třída Train. Při vyvolání pohybu vlaku požádá instance třídy Train instanci třídy Stepper o další přírůstek. Pokud již není vyčerpán počet přírůstků na daném místě, je vrácen nový přírůstek. Ten je připočítán k aktuální pozici vlaku a vlak se tak posune. Třída Stepper dokáže sama vytvořit seznam přírůstků v daném směru pohybu. Stačí pouze informace o směru, kterým pojedeme a seznam přírůstků, ze kterých konečný seznam vygenerujeme. Jedna položka konečného seznamu přírůstků je dvojice celých čísel, o které vlak posunujeme. Jedno číslo pro osu x, druhé pro osu y. Obě čísla mají vždy buď stejnou hodnotu, nebo se liší znaménkem, nebo je nějaká složka nulová (mohou být obě dvě). Takto jednoduše lze vytvořit přírůstek v libovolném směru, ve kterých vlak může jezdit, za což vděčíme opět zejména způsobu zobrazení trati.
6.6.4 Generování výchozích přírůstků Ještě zbývá uvést, odkud se bere výchozí seznam přírůstků. Ten se vygeneruje v metodě makeChange při kolizi vlaku s kolizním bodem jak je vidět z algoritmu v předchozí podkapitole. Statická metoda generateVelocities třídy CollisionPoint tento výchozí seznam vygeneruje. Položka seznamu je vždy kladné celé číslo nebo nula. Výchozí přírůstky se vztahují pouze ke vzdálenosti, kterou mají překonat za určitý čas, přičemž nezáleží na směru. Konkrétní přírůstky vygeneruje až instance třídy Stepper. Algoritmus generování není opět nikterak složitý: 1. Spočítej počet kroků pohybu ( čas / časový posun), minimálně však vždy 1. 2. Spočítej průměrný přírůstek (vzdálenost / počet kroků). 3. Vytvoř seznam velký jako počet kroků, každou položku nastav na průměrný přírůstek (zaokrouhlený dolů na celé číslo). 4. R := kolik kroků celkově zbývá, M := 2. 5. Dokud R > 0 prováděj: •
Procházej od konce seznam přírůstků: o Pokud je index v seznamu dělitelný beze zbytku M nebo se jedná o poslední
položku
seznamu,
inkrementuj
položku
seznamu,
dekrementuj R. o Pokud R = 0, tak ukonči cyklus. •
Inkrementuj M.
Tímto způsobem jsou jednotlivé přírůstky rozmístěny relativně rovnoměrně. Proč se seznam prochází od konce a proč je tam podmínka, že se jedná o poslední položku seznamu, má svůj důvod. Tím je podobná věc jako v případě anomálie s průměrným přírůstkem. Mohlo by se stát, že průměrný přírůstek zaokrouhlený na celé číslo bude 0. Pokud bychom seznam začali procházet od začátku, mohlo by se stát, že posledních několik kroků bude mít prázdný přírůstek. Tedy do následujícího kolizního bodu bychom se dostali dříve, než jsme měli původně v plánu, jenže to už je
- 42 -
zaregistrována kolize s novým bodem a tedy se generují nové rychlosti pro následující úsek. A tedy jsme opět s vlakem předběhli čas a přijeli do stanice dříve.
6.6.5 Zaokrouhlovací chyby Tím, že jsou použita celá čísla dochází k zaokrouhlovacím chybám. Tyto chyby ale nemají větší dopad na věrohodnost simulace. Použitou metodou Krokování se dosáhlo toho, že odchylka je zanedbatelná.
- 43 -
7 Automatické řízení provozu 7.1 Úloha dispečera Základním stavebním kamenem samotného řízení provozu je stavění cest. Vlak nemá jednoznačně určenou cestu, kudy pojede. Trasa je pro každý vlak plánována – stavěna – až v době jeho jízdy. Díky tomu je možné trasu určitým způsobem měnit. Nelze ji sice změnit úplně, nicméně ji lze modifikovat tak, aby docházelo k pokud možno co nejmenšímu zpoždění. Někdy se může přihodit nečekaná událost, na trati se něco stane a vlaky nemůžou po dané koleji jet. Pak je nutné trasu uzpůsobit aktuálním možnostem. Najít alternativní cesty, některé vlaky pozastavit, jiným dát přednost v jízdě. Tomuto se věnuje právě dispečer. Ve skutečném provozu se jedná o člověka, který tyto situace řeší. Program RTS se snaží tento proces určitým způsobem zautomatizovat, řídit tento provoz a v případě potřeby hledat alternativní možnosti vedení vlaků. Dispečer je v RTS reprezentován třídou BuiltPathStorage. Kdyby provoz řídilo více dispečerů, museli by svou činnost složitě koordinovat. Bylo by lepší mít pouze jednoho dispečera, který bude provoz řídit. Proto je zde opět použit návrhový vzor Singleton [4], který zajistí jedinečnost dispečera v rámci instance programu.
7.2 Stavění cest Jak již bylo zmíněno, stavění cest je základním stavebním kamenem řízení provozu. Postavená cesta je podcesta aktuální kolizní cesty. Je tedy tvořena pouze posloupností kolizních bodů. Výchozí kolizní cesta vlaku je tedy výchozí cestou, kudy vlak pojede. Podle této cesty se snaží dispečer cestu stavět. Jak bylo zmíněno v kapitole 6.5 Pohyb vlaků, při kolizi kolizního bodu s vlakem je, pokud to lze, dán požadavek dispečerovi k přidání dalšího kolizního bodu do kolizní cesty a je též dán požadavek dispečerovi, aby předchozí kolizní bod uvolnil z aktuální postavené cesty. Kvůli tomuto způsobu stavění cest je tedy nutné, aby byly kolizní cesty známy dopředu celé až do cíle. Jinak by nebylo možné zjistit následníka aktuálního kolizního bodu. Vlastní postavená cesta je programově zajištěna třídou BuiltPath. Jejím úkolem je pouze zajišťovat údaje o aktuální postavené cestě, přidávat nové kolizní body do postavené cesty, odebírat body a též aktuální postavenou cestu vykreslovat. Žádné další speciální úkoly třída nemá.
7.3 Řízení provozu Vlaky samy o sobě vůbec netuší, jakou cestu zrovna mají postavenou. Pokud by si vlaky samy cestu plánovali, musely by vědět ještě něco o pohybu ostatních vlaků na trati. Z toho důvodu je veškerá režie stavění cest soustředěna do dispečera a vlaky při požadavcích na postavení cesty komunikují výhradně s ním. Proto jsou také požadavky na zařazení dalšího kolizního bodu, a tedy postavení dalšího úseku cesty, případně odebrání kolizního bodu z postavené cesty, zasílány dispečerovi, ne postavené cestě asociované s daným vlakem.
- 44 -
7.3.1 Postavení nového úseku cesty Aby mohl dispečer dobře stavět cesty, musí vědět, které kolejové bloky už jsou zabrány kterými vlaky a tudíž nejsou k dispozici. Stejný seznam zabraných kolejových bloků se využívá i v případě, kdy uživatel v průběhu simulace přeruší kolejový blok. Jediný rozdíl je v tom, že v tomto případě není uveden vlak, který se na daném kolejovém bloku právě nachází. Jak již bylo zmíněno, postavení nového úseku se děje na žádost o zařazení dalšího kolizního bodu do postavené cesty zaslanou dispečerovi kolizním bodem, se kterým vlak přišel právě do kolize. Samotné zařazení do postavené cesty není tak jednoduché, protože se může stát, že nový blok je již obsazen. Proces stavění nového úseku cesty popisuje následující algoritmus: 1. Přidej nový blok do postavené cesty. 2. Pokud nový blok není používaný, zařaď ho do seznamu používaných bloků. 3. Jinak: •
Vytvoř nový graf tratě: o Pokud blok používá vlak, vytvoř graf bez aktuálně postavené cesty tohoto vlaku – zkusíme najít cestu, jak tento vlak objet, příp. se s ním minout. o Pokud blok nepoužívá vlak, tedy blok je pouze přerušen, vytvoř graf bez přerušených bloků – zkusíme najít cestu, jak objet tento blok. o Jinak vytvoř graf bez blokovaných staničních kolejí, na kterých momentálně stojí vlaky.
•
Proveď hledání nejkratší cesty pomocí Dijkstrova algoritmu v novém grafu z počátečního vrcholu, který odpovídá aktuální pozici vlaku.
•
Extrahuj cestu z aktuální pozice do cílového vrcholu grafu.
•
Pokud taková cesta existuje a je vhodná k použití (viz dále), vyměň starou cestu vlaku za novou a zaregistruj novou cestu u manažera simulátoru.
•
Pokud nová cesta neexistuje, zastav vlak a vytvoř u dispečera žádost o uvolnění daného bloku, ale pouze v případě, že se nejedná o vzájemné zablokování – tzn. dva vlaky se navzájem blokují.
Je důležité ještě zmínit, co znamená, že nová nalezená cesta je vhodná. Cestu je výhodné použít tehdy, pokud strávím kratší čas jízdou po nové cestě, než když budu čekat, až mi vlak, který kolejový blok obsazuje, blok uvolní a než daný kolejový blok přejedu. Druhou podmínkou výhodnosti cesty je spíše taková nutná podmínka - na nové cestě musí ležet všechny dosud nenavštívené zastávky. Při nevhodném nastavení kolejiště se totiž může stát, že se podaří nalézt cestu do cíle, která je alternativou cesty - 45 -
původní. Ovšem nová cesta nemusí obsahovat všechny zastávky, které byly na původní nejkratší cestě. Z toho důvodu si každý vlak hlídá, jaké zastávky navštívil, a tedy také ví, v jakých ještě nebyl. Proto nově nalezená cesta musí obsahovat všechny dosud nenavštívené zastávky.
7.3.2 Uvolnění nepoužívaného úseku cesty Cesty nelze pouze stavět, je též nutné za sebou cesty uvolňovat, aby byly použitelné pro vlaky, které tudy pojedou v následujícím čase. Uvolnění nepoužívaného úseku cesty je též plně v režii dispečera, který tak učiní na žádost kolizního bodu, který při opouštění zadá žádost o smazání předchozího kolizního bodu z postavené cesty. Opět nelze blok z cesty jednoduše vypustit, je třeba si uvědomit, že mohou existovat vlaky, které právě čekají na uvolnění tohoto bloku a tedy je potřeba se podle toho tak zachovat. Průběh uvolnění nepoužívaného bloku popisuje následující algoritmus: 1. Smaž z postavené cesty již nepoužívaný kolizní bod. 2. Smaž ze seznamu používaných bloků blok, který se týká odstraňovaného kolizního bodu. 3. Najdi nejvhodnější vlak T, který čeká na uvolnění. 4. Najdi jeho kolizní cestu B. 5. Pokud je celá cesta B volná, najdi kolizní bod C, který odpovídá pozici vlaku T. Pokud takový bod C existuje a pokud existuje i jeho předchůdce, zašli žádost o smazání jeho předchůdce z cesty B, spusť pohyb vlaku T. 6. Smaž žádost vlaku T v seznamu čekajících na uvolnění. 7. Aktualizuj zastavené vlaky. Zastavené vlaky je nutné aktualizovat z toho důvodu, kdyby byl náhodou uvolněn blok, který utváří alternativní cestu pro nějaký stojící vlak. Postup aktualizace se velmi podobá stavění cest, protože se ve své podstatě o stavění cest jedná. Vytvoří se graf bez přerušených kolejových bloků a zkusí se v něm najít pro vlak vhodná cesta. Pokud ovšem cesta nalezena není, nic se nestane, vlak bude stát dále.
7.3.3 Hledání nejvhodnějšího čekajícího vlaku Může se stát, že na uvolnění jednoho bloku čeká více vlaků. V takovém případě je nutné dát některému vlaku přednost před jiným. Největší přednost mají vlaky označené jako EC (EuroCity), IC (InterCity) a EN (EuroNight). Dalšími v pořadí jsou obecně všechny vlaky osobní, a dále vlaky mimořádné. Nejmenší prioritu mají vlaky nákladní, které se odbavují až jako poslední.
- 46 -
8 Závěr Cílem této bakalářské práce bylo vytvořit grafický editor železničních tratí se simulátorem, na kterém by bylo možno provést simulaci provozu na vytvořené trati. Vytvořil jsem program RTS, který umožňuje uživateli modelovat pokročilé modely železničních tratí, vytvářet vlaky a jízdní řády. Pomocí grafického simulátoru může uživatel simulaci spustit a zkoumat, jaký vliv na provoz mohou mít různé mimořádnosti, které se na trati vyskytnou. Samotný program RTS je vytvořen tak, aby byl pokud možno co nejvíce uživatelsky přívětivý, tj. především jednoduchým ovládáním, možností vkládání a kopírování částí diagramu a vlaků. Důležitou vlastností je též možnost vracet zpět veškeré provedené operace. RTS neklade žádná velká omezení na tvorbu modelu kolejiště. Výsledkem je možnost modelování reálných železničních tratí. Tvorba simulátoru mi pak pomohla vyzkoušet si implementaci opravdu náročného problému – a to spojité simulace. Přineslo mi to řadu zkušeností, které budu určitě moci v budoucnu využít, ať už v akademické, či komerční sféře. Řešení mimořádností při tvorbě automatického řízení provozu mě pouze utvrdilo v tom, že úloha dispečerů na trati je opravdu důležitá a natolik obtížná, že pětiminutové zpoždění, které vlaky dnes běžně mají je v podstatě plně zanedbatelné ve srovnání se zpožděním, které by vlaky měly, pokud by nebyl provoz nijak efektivně řízen.
8.1 Budoucnost programu RTS Současná verze programu RTS rozhodně není v takovém stádiu, aby se dal program jednoduše uzavřít s tím, že už jej nelze dále rozšiřovat nebo opravovat. Už z implementačního hlediska jsem kladl poměrně velký důraz právě na to, aby se dal program v budoucnu dobře rozšířit. Je použito hodně programátorských technik, které vedou k dobré možnosti budoucího rozšíření. V budoucnu by program RTS mohl být rozšířen o následující funkce: • Grafický generátor jízdních řádů, podobný tomu, který se skutečně používá na železnici. • Tisk jízdních řádů a diagramu kolejiště • Vytváření statistiky zpoždění. • Hledání slabých míst tratě, tzn. takových, kde dochází k největšímu zdržení. • Vylepšení automatického řízení o lepší predikci možného zpoždění, ať už z aktuální situace nebo ze statistik. • Vytváření kyvadlové dopravy osobních vlaků. • Vylepšení simulace pohybu vlaků, tzn. minimálně o rozjezdy a zpomalování vlaků. • Možnost přímého určení cesty vlaků. • Rozšíření simulátoru o možnost běhu více simulací najednou v jednotném čase spolu s vzájemnou provázaností spuštěných simulací.
- 47 -
Literatura [1] Jan Konrad, simulační program Multikon http://softikon.wz.cz/multikon.htm [2] I.Mlýnková, J.Pokorný, K.Richta, K.Toman, V.Toman: Technologie XML, skripta, Nakladatelství Karolinum, Praha 2006 [3] Dr. Ir. Frank Vanden Bergen, C++ XML Parser http://www.applied-mathematics.net [4] E. Gamma, R. Helm, R. Johnson, J. Vlissides Design Patterns – Elements of Reusable Object-Oriented Software, Addison – Wesley professional computing series, 1995 [5] České dráhy: Traťové jízdní řády http://www.cd.cz [6] Microsoft Developer Network http://msdn.microsoft.com
- 48 -
Přílohy Instalační CD Přílohou práce je instalační CD, které obsahuje: •
Instalační balík RTSSetup.exe
•
Zdrojové kódy aplikace v jazyce C++ pro Microsoft Visual Studio 2008
•
Programátorská příručka vygenerovaná programem Doxygen
•
Schéma používaných XML souborů v jazyce XML Schema
- 49 -