---
title: |
| 
| 'City Traffic Simulator'
author: |
| Maciej Adryan
| Aleksander Błaszkiewicz
| Michał Matejuk
| Jakub Brzozowski
header-includes: |
\usepackage{fontspec}
\usepackage{titletoc}
\usepackage[english,polish]{babel}
\selectlanguage{polish}
\setmainfont{Arial}
\raggedbottom
\usepackage[fontsize=11pt]{scrextend}
\usepackage{setspace}
\linespread{1.20}
\usepackage{xcolor}
\usepackage{color}
\renewcommand*{\figureautorefname}{rys.}
\usepackage{float}
\floatplacement{figure}{H}
\lstset{
escapeinside={(*@}{@*)}, % if you want to add LaTeX within your code
}
\lstdefinelanguage{Dockerfile}
{
morekeywords={FROM, RUN, CMD, LABEL, MAINTAINER, EXPOSE, ENV, ADD, COPY,
ENTRYPOINT, VOLUME, USER, WORKDIR, ARG, ONBUILD, STOPSIGNAL, HEALTHCHECK,
SHELL},
morecomment=[l]{\#},
morestring=[b]",
frame=single,
aboveskip=1ex,
belowskip=1ex,
framexrightmargin=0em,
framexleftmargin=0em,
}
\lstdefinestyle{yaml}{
basicstyle=\color{blue}\scriptsize,
breaklines=true,
rulecolor=\color{black},
string=[s]{'}{'},
stringstyle=\color{blue},
comment=[l]{:},
commentstyle=\color{black},
morecomment=[l]{-},
breaklines=true,
columns=fullflexible,
frame=single,
aboveskip=1ex,
belowskip=1ex,
framexrightmargin=0em,
framexleftmargin=0em,
}
\usepackage{titlesec}
\titleformat{\chapter}[hang]{\normalfont\fontsize{13}{13}\bfseries}{\thechapter.}{1em}{\MakeUppercase}
\titleformat{\section}
{\normalfont\fontsize{11}{11}\bfseries\itshape}{\thesection}{1em}{}
\titleformat{\subsection}
{\normalfont\fontsize{11}{11}\itshape}{\thesubsection}{1em}{}
\usepackage{indentfirst}
\setlength{\parindent}{1.25cm}
\setlength{\parskip}{1pt}
\selectfont
\definecolor{mygreen}{rgb}{0,0.6,0}
\definecolor{mygray}{rgb}{0.5,0.5,0.5}
\definecolor{mymauve}{rgb}{0.58,0,0.82}
\selectlanguage{polish}
\titlespacing*{\chapter}{0pt}{12pt}{6pt}
\lstset{ %
backgroundcolor=\color{white}, % choose the background color
basicstyle=\scriptsize, % size of fonts used for the code
breaklines=true, % automatic line breaking only at whitespace
captionpos=b, % sets the caption-position to bottom
commentstyle=\color{mygreen}, % comment style
escapeinside={\%*}{*)}, % if you want to add LaTeX within your code
keywordstyle=\color{blue}, % keyword style
stringstyle=\color{mymauve}, % string literal style
frame=single,
aboveskip=1ex,
belowskip=1ex,
framexrightmargin=0em,
framexleftmargin=0em,
}
\makeatletter
\newcommand{\fakechapter}[1]{%
% go to vertical mode and don't allow a page break here
\par\nopagebreak
% step up the counter
\refstepcounter{chapter}
% teach nameref the title
\def\@currentlabelname{#1}
% add to TOC
\addcontentsline{toc}{chapter}{\protect\numberline{\thechapter}#1}
}
\newcounter{oldtocdepth}
\newcommand{\hidefromtoc}{%
\setcounter{oldtocdepth}{\value{tocdepth}}%
\addtocontents{toc}{\protect\setcounter{tocdepth}{-10}}%
}
\newcommand{\unhidefromtoc}{%
\addtocontents{toc}{\protect\setcounter{tocdepth}{\value{oldtocdepth}}}%
}
\usepackage{hyperref}
\usepackage{bookmark}
classoption: twoside
subparagraph: yes
...
\titlespacing*{\chapter}{0pt}{12pt}{6pt}
\selectlanguage{polish}
\hidefromtoc
\begin{otherlanguage}{polish}
\pagebreak
\chapter*{Streszczenie}
\label{StreszczenieRozdzial}
\addcontentsline{toc}{chapter}{\protect\numberline{}Streszczenie}
Celem pracy był projekt i realizacja prototypowego symulatora ruchu miejskiego i mikroserwisów obejmujących aspekty, jak:
\begin{itemize}
\item wpływ zachowań kierowców na zakorkowanie miasta,
\item optymalny dobór infrastruktury drogowej.
\end{itemize}
W ramach pracy stworzono symulator ruchu miejskiego, który składa się z 4 komponentów:
\begin{itemize}
\item symulator - aplikacja wykonana w technologii Unity odpowiedzialna za zbudowanie mapy i przeprowadzenie symulacji zgodnie z wprowadzonymi parametrami. Pozwala na pełną dowolność w budowaniu infrastruktury, zapewniając nie tylko różne gotowe elementy, ale także możliwość tworzenia własnych. Zawiera warstwę logiczną, która pozwala kierowcom respektować zasady ruchu drogowego jak dozwolona prędkość, światła drogowe, skrzyżowania ze światłami, skrzyżowania z pierwszeństwem, skrzyżowania z warunkowym skrętem oraz ronda,
\item backend - aplikacja wykonana w technologii .NET z wykorzystaniem bazy danych NoSQL (MongoDB). Odpowiedzialna za komunikację z pozostałymi podsystemami, zapisuje dane dotyczące przeprowadzanych symulacji, uruchamia backend obliczeniowy, dostarcza gotowych danych statystycznych do aplikacji frontendowej,
\item backend obliczeniowy - aplikacja wykonana w Pythonie z wykorzystaniem frameworka Flask. Służy do tworzenia statystyk dotyczących przebiegu symulacji oraz udostępniania API do inicjowania tych statystyk. Statystyki są tworzone dla każdego uruchomienia symulacji na podstawie danych otrzymanych z aplikacji backendowej,
\item frontend - aplikacja wykonana za pomocą pythonowego frameworka Dash by Plotly. Służy do wizualizacji otrzymanych wyników oraz, w razie potrzeby, przetwarzania tych danych. Celem tego podsystemu jest uproszczenie analizy wyników oraz umożliwienie użytkownikowi odtworzenia przebiegu symulacji.
\end{itemize}
Wszystkie podsystemy są ze sobą ściśle powiązane i komunikują się ze sobą warstwą sieciową. Wysokopoziomowym zamysłem jest umożliwienie użytkownikowi frontendowego serwisu przeglądania wyników wygenerowanych przez symulator i obliczonych przez backend obliczeniowy, do których ma dostęp poprzez backend.
W rezultacie powstał kompletny system, na który składają się mikroserwisy i sam symulator, które połączone potrafią tworzyć, analizować i zachowywać wyniki przeprowadzonych symulacji. System pozwala na badanie rozległych sieci dróg, ale także dzięki swojej dokładności jest w stanie zbadać przepustowości pojedynczych elementów drogowych w zależności od warunków zewnętrznych.
Aleksander Błaszkiewicz był odpowiedzialny za wykonanie symulatora w technologii Unity, skonfigurowanie serwera VPS, zaimplementowanie ciągłego dostarczania oraz przeprowadzenie badań.
Jest autorem rozdziałów i podrozdziałów \ref{definicjaSymulacjiPodrozdzial}, \ref{probkowaniePodrozdzial}, \ref{symRuchuWgrach}, \ref{InfrastrukturaPodrozdzial}, \ref{SymulatorPodrozdzial}, \ref{pieckimigowo}, \ref{autonomicznePojazdyPodrozdzial}, \ref{rondoVSskrzyzowanie}, \ref{zajmowaniePasowPodrozdzial} oraz współautorem rozdziałów i podrozdziałów \ref{ProjektSystemuRozdzial}, \ref{PhantomTrafficPodrozdzial} i \ref{PodsumowanieRozdzial}.
Maciej Adryan był odpowiedzialny za utworzenie warstw frontendowych oraz backendowych aplikacji dashboardowej opisanej w podrozdziale \ref{AplikacjaDashboardowaPodrozdzial}, opracowanie systemu tworzenia niniejszego dokumentu tekstowego opisanego w podrozdziale \ref{ProcesTworzeniaDokumentuPodrozdzial} oraz sprawował pieczę nad poprawnością jego powstawania.
Jest autorem rozdziałów i podrozdziałów: \ref{AplikacjaDashboardowaPodrozdzial} i \ref{ProcesTworzeniaDokumentuPodrozdzial} oraz współautorem rozdziałów i podrozdziałów: \ref{WstepICelRozdzial}, \ref{SymulacjaRuchuRozdzial}, \ref{ProjektSystemuRozdzial} i \ref{PodsumowanieRozdzial}.
Jakub Brzozowski był odpowiedzialny za przetwarzanie danych o symulacjach w celu późniejszej analizy przebiegu symulacji. W tym celu stworzył aplikację w języku Python wykorzystującą framework Flask, która agreguje i dostosowuje dane do formatu wymaganego do wyświetlenia w aplikacji dashboardowej.
Jest autorem rozdziałów i podrozdziałów: \ref{BackendObliczeniowyPodrodział} oraz współautorem rozdziałów i podrozdziałów: \ref{ProjektSystemuRozdzial} i \ref{PodsumowanieRozdzial}.
Michał Matejuk był odpowiedzialny za połączenie wszystkich warstw systemu przez stworzenie aplikacji backendowej w technologii ASP .NET będącej pośrednikiem pomiędzy aplikacją symulatora a backendem obliczeniowym i aplikacją frontendową oraz stworzenie, utrzymywanie i operacje na danych w dokumentowej bazie danych MongoDB.
Jest autorem rozdziałów i podrozdziałów: \ref{AplikacjaBackendowaPodrozdzial}, \ref{UruchomieniePodrozdzial}, \ref{PhantomTrafficPodrozdzial} oraz współautorem rozdziałów i podrozdziałów: \ref{WstepICelRozdzial}, \ref{AnalizaRozdzial} i \ref{PodsumowanieRozdzial}.
\end{otherlanguage}
\begin{otherlanguage}{english}
\pagebreak
\chapter*{Abstract}
\label{StreszczenieAngRozdzial}
\addcontentsline{toc}{chapter}{\protect\numberline{}Abstract}
The goal of the work was to design and implement a prototype of a city traffic simulator that covers aspects such as:
\begin{itemize}
\item the impact of driver behavior on city congestion,
\item optimal selection of road infrastructure
\end{itemize}
The project consists of four subsystems:
\begin{itemize}
\item simulator - a Unity-based application responsible for building the map and conducting the simulation according to the parameters introduced. It allows full flexibility in building infrastructure, providing not only various ready-made elements but also the ability to create custom ones. It contains a logical layer that allows drivers to respect traffic rules such as allowed speed, traffic lights, intersections with lights, intersections with priority, intersections with conditional turns, and roundabouts,
\item backend - a .NET-based application using a NoSQL database (MongoDB). Responsible for communication with the other subsystems, it stores data on conducted simulations, starts the computational backend, and provides ready statistical data to the frontend application,
\item computational backend - a Python-based application using the Flask framework. It is used to create statistics on the simulation and to provide an API for initiating these statistics. Statistics are created for each simulation run based on data obtained from the backend application,
\item frontend - an application created using the Python Dash by Plotly framework. It is used to visualize the obtained results and, if necessary, to process these data. The goal of this subsystem is to simplify the analysis of results and enable the user to recreate the simulation.
\end{itemize}
All subsystems are tightly connected and communicate with each other through the network layer. The high-level idea is to enable the user of the frontend service to browse the results generated by the simulator and calculated by the computational backend, which they have access to through the backend.
\end{otherlanguage}
\selectlanguage{polish}
\titlespacing*{\chapter}{0pt}{0pt}{6pt}
\unhidefromtoc
\titleformat{\chapter}[hang]{\normalfont\fontsize{13}{13}\bfseries}{\thechapter.}{1em}{\MakeUppercase}
\titlespacing*{\chapter}{0pt}{-3em}{1.1\parskip}
\titlelabel{\thetitle\quad}
\linespread{1.0}
\tableofcontents
\linespread{1.20}
\titlespacing*{\chapter}{0pt}{12pt}{6pt}
\pagebreak
\chapter*{Słownik skrótów i pojęć (Michał Matejuk)}
\addcontentsline{toc}{chapter}{\protect\numberline{}Słownik skrótów pojęć (Michał Matejuk) }
\fakechapter{A fake chapter}\label{SlownikPojecPodrozdzial}
- *frontend* - część systemu informatycznego odpowiedzialna za wyświetlanie i interakcję z użytkownikiem (UI), zazwyczaj za pomocą przeglądarki internetowej,
- *backend* - część systemu informatycznego odpowiedzialna za logikę biznesową i przetwarzanie danych, zazwyczaj uruchamiana na serwerze,
- *CI/CD* (Continuous Integration/Continuous Deployment) - metodologia tworzenia oprogramowania, polegająca na ciągłym integrowaniu i wdrażaniu zmian do aplikacji,
- *krzywa Beziera* - matematyczny sposób reprezentowania krzywych w grafice komputerowej, służący do tworzenia wielokątów i splajnów,
- *Github* - platforma internetowa, na której użytkownicy mogą przechowywać i współdzielić swój kod. GitHub umożliwia współpracę nad projektami oraz ich wersjonowanie, dzięki czemu możliwe jest śledzenie zmian w kodzie oraz powrót do poprzednich wersji,
- *Github Actions* - narzędzie dostępne na platformie GitHub, umożliwiające automatyzację procesów związanych z tworzeniem, testowaniem i wydawaniem oprogramowania. Dzięki niemu można zdefiniować sekwencję działań, które zostaną wykonane w odpowiedzi na określone zdarzenia (np. push do repozytorium) i uruchamiać je w chmurze. GitHub Actions pozwala na stworzenie spójnego i zautomatyzowanego procesu tworzenia i wydawania oprogramowania. Inne znane narzędzia tego typu to np. Azure DevOps lub Jenkins,
- *metadane* - informacje o innych danych. Są one zazwyczaj dodawane do plików lub dokumentów, aby opisać ich zawartość lub ułatwić ich wyszukiwanie. Metadane w projekcie opisują między innymi tagi/typy pojazdów lub numer uruchomienia symulacji,
- *caching* - proces przechowywania danych w celu ich szybszego dostępu w przyszłości. W przypadku stron internetowych caching polega na zapisywaniu kopii stron lub poszczególnych elementów na lokalnym komputerze użytkownika, dzięki czemu przy kolejnym odwiedzeniu tej samej strony część danych jest pobierana z lokalnej pamięci, co znacznie przyspiesza jej wczytanie,
- *API* (ang. *Application Programming Interface*) - interfejs programistyczny, który umożliwia komunikację pomiędzy różnymi aplikacjami lub systemami. API definiuje sposób, w jaki aplikacje mogą wymieniać dane i wykonywać określone operacje. Dzięki API możliwe jest wykorzystywanie funkcjonalności innych aplikacji bez konieczności zgłębiania ich wewnętrznej struktury,
- *REST* (ang. *REpresentational State Transfer*) - architektura sieci Web, która definiuje zasady tworzenia i wymiany danych w sieci. REST opiera się na wykorzystaniu protokołu HTTP do przekazywania danych w postaci dokumentów, takich jak XML lub JSON. REST jest często wykorzystywany do tworzenia API, ponieważ umożliwia proste i elastyczne wymianę danych pomiędzy różnymi aplikacjami.
- *Docker* - narzędzie, które umożliwia tworzenie, uruchamianie i zarządzanie kontenerami w dowolnym systemie operacyjnym. Kontenery to lekkie i izolowane od siebie środowiska, które zawierają wszystko, co jest potrzebne do uruchomienia aplikacji, w tym kod, zależności i konfiguracje. Dzięki temu, że kontenery są lekkie i izolowane, można je łatwo przenosić i uruchamiać na różnych systemach operacyjnych bez konieczności modyfikowania kodu ani konfiguracji. Docker umożliwia też tworzenie i wdrażanie aplikacji w postaci kontenerów, co ułatwia zarządzanie nimi i wdrażanie na różnych środowiskach,
- *YAML* - język opisowy, który służy do zapisywania danych w formie tekstowej. Jest on bardzo prosty, dzięki czemu łatwo można go wykorzystać do konfiguracji różnych aplikacji i systemów. YAML opiera się na indeksowaniu danych za pomocą kluczy i wartości, a także na strukturze danych za pomocą odpowiednich znaków takich jak dwukropek, kreska i wcięcia. Dzięki temu dane zapisane w YAML są bardzo czytelne nawet dla osób bez doświadczenia w programowaniu.
- *spawner* - obiekt w unity odpowiedzialny za instancjonowanie innych obiektów typu **GameObject**,
- *DTO* (ang. *Data transfer object*) - obiekt, który można zserializować i jest używany do przesyłania informacji pomiędzy komponentami,
- *UX* (ang. *User experience*) - określa doświadczenie użytkownika, jakie towarzyszy mu podczas korzystania z produktu,
- *Kubernetes* - przenośna, rozszerzalna platforma oprogramowania służąca do zarządzania zadaniami i serwisami uruchamianymi w kontenerach,
- *SSR* (ang. Server Side Rendering) - technika renderowania stron internetowych, w której proces renderowania strony jest przeprowadzany na serwerze, a nie w przeglądarce użytkownika.
# Wstęp i cel pracy
\label{WstepICelRozdzial}
Większość ludzi w miastach porusza się pojazdami, które korzystają z infrastruktury drogowej. Jednym z największych problemów użytkowników sieci drogowych są zatory. W ogólności, im więcej pojazdów pojawi się w miejskiej sieci, tym dłużej zajmie pokonanie danej trasy. Aby zminimalizować skutki rosnącej liczby pojazdów na drogach, ważne jest odpowiednie dobranie elementów infrastruktury, ale także poprawne zachowanie kierowców.
Dużą rolę odgrywają miejskie zespoły planowania ruchu - specjalne jednostki odpowiedzialne za zarządzanie i optymalizację ruchu drogowego w miastach. Są one zaangażowane w monitorowanie ruchu drogowego, wprowadzanie rozwiązań mających na celu poprawę jego efektywności oraz współpracę z kierowcami i użytkownikami drogi w celu promowania poprawnych zachowań. Zespoły te korzystają z różnych metod optymalizacji ruchu drogowego, w tym analizy danych ruchu, modeli matematycznych i symulacji komputerowych. Dzięki temu mogą one przeprowadzać testy różnych scenariuszy i zmian w infrastrukturze drogowej, aby zidentyfikować te, które prowadzą do najlepszych wyników.
Celem projektu jest zbadanie, w jakim stopniu wybrane czynniki wpływają na powstawanie zatorów reprezentując przepływ samochodów przez różne konfiguracje dróg w postaci wykresów i obliczając statystyki jak mapy cieplne pozycji oraz mapy cieplne prędkości
Kluczowymi zagadnieniami, które należy przeanalizować w ramach tej pracy inżynierskiej są:
- rodzaje symulacji,
- zasady budowania symulatora ruchu miejskiego,
- interakcje pomiędzy mikroserwisami,
- utrzymywanie serwera VPS,
- automatyczne wdrażanie i ciągłe dostarczanie,
- rola autonomicznych pojazdów w usprawnieniu ruchu w sieci miejskiej (przypadek braku czasu reakcji),
- zjawisko tworzenia się sztucznych zatorów na drogach z powodu wysokiego czasu reakcji kierowców,
- czynniki determinujące wymianę tradycyjnego skrzyżowania na rondo,
- wpływ harmonogramu świateł na przepustowość skrzyżowań,
Kolejne rozdziały tej pracy przedstawią proces wytwarzania oprogramowania, użyte
przez nas technologie, oraz podejście do problemu i zaproponowane rozwiązania:
- Rozdział 2 - definicja symulatora, rodzaje symlacji, problem korków w miastach oraz istniejące rozwiązania,
- Rozdział 3 - opisuje cel i przeznaczenie systemu oraz specyfikacje wymagań funkcjonalnych i użytkowych
- Rozdział 4 - opis infrastruktury i środowiska, na którym udostępnione są poszczególne mikroserwisy, opis kluczowych elementów symulatora, frontendu, backend oraz backendu obliczeniowego, diagramy przepływu danych pomiędzy komponentami
- Rozdział 5 - badania przeprowadzone w symulatorze oraz wnioski tych badań
# Symulacja ruchu drogowego
\label{SymulacjaRuchuRozdzial}
## Definicja symulacji (Aleksander Błaszkiewicz)
\label{definicjaSymulacjiPodrozdzial}
*Symulacja* to przybliżone odtwarzanie zjawisk czy zachowań pewnego obiektu i środowiska, w którym się ten obiekt znajduje za pomocą modelu matematycznego, który stanowi próbę przybliżenia rzeczywistych zachowań obiektu przy jednoczesnym ograniczeniu jego złożoności. Stopień dokładności modelu zależy od konkretnych potrzeb/zastosowania, ale przy nietrywialnych problemach będzie on zawsze, w mniejszym lub większym stopniu, zależny od modelowanego zjawiska.
> ‘‘All models are wrong but some are useful’’ - George Box
Symulatorem nazywamy program, który pozwala przeprowadzić symulację. Taki program charakteryzuje się tym, że jest przystosowany do danego typu symulacji. Przykładowo w przypadku symulatorów ruchu miejskiego będą to dedykowane widoki do edycji parametrów pojazdów, układu ulic czy harmonogramu świateł.
Cele i zastosowania symulatorów są bardzo różnorodne. Przykładowymi celami mogą być m.in.:
- zbadanie, czy dany system działa z optymalną wydajnością,
- trenowanie pracowników,
- rozrywka (gry wideo),
- przeprowadzenie symulacji w warunkach niemożliwych do odwzorowania w aktualnych warunkach na Ziemii (np. lądowanie na innej planecie),
- przeprowadzenie symulacji w warunkach na tyle niebezpiecznych, że stwarzałyby zagrożenie dla ludzi.
Problemy tworzenia symulacji zależą od badanego zjawiska oraz środowiska, w którym pracują, ale do najczęstszych należą:
- są one zwykle bardzo złożonymi systemami, które wymagają dużej ilości danych wejściowych i wyjściowych, a także precyzyjnego modelowania różnych procesów i zjawisk. Dlatego tworzenie symulatorów może być czasochłonne i kosztowne,
- dokładność symulacji (niekiedy odwzorowywane modele muszą być bardzo dokładne, aby zapewnić wiarygodne wyniki),
- trudność w doborze właściwych parametrów,
- ograniczenia wydajnościowe programu symulującego,
- ograniczenia czasowe (symulacja długotrwałych procesów może być czasochłonna),
- ryzyko błędów w implementacji.
## Typy symulacji
### Próbkowanie (Aleksander Błaszkiewicz gówno)
\label{probkowaniePodrozdzial}
Symulacje można podzielić na dwa główne typy[^rodzaje_symulacji_twi]:
- *dyskretne* - zdarzenia dzieją się w określonych punktach czasowych, zmieniając stan symulowanego obiektu. Liczba "punktów" czasu w trakcie symulacji jest skończona,
- *ciągłe (dynamiczne)* - stan zmienia się w sposób ciągły - taka symulacja zamodelowana jest przy pomocy równań różniczkowych.
Trzeba przy tym pamiętać, że komputery z powodu swojej cyfrowej natury nie mogą przeprowadzać rzeczywistych ciągłych symulacji. Bardzo często spotykanym zabiegiem jest ustalenie na tyle krótkiego odstępu pomiędzy kolejnymi punktami symulacji, aby symulacja dawała wrażenie ciągłej (ang. *near real-time*). Zabieg dzielenia czasu na coraz mniejsze odcinki ma na celu zwiększenie realizmu symulacji.
[^rodzaje_symulacji_twi]: Internet [WHAT IS SIMULATION? WHAT DOES IT MEAN? (DEFINITION AND EXAMPLES https://www.twi-global.com/technical-knowledge/faqs/faq-what-is-simulation)](https://www.twi-global.com/technical-knowledge/faqs/faq-what-is-simulation)
### Rozmiar (Maciej Adryan)
[^rodzaje_symulacji]: Internet [Burghout, W., Koutsopoulos, H. N., & Andréasson, I. (2005). Hybrid Mesoscopic–Microscopic Traffic Simulation. Transportation Research Record, 1934(1), 218–225.](https://doi.org/10.1177/0361198105193400123)
Ze względu na wymagania oraz możliwości przeprowadzenia symulacji, naturalnie wyodrębniły się trzy najpopularniejsze rodzaje symulacji ruchu drogowego[^rodzaje_symulacji]:
- mikrosymulacje (ang. *micro simulations*)
- pozwalają uzyskać najwyższy poziom detali oraz szczegółowość,
- symulują poszczególne agenty biorące udział w ruchu drogowym.
- mesosymulacje (ang. *meso simulations*)
- pozwalają uzyskać niższy poziom detali w porównaniu do mikrosymulacji,
- są szybsze, mniej czasochłonne i zasobochłonne,
- ze względu na mniejszą złożoność ułatwiają symulowanie większych i bardziej zaawansowanych scenariuszy w porównaniu do mikrosymulacji.
- symulacje hybrydowa (ang. *hybrid simulations*)
- pozwalają na dobór poziomu detali w taki sposób, aby wybrane komponenty były symulowane w sposób dokładny lub mniej dokładny w zależności od potrzeb użytkownika.
## Symulatory ruchu miejskiego w grach (Aleksander Błaszkiewicz)
\label{symRuchuWgrach}
Popularnym zastosowaniem symulatorów ruchu miejskiego są gry. Logika symulacji pozwala na zintegrowanie elementów infrastruktury drogowej z resztą gry. Dzięki symulacji budowanie dróg nie jest prostym zadaniem, a wymaga przemyślenia, w jaki sposób funkcjonuje miasto.
Jednym z przykładów gier opierających się na symulowaniu ruchu drogowego jest gra **Cities: Skylines** (\autoref{CitiesSkylines}). W grze tej gracz wciela się w projektanta miasta. Jego zadaniem jest zaprojektowanie sieci drogowej w taki sposób, żeby sztuczni agenci mogli sprawnie pokonywać miasto i żeby nie powstawały korki.

Kolejnym przykładem gry opierającej się na podobnej mechanice jest gra **Mini Metro**. W grze tej gracz staje się planistą sieci metra, którego zadaniem jest optymalizacja tej sieci (\autoref{MiniMetro}).

Innym przykładem z rodziny gier **Mini** jest **Mini Motorways**. Zasada działania jest taka sama jak w przypadku poprzedniej gry, jednak tutaj zamiast sieci metra gracz planuje sieć drogową aut (\autoref{MiniMotorways}).

Ostatni przykład to gra **Freeways**, w której gracz ma się skupić bardziej na optymalizacji jednego skrzyżowania, niż na całej sieci drogowej (\autoref{Freeways}).

## Zastosowanie symulatorów do planowania ruchu miejskiego (Maciej Adryan)
Oprócz zastosowania w dziedzinie rozrywki, symulatory znajdują szerokie zastosowanie w praktyce. W zależności od stopnia zaawansowania pozwalają one na mniej lub bardziej skomplikowane i szczegółowe symulowanie, a co za tym, badanie oraz dalszą analizę ruchu drogowego której celem mogą być m.in:
- planowanie sieci ulic,
- planowanie rozmieszczenia skrzyżowań oraz dobrania prawidłowego typu spośród skrzyżowań:
- o ruchu okrężnym (ronda),
- o ruchu kierowanym,
- bezkolizyjne,
- równorzędne,
- nierównorzędne,
- w kształcie litery "Y" (rozwidlenia),
- w kształcie litery "T",
- w kształcie litery "X".
- planowanie rozmieszczenia sygnalizacji świetlnej,
- planowanie rozmieszczenia znaków drogowych,
- planowanie odpowiednich dla infrastruktury oraz architektury ograniczeń prędkości,
- unikanie zastojów (ang. *deadlocks*),
- planowanie architektury mającej zapewnić pieszym bezpieczeńtwo
- rozplanowanie przejść dla pieszych.
- badanie wpływu tymczasowego bądź stałego zamknięcia danej ulicy (np. celem jej modernizacji) i wynikających z niej potencjalnych problemów w ruchu miejskim,
- skutki zwiększenia/zmniejszenia ilości pasów ruchu,
- integracja oraz planowanie ruchu komunikacji miejskiej, np.
- autobusów,
- tramwaji,
- trolejbusów.
- integracja oraz planowanie architektury komunikacji miejskiej, np.
- przystanki autobusowe,
- przystanki tramwajowe,
- przystanki trolejbusowe,
- przejazdy kolejowe.
- optymalizacja i skoordynowanie czasu trwania sygnalizacji świetlnej na wybranym odcinku drogi lub w danym sąsiedztwie,
- skutki integracji nowych punktów zainteresowania na mapie miejskiej, takich jak:
- galerie handlowe,
- centra rozrywki,
- węzły komunikacyjne (dworce autobusowe, dworce kolejowe, lotniska),
- parkingi,
- osiedla mieszkaniowe.
- badanie spodziewanej emisji spalin towarzyszącej wyżej wymienionym zdarzeniom.
## Wybrane rozwiązania dostępne na rynku
* [Road Traffic Simulation Software](https://www.anylogic.com/road-traffic/) --
Zaawansowane narzędzie komercyjne widoczne na \autoref{RTSS}, skupiające się na:
- planowaniu sieci dróg i autostrad,
- ocenianiu przepływu oraz tendencji do korkowania się ulic,
- planowaniu harmonogramów sygnalizacji świetlnej,
- integrowaniu budynków użyteczności publicznej z siecią drogową.

* [SUMO (Simulation of Urban MObility)](https://www.eclipse.org/sumo/) --
Otwartoźródłowe narzędzie widoczne na \autoref{SUMO}, udostępnione na licencji Eclipse Public License Version 2. Służy do przeprowadzania mikrosymulacji na dużą skalę.

* [OpenTrafficSim](https://opentrafficsim.org/manual/) --
Otwartoźródłowe narzędzie na licencjach BSD, Apache oraz MIT służące do przeprowadzania mikro- oraz makrosymulacji będące owocem pracy grupy pracowników Uniwersytetu Technicznego w Delft.
* [SIMWALK Road Traffic Simulator](https://www.simwalk.com/modules/simwalk_roadtraffic.html) --
Narzędzie komercyjne widoczne na \autoref{SIMWALK}. Dedykowane jest do badania interakcji ruchu pieszego i samochodowego o małym i średnim natężeniu np. badanie poszczególnych skrzyżowań, małych obszarów miejskich okolic węzłów komunikacyjnych.

* [SIMTERACT TRAFFIC AI](https://simteract.com/projects/traffic-ai/) --
Biblioteka, dostępna komercyjnie, którą można zintegrować z symulatorem bądź grą wideo. Została wykorzystana do szkolenia inteligentnych algorytmów służących do kierowania prawdziwymi, autonomicznymi pojazdami. Biblioteka pozwala na:
- wprowadzenie dynamicznych zachowań kierowców:
- zmienianie pasów,
- wyprzedzanie,
- omijanie kolizji.
- konfigurowanie liczności pojazdów,
- występowania specjalnych stref wpływających na zachowania kierowców,
- konfigurowanie scenariuszy zachowań,
- tworzenie opartego o siatkę systemu dróg.
* [Traffic3D](https://traffic3d.org/) --
Otwartoźródłowe narzędzie widoczne na \autoref{Traffic3D}. Udostępnione na licencji Mozilla Public License Version 2.0. Narzędzie jest wyposażone w komponenty ułatwiające mimikowanie istniejących dróg za pomocą projektu OpenStreetMap. Narzędzie korzysta również z wyżej wspomnianego narzędzia [SUMO (Simulation of Urban MObility)](https://www.eclipse.org/sumo/).

# Projekt systemu
## Cel i przeznaczenie systemu
\label{ProjektSystemuRozdzial}
### Założenie i cel tworzenia aplikacji
Aplikacja nastawiona jest na optymalizację infrastruktury drogowej i zachowania kierowców. Chcemy, aby jak najwięcej parametrów było modyfikowalnych, a dodatkowo, żeby odbywało się to w przemyślany sposób (na przykład nie podawanie średniego czasu reakcji kierowców, tylko funkcji rozkładu tych czasów). Zależy nam także na bardzo szczegółowym tworzeniu map (wielopasowe skrzyżowania z warunkowymi pasami skrętu).
Ważne jest również, aby aplikacja umożliwiała tworzenie bardzo szczegółowych map skrzyżowań. Końcowy użytkownik aplikacji nie musi mieć wiedzy technicznej, aby skorzystać z jej funkcjonalności - wyniki będą przedstawione w prosty i czytelny sposób w aplikacji frontendowej.
### Ogólna charakterystyka systemu
Aplikacja przeprowadza symulację ruchu na mapie przygotowanej przez użytkownika. Nieprzerwanie komunikuje się z mikroserwisem backendowym, wysyłając informacje o dobranych parametrach oraz samych samochodach (pozycje, odległość od najbliższego samochodu, odległość do najbliższego skrzyżowania itp.). Po zakończeniu symulacji mikroserwis backendu obliczeniowego odbiera te dane, przetwarza je (wylicza interesujące wskaźniki, generuje odpowiednie heatmapy) i oddaje je aplikacji backendowej, która umieszcza te wyniki w bazie danych. Finalnie użytkownik może przejrzeć podsumowanie symulacji w aplikacji frontendowej.
### Ograniczenia dotyczące projektu aplikacji
W projektowanej aplikacji nie planujemy losowych zdarzeń jak:
- wypadki,
- kierowcy zajmujący złe pasy ruchu,
- piesi,
- pojazdy uprzywilejowane.
### Środowisko pracy systemu
Backend oraz backend obliczeniowy to skonteneryzowane aplikacje działające na serwerze Linuksowym. Aplikacja symulatora stworzona w środowisku Unity zbudowana jest dla systemu operacyjnego Windows. Frontend natomiast może być włączony na każdym urządzeniu posiadającym nowoczesną przeglądarkę internetową.
## Specyfikacja wymagań funkcjonalnych
Specyfikacja zawiera ogólne wymagania użytkowe dotyczące aplikacji symulatora ruchu drogowego, a także szczegółowe wymagania dotyczące symulatora, backendu, backendu obliczeniowego oraz frontendu.
### Ogólne wymagania użytkowe
- użytkownik może przeprowadzić symulację ruchu drogowego na okrojonym fragmencie miasta,
- dane dotyczące map i wyników symulacji zapisywane są w bazie danych,
- użytkownik może zobaczyć wyniki symulacji. Może w szczególności przeglądać różne wyniki symulacji dla różnych zestawów parametrów dla tej samej mapy.
### Wymaganie względem symulatora
- auta potrafią poruszać się po siatce ulic i skrzyżowań,
- auta respektują zasady ruchu drogowego (światła, skrzyżowania z pierwszeństwem, ronda),
- symulatorowi można podawać zestawy parametrów, które wpływają na wynik symulacji (zachowania kierowców, czasy świateł),
- można tworzyć i zapisywać mapy.
### Wymagania względem backendu
- serwis musi w czasie rzeczywistym zapisywać dane o przeprowadzanej przez aplikację Unity symulację,
- serwis nie może pozwolić sobie na utratę informacji od aplikacji Unity, bo skutkować to będzie niedokładnymi późniejszymi wynikami aplikacji obliczeniowej,
- serwis powinien pozwalać na jak najszybszy odczyt nowych danych z symulacji, w celu sprawnego przeprowadzania obliczeń,
- serwis na żądanie aplikacji frontendowej powinien udostępniać dane o wybranej symulacji - statystyki, heatmapy, strukturę dróg.
### Wymagania względem backendu obliczeniowego
- serwis musi udostępniać API dla backendu do inicjowania tworzenia statystyk,
- serwis musi być odporny na złe dane,
- serwis musi tworzyć statystyki i zapisywać je do bazy danych,
- serwis musi tworzyć statystyki takie jak:
- średnia prędkość wszystkich pojazdów,
- mapa cieplna (ang. *heatmap*) pozycji,
- mapa cieplna prędkości,
- mapa cieplna przyśpieszeń.
### Wymagania względem frontendu
- serwis ma prezentować przekazane mu przez backend wyniki dotyczące przeprowadzonej symulacji w schludny oraz czytelny sposób,
- typ danych które będą w danym momencie wyświetlane będzie konfigurowalny przez użytkownika serwisu frontendowego,
- interfejs aplikacji będzie responsywny i zmieniał wyświetlane dane w zależności od ww. konfiguracji,
- serwis ma być odporny na złe dane,
- nawigacja po serwisie odbywać się będzie w intuicyjny sposób.
## Specyfikacja wymagań użytkowych
### Wymagania jakościowe
- interfejs serwisu frontendowego oraz symulacji jest schludny, przejrzysty i naturalny w obsłudze (nie wymaga szkolenia ani poradnika, żeby go obsłużyć),
- użytkownik nieposiadający wiedzy z zakresu programowania jest w stanie stworzyć nowe mapy do symulacji.
### Wymagania wydajnościowe
- serwis frontendowy działa poprawnie na każdym urządzeniu z nowoczesną przeglądarką,
- symulacja działa w minimum 60 klatkach na sekundę w rozdzielczości 1080p na komputerze z systemem operacyjnym Windows z procesorem Ryzen 5 3600 lub lepszym i z 8Gb pamięci RAM lub więcej.
# Charakterystyka i implementacja systemu
## Infrastruktura (Aleksander Błaszkiewicz)
\label{InfrastrukturaPodrozdzial}
### Przepływ danych między podsystemami
Diagram głównych komponentów systemu oraz przepływu danych pomiędzy nimi przedstawiono na \autoref{ModelPrzeplywu}.

**Użytkownik włącza symulację (prostokąt Symulator)**
Niebieski - w trakcie trwania symulacji *Unity* wysyła do backendu zserializowane informacje o mapie, samochodach oraz ustawieniach co stały interwał.
Zielony - po zakończeniu symulacji *Unity* wysyła informację do backendu obliczeniowego, że wszystkie dane symulacji zostały już załadowane i może zacząć obliczenia
**Użytkownik włącza aplikację frontendową (prostokąt *Frontend*)**
Czerwone - użytkownik pobiera od backendu obliczone dane symulacji
### Dedykowany serwer
Jako platformę, na której uruchomione są wszystkie mikroserwisy wybraliśmy serwis z maszynami dedykowanymi mikr.us. Ograniczenia serwera to współdzielony procesor, 768Mb pamięci RAM oraz tylko jeden port ale to w zupełności wystarcza na potrzeby projektu.
### Domeny
Mikr.us oferuje darmowe subdomeny z sufixem ".bieda.it" jak przedstawiono na \autoref{domeny}. Można je zdobyć z poziomu panela serwera.

Wszystkie darmowe domeny domyślnie kierują na port wewnętrzny 80 serwera.
### Wystawienie usług na świat z jednym portem
Nasza architektura zakłada istnienie 3 mikroserwisów. Chcieliśmy, aby do wszystkich z nich był dostęp z poziomu sieci internet, jednak ograniczeniem jest wcześniej wspomniany jeden port.
Rozwiązaniem problemu jest usługa typu reverse-proxy zawierające mapę połączeń domena-port_wewnętrzny. Przy obsługiwaniu żądania przez serwer, reverse-proxy najpierw sprawdza oryginalną domenę i na podstawie tego parametru kieruje żądanie do odpowiedniego mikroserwisu jak przedstawiono na \autoref{ReverseProxy}.

### Konteneryzacja
Wszystkie mikroserwisy oprócz symulatora są skonteneryzowane, a jako narzędzie konteneryzacji wybraliśmy Docker. Serwer mikr.us sam w sobie nie jest dedykowaną maszyną, tylko kontenerem Proxmox, dlatego wybór Dockera nie był przypadkowy - jest to jedyne narzędzie które działa na serwerze nie wymagając przy tym dodatkowej konfiguracji.
### Automatyczne wprowadzanie
Aby nasz projekt był zgodny z kulturą DevOps, wszystkie mikroserwisy oprócz symulatora mają zaimplementowane akcje, które automatycznie konteneryzują aplikację, wysyłają ją do repozytorium Dockerhub, a następnie łączą się z naszym serwerem i włączają zaktualizowaną wersję jak przedstawiono na \autoref{GHActions}.
Byliśmy to w stanie osiągnąć dzięki [Github Actions](https://github.com/features/actions). Dodatku do serwisu Github, który oferuje nieograniczony i darmowy dostęp do maszyn Ubuntu dla projektów open-source.

## Symulator (Aleksander Błaszkiewicz)
\label{SymulatorPodrozdzial}
### Pojazd
Silnik fizyki Unity jest znacznie bardziej zaawansowany niż to, czego wymagamy w tym symulatorze, a co za tym idzie, wymaga znacznie więcej zasobów. Po dokładnym przyjrzeniu się wymaganiom projektu, doszliśmy do wniosku, że silnik fizyki w ogóle nie jest potrzebny. Ruch pojazdów można zasymulować równaniami matematycznymi. Poza tym każdy pojazd przestrzega zasad ruchu drogowego, dlatego nie ma potrzeby sprawdzania kolizji pomiędzy pojazdami.
Pojazd składa się z podstawowych brył. Zdecydowaliśmy się na uproszczony model aby nie rozpraszać się rzeczami, które nie mają wpływu na zachowanie w trakcie symulacji, ale także ze względu na wydajność - prosty model zajmuje o wiele mniej czasu, żeby go wyrenderować \autoref{Pojazd}.

### Czujnik odległości
Pojazd musi być świadomy tego, czy może się poruszać. W tym celu posiada klasę **ProximitySensor**.
Czujnik odległości odpowiada nie tylko za wykrywanie odległości do najbliższego obiektu, ale także za:
- wykrywanie odległości do najbliższego obiektu oraz jego identyfikacja (czy to inny samochód, czy to detektor kolizji ograniczający poruszanie się na skrzyżowaniach -na przykład skręt kolizyjny, warunkowy lub światła drogowe),
- przekazywanie maszynie stanów informacji na temat typu wykrytego obiektu.
### Silnik
Jako że pojazd nie jest bryłą sztywną obsługiwną przez silnik fizyczny Unity (klasa **Rigidbody**), to musi posiadać jednostkę sterującą jego zachowaniem natury fizycznej. Posiada więc klasę **Engine**, która odpowiada za jego poruszanie się. Udostępnia ona m.in. metodę **SetCanMove()**, która informuje silnik, czy samochód ma przyspieszać czy zwalniać. Aby zachowanie samochodu jak najlepiej odwzorowywało rzeczywistość, jego siła hamowania wyrażona jest w funkcji dystansu do obiektu, przed którym ma zahamować. Pozwala na to zmienna Unity typu **Curve** którą przedstawiono na \autoref{krzywaHamowania}.

Na podstawie zmiennej **canMove** silnik przykłada do samochodu przyspieszenie oraz odpowiedzialny jest za nałożenie prędkości na trasę samochodu, którą pobiera z klasy **PathPlanner**
### Układanie trasy
Aby pojazd wiedział, po jakich drogach ma się poruszać, posiada klasę **PathPlanner**. Odpowiedzialna jest ona za pobranie z danych elementów infrastruktury drogowej konkretnych dróg, którymi będzie poruszał się pojazd. Zasada działania dróg wytłumaczona jest w podrozdziale 4.2.9
### Maszyna stanów
Pojazd posiada maszynę stanów, dzięki czemu łatwiej zorganizować kod odpowiedzialny za poruszanie się pojazdu, a także łatwo go zserializować.
Maszyna stanów wspiera także propagację stanów, czyli na przykład w sytuacji w której pierwszy pojazd zatrzymał się, ponieważ ma czerwone światło, drugi pojazd stojący za nim również ustawi taki stan (mimo że bezpośrednim powodem zatrzymania się, nie jest czerwone światło, tylko pojazd, który zatrzymał się przed nim)
### Tworzenie dróg
Drogi reprezentowane są za pomocą krzywych Beziera. Każdy pas na jezdni to oddzielna krzywa B-sklejana. Skorzystaliśmy z gotowego narzędzia Sebastiana Lague. Narzędzie posiada funkcje:[^sebastian_krzywe]
[^sebastian_krzywe]: Internet [Sebastian Lague - paczka do krzywych beziera https://assetstore.unity.com/packages/tools/utilities/b-zier-path-creator-136082](https://assetstore.unity.com/packages/tools/utilities/b-zier-path-creator-136082)
- znalezienie najbliższego punktu na krzywej na podstawie podanej pozycji na scenie,
- znalezienie punktu na krzywej na podstawie przebytego dystansu,
- wyznaczenie wektora normalnego w dowolnym punkcie krzywej (żeby samochód był zwrócony wzdłuż krzywej),
- stworzenie modelu drogi.

Na potrzeby uproszczenia symulacji wszystkie drogi reprezentowane są na płaszczyźnie poziomej *XZ* (rzut z góry)
### Podstawowa droga
Aby zapewnić generyczność systemu dróg, stworzyliśmy element, który nazwaliśmy **IRoadElement**.
Instancją **IRoadElement** jest zbiór poddróg, które pozwalają przejechać przez dany element sieci dróg. Charakteryzuje się tym, że posiada:
- wejścia,
- wyjścia,
- poddrogi łączące wejścia z wyjściami.
Szczególnym przypadkiem **IRoadElement** jest zwykły odcinek drogi, która ma jedno wejście, jedno wyjście i nie zawiera poddróg jak na \autoref{prostyIRoadElement}.

**IRoadElement** jest świadomy tego, w jaki sposób należy po nim przejechać, znając wejście i wyjście. Ta teoria zostanie wytłumaczona lepiej w podrozdziale **Skrzyżowanie**
### Skrzyżowanie
Skrzyżowanie to typ **IRoadElement**, który zawiera w sobie poddrogi służące do przejechania po danym elemencie jak na \autoref{przykladSkrzyzowania}.

Zakładając, że trasa agenta składa się z drogi 1, skrzyżowania, a następnie drogi 2, to jeżeli taki agent poda skrzyżowaniu (**IRoadElement**) takie dane, to skrzyżowanie odpowie mu, że aby przez nie przejechać w takiej konfiguracji, należy to zrobić drogą numer 3
W ramach debugu i lepszego zrozumienia, w jaki sposób zachowuje się konkretne skrzyżowanie, inspektor Unity tej klasy udostępnia wygodne listy jak na \autoref{ispektorListySkrzyzowanie}.

**PreviousRoadElements** to referencje na drogi, które dochodzą do skrzyżowania
**NextRoadElements** to referencje na drogi, które wychodzą ze skrzyżowania
**PathCreatorsMap** to obiekty, które dla danej pary dróg wchodzącej i wychodzącej zawiera referencję na poddrogę, która łączy te dwie drogi
### Budowanie zależności między drogami
Opisany wyżej system pozwala samochodom pokonywać dowolnie skomplikowane skrzyżowania, ale najciekawsza część systemu to samo pokonywanie konkretnego skrzyżowania. Skrzyżowanie musi wiedzieć, w jaki sposób należy je pokonać.
Jednym z potencjalnych rozwiązań jest udostępnienie listy ze środka klasy do edytora Unity i dać użytkownikowi wypełnić wszystkie referencje ręcznie. Jest to rozwiązanie poprawne, jednak bardzo czasochłonne.
W naszym symulatorze chcieliśmy to zautomatyzować. W tym celu istnieje seria klas, które dla każdej drogi jaka jest w symulacji biorą jej koniec i początek, a następnie przeszukują wszystkie inne dostępne ścieżki, żeby znaleźć te, które się z nimi łączą.
Taka kalkulacja wykonywana jest za każdym razem, gdy startuje symulacja. Ta sama metoda wyszukiwania dróg używana jest do łączenia potencjalnych dróg oraz do łączenia poddróg z potencjalnymi drogami
### Budowanie zależności między drogami - przykład 1
Najprostszy element drogowy to element zawierający w sobie jedną drogę jak na \autoref{elementDrogowyPrzyklad1}.

Na początku symulacji taki element najpierw sprawdza, jakie znajdują się w nim drogi. W tym wypadku to **Droga 1**. Następnie na podstawie punktów startowych i końcowych dróg w środku wyznacza swoje punkty startowe i końcowe jak na \autoref{elementDrogowyPrzyklad2}.

Taki element gotowy jest na to, aby połączyć się z innymi elementami w celu zbudowania sieci drogowej.
Najprostszy przykład takiej sieci to 2 elementy drogowe jak na \autoref{elementDrogowyPrzyklad3}.

Na początku symulacji już po wyznaczeniu punktów końcowych oraz startowych elementów drogowych następuje część kojarzenia między sobą poszczególnych elementów.
Pierwszy krok to zebranie listy punktów startowych i końcowych.
W tym wypadku będzie to lista punktów **[1,2,3,4]** jak na \autoref{elementDrogowyPrzyklad4}.
Kolejny krok to znalezienie par punktów, między którymi odległość jest mniejsza niż ustalona. W tym wypadku taką parą są punkty **[2,3]**.
Po znalezieniu takiej pary następuje kojarzenie jak na \autoref{elementDrogowyPrzyklad4}.

Element drogowy 1 zapisuje w sobie informację, że jednym z jego potencjalnych elementów wyjściowych jest Element drogowy 2.
Tak zbudowana sieć pozwala teraz pojazdowi pokonać trasę składającą się z elementów drogowych 1 oraz 2.
Pojazd, który chce przejechać taką trasę, "spyta się" elementu drogowego 1 - w jaki sposób mogę przez ciebie trafić do elementu drogowego 2?
Element drogowy numer 1 odpowie wtedy, zwracając pojazdowi drogę znajdującą się w środku - **Droga 1**.
### Budowanie zależności między drogami - przykład 2
Najprostszym przykładem z elementem drogowym zawierającym więcej niż jedna droga jest takie rozwidlenie jak na \autoref{trudnaDrogaPrzyklad1}.

Krok pierwszy - kojarzenie punktów startowych z końcowymi jak na \autoref{trudnaDrogaPrzyklad2}.

Należy zwrócić uwagę na to, że punkt **2** został skojarzony z dwoma punktami - **3** oraz **4**. Jest to jak najbardziej możliwa sytuacja. Oznacza to, że z elementu drogowego 1 można dostać się do kilku innych dróg.
Zakładając, że autko planuje pokonać trasę elementów drogowych 1, 2 oraz 4, jego seria zapytań będzie wyglądała następująco:
- zapytanie elementu drogowego, w jaki sposób go pokonać, aby dojechać do elementu drogowego 2. Element odpowie referencją na obiekt **Droga 1**,
- zapytanie elementu drogowego, w jaki sposób go pokonać, aby dojechać do elementu drogowego 4. Element odpowie referencją na obiekt **Droga 3**.
Na tym przykładzie widać, dlaczego same drogi ukryte są w elementach drogowych. Pojazd nie musi wiedzieć, w jaki sposób działają skrzyżowania. Logika ta ukryta jest w samym skrzyżowaniu i to ono odpowiada na pytania, w jaki sposób je pokonać w zależności od poprzedniego oraz następnego elementu drogowego.
Po "przepytaniu" elementów drogowych pojazd zostanie z listą dróg [**Droga 1**, **Droga 3**, **Droga 1**], a to jest już coś, co pojazd jak najbardziej rozumie. Wystarczy teraz zmieniać pokonany dystans na każdej drodze, a po pokonaniu całej drogi zacząć pokonywać następną
### Sygnalizacja świetlna
Sygnalizacja świetlna zrealizowana jest jako prostopadłościany z komponentem **Collider**, które wykrywa **ProximitySensor** i przekazuje tę informację pojazdowi jak na \autoref{skrzyzowanieEdytorUnity}.
{ height=250px }
Skrzyżowanie ma na sobie klasę **LightsTimer**. Klasa ta odpowiedzialna jest za ustalenie harmonogramu świateł. Wygodny edytor dostępny jest w inspektorze Unity. Przedstawiono go na \autoref{klasaHarmonogramSwiatel}
{ height=250px }
Klasa iterując po elementach listy odpowiednio:
- wyłącza wszystkie światła powiązane ze skrzyżowaniem,
- włącza światła w danym elemencie listy,
- czeka **Duration** sekund i powtarza całą sytuację.
Coś, co trudno było z początku przewidzieć, to zachowanie pojazdów, w którym niekiedy są blokowane przez światła, które ich nie dotyczą. Rozwiązaniem tego problemu jest przypisanie świateł do drogi, której mają dotyczyć (\autoref{dzialanieSwiatel1}).
{ height=250px }
Na takie jak na \autoref{dzialanieSwiatel2}.
{ height=250px }
Dzięki temu jeżeli pojazd przypadkiem trafi promieniem w czerwone światło, które go nie dotyczy, nie spowoduje to zatrzymania się pojazdu
### Skręty kolizyjne - definicja
Przykładowe skrzyżowanie, w którym pojazdy znajdujące się na dole mogą jechać prosto lub skręcić w lewo, a pojazdy znajdujące się na górze mogą jechać tylko prosto jak na \autoref{skretyKolizyjne1}.
{ height=250px }
W momencie gdy pojazdy z przeciwległych pasów mogą się poruszać, istnieje szansa, że zderzą się w tym punkcie jak na \autoref{skretyKolizyjne2}.
{ height=250px }
Aby temu zapobiec, należy w jakiś sposób kontrolować ruch pojazdów, które przecinają inny pas. W tym wypadku będą to pojazdy z dołu. Na takich pasach stoi zatem bariera (czerwony kolor) jak na \autoref{skretyKolizyjne3}.
{ height=250px }
Taka bariera nie może jednak cały czas blokować pojazdów. Powinna to robić jedynie w momencie, w którym istnieje ryzyko zderzenia.
Zatem bariera powiązana jest z czujnikiem pojazdów i jest aktywna tylko jeżeli czujnik pojazdów coś wykrywa, co przedstawiono na \autoref{skretyKolizyjne4}.
{ height=250px }
Poniżej przykład działania całego mechanizmu. Pojazd 2 chce dokonać skrętu kolizyjnego. Bariera wykryła pojazd 1 jadący z naprzeciwka, dlatego się uaktywniła. Pojazd 2 wykrywa barierę i się przed nią zatrzymuje jak na \autoref{skretyKolizyjne5}.
{ height=250px }
Następnie pojazd 1 wyjeżdża już z zakresu czujnika aut, co powoduje dezaktywację z bariery, co z kolei pozwala pojazdowi 2 pokonać skrzyżowanie jak na \autoref{skretyKolizyjne6}.
{ height=250px }
Rozwiązanie wydaje się być gotowe, jednak istnieje kilka przypadków szczególnych, które zostaną omówione w następnych podrozdziałach.
### Skręty kolizyjne - problem przynależności bariery
Przykład skrzyżowania omówiony przy definicji skrętów warunkowych jest trywialny - w rzeczywistości w symulatorze istnieją bardziej skomplikowane skrzyżowania.
Minimalnym przykładem skrzyżowania uwidaczniającego problem przynależności bariery jest \autoref{problemBariery1}.
{ height=250px }
Zakładając, że jest to skrzyżowanie ze światłami i według harmonogramu świateł pojazd 1 oraz 2 nigdy nie mogą się zderzyć, pojawia się problem. Czujnik zapobiegający zderzeniom na skręcie warunkowym blokuje również przejazd auta numer 2. Dzieje się tak całkowicie przypadkiem - bariera stoi po prostu na dwóch pasach jednocześnie.
Aby to rozwiązać, wprowadziłem przynależność bariery do danego pasa ruchu.
Bariera posiada w sobie referencję na obiekt drogi, którego ma dotyczyć. Jako że nie da się tego ustalić automatycznie, w inspektorze Unity skrypt bariery ma w sobie pole widoczne w inspektorze na \autoref{inspektorBariera}, do którego wygodnie można dodawać daną drogę
{ height=250px }
Oprócz samego dowiązania drogi do bariery wymagało to również modyfikacji zasady działania wykrywania przeszkód przez czujnik odległości.
Z początkowego wykrywania w sposób jak na \autoref{sposobWykrywania1}.
{ height=250px }
Na sposób jak na \autoref{sposobWykrywania2}.
{ height=250px }
### Skręty kolizyjne - problem przeciwległych pasów kolizyjnych
Problem pojawia się w momencie, gdy obydwa pojazdy jadące z naprzeciwka dokonują jednocześnie skrętu kolizyjnego jak przedstawiono na \autoref{przeciwlegleKolizje1}
{ height=250px }
Czujniki w obydwu pojazdach wykryją pojazd jadący z naprzeciwka, przez co obydwa się zatrzymają.
Doprowadziło to do zmiany zasady działania czujnika odległości. Wcześniejsza zasada, która strzelała promieniem RayCast szukając kolizji z pojazdem została wzbogacona o dodatkowy warunek.
Teraz czujnik odległości szuka kolizji ze specjalnym obiektem, który wyznacza tył auta jak na \autoref{nowaKolizja}.
{ height=250px }
W przypadku gdy dwa pojazdy jadą na siebie z naprzeciwka, czujnik odległości nie zwraca wykrycia przeszkody - taka sytuacja zawsze oznacza tylko chwilowe ustawienie pojazdów w ten sposób i nie powinna być traktowana jako przeszkoda
### Skręty kolizyjne - problem zakleszczenia
W ruchu drogowym, który odbywa się według wszystkich poprzednich zasad może dojść do wyjątkowej sytuacji zakleszczenia na skrzyżowaniu
{ height=250px }
Pojazdy oznaczone jako "A" chcą przez skrzyżowanie przejechać prosto, a pojazdy oznaczone jako "B" chcą wykonać skręt kolizyjny. Zgodnie z zasadą działania czujników na skrzyżowaniu, w momencie, który jest przedstawiony na rysunku auta oznaczone jako "A" spowodują ustawienie barier dla obydwu samochodów oznaczonych jako "B".
Samochody oznaczone jako "B" nigdy nie przejadą przez skrzyżowanie, co zablokuje również samochody "A".
Aby temu zapobiec, czujniki na skrzyżowaniach sprawdzają dodatkowy warunek. Oprócz wcześniejszego sprawdzania, czy w ich środku znajduje się pojazd, teraz sprawdzają również, czy znajdujący się w środku pojazd się porusza. Jeżeli nie, to bariera się odblokowuje do kolejnej zmiany swojego stanu (wjechanie kolejnego pojazdu).
W tym wypadku po puszczeniu pojazdów B problem zakleszczenia znika jak na \autoref{rozwiazanieZakleszczenia}.
{ height=250px }
Istnieje jednak szansa, że puszczenie jednej serii samochodów w przypadku zakleszczenia nie rozwiąże go. Logika czujnika jest napisana tak, żeby kontynuowała puszczanie po jednym samochodzie w przypadku powtórzenia sytuacji zakleszczenia.
Dzięki temu wszystkie sytuacje zakleszczenia są poprawnie obsłużone
### Skrzyżowanie o ruchu okrężnym - struktura
Problem przedstawienie ronda używając istniejącego rozwiązania do generowania dróg można rozwiązać po zauważeniu, że rondo tak naprawdę jest po prostu serią skrzyżowań.
Rondo jak na \autoref{rondoPrzedPo} można przeciąć na okręgu, co po "rozłożeniu" układa się w serię skrzyżowań.
{ height=250px }
Pojedyncze skrzyżowanie może być przedstawione jako struktura zawierająca kawałek drogi należącej do ronda, wjazd oraz wyjazd jak na \autoref{rondo3}.

Rondo zatem jest serią skrzyżowań złożonych ze struktur tego typu.
### Serializacja symulacji w czasie rzeczywistym
Pojazdy implementują klasę **ISerializable**, co pozwala w łatwy sposób je serializować. Klasa **Car** posiada metodę **GenerateCarDTO**, która zwraca obiekt typu **CarDTO**.
Obiekt typu **CarDTO** posiada pola:
- id - losowo nadany identyfikator,
- position - wektor 2D pozycji,
- velocity - wektor 2D prędkości.
Co każdą klatkę symulacji obiekt **JsonSerializer** serializuje wszystkie auta i zapisuje wynik w liście. Dodatkowo wyznacza też hash mapy oraz hash ustawień. Tak przygotowane parametry składają się na obiekt typu **SimulationChunkDTO**, który zawiera:
- frameNumber - liczba reprezentująca aktualną klatkę,
- cars - lista zserializowanych pojazdów,
- mapHash - hash, który stworzony jest z tego, jak zbudowa jest mapa. Pozwala jednoznacznie określić, do jakiej mapy należy to *DTO*,
- settingsHash - hash, który stworzony jest z ustawień kierowców wprowadzonych przez użytkownika.
### Serializacja mapy
Wszystkie drogi zbudowane są z krzywych beziera, a te serializujemy według ogólnie przyjętej zasady podawania po kolei współczynników jako punkty *[X, Y]* w kolejności [Punkt A, Modyfikator punktu A, Modyfikator punktu B, Punkt B] jak na \autoref{krzyweBeziera}

Klasa **JSONSerializer** na początku symulacji znajduje wszystkie obiekty typu **PathCreator**, a następnie wyciąga z nich referencje na obiekt typu **BezierCurve** i z każdego obiektu tego typu tworzy listę punktów według wcześniej ustalonej zasady. Końcowy obiekt ma strukturę jest obiektem typu **MapDTO**, który zawiera listę obiektów **RoadDTO**, które to zawierają listę obiektów **Vector2**
### Szukanie ścieżki
Za szukanie najkrótszej ścieżki pomiędzy elementami odpowiedzialna jest klasa **PathFinder**. Posiada ona metodę **FindPath()**, która zwraca listę obiektów **IRoadElement**, które należy pokonać, aby dostać się z elementu **start** do elementu **end** najkrótszą trasą. Algorytm rekurencyjnie zaczynając od elementu start wykonuje swój krok, czyli:
- wyznacza wszystkie możliwe wariacje tras, które mogą powstać. W każdym następnym,
- wykonuje sam siebie podając aktualnie już sprawdzone elementy **IRoadElement** jako dodatkowy argument.
Algorytm kończy się w momencie gdy dotrze do elementu **end**. Wtedy zwraca listę sprawdzonych elementów, które go do tego elementu doprowadziły.
### Spawnery pojazdów
Klasa odpowiedzialna za tworzenie pojazdów to **CarSpawner**. Tworzy ona pojazdy co losowy czas, który ustala się za pomocą zmiennych udostępnionych do inspektora Unity:
- minSpawnInterval,
- maxSpawnInterval.
Spawner w momencie tworzenia samochodu może mu nadać jedną z 3 właściwości:
- podać samochodowi zadaną trasę jako listę obiektów **IRoadElement**,
- stworzyć samochód podając mu tylko element początkowy **IRoadElement** i polecić mu, aby przejechał trasę losowo (przy każdym przejeździe na nowe skrzyżowanie pojazd wybierze losową opcję),
- stworzyć samochód podając mu listę możliwych tras - pojazd wybierze wtedy jedną z możliwych tras i zadziała analogicznie do pierwszego podpunktu.
### Gizmo - Kierunki dróg
Aby ułatwić tworzenie aplikacji, edytor Unity udostępnia programiście możliwość rysowania dodatkowych gizmo ponad już istniejącymi. W symulatorze znalazło się na to kilka zastosowań.
Każda droga, która znajduje się na mapie jest jednokierunkowa. Aby ułatwić wizualizację, w którą stronę odbywa się ruch na danej drodze, istnieje pomocnicza metoda na klasie reprezentującej drogę, która rysuje niebieskie strzałki symbolizujące kierunek poruszania jak na \autoref{gizmoStrzalki}.

### Gizmo - Wykrywacze aut
Aby lepiej zwizualizować zachowanie klasy **ProximitySensor**, oprócz wykonywania samego RayCast, rysuje też ona wizualizację tego, co się stało. Przedstawia to \autoref{gizmoCzujnik}:
- niebieski promień - nic nie zostało wykryte w żadnej odległości,
- czerwony promień - wykryto przeszkodę, która potencjalnie może zatrzymać pojazd.

### Wykrywacze aut


Wykrywacze, które używane są przy skrętach kolizyjnych oraz w przypadku ustępowania pierwszeństwa symbolizowane są jako zielone prostopadłościany na \autoref{gizmoWykrywacz1}, które stają się czerwone, gdy powinny zgłosić, że w ich obrębie jest jakiś pojazd jak na \autoref{gizmoWykrywacz2}