Skip to content

Commit

Permalink
Merge pull request #690 from datanel/export_gtfs_mode_route_shortname
Browse files Browse the repository at this point in the history
[feature] ntfs2gtfs: add flag mode_in_route_short_name
  • Loading branch information
patochectp authored Aug 26, 2020
2 parents ba45931 + 536937b commit 3f3f196
Show file tree
Hide file tree
Showing 43 changed files with 102 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
authors = ["Kisio Digital <[email protected]>", "Guillaume Pinot <[email protected]>"]
name = "transit_model"
version = "0.30.0"
version = "0.30.1"
license = "AGPL-3.0-only"
description = "Transit data management"
repository = "https://github.com/CanalTP/transit_model"
Expand Down
40 changes: 25 additions & 15 deletions documentation/ntfs_to_gtfs_specs.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# NTFS to GTFS conversion

## Introduction

This document describes how a [NTFS] is transformed into a [GTFS] feed in Navitia Transit Model.

The resulting GTFS feed is composed of the following objects:

* [agency](#agencytxt)
* [routes](#routestxt)
* [stops](#stopstxt)
Expand All @@ -11,6 +14,7 @@ The resulting GTFS feed is composed of the following objects:
* [calendar_dates](#calendar_datestxt): only this file is provided instead of the calendar.txt file.

The following additional files are generated only if the corresponding objects are present in the NTFS.

* [transfers](#transferstxt)
* [shapes](#shapestxt)
* [stop_extensions](#stop_extensionstxt): additional information providing the complementary stop codes used in external systems.
Expand All @@ -19,7 +23,8 @@ The following additional files are generated only if the corresponding objects a
[NTFS]: https://github.com/CanalTP/ntfs-specification/blob/master/ntfs_fr.md

## Mapping between NTFS and GTFS objects
#### agency.txt

### agency.txt

| GTFS field | Required | NTFS file | NTFS field | Note |
| --------------- | -------- | ------------ | ---------------- | ------------------------------------------------------ |
Expand All @@ -30,19 +35,20 @@ The following additional files are generated only if the corresponding objects a
| agency_lang | no | networks.txt | network_lang | |
| agency_phone | no | networks.txt | network_phone | |

#### routes.txt
### routes.txt

Each line of this file corresponds to a transit line modeled in the NTFS feed. In case a transit line uses more than one modes of transportation, it should be modeled separately for each different mode, according to the mapping of modes presented below. The priorities follow the [NeTex Specification](http://www.normes-donnees-tc.org/wp-content/uploads/2014/05/NF_Profil_NeTEx_pour_les_arrets-_F-_-_v2.pdf) (cf. chapter 6.2.3).

| GTFS field | Required | NTFS file | NTFS field | Note |
| ---------------- | -------- | --------- | --------------- | ------------------------------------------------------------------------------------------------------- |
| route_id | yes | lines.txt | line_id | See below for lines containing trips with different modes |
| agency_id | no | lines.txt | network_id | (link to the [agency.txt](#agencytxt) file) |
| route_short_name | yes | lines.txt | line_code | empty string "" if the value is not provided |
| route_long_name | yes | lines.txt | line_name | |
| route_type | yes | | | The corresponding physical mode of the trips of the line. See the table below for the mapping of modes. |
| route_color | no | lines.txt | line_color | |
| route_text_color | no | lines.txt | line_text_color | |
| route_sort_order | no | lines.txt | line_sort_order | |
| GTFS field | Required | NTFS file | NTFS field | Note |
| ---------------- | -------- | --------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| route_id | yes | lines.txt | line_id | See below for lines containing trips with different modes |
| agency_id | no | lines.txt | network_id | (link to the [agency.txt](#agencytxt) file) |
| route_short_name | yes | lines.txt | line_code | empty string "" if the value is not provided. If `--mode-in-route-short-name` is provided to the binary, the commercial mode will be added to the route short name |
| route_long_name | yes | lines.txt | line_name | |
| route_type | yes | | | The corresponding physical mode of the trips of the line. See the table below for the mapping of modes. |
| route_color | no | lines.txt | line_color | |
| route_text_color | no | lines.txt | line_text_color | |
| route_sort_order | no | lines.txt | line_sort_order | |

**Mapping of `route_type` with physical modes**

Expand All @@ -69,13 +75,13 @@ If the physical_mode is unknown, trips should be considered as Bus (route_type =

**Export of NTFS lines containing trips with different modes**
A GTFS `route` can only contains trips with one mode (ie. `route_type`).
If a NTFS `line` contains `trip`s that should be associated with different gtfs `route_type`s, 2 different GTFS `route`s must be generated :
If a NTFS `line` contains `trip`s that should be associated with different gtfs `route_type`s, 2 different GTFS `route`s must be generated:

* The trips using the physical mode with the lowest priority are modeled by a GTFS `route` with the field `route_id` matching the value of the NTFS `line_id`.
* The trips using other physical modes are modeled by a separate GTFS `route` for each corresponding `route_type`, adding the suffix ":<physical_mode_id>" to the value of `route_id` and assigning the corresponding physical mode to the field `route_type`.



### stops.txt

Stop zones (NTFS stops having `location_type` = 2) are ignored in the current version.

| GTFS field | Required | NTFS file | NTFS field | Note |
Expand Down Expand Up @@ -106,10 +112,12 @@ Stop zones (NTFS stops having `location_type` = 2) are ignored in the current ve
| bikes_allowed | no | trip_properties.txt | bike_accepted | The value of `bike_accepted` referenced by the `trip_property_id` of this trip. |

(1) If the value of the `physical_mode_id` for this trip is `LocalTrain`, `LongDistanceTrain`, `Metro`, `RapidTransit` or `Train`,

* the field `trip_short_name` takes after the value of the `trip_headsign` field in the NTFS
* the field `trip_headsign` contains the value of the `stop_name` linked to the stop_point of this trip with the higher order in the trip (i.e. the name of the last stop of the trip).

Otherwise,

* the field `trip_short_name` is empty
* the field `trip_headsign` contains
* the value of the `trip_headsign` field in the NTFS, if present
Expand All @@ -131,6 +139,7 @@ Otherwise,
| local_zone_id | no | stop_times.txt | local_zone_id | |

### calendar_dates.txt

This file is the same as the NTFS calendar_dates.txt file. All dates of service are included in this file (no calendar.txt file provided).

### transfers.txt
Expand All @@ -152,6 +161,7 @@ This file is the same as the NTFS calendar_dates.txt file. All dates of service
| shape_pt_sequence | yes | | | Integer starting at 0 and increase by an increment of one for every point in the shape |

### stop_extensions.txt

This file contains the complementary stop codes from the NTFS object_codes.txt file. If no additional stop code is specified, this file is not generated.
If N complementary codes are specified for a stop, there will be N separate lines in the file for the different stop_id/system_name pairs.

Expand Down
2 changes: 1 addition & 1 deletion ntfs2gtfs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ntfs2gtfs"
version = "1.0.0"
version = "1.1.0"
authors = ["Kisio Digital <[email protected]>"]
license = "AGPL-3.0-only"
description = "Binary to convert Transit data from NTFS format to GTFS"
Expand Down
1 change: 1 addition & 0 deletions ntfs2gtfs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ ntfs2gtfs --input /path/to/ntfs/folder/ --output /path/to/gtfs/

* `--input` is the path to a folder containing NTFS data format
* `--output` is the path to a folder where the GTFS will be exported
* `--mode-in-route-short-name` (optional) allows adding the commercial mode at the beginning of the route short name.

Get more information about the available options with `ntfs2gtfs --help`.

Expand Down
35 changes: 35 additions & 0 deletions ntfs2gtfs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2017 Kisio Digital and/or its affiliates.
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// <http://www.gnu.org/licenses/>.

use transit_model::{Model, Result};

pub fn add_mode_to_line_code(model: Model) -> Result<Model> {
let mut collections = model.into_collections();
let indexes: Vec<_> = collections.lines.iter().map(|(idx, _)| idx).collect();
for idx in indexes {
let mut line = collections.lines.index_mut(idx);
let mode = collections.commercial_modes.get(&line.commercial_mode_id);
let code = match (line.code.clone(), mode) {
(Some(c), Some(m)) => Some(m.name.clone() + " " + &c),
(Some(c), None) => Some(c),
(None, Some(m)) => Some(m.name.clone()),
_ => None,
};
line.code = code;
}

Ok(Model::new(collections)?)
}
16 changes: 13 additions & 3 deletions ntfs2gtfs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// <http://www.gnu.org/licenses/>.

use log::info;
use ntfs2gtfs::add_mode_to_line_code;
use slog::{slog_o, Drain};
use slog_async::OverflowStrategy;
use std::path::PathBuf;
Expand All @@ -25,12 +26,16 @@ use transit_model::Result;
#[structopt(name = "ntfs2gtfs", about = "Convert an NTFS to a GTFS.")]
struct Opt {
/// Input directory.
#[structopt(short = "i", long = "input", parse(from_os_str), default_value = ".")]
#[structopt(short, long, parse(from_os_str), default_value = ".")]
input: PathBuf,

/// Output directory.
#[structopt(short = "o", long = "output", parse(from_os_str))]
#[structopt(short, long, parse(from_os_str))]
output: PathBuf,

/// Add the commercial mode at the beginning of the route short name.
#[structopt(short, long)]
mode_in_route_short_name: bool,
}

fn init_logger() -> slog_scope::GlobalLoggerGuard {
Expand All @@ -54,7 +59,12 @@ fn init_logger() -> slog_scope::GlobalLoggerGuard {

fn run(opt: Opt) -> Result<()> {
info!("Launching ntfs2gtfs...");
let model = transit_model::ntfs::read(opt.input)?;
let mut model;
model = transit_model::ntfs::read(opt.input)?;

if opt.mode_in_route_short_name {
model = add_mode_to_line_code(model)?;
}

transit_model::gtfs::write(model, opt.output)?;
Ok(())
Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions ntfs2gtfs/tests/fixtures/input/lines.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
line_id,line_name,network_id,commercial_mode_id,geometry_id,line_code
line:1,Metro 1,network:kept,Metro,,1
line:2,Metro 2,network:removed,Metro,,
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,route_text_color,route_sort_order
line:1,network:kept,,Metro 1,,1,,,,
line:1,network:kept,1,Metro 1,,1,,,,
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,route_text_color,route_sort_order
line:1,network:kept,Metro 1,Metro 1,,1,,,,
24 changes: 20 additions & 4 deletions tests/ntfs2gtfs.rs → ntfs2gtfs/tests/ntfs2gtfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,44 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>

use ntfs2gtfs::add_mode_to_line_code;
use transit_model::test_utils::*;

#[test]
fn test_stop_zones_not_exported_and_cleaned() {
test_in_tmp_dir(|path| {
let input = "./tests/fixtures/ntfs2gtfs/input";
let input = "./tests/fixtures/input";
let model = transit_model::ntfs::read(input).unwrap();
transit_model::gtfs::write(model, path).unwrap();
compare_output_dir_with_expected(&path, None, "./tests/fixtures/ntfs2gtfs/output");
compare_output_dir_with_expected(&path, None, "./tests/fixtures/output");
});
}

#[test]
fn test_mode_in_route_shortname() {
test_in_tmp_dir(|path| {
let input = "./tests/fixtures/input";
let model = transit_model::ntfs::read(input).unwrap();
let model = add_mode_to_line_code(model).unwrap();
transit_model::gtfs::write(model, path).unwrap();
compare_output_dir_with_expected(
&path,
Some(vec!["routes.txt"]),
"./tests/fixtures/output_route_shortname_with_mode",
);
});
}

#[test]
fn test_platforms_preserving() {
test_in_tmp_dir(|path| {
let input = "./tests/fixtures/ntfs2gtfs/platforms/input";
let input = "./tests/fixtures/platforms/input";
let model = transit_model::ntfs::read(input).unwrap();
transit_model::gtfs::write(model, path).unwrap();
compare_output_dir_with_expected(
&path,
Some(vec!["stops.txt"]),
"./tests/fixtures/ntfs2gtfs/platforms/output",
"./tests/fixtures/platforms/output",
);
});
}
3 changes: 0 additions & 3 deletions tests/fixtures/ntfs2gtfs/input/lines.txt

This file was deleted.

0 comments on commit 3f3f196

Please sign in to comment.