Powered by AppSignal & Oban Pro

Lignes et Horaires - Rochefort

reseau_rochefort.livemd

Lignes et Horaires - Rochefort

defmodule Rochefort do
  def repo_root do
    Path.join(__DIR__, "../..")
  end

  def rbus_file do
    Path.join(repo_root(), "/data/ca_rochefort_ocean-aggregated-netex-2025-03-03.zip")
  end

  def install_required_libraries() do
    Mix.install([
      {:kino, "~> 0.19.0"},
      {:kino_maplibre, "~> 0.1.13"},
      {:req, "~> 0.5.17"},
      {:unzip, "~> 0.13.0"},
      {:saxy, "~> 1.6"}
    ])
  end

  def compile_required_code() do
    Code.compile_file("lib/zip_support.ex", repo_root())
    Code.compile_file("lib/kino_tooling.ex", repo_root())
    Code.require_file("lib/xml_support.ex", repo_root())
    Code.require_file("lib/xml_summariser.ex", repo_root())
    Code.require_file("lib/helpers.ex", repo_root())
  end

  def entries(file) do
    file
    |> ZipSupport.open_zip!()
    |> ZipSupport.list_zip_entries()
  end

  def list_netex_content(mode, file \\ rbus_file())
  
  def list_netex_content(:datatable, file) do
    file
    |> entries()
    |> Enum.map(& %{"name" => &1})
    |> Kino.DataTable.new()
  end

  def list_netex_content(:markdown, file) do
    file
    |> entries
    |> Enum.map(& "* `#{&1}`")
    |> Enum.join("\n")
    |> Kino.Markdown.new()
  end

  def zip_stream(zip, entry_name) do
    zip
    |> Unzip.file_stream!(entry_name)
  end

  def xml_summary(file_filter, file \\ rbus_file()) when is_struct(file_filter, Regex) do
    zip_handle = file
    |> ZipSupport.open_zip!()

    entry_name = zip_handle
    |> ZipSupport.list_zip_entries()
    |> Enum.filter(& &1 =~ file_filter)
    |> Helpers.one!()

    summary = zip_handle
    |> Unzip.file_stream!(entry_name)
    |> Stream.map(&IO.iodata_to_binary(&1))
    |> XmlSummariser.summarise!()

    """
    ```xml
    #{summary}
    ```
    """
    |> Kino.Markdown.new()
  end
end

Rochefort.install_required_libraries()
Rochefort.compile_required_code()

# Geo library must be already required
defmodule Rochefort.Carto do
  def show_route_link(file_filter, route_link_xpath) do
    zip = ZipSupport.open_zip!(Rochefort.rbus_file())
    line_file = ZipSupport.list_zip_entries(zip)
     |> Enum.filter(& &1 =~ file_filter)
     |> Helpers.one!()

    content = ZipSupport.read_entry!(zip, line_file) |> XmlSupport.string_to_xmerl!()
    routelink = content |> XmlSupport.xpath!(route_link_xpath) |> List.first()

    {:xmlObj, :string, data} = :xmerl_xpath.string(
      ~c"string(gis:LineString/gis:posList/text())",
      routelink)

    coordinates = data
    |> :erlang.list_to_binary()
    |> String.split(~r/\s/)
    |> Enum.map(&String.to_float(&1))
    |> Enum.chunk_every(2)
    |> Enum.map(fn(x) -> Enum.reverse(x) end)
    |> Enum.map(&List.to_tuple(&1))

    geom = %Geo.LineString{coordinates: coordinates}

    # TODO: compute proper bounding box based on coordinates
    MapLibre.new(style: "https://tiles.openfreemap.org/styles/liberty", center: {-0.9572910070419312, 45.925331115722656}, zoom: 15)
    |> MapLibre.add_geo_source("geom", geom)
    |> MapLibre.add_layer(
      id: "geom_line",
      source: "geom",
      type: :line,
      paint: [line_color: "#f63b8a", line_opacity: 0.7, line_width: 5]
    )
  end
end

:ok

INTRODUCTION - 00:00:00

Bienvenue dans la partie de formation qui traite du Réseau ! Nous aborderons entre autres les principes des Lignes, des Itinéraires, des Horaires et Calendriers…

🔹 Déroulement de la formation

  • Nous commencerons par une approche sur le réel, en partant de l’offre de “Rochefort Océan”

  • Nous plongerons ensuite dans les données des fichiers NeTEx

  • Et nous mettrons au fur et à mesure en lien le réel et les données NeTEx, pour ce qui concerne la topologie et les horaires des lignes ainsi que la définition des calendriers.

🔹 Ce que vous allez apprendre

  • Les bases du format NeTEx et son utilisation dans la modélisation des lignes et des horaires de passage.

  • Les principaux éléments XML décrivant un Réseau (Line, Route, ServiceJourneyPattern, ServiceJourney…) et les Calendriers.

  • Comment lire un fichier NeTEx et en extraire des informations utiles.

💡 Bon à savoir : Aucun prérequis technique avancé n’est nécessaire, mais une familiarité avec les données de transport ou le format XML sera un plus.

🚀 Prêt à plonger dans l’univers de NeTEx ? Alors, commençons !

PARTIR DU RÉEL - L’OFFRE DE “ROCHEFORT OCEAN” - 00:02:00

Pour la suite de cette présentation, nous partons du réel, sur le territoire de la Communauté d’agglomération de Rochefort Océan (CARO).

Source: Fiche Mémo Mobilités de la Communauté d’agglomération Rochefort Océan

On retrouve sur le site associé R’Bus Transport la liste des lignes disponibles.

Voici les lignes régulières présentes au moment où cette formation a été conçue :

Source: Plan du réseau RBus

Source: Plan du réseau RBus

Il existe également sur le territoire :

  • du TAD (Transport À la Demande),
  • des circuits scolaires (S ou RPI - Regroupement Pédagogique Intercommunal),
  • et des lignes régionales desservant la CARO.

Ces lignes ne seront pas abordées lors de cette présentation.

DIRECTION : LA DONNÉE NETEX - 00:05:00

Si on se rend à présent sur https://transport.data.gouv.fr, le Point d’Accès National (aux données de transport), on retrouve des données reliées à ce territoire :

Si on télécharge le fichier NeTEx de R’Bus (archive ZIP), et qu’on la décompresse, on voit que l’archive NeTEx comporte les fichiers suivants :

Rochefort.list_netex_content(:markdown)

DESCRIPTION GÉNÉRALE DU RÉSEAU - 00:10:00

Dans l’archive, nous allons à présent descendre dans le fichier “commun”.

Rochefort.xml_summary(~r/commun/)

Les notions de Network et de Line sont définies dans les sections suivantes. En ce qui concerne les autres éléments du fichier, en voici des définitions succintes :

  • Operator : un Operator représente une entreprise ou une entité qui exploite un service de transport public. Cela peut être une compagnie de bus, un exploitant ferroviaire, un opérateur de métro, etc. (ex : RATP, SNCF, Ilevia…).

  • Authority : Authority représente une autorité organisatrice des transports (AOT). C’est une entité qui planifie, régule ou finance les services de transport public. Cela peut être une organisation gouvernementale, une collectivité locale ou une entité privée ayant des responsabilités dans l’organisation des transports. Une Authority peut superviser plusieurs Operators (opérateurs de transport).

  • SiteConnection : un SiteConnection représente une connexion physique ou logique entre deux lieux (ex. gares, arrêts, terminaux, hubs de transport). Il est utilisé pour modéliser les correspondances piétonnes, les liaisons intermodales et les temps de transfert entre des sites de transport.

🔹 Fichier “commun” > Network - 00:13:00

Dans le fichier commun/partie Network, on définit le réseau (et les lignes rattachées).

Rappel définition : Un Network est un GROUPE DE LIGNES disposant d’un nom sous lequel un réseau de transport est connu.

Cf Profil France NETEX : Network

💡 Attention, ici les lignes ne sont que référencées (et non pas définies).

💡 De manière générale, les identifiants NeTEx ne doivent pas être utilisées à des fins sémantiques. Un identifiant ne doit pas être “parsé” pour en extraire des données.

import Kino.Shorts


xml_1 = "snippets/001-network.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
image_1 = "files/planReaseauRBus_lignes_regulieres.jpg" |> Tooling.file(__DIR__) |> Kino.Image.new("image/jpeg")
image_2 = "files/planReaseauRBus_lignesScolaires.jpg" |> Tooling.file(__DIR__) |> Kino.Image.new("image/jpeg")

grid([xml_1, image_1, image_2], columns: {2, 1, 1})

🫵 À vous :

✍️ Exercice :

  • Quel est le nom complet du Réseau ?
  • Combien de lignes y sont rattachées ?
Solution * Nom complet du réseau : R'bus (Rochefort Océan) * Nombre de lignes rattachées au réseau : 14

🔹 Fichier “commun” > Line - 00:18:00

Pour chaque ligne, on définit des informations générales telles que son nom, son code, son mode, etc.

Rappel définition : Une LIGNE (Line) est un groupe d’ITINÉRAIREs (voir plus bas - Route) qui est en général connu du public par une appellation commune (nom ou numéro, extrémités de ligne, etc.).

Cf. Profil France NETEX : Line

L’objectif de la Line dans NETEX est de décrire de manière précise et structurée l’ensemble des éléments nécessaires à l’organisation et à l’exploitation d’un service de transport public. Cela permet aux autorités et opérateurs de transport de partager des informations sur les lignes de manière standardisée, facilitant ainsi la gestion des horaires et des itinéraires à l’échelle d’un réseau de transport.

line_complete = "snippets/002-line.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
line_name = "snippets/002-line-name.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
line_mode = "snippets/002-line-mode.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
line_code = "snippets/002-line-code.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
line_logo = "snippets/002-line-logo.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
logo_ligne = "files/logo_ligne_B.jpg" |> Tooling.file(__DIR__) |> Kino.Image.new("image/jpeg")

tabs([
  Line: line_complete,
  "Nom de la ligne": line_name,
  "Mode de la ligne": line_mode,
  "Code de la ligne": line_code,
  "Badge de ligne": grid([line_logo, logo_ligne], columns: {6, 1})
])

✍️ Exercice : Trouvez le code, le nom le mode et les couleurs de la ligne F

💡 Attention, la couleur est exprimée au format hexadécimal. N’hésitez pas à utiliser un outil en ligne pour identifier la couleur voulue (ex : google.com : recherche “color hex”).

Solution * Code : F * Nom : Rochefort / Echillais / Soubise / Saint-Nazaire / Port des Barques Font Renaud * Mode : bus * Couleurs : Blanc sur fond Violet ```xml Rochefort / Echillais / Soubise / Saint-Nazaire / Port des Barques Font Renaud Rochefort / Echillais / Soubise / Saint-Nazaire / Port des Barques Font Renaud bus F 8D61A9 FFFFFF ```

DESCRIPTION D’UNE LIGNE - 00:25:00

Dans ce fichier, on définit :

  • La topologie de la ligne
  • Ses horaires
line_complete = "snippets/003-line-frames.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
line_topo = "snippets/003-line-topo.xml" |> Tooling.file(__DIR__) |> Tooling.xml()
line_horaires = "snippets/003-line-horaires.xml" |> Tooling.file(__DIR__) |> Tooling.xml()

tabs([
  Line: line_complete,
  "Topologie de la ligne": line_topo,
  "Horaires de la ligne": line_horaires
])

🔹Topologie de la ligne

Dans le GeneralFrame “LIGNE”, on définit la topologie de la ligne.

<GeneralFrame version="any" id="CA_ROCHEFORT_OCEAN:NETEX_LIGNE-20250210000707Z:LOC">
    <TypeOfFrameRef ref="FR:TypeOfFrame:NETEX_LIGNE:">version="1.1:FR-NETEX_LIGNE-2.2"</TypeOfFrameRef>
    <members>
      <RouteLink version="any" id="CA_ROCHEFORT_OCEAN:RouteLink:B_F36FA40C125B3C6E9206EB371729B19A_52_P105843_P104746_100:LOC">
      ...
      <Route version="any" id="CA_ROCHEFORT_OCEAN:Route:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <Direction version="any" id="CA_ROCHEFORT_OCEAN:Direction:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <ServiceJourneyPattern version="any" id="CA_ROCHEFORT_OCEAN:ServiceJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <ScheduledStopPoint version="any" id="CA_ROCHEFORT_OCEAN:ScheduledStopPoint:B_9523CEB527B7855DF453D065F3F80B97aP104781ScheduledScheduled:LOC">
      ...
      <PassengerStopAssignment order="0" version="any" id="CA_ROCHEFORT_OCEAN:PassengerStopAssignment:B_71949A53A89CEE2A22C4F74ED125BEA3aP106997ScheduledScheduled:LOC">
    </members>
</GeneralFrame>

✍️ Exercice : Combien y a-t-il de Route dans le fichier de la ligne B ?

Solution 💡 _N'hésitez pas à utiliser le [plugin](https://marketplace.visualstudio.com/items?itemName=EddilbertMacharia.jsonxmlgridviewer) de VisualStudioCode qui permet de visualiser un fichier XML sous forme tabulaire en regroupant et comptant les éléments._ Il y a 4 `Route` ! ```xml Parc des Fourriers -> Hôpital inbound Hôpital -> Parc des Fourriers outbound La Croix Breuil Magne -> Parc des Fourriers outbound Parc des Fourriers -> La Croix Breuil Magne inbound ```

🔹🔹Route

Fichier d’une ligne > LIGNE > Route : on définit les itinéraires

Rappel définition : Un ITINÉRAIRE (Route) est une liste ordonnée de POINTs (RoutePoints) définissant un seul chemin à travers le réseau routier (ou ferré) dans une DIRECTION (Direction) donnée. Un ITINÉRAIRE peut passer deux fois par un même POINT.

Un ITINÉRAIRE appartient toujours à une LIGNE (Line). Une LIGNE est composée d’au moins un ITINÉRAIRE avec une DIRECTION. Une LIGNE peut donc comporter plusieurs ITINÉRAIREs, chacun avec sa DIRECTION.

💡 Les RoutePoints constitutifs d’un ITINÉRAIRE sont toujours des POINTs. Ils peuvent être des ScheduledStopPoint, comme dans l’exemple de Rochefort.

💡 Les ITINÉRAIREs sont généralement très similaires d’un point de vue topologique, c’est-à-dire des variantes d’un itinéraire principal avec quelques écarts seulement sur certaines parties (par exemple : arrêts en moins ou terminus anticipé par rapport à un itinéraire plus “complet”).

💡 Deux ITINÉRAIREs utilisant la même d’infrastructure (ou des voies parallèles), mais avec des DIRECTIONS opposées, appartiendront le plus souvent à la même LIGNE.

Cf. Profil France NETEX : Route

graph LR
  Line("Line (Ligne)") -- est composée de plusieurs --> Route("Route (Itinéraire)")
  Route -- est sur une unique --> Line
  Route -- est composé de plusieurs --> RoutePoint@{ shape: procs, label: "RoutePoint (ex : ScheduledStopPoint)"}
  Route -- est dans une --> Direction(Direction)

<!--<GeneralFrame version="any" id="CA_ROCHEFORT_OCEAN:NETEX_LIGNE-20250210000707Z:LOC">
    <TypeOfFrameRef ref="FR:TypeOfFrame:NETEX_LIGNE:">version="1.1:FR-NETEX_LIGNE-2.2"</TypeOfFrameRef>
    <members>
      <RouteLink version="any" id="CA_ROCHEFORT_OCEAN:RouteLink:B_F36FA40C125B3C6E9206EB371729B19A_52_P105843_P104746_100:LOC">
      ...-->
      <Route version="any" id="CA_ROCHEFORT_OCEAN:Route:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
        <Name>Parc des Fourriers -> Hôpital</Name>
        <LineRef ref="CA_ROCHEFORT_OCEAN:Line:B:LOC"/>
<!--<DirectionType>inbound</DirectionType>-->

        <DirectionRef ref="CA_ROCHEFORT_OCEAN:Direction:B_F36FA40C125B3C6E9206EB371729B19A:LOC" version="any"/>
       </Route>
      <!--<Direction version="any" id="CA_ROCHEFORT_OCEAN:Direction:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <ServiceJourneyPattern version="any" id="CA_ROCHEFORT_OCEAN:ServiceJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <ScheduledStopPoint version="any" id="CA_ROCHEFORT_OCEAN:ScheduledStopPoint:B_9523CEB527B7855DF453D065F3F80B97aP104781ScheduledScheduled:LOC">
      ...
      <PassengerStopAssignment order="0" version="any" id="CA_ROCHEFORT_OCEAN:PassengerStopAssignment:B_71949A53A89CEE2A22C4F74ED125BEA3aP106997ScheduledScheduled:LOC">
    </members>
</GeneralFrame>-->

⚠️ Les séquences de points sont actuellement, dans le fichier de Rochefort, définies à l’intérieur du ServiceJourneyPattern, et non pas de la Route. En théorie dans le profil France : il est obligatoire de les avoir dans la Route, et facultatif dans le ServiceJourneyPattern.

🔹🔹Direction

Fichier d’une ligne > LIGNE > Direction : on définit les directions possibles de nos Routes

Rappel définition : une DIRECTION (Direction) représente le sens de circulation d’une ligne de transport, souvent utilisée pour décrire les parcours aller-retour ou les différentes orientations d’un ITINéRAIRE (Route).

Dans l’extrait ci-dessous, on visualise la définition de la Direction ainsi que la référence de la Route vers cette Direction (DirectionRef)

<!--<GeneralFrame version="any" id="CA_ROCHEFORT_OCEAN:NETEX_LIGNE-20250210000707Z:LOC">
    <TypeOfFrameRef ref="FR:TypeOfFrame:NETEX_LIGNE:">version="1.1:FR-NETEX_LIGNE-2.2"</TypeOfFrameRef>
    <members>
      <RouteLink version="any" id="CA_ROCHEFORT_OCEAN:RouteLink:B_F36FA40C125B3C6E9206EB371729B19A_52_P105843_P104746_100:LOC">
      ...-->
      <!--<Route version="any" id="CA_ROCHEFORT_OCEAN:Route:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
        <Name>Parc des Fourriers -> Hôpital</Name>
        <LineRef ref="CA_ROCHEFORT_OCEAN:Line:B:LOC"/>
        <DirectionType>inbound</DirectionType>-->
        <DirectionRef ref="CA_ROCHEFORT_OCEAN:Direction:B_F36FA40C125B3C6E9206EB371729B19A:LOC" version="any"/>
<!--</Route>-->

      ...
      <Direction version="any" id="CA_ROCHEFORT_OCEAN:Direction:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
        <Name>Hôpital</Name>
      </Direction>
      ...
      <!--<ServiceJourneyPattern version="any" id="CA_ROCHEFORT_OCEAN:ServiceJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <ScheduledStopPoint version="any" id="CA_ROCHEFORT_OCEAN:ScheduledStopPoint:B_9523CEB527B7855DF453D065F3F80B97aP104781ScheduledScheduled:LOC">
      ...
      <PassengerStopAssignment order="0" version="any" id="CA_ROCHEFORT_OCEAN:PassengerStopAssignment:B_71949A53A89CEE2A22C4F74ED125BEA3aP106997ScheduledScheduled:LOC">
    </members>
</GeneralFrame>-->

✍️ Exercice : Dans quelle Direction (trouver son Name) va la Route d’identifiant CA_ROCHEFORT_OCEAN:Route:B_71949A53A89CEE2A22C4F74ED125BEA3:LOC de la ligne B ?

Solution On retrouve la Route qui a cet identifiant : ```xml Hôpital -> Parc des Fourriers outbound ``` On récupère l'identifiant de la `Direction` référencée : ```xml ``` On cherche l'élément `Direction` qui possède cet identifiant et on visualise son `Name` : ```xml Parc des Fourriers ```

🔹🔹ScheduledStopPoint

Fichier d’une ligne > LIGNE > ScheduledStopPoint : on définit les points d’arrêt planifiés

Rappel définition : un POINT D’ARRÊT PLANIFIÉ (ScheduledStopPoint) est un POINT où les passagers peuvent monter à bord ou descendre des véhicules.

Cf. Profil France NETEX : ScheduledStopPoint

💡 Un ScheduledStopPoint est un arrêt logique et non pas physique. Néanmoins, pour des questions pratiques (avoir un jeu de données presque autoporteur), la localisation a été précisée ici car les arrêts physiques sont définis dans l’aggrégat des arrêts mutualisé au niveau régional (Agrégat des réseaux urbains et interurbains de la région Nouvelle Aquitaine). Le lien avec ces arrêts physiques est fait à l’aide des PassengerStopAssignment définis dans le chapitre suivant.

<!--<GeneralFrame version="any" id="CA_ROCHEFORT_OCEAN:NETEX_LIGNE-20250210000707Z:LOC">
    <TypeOfFrameRef ref="FR:TypeOfFrame:NETEX_LIGNE:">version="1.1:FR-NETEX_LIGNE-2.2"</TypeOfFrameRef>
    <members>
      <RouteLink version="any" id="CA_ROCHEFORT_OCEAN:RouteLink:B_F36FA40C125B3C6E9206EB371729B19A_52_P105843_P104746_100:LOC">
      ...
      <Route version="any" id="CA_ROCHEFORT_OCEAN:Route:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <Direction version="any" id="CA_ROCHEFORT_OCEAN:Direction:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <ServiceJourneyPattern version="any" id="CA_ROCHEFORT_OCEAN:ServiceJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...-->
      <ScheduledStopPoint version="any" id="CA_ROCHEFORT_OCEAN:ScheduledStopPoint:B_9523CEB527B7855DF453D065F3F80B97aP104781ScheduledScheduled:LOC">
        <Location>
          <Longitude>-0.965409</Longitude>
          <Latitude>45.958561</Latitude>
        </Location>
      </ScheduledStopPoint>
      ...
      <!--<PassengerStopAssignment order="0" version="any" id="CA_ROCHEFORT_OCEAN:PassengerStopAssignment:B_71949A53A89CEE2A22C4F74ED125BEA3aP106997ScheduledScheduled:LOC">
    </members>
</GeneralFrame>-->

🔹🔹PassengerStopAssignment

Fichier d’une ligne > LIGNE > PassengerStopAssignment : on définit les affectations des arrêts

Rappel définition : Un PassengerStopAssignment définit l’affectation d’un POINT D’ARRÊT PLANIFIÉ (ScheduledStopPoint) à un LIEU D’ARRÊT (ou un de ses composant de type ZONE D’EMBARQUEMENT (Quay) ou POSITION D’EMBARQUEMENT) pour un service passager.

Cf. Profil France NETEX : PassengerStopAssignment

graph LR
  PassengerStopAssignment -- référence un --> ScheduledStopPoint
  PassengerStopAssignment -- référence un --> Quay

💡 Comme indiqué dans la section précédente, un PassengerStopAssignment permet donc de faire le lien entre arrêt logique et arrêt physique.

💡 Les Quay sont définis en dehors du cadre de cette présentation, dans l’aggrégat des arrêts mutualisé au niveau régional (Agrégat des réseaux urbains et interurbains de la région Nouvelle Aquitaine). Celui-ci contient entre autres la liste des Quay et des StopPlace, et permet notamment de retrouver le nom des arrêts, leur localisation précise, ainsi que les informations d’accessibilité plus détaillées.

🔹🔹ServiceJourneyPattern

Fichier d’une ligne > LIGNE > ServiceJourneyPattern : on définit les parcours commerciaux

Rappel définition : Un PARCOURS COMMERCIAL (ServiceJourneyPattern) est un PARCOURS associé à une COURSE COMMERCIALE (transportant des passagers). Il liste les POINTs SUR PARCOURS (PointInJourneyPattern) parcourus, dans l’ordre, et sur un ITINERAIRE (Route) de référence (et donc dans la direction indiquée par l’itinéraire).

Cf. Profil France NETEX : ServiceJourneyPattern

💡 On parle aussi de MISSION COMMERCIALE.

💡 Dans notre exemple de Rochefort, les PointInJourneyPattern sont de type ScheduledStopPoint, ce qui n’est pas systématiquement le cas. En effet ils peuvent être de type TimingPoint.

graph LR
  Route("Route (Itinéraire)") -- est le support du -->ServiceJourneyPattern("ServiceJourneyPattern (Parcours commercial)")
  ServiceJourneyPattern -- est sur un unique --> Route
  ServiceJourneyPattern -- est composé de plusieurs  --> PointInJourneyPattern@{ shape: procs, label: "PointInJourneyPattern (ex : ScheduledStopPoint)"}

<!--<GeneralFrame version="any" id="CA_ROCHEFORT_OCEAN:NETEX_LIGNE-20250210000707Z:LOC">
    <TypeOfFrameRef ref="FR:TypeOfFrame:NETEX_LIGNE:">version="1.1:FR-NETEX_LIGNE-2.2"</TypeOfFrameRef>
    <members>
      <RouteLink version="any" id="CA_ROCHEFORT_OCEAN:RouteLink:B_F36FA40C125B3C6E9206EB371729B19A_52_P105843_P104746_100:LOC">
      ...
      <Route version="any" id="CA_ROCHEFORT_OCEAN:Route:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...
      <Direction version="any" id="CA_ROCHEFORT_OCEAN:Direction:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
      ...-->
      <ServiceJourneyPattern version="any" id="CA_ROCHEFORT_OCEAN:ServiceJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19A:LOC">
        <Name>HOPITAL</Name>
        <RouteRef ref="CA_ROCHEFORT_OCEAN:Route:B_F36FA40C125B3C6E9206EB371729B19A:LOC" version="any"/>
        <DestinationDisplayRef ref="CA_ROCHEFORT_OCEAN:DestinationDisplay:B_F36FA40C125B3C6E9206EB371729B19A-B_F36FA40C125B3C6E9206EB371729B19AaP105843ScheduledScheduled:LOC" version="any"/>
        <pointsInSequence>
          <StopPointInJourneyPattern order="1" version="any" id="CA_ROCHEFORT_OCEAN:StopPointInJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19AaP105843ScheduledScheduled:LOC">
          <StopPointInJourneyPattern order="2" version="any" id="CA_ROCHEFORT_OCEAN:StopPointInJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19AaP104746ScheduledScheduled:LOC">
          <StopPointInJourneyPattern order="3" version="any" id="CA_ROCHEFORT_OCEAN:StopPointInJourneyPattern:B_F36FA40C125B3C6E9206EB371729B19AaP104745ScheduledScheduled:LOC">
          ...
        </pointsInSequence>
        <ServiceJourneyPatternType>passenger</ServiceJourneyPatternType>
      </ServiceJourneyPattern>
      ...
      <!--<ScheduledStopPoint version="any" id="CA_ROCHEFORT_OCEAN:ScheduledStopPoint:B_9523CEB527B7855DF453D065F3F80B97aP104781ScheduledScheduled:LOC">
      ...
      <PassengerStopAssignment order="0" version="any" id="CA_ROCHEFORT_OCEAN:PassengerStopAssignment:B_71949A53A89CEE2A22C4F74ED125BEA3aP106997ScheduledScheduled:LOC">
    </members>
</GeneralFrame>-->

✍️ Exercice :

  1. À quelle Route (trouver son Name) est rattaché le ServiceJourneyPattern (PARCOURS) d’identifiant CA_ROCHEFORT_OCEAN:ServiceJourneyPattern:B_BE7025F3F49C102A55A60E2C0071A38B:LOC ?
  2. Combien d’arrêts sont prévus dans ce PARCOURS ?
  3. Quelles sont les coordonnées géographiques du 3ème arrêt du PARCOURS ?
Solution **Question 1** On retrouve le `ServiceJourneyPattern` qui a cet identifiant : ```xml LA CROIX BREUIL MAGNE ... passenger ``` On retrouve la `Route` via son identifiant référencée (RouteRef) : ```xml Parc des Fourriers -> La Croix Breuil Magne inbound ``` --> son nom est "Parc des Fourriers -> La Croix Breuil Magne" On cherche l'élément `Direction` qui possède cet identifiant et on visualise son `Name` : ```xml La Croix Breuil Magne ``` **Question 2** On compte (via la plugin par exemple) le nombre d'éléments `StopPointInJourneyPattern` : il y en a 23 ! **Question 3** Dans le `ServiceJourneyPattern`, on retrouve le `StopPointInJourneyPattern` tel que son attribut XML "order" est égal à 3. ```xml true true false ``` On récupère le `ScheduledStopPoint` via son identifiant référencée (ScheduledStopPointRef) : ```xml -0.959909 45.924866 ``` ## 🔹🔹RouteLink ### Fichier d'une ligne > LIGNE > RouteLink : on définit les tronçons d'itinéraires 💡 Nous n'aborderons pas les `RouteLink` en détails à ce stade. Pour plus d'informations, voir la [section correspondante en fin de présentation](#routelink-d%C3%A9tails). ## 🔹Horaires de la ligne Dans le GeneralFrame "HORAIRES", on définit les horaires de la ligne. ![](files/ligneB_fiche_horaire.JPG) ```xml version="1.1:FR-NETEX_HORAIRE-2.2" ... ``` ## 🔹🔹ServiceJourney ### Fichier d'une ligne > HORAIRES > ServiceJourney : on définit les courses **_Rappel définition_** : Une COURSE (`ServiceJourney`) est le mouvement défini d’un véhicule utilisant un PARCOURS COMMERCIAL (`ServiceJourneyPattern`) spécifié avec des arrêts et des horaires déterminés. C'est une instance de PARCOURS COMMERCIAL (`ServiceJourneyPattern`) pour un TYPE DE JOUR (`DayType`) donné. Cf. [Profil France NETEX : ServiceJourney](https://normes.transport.data.gouv.fr/normes/netex/horaires/#service-journey-course-commerciale) ```elixir service_journey = "snippets/004-service-journey.xml" |> Tooling.file(__DIR__) |> Tooling.xml() service_journey_patternRef = "snippets/004-service-journey-pattern-ref.xml" |> Tooling.file(__DIR__) |> Tooling.xml() service_journey_pattern = "snippets/004-service-journey-pattern.xml" |> Tooling.file(__DIR__) |> Tooling.xml() service_journey_passingTimes = "snippets/004-service-journey-passing-times.xml" |> Tooling.file(__DIR__) |> Tooling.xml() service_journey_dayTypes = "snippets/004-service-journey-day-types.xml" |> Tooling.file(__DIR__) |> Tooling.xml() dayTypes_description = Kino.Markdown.new(""" Les dayTypes permettent de définir sur quels jours types la course est valable. Ici, la fiche horaire indique par exemple : “Toute l’année (sauf jours fériés)” et “Du Lundi au Samedi”. Le fichier xml référence le DayType “S1ETE_LMWJVS”. Celui-ci est réellement défini dans le fichier “calendrier”. """) serviceJourneyImg = "files/ligneB_fiche_horaire_ServiceJourney - cropped.jpg" |> Tooling.file(__DIR__) |> Kino.Image.new("image/jpeg") passingTimesImg = "files/ligneB_fiche_horaire_ServiceJourney_passingTimes.jpg" |> Tooling.file(__DIR__) |> Kino.Image.new("image/jpeg") dayTypesImg = "files/ligneB_fiche_horaire_ServiceJourney_dayTypes.jpg" |> Tooling.file(__DIR__) |> Kino.Image.new("image/jpeg") Kino.Layout.tabs([ ServiceJourney: Kino.Layout.grid([service_journey, serviceJourneyImg], columns: {2,1}), JourneyPatternRef: Kino.Layout.grid([service_journey_patternRef, service_journey_pattern], columns: 2), passingTimes: Kino.Layout.grid([service_journey_passingTimes, service_journey_pattern, passingTimesImg], columns: 3), dayTypes: Kino.Layout.grid([service_journey_dayTypes, dayTypesImg, dayTypes_description], columns: 3) ]) ``` ## DESCRIPTION DES PERIODES ET DES JOURS TYPES - 01:10:00 ![](files/liste_fichiers_netex_calendriers.jpg) Les DayTypeAssignment assignent des jours types (`DayType`) à des périodes de service (`OperatingPeriod`) ou des dates précises (`Date`). Ceci permet de définir les conditions de validité temporelle des COURSES (`ServiceJourney`) que nous avons vues dans la section précédente. ```elixir generalFrame_calendrier = "snippets/005-calendar-general-frame.xml" |> Tooling.file(__DIR__) |> Tooling.xml() dayType = "snippets/005-calendar-day-type.xml" |> Tooling.file(__DIR__) |> Tooling.xml() operatingPeriod = "snippets/005-calendar-operating-period.xml" |> Tooling.file(__DIR__) |> Tooling.xml() dayTypeAssignment = "snippets/005-calendar-day-type-assignment.xml" |> Tooling.file(__DIR__) |> Tooling.xml() Kino.Layout.tabs([ GeneralFrame: generalFrame_calendrier, DayType: dayType, OperatingPeriod: operatingPeriod, DayTypeAssignment: Kino.Layout.grid([dayTypeAssignment, dayType, operatingPeriod], columns: 3) ]) ``` ✍️ **Exercice** : 1. Quelles sont les conditions temporelles de validité du `ServiceJourney` (COURSE) d'identifiant _CA_ROCHEFORT_OCEAN:ServiceJourney:S11185:LOC_ ? 2. Quel est l'horaire de passage au `ScheduledStopPoint` d'identifiant _CA_ROCHEFORT_OCEAN:ScheduledStopPoint:B_BE7025F3F49C102A55A60E2C0071A38BaP104745ScheduledScheduled:LOC_ ? (💡 Indice : le ServiceJourneyPattern référencé contient les _pointsInSequence_ dans le même ordre que les _passingTimes_ de la COURSE) Solution **Question 1** Dans le fichier de la ligne B, on retrouve le `ServiceJourney` qui a cet identifiant et on récupère le `DayType` référencé : ```xml ``` Dans le fichier des calendrier, on retrouve le `DayType` : la COURSE est valide du lundi au samedi ! ```xml Monday Tuesday Wednesday Thursday Friday Saturday ``` On récupère tous les `DayTypeAssignment` qui référencent ce `DayType` : ```xml 2025-07-14 false 2025-08-15 false ``` Pour le 1er, on voit qu'il faut aller chercher l'`OperatingPeriod` correspondante : ```xml 2025-07-07T00:00:00 2025-08-30T00:00:00 ``` On peut donc conclure que la COURSE est valide du lundi au samedi, tout l'été du 7 juillet 2025 au 30 août 2025, sauf les 14 juillet et 15 août ! **Question 2** Dans le fichier de la ligne B, on récupère le `ServiceJourneyPattern` référencé par le `ServiceJourney`. ```xml ``` Dans les pointsInSequence, on récupère celui qui a l'identifiant du `ScheduledStopPoint` voulu et on note son ordre : **order = 3**. ```xml true true false ``` En retournant dans le `ServiceJourney`, on récupère le 3ème passingTime. ```xml 09:03:00 09:03:00 ... ``` On en conclut que l'horaire de passage à l'arrêt voulu (pour la COURSE donnée) est : **09:03:00**. ## RÉCAPITULATIFS DES CONCEPTS TRANSMODEL UTILISÉS - 01:25:00 Les concepts [Transmodel](https://transmodel-cen.eu) permettent de modéliser la réalité terrain du monde du transport (voir [Transmodel at a glance](https://transmodel-cen.eu/index.php/transmodel-at-a-glance/)). Voici le sous-ensemble sur lequel cette présentation s'appuie : ```mermaid graph TD RouteLink("RouteLink (Tronçon d'itinéraire)") -- référence des --> RoutePoint Network("Network (Réseau)") -- est un groupe de --> Line Line("Line (Ligne)") -- est composée de plusieurs --> Route("Route (Itinéraire)") Route -- est sur une unique --> Line Route -- est composé de plusieurs --> RoutePoint@{ shape: procs, label: "RoutePoint (ex : ScheduledStopPoint)"} Route -- est dans une --> Direction(Direction) Route -- est le support du -->ServiceJourneyPattern("ServiceJourneyPattern (Parcours commercial)") ServiceJourneyPattern -- est sur un unique --> Route ServiceJourneyPattern -- est composé de plusieurs --> PointInJourneyPattern@{ shape: procs, label: "PointInJourneyPattern (ex : ScheduledStopPoint)"} ServiceJourneyPattern -- est le support du --> ServiceJourney("ServiceJourney (Course)") ServiceJourney -- est defini pour un --> DayType("DayType (Type de jour)") ``` ## RouteLink - détails - BONUS **_Rappel définition_** : Un TRONCON D'ITINERAIRE (`RouteLink`) est un tronçon orienté entre deux `RoutePoint` (POINTs D’ITINÉRAIRE) permettant une définition univoque d’un chemin à travers le réseau. Cf. [Profil France NETEX : RouteLink](https://normes.transport.data.gouv.fr/normes/netex/reseaux/#route-link-tron%C3%A7on-ditin%C3%A9raire) Dans notre exemple, le `RouteLink` part ici d'un `ScheduleStopPoint` et arrive à un autre `ScheduleStopPoint`, en suivant un tracé qui est son itinéraire intermédiaire, donné sous forme de coordonnées géographiques : ```xml 913.5795215028178 45.92617416381836 -0.9510250091552734 45.926109313964844 -0.950980007648468 45.925838470458984 -0.9517800211906433 45.92591094970703 -0.9518700242042542 45.927120208740234 -0.9529399871826172 45.92715835571289 -0.9530400037765503 45.92716979980469 -0.9531800150871277 45.927101135253906 -0.9539200067520142 45.92639923095703 -0.9538800120353699 45.926231384277344 -0.9538999795913696 45.926109313964844 -0.9539700150489807 45.926021575927734 -0.9540600180625916 45.9258918762207 -0.9542499780654907 45.925228118896484 -0.9562399983406067 45.92522048950195 -0.9563300013542175 45.925228118896484 -0.9566100239753723 45.92530059814453 -0.9573000073432922 45.925331115722656 -0.9572910070419312 ... ``` Un programme informatique (ou un humain motivé) peut, à partir de ces coordonnées, afficher le tronçon sur une carte, comme ci-dessous. Choisissez la position (numéro d'index) du `RouteLink` dans le fichier : ```elixir numero_du_routelink = Kino.Input.text("Numéro du RouteLink", default: "1") ``` Puis cliquez sur "Reevaluate" ci-dessous pour l'afficher: ```elixir Rochefort.Carto.show_route_link( ~r/RBUS_B_B/, "//RouteLink[#{Kino.Input.read(numero_du_routelink)}]" ) ``` ## FIN 🫵 À vous : Utilisez les liens de navigations ci-dessous pour passer à la partie suivante ("Lieux d'arrêts - Rouen") ou revenir à la partie précédente ("Introduction"). Introduction Lignes et Horaires - Rochefort Lieux d'arrêts - Rouen