Chartsfinder

 

Contexte

Je suis depuis plusieurs années sur un réseau de simulation IVAO qui permet aux passionés d'aviation de se retrouver. Ce réseau permet aux pilotes étant sur des simulateurs de vol de se connecter en ligne afin de pouvoir voir les autres trafics Certains membres (dont moi), préfèrent jouer le rôle du contrôleur aérien, ils utilisent donc un logiciel permettant de voir les autres membres pilotes, comme dans une tour de contrôle.

Les vraies procédures sont utilisées, tout comme les phraséologies (anglaise et française) ainsi que les cartes. C'est pourquoi avoir un accès facile et rapide aux cartes peut être très intéressant.

Problème

Le site de la SIA est le site officiel du gouvernement et donne gratuitement accès aux différentes cartes aéronautiques. Après une grosse mise à jour du site, il n'était pas très facile de s'y retrouver et l'expérience utilisateur pour rechercher les cartes n'était optimale (de mon point de vu). C'est pourquoi j'ai décider de commencer mon projet Chartsfinder.

Technologies

Durant mon BTS (2014-2016) j'ai effectué des cours de C# WPF et ce langage m'a tout de suite plu. C'est pourquoi j'ai décidé de l'utiliser dans ce projet pour pouvoir en découvrir plus sur cette technologie.

Fonctionnement

Chargement des URLs

Depuis la version 3.4.0, les URLs sont chargées automatiquement. Dans un premier temps, je cherchais une API permettant de me donner la date de sortie de chaque AIRAC[1] afin de pouvoir construire l'URL. Mais en regardant de plus près sur les sites officiels, je me suis rendu compte qu'il était facile de calculer l'AIRAC en cours et la date du prochain. En effet, un AIRAC est publié exactement tous les 28 jours et ce depuis la date (fictive) du 01 janvier 1901. Il est alors facile de calculer l'AIRAC en cour a partir d'une date donnée :

/// <summary>
/// Get active AIRAC for the given date
/// </summary>
/// <param name="instant"></param>
/// <returns></returns>
public static Airac FromInstant(DateTime instant)
{
    // Difference between the given date and 10/01/1901 (here epoch variable)
	TimeSpan between = instant.ToUniversalTime().Subtract(epoch);
    // Calculation of number of cycle of 28 days (durationCycle)
	int cycles = (int)(between.TotalSeconds / durationCycle.TotalSeconds);
    // Get the durantion between 10/01/1901 and current cycle
	TimeSpan duration = new TimeSpan(durationCycle.Ticks * cycles);
    // get release date
	DateTime release = epoch.Add(duration);
	string code = GetCode(release);
	return new Airac(code, release, cycles);
}

Chargement des cartes

Afin de récupérer les différentes cartes aéronutiques, le logiciels va scraper les pages html de la SIA afin d'aller chercher les cartes aéronautiques et de les associer aux aéroports.

Quand l'utilisateur clique sur l'icône de rechargement, le site va dans un premier temps aller récupérer une node HTML indiquant le niveau à aller fouiller dans l'arborescence HTML. Pour trouver cette arborescence, je suis simplement allé sur le site de la SIA, j'ai inpecté la page qui m'intéressais et noté l'arboresce qui contenait les données voulues.

Le code ci-dessous permet de récupérer une liste d'aéroport list_airport. L'objet Airport contient deux propriétés : icao correspondant au code unique donnée à un aéroport et list_cartes_url un Dictionary<string, string> ayant comme clé le type de carte et comme valeur son url.

HtmlNode[] nodes = document_list_airport.DocumentNode.SelectNodes("/html/body/div[@id='ADdetails']/div[@id='AD-2details']/div[contains(@class,'H3')]/a[@title='Aerodrome']").ToArray();

Parallel.ForEach(nodes, node => {
    string icao = node.Attributes["id"].Value.Split('.')[2];
    Console.WriteLine(icao + Thread.CurrentThread.ManagedThreadId);
    Dictionary<string, string> list_charts = GetAllChartsInUrl(node.Attributes["href"].Value, icao);
    list_airport.Add(new Airport(icao, list_charts));
});

Le code ICAO est récupéré directement depuis le node HTML. Pour récupérer la liste des cartes et des URL associées, je fais appel à la fonction GetAllChartsInUrl(string url, string icao). Celle-ci va dans un premier temps récumérer lla page HTML donnée en paramètre. Elle va ensuite allé chercher la liste des cartes disponible pour l'aéroport.

HtmlDocument document_list_chart = web.Load(url_without_sia + "/eAIP/" + url);
HtmlNode[] nodes = document_list_chart.DocumentNode.SelectNodes("/html/body/div[@id='AD-2']/div[@id='AD-2." + icao + "']/div[@id='AD-2.24.eAIP." + icao + "']/div").ToArray();

foreach (var node in nodes)
{
    HtmlNode[] tab = node.Descendants("div").Where(d => d.Attributes["class"].Value.Contains("Figure")).ToArray();
    foreach (var ta in tab)
    {
        HtmlNode a_node = ta.Descendants("a").First();
        dictionnary[a_node.InnerHtml] = url_without_sia + "/eAIP/" + a_node.Attributes["href"].Value;
    }
}

L'annexe 1 montre la structure du HTML pour l'aéroport d'Agen (LFBA). Ici les div ayant un id commençant par eaip_ sont les cartes disponibles pour l'aéroport. Pour récupérer le lien des cartes il suffit donc d'aller dans #AD-2.24.eAIP.LFBA, de récupérer un tableau des sous-divisions. Il reste donc à parcourir le tableau , aller chercher la valeur dans le lien pour récupérer le type de carte et de prendre le contenue de href pour avoir l'url.

Annexes

Annexe 1 : Structure HTML

Footnotes

  1. ^ Aeronautical Information Regulation And Control : Mise à jour des données aéronautique