forked from opentripplanner/OpenTripPlanner
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'consolidated-stops' into shared-stops
- Loading branch information
Showing
67 changed files
with
1,333 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<!-- | ||
NOTE! Part of this document is generated. Make sure you edit the template, not the generated doc. | ||
- Template directory is: /doc-templates | ||
- Generated directory is: /docs | ||
--> | ||
# Stop consolidation | ||
|
||
## Contact Info | ||
|
||
- [Jon Campbell](mailto:[email protected]), Arcadis, USA | ||
|
||
## Feature explanation | ||
|
||
This sandbox feature allows you to "combine" equivalent stops from across several feeds into a single, | ||
consolidated one. | ||
|
||
It is achieved by defining a "primary" stop and one or more "secondary" stops. During the graph | ||
build all trip patterns are modified so that the secondary ones are swapped out for their | ||
primary equivalent. | ||
|
||
## Effects | ||
|
||
This has the following consequences | ||
|
||
- When you query the departures for a primary stop you see a consolidated view of all the equivalent departures. | ||
- When transferring at a consolidated stop you no longer get instructions like "walk 5 meters to stop X" | ||
|
||
!!! warning "Downsides" | ||
|
||
However, this feature has also severe downsides: | ||
|
||
- It makes realtime trip updates referencing a stop id much more complicated and in many cases | ||
impossible to resolve. | ||
You can only reference a stop by its sequence, which only works in GTFS-RT, not Siri. | ||
- Fare calculation and transfers are unlikely to work as expected. | ||
|
||
|
||
## Configuration | ||
|
||
To enable this feature you need to add a file to OTP's working directory and configure | ||
its name like this: | ||
|
||
<!-- INSERT: config --> | ||
|
||
The additional config file must look like the following: | ||
|
||
<!-- INSERT: file --> | ||
|
||
The column names mean the following: | ||
|
||
- `stop_group_id`: id to group several rows in the file together | ||
- `feed_id`: feed id of the stop | ||
- `stop_id`: id of the stop | ||
- `is_primary`: whether the row represents a primary stop, `1` means yes and `0` means no | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"transitModelTimeZone": "America/Los_Angeles", | ||
"fares": "orca", | ||
"stopConsolidationFile": "consolidated-stops.csv" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<!-- | ||
NOTE! Part of this document is generated. Make sure you edit the template, not the generated doc. | ||
- Template directory is: /doc-templates | ||
- Generated directory is: /docs | ||
--> | ||
# Stop consolidation | ||
|
||
## Contact Info | ||
|
||
- [Jon Campbell](mailto:[email protected]), Arcadis, USA | ||
|
||
## Feature explanation | ||
|
||
This sandbox feature allows you to "combine" equivalent stops from across several feeds into a single, | ||
consolidated one. | ||
|
||
It is achieved by defining a "primary" stop and one or more "secondary" stops. During the graph | ||
build all trip patterns are modified so that the secondary ones are swapped out for their | ||
primary equivalent. | ||
|
||
## Effects | ||
|
||
This has the following consequences | ||
|
||
- When you query the departures for a primary stop you see a consolidated view of all the equivalent departures. | ||
- When transferring at a consolidated stop you no longer get instructions like "walk 5 meters to stop X" | ||
|
||
!!! warning "Downsides" | ||
|
||
However, this feature has also severe downsides: | ||
|
||
- It makes realtime trip updates referencing a stop id much more complicated and in many cases | ||
impossible to resolve. | ||
You can only reference a stop by its sequence, which only works in GTFS-RT, not Siri. | ||
- Fare calculation and transfers are unlikely to work as expected. | ||
|
||
|
||
## Configuration | ||
|
||
To enable this feature you need to add a file to OTP's working directory and configure | ||
its name like this: | ||
|
||
<!-- config BEGIN --> | ||
<!-- NOTE! This section is auto-generated. Do not change, change doc in code instead. --> | ||
|
||
```JSON | ||
// build-config.json | ||
{ | ||
"stopConsolidationFile" : "consolidated-stops.csv" | ||
} | ||
``` | ||
|
||
<!-- config END --> | ||
|
||
The additional config file must look like the following: | ||
|
||
<!-- file BEGIN --> | ||
<!-- NOTE! This section is auto-generated. Do not change, change doc in code instead. --> | ||
|
||
``` | ||
stop_group_id,feed_id,stop_id,is_primary | ||
1,pierce,1705867009,0 | ||
1,kcm,10225,1 | ||
2,pierce,1569,0 | ||
2,commtrans,473,0 | ||
2,kcm,1040,1 | ||
``` | ||
|
||
<!-- file END --> | ||
|
||
The column names mean the following: | ||
|
||
- `stop_group_id`: id to group several rows in the file together | ||
- `feed_id`: feed id of the stop | ||
- `stop_id`: id of the stop | ||
- `is_primary`: whether the row represents a primary stop, `1` means yes and `0` means no | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
...t-test/java/org/opentripplanner/ext/stopconsolidation/ConsolidatedStopNameFilterTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.opentripplanner.ext.stopconsolidation; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.opentripplanner.ext.stopconsolidation.TestStopConsolidationModel.STOP_C; | ||
import static org.opentripplanner.ext.stopconsolidation.TestStopConsolidationModel.STOP_D; | ||
import static org.opentripplanner.model.plan.PlanTestConstants.T11_05; | ||
import static org.opentripplanner.model.plan.PlanTestConstants.T11_12; | ||
|
||
import java.util.List; | ||
import org.junit.jupiter.api.Test; | ||
import org.opentripplanner.ext.stopconsolidation.internal.DefaultStopConsolidationRepository; | ||
import org.opentripplanner.ext.stopconsolidation.internal.DefaultStopConsolidationService; | ||
import org.opentripplanner.ext.stopconsolidation.model.ConsolidatedStopGroup; | ||
import org.opentripplanner.model.plan.Place; | ||
import org.opentripplanner.model.plan.PlanTestConstants; | ||
import org.opentripplanner.model.plan.TestItineraryBuilder; | ||
|
||
class ConsolidatedStopNameFilterTest { | ||
|
||
@Test | ||
void changeNames() { | ||
var transitModel = TestStopConsolidationModel.buildTransitModel(); | ||
|
||
var groups = List.of(new ConsolidatedStopGroup(STOP_C.getId(), List.of(STOP_D.getId()))); | ||
var repo = new DefaultStopConsolidationRepository(); | ||
repo.addGroups(groups); | ||
|
||
var service = new DefaultStopConsolidationService(repo, transitModel); | ||
var filter = new ConsolidatedStopNameFilter(service); | ||
|
||
var itinerary = TestItineraryBuilder | ||
.newItinerary(Place.forStop(STOP_C)) | ||
.bus(TestStopConsolidationModel.ROUTE, 1, T11_05, T11_12, Place.forStop(STOP_C)) | ||
.bus(1, T11_05, T11_12, PlanTestConstants.E) | ||
.bus(1, T11_05, T11_12, PlanTestConstants.F) | ||
.build(); | ||
|
||
var filtered = filter.filter(List.of(itinerary)); | ||
assertFalse(filtered.isEmpty()); | ||
|
||
var updatedLeg = filtered.get(0).getLegs().get(0); | ||
assertEquals(STOP_D.getName(), updatedLeg.getFrom().name); | ||
assertEquals(STOP_D.getName(), updatedLeg.getTo().name); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/ext-test/java/org/opentripplanner/ext/stopconsolidation/StopConsolidationModuleTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package org.opentripplanner.ext.stopconsolidation; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.opentripplanner.ext.stopconsolidation.TestStopConsolidationModel.PATTERN; | ||
import static org.opentripplanner.ext.stopconsolidation.TestStopConsolidationModel.STOP_A; | ||
import static org.opentripplanner.ext.stopconsolidation.TestStopConsolidationModel.STOP_B; | ||
import static org.opentripplanner.ext.stopconsolidation.TestStopConsolidationModel.STOP_C; | ||
import static org.opentripplanner.ext.stopconsolidation.TestStopConsolidationModel.STOP_D; | ||
|
||
import java.util.List; | ||
import org.junit.jupiter.api.Test; | ||
import org.opentripplanner.ext.stopconsolidation.internal.DefaultStopConsolidationRepository; | ||
import org.opentripplanner.ext.stopconsolidation.model.ConsolidatedStopGroup; | ||
import org.opentripplanner.transit.model.network.TripPattern; | ||
|
||
class StopConsolidationModuleTest { | ||
|
||
@Test | ||
void replacePatterns() { | ||
var groups = List.of(new ConsolidatedStopGroup(STOP_D.getId(), List.of(STOP_B.getId()))); | ||
|
||
var transitModel = TestStopConsolidationModel.buildTransitModel(); | ||
transitModel.addTripPattern(PATTERN.getId(), PATTERN); | ||
var repo = new DefaultStopConsolidationRepository(); | ||
var module = new StopConsolidationModule(transitModel, repo, groups); | ||
module.buildGraph(); | ||
|
||
var modifiedPattern = transitModel.getTripPatternForId(PATTERN.getId()); | ||
assertFalse(modifiedPattern.getRoutingTripPattern().getPattern().sameAs(PATTERN)); | ||
assertFalse(modifiedPattern.sameAs(PATTERN)); | ||
|
||
var modifiedStop = modifiedPattern | ||
.getRoutingTripPattern() | ||
.getPattern() | ||
.getStopPattern() | ||
.getStop(1); | ||
assertEquals(modifiedStop, STOP_D); | ||
|
||
var patterns = List.copyOf(transitModel.getAllTripPatterns()); | ||
|
||
var stops = patterns.stream().map(TripPattern::getStops).toList(); | ||
assertEquals(List.of(List.of(STOP_A, STOP_D, STOP_C)), stops); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/ext-test/java/org/opentripplanner/ext/stopconsolidation/StopConsolidationParserTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package org.opentripplanner.ext.stopconsolidation; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import java.io.IOException; | ||
import java.util.List; | ||
import org.junit.jupiter.api.Test; | ||
import org.opentripplanner.test.support.ResourceLoader; | ||
import org.opentripplanner.transit.model.framework.FeedScopedId; | ||
|
||
class StopConsolidationParserTest { | ||
|
||
@Test | ||
void parse() { | ||
try (var file = ResourceLoader.of(this).inputStream("consolidated-stops.csv")) { | ||
var groups = StopConsolidationParser.parseGroups(file); | ||
assertEquals(20, groups.size()); | ||
|
||
var first = groups.get(0); | ||
assertEquals("kcm:10225", first.primary().toString()); | ||
assertEquals( | ||
List.of("pierce:1705867009"), | ||
first.secondaries().stream().map(FeedScopedId::toString).toList() | ||
); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/ext-test/java/org/opentripplanner/ext/stopconsolidation/TestStopConsolidationModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package org.opentripplanner.ext.stopconsolidation; | ||
|
||
import static org.opentripplanner.transit.model._data.TransitModelForTest.id; | ||
|
||
import java.util.List; | ||
import org.opentripplanner.transit.model._data.TransitModelForTest; | ||
import org.opentripplanner.transit.model.framework.Deduplicator; | ||
import org.opentripplanner.transit.model.framework.FeedScopedId; | ||
import org.opentripplanner.transit.model.network.Route; | ||
import org.opentripplanner.transit.model.network.StopPattern; | ||
import org.opentripplanner.transit.model.network.TripPattern; | ||
import org.opentripplanner.transit.model.organization.Agency; | ||
import org.opentripplanner.transit.model.site.RegularStop; | ||
import org.opentripplanner.transit.service.TransitModel; | ||
|
||
class TestStopConsolidationModel { | ||
|
||
private static final TransitModelForTest testModel = TransitModelForTest.of(); | ||
public static final RegularStop STOP_A = testModel.stop("A").withCoordinate(1, 1).build(); | ||
public static final RegularStop STOP_B = testModel.stop("B").withCoordinate(1.1, 1.1).build(); | ||
public static final RegularStop STOP_C = testModel.stop("C").withCoordinate(1.2, 1.2).build(); | ||
public static final StopPattern STOP_PATTERN = TransitModelForTest.stopPattern( | ||
STOP_A, | ||
STOP_B, | ||
STOP_C | ||
); | ||
static final String SECONDARY_FEED_ID = "secondary"; | ||
static final Agency AGENCY = TransitModelForTest | ||
.agency("agency") | ||
.copy() | ||
.withId(new FeedScopedId(SECONDARY_FEED_ID, "agency")) | ||
.build(); | ||
static final Route ROUTE = TransitModelForTest | ||
.route(new FeedScopedId(SECONDARY_FEED_ID, "route-33")) | ||
.withAgency(AGENCY) | ||
.build(); | ||
static final RegularStop STOP_D = testModel | ||
.stop("D") | ||
.withId(new FeedScopedId(SECONDARY_FEED_ID, "secondary-stop-D")) | ||
.build(); | ||
|
||
static final TripPattern PATTERN = TripPattern | ||
.of(id("123")) | ||
.withRoute(ROUTE) | ||
.withStopPattern(STOP_PATTERN) | ||
.build(); | ||
|
||
static TransitModel buildTransitModel() { | ||
var stopModelBuilder = testModel.stopModelBuilder(); | ||
List.of(STOP_A, STOP_B, STOP_C, STOP_D).forEach(stopModelBuilder::withRegularStop); | ||
return new TransitModel(stopModelBuilder.build(), new Deduplicator()); | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
...pentripplanner/ext/stopconsolidation/internal/DefaultStopConsolidationRepositoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package org.opentripplanner.ext.stopconsolidation.internal; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
import static org.opentripplanner.transit.model._data.TransitModelForTest.id; | ||
|
||
import java.util.List; | ||
import org.junit.jupiter.api.Test; | ||
import org.opentripplanner.ext.stopconsolidation.model.ConsolidatedStopGroup; | ||
|
||
class DefaultStopConsolidationRepositoryTest { | ||
|
||
private static final ConsolidatedStopGroup GROUP = new ConsolidatedStopGroup( | ||
id("123"), | ||
List.of(id("456")) | ||
); | ||
|
||
@Test | ||
void add() { | ||
var subject = new DefaultStopConsolidationRepository(); | ||
assertEquals(List.of(), subject.groups()); | ||
subject.addGroups(List.of(GROUP)); | ||
|
||
assertEquals(List.of(GROUP), subject.groups()); | ||
} | ||
|
||
@Test | ||
void groupsAreImmutable() { | ||
var subject = new DefaultStopConsolidationRepository(); | ||
assertThrows(Exception.class, () -> subject.groups().add(GROUP)); | ||
} | ||
} |
Oops, something went wrong.