Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not allowed transfers and support for GTFS transfer points #3792

Merged
merged 26 commits into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4a931a5
feat: Extend internal model to allow implementing not-allowed transfers.
t2gran Nov 15, 2021
e472a11
feat: Extend Raptor with support for not-allowed transfers.
t2gran Nov 15, 2021
4f44616
feat: Extend Raptor and optimized transfers with support for not-allo…
t2gran Nov 16, 2021
cca1168
feat: Extend ConstrainedBoardingSearch with support for not-allowed t…
t2gran Nov 15, 2021
ad6c2cc
refactor: Make transfer constraint none null.
t2gran Dec 20, 2021
268b079
test: Add test on ConstrainedBoardingSearch
t2gran Dec 20, 2021
072731f
refactor: remove unused method in ConstrainedBoardingSearchStrategy
t2gran Dec 20, 2021
ddaa114
refactor: Improve TransferPoints toString()
t2gran Dec 20, 2021
2be63f4
refactor: Cleanup T2 equals() and add test
t2gran Nov 29, 2021
539bf9a
refactor: cleanup TripPattern
t2gran Dec 17, 2021
29be403
refactor: StopTransferPriorityMapper renamed from TransferPriorityMapper
t2gran Dec 20, 2021
c706ecf
refactor: rename local variable in RangeRaptorWorker
t2gran Dec 20, 2021
0a0cf45
refactor: improve encapsulation in StopIndexForRaptor
t2gran Dec 20, 2021
5ce3d16
feat: Support for GTFS Trip, Route, Stop & Station Transfers
t2gran Dec 18, 2021
d1cbca0
refactor: Update otp.serialization.version.id
t2gran Dec 20, 2021
594f8f4
refactor: Encapsulate StopPattern in TripPattern
t2gran Jan 7, 2022
1390922
feat: Support for GTFS Trip, Route, Stop & Station Transfers
t2gran Jan 6, 2022
4950704
fix: NPE in TransferIndexGenerator
t2gran Jan 13, 2022
4e4339a
Apply suggestions from code review
t2gran Jan 13, 2022
2a08080
refactor: Review
t2gran Jan 13, 2022
768117c
Merge remote-tracking branch 'otp/dev-2.x' into otp2_not_allowed_tran…
t2gran Jan 14, 2022
0ccdf70
Merge remote-tracking branch 'otp/dev-2.x' into otp2_not_allowed_tran…
t2gran Jan 14, 2022
1e82238
review: Update src/main/java/org/opentripplanner/model/transfer/Trans…
t2gran Jan 25, 2022
6028793
Merge remote-tracking branch 'otp/dev-2.x' into otp2_not_allowed_tran…
t2gran Jan 26, 2022
244b30e
review: Cleanup AccessEgressMapper
t2gran Jan 26, 2022
3e447f4
feat: Abort constrained transfer search after 5 normal boardings found
t2gran Jan 26, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
</scm>

<properties>
<otp.serialization.version.id>14</otp.serialization.version.id>
<otp.serialization.version.id>16</otp.serialization.version.id>
<!-- Lib versions - keep list sorted on property name -->
<geotools.version>25.2</geotools.version>
<jackson.version>2.12.5</jackson.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public void shouldNotInterpolateFlexTimes() {
var feedId = graph.getFeedIds().iterator().next();
var pattern = graph.tripPatternForId.get(new FeedScopedId(feedId, "090z:0:01"));

assertEquals(3, pattern.getStops().size());
assertEquals(3, pattern.numberOfStops());

var tripTimes = pattern.getScheduledTimetable().getTripTimes(0);
var arrivalTime = tripTimes.getArrivalTime(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

import java.net.URISyntaxException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/**
* A very simple CSV builder to create CSV reports.
* <p>
* This class helps formatting common types like time, duration and enums.
* This class helps to format common types like time, duration and enums.
*/
class CsvReportBuilder {
private final String sep;
Expand Down Expand Up @@ -51,12 +51,12 @@ void addText(String text) {
}

void addNumber(Number num) {
buf.append(num.toString());
buf.append(num == null ? "" : num.toString());
sep();
}

void addBoolean(Boolean b) {
buf.append(b.toString());
buf.append(b == null ? "" : b.toString());
sep();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,31 @@
import static org.opentripplanner.util.time.DurationUtils.durationToStr;

import java.util.List;
import org.locationtech.jts.geom.Coordinate;
import org.opentripplanner.common.geometry.SphericalDistanceLibrary;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.Station;
import org.opentripplanner.model.StopLocation;
import org.opentripplanner.model.Trip;
import org.opentripplanner.model.TripPattern;
import org.opentripplanner.model.WgsCoordinate;
import org.opentripplanner.model.transfer.ConstrainedTransfer;
import org.opentripplanner.model.transfer.RouteStationTransferPoint;
import org.opentripplanner.model.transfer.RouteStopTransferPoint;
import org.opentripplanner.model.transfer.StationTransferPoint;
import org.opentripplanner.model.transfer.StopTransferPoint;
import org.opentripplanner.model.transfer.TransferPoint;
import org.opentripplanner.model.transfer.TripTransferPoint;
import org.opentripplanner.routing.graph.GraphIndex;


/**
* This class is used to export transfers for human verification to a CSV file. This is useful
* when trying to debug the rather complicated NeTEx data format or to get the GTFS transfers in a
* more human readable form. It can also be used to test transfer functionality, since it is easy
* more human-readable form. It can also be used to test transfer functionality, since it is easy
* to read and find special test-cases when needed.
*/
public class TransfersReport {
private static final boolean BOARD = true;
private static final boolean ALIGHT = false;
private static final int NOT_SET = -1;


Expand All @@ -41,32 +50,42 @@ public static String export(List<ConstrainedTransfer> transfers, GraphIndex inde

String export() {
buf.addHeader(
"Id", "Operator", "FromTripId", "FromTrip", "FromStop",
"ToTripId", "ToTrip", "ToStop", "ArrivalTime", "DepartureTime", "TransferTime",
"Walk", "Priority", "MaxWaitTime", "StaySeated", "Guaranteed"
"Id", "Operator", "From", "FromId", "FromRoute", "FromTrip", "FromStop",
"FromSpecificity", "To", "ToId", "ToRoute", "ToTrip", "ToStop", "ToSpecificity",
"ArrivalTime", "DepartureTime", "TransferTime", "Walk", "Priority", "MaxWaitTime",
"StaySeated", "Guaranteed"
);

transfers.forEach(t -> {
var from = pointInfo(t.getFrom(), true);
var to = pointInfo(t.getTo(), false);
var dist = (from.c == null || to.c == null)
var from = pointInfo(t.getFrom(), ALIGHT);
var to = pointInfo(t.getTo(), BOARD);
var dist = (from.coordinate == null || to.coordinate == null)
? ""
: String.format(
"%.0fm",
SphericalDistanceLibrary.fastDistance(from.c, to.c)
SphericalDistanceLibrary.fastDistance(
from.coordinate.asJtsCoordinate(),
to.coordinate.asJtsCoordinate()
)
);
var duration = (from.time == NOT_SET || to.time == NOT_SET)
? "" : durationToStr(to.time - from.time);
var c = t.getTransferConstraint();

buf.addText(t.getId() == null ? "" : t.getId().getId());
buf.addText(t.getFrom().getTrip().getOperator().getId().getId());
buf.addText(from.tripId);
buf.addText((from.operator.isEmpty() ? to : from).operator);
buf.addText(from.type);
buf.addText(from.entityId);
buf.addText(from.route);
buf.addText(from.trip);
buf.addText(from.loc);
buf.addText(to.tripId);
buf.addText(from.location());
buf.addNumber(from.specificity);
buf.addText(to.type);
buf.addText(to.entityId);
buf.addText(to.route);
buf.addText(to.trip);
buf.addText(to.loc);
buf.addText(to.location());
buf.addNumber(to.specificity);
buf.addTime(from.time, NOT_SET);
buf.addTime(to.time, NOT_SET);
buf.addText(duration);
Expand All @@ -80,47 +99,106 @@ String export() {
return buf.toString();
}

private TxPoint pointInfo(
TransferPoint p,
boolean arrival
) {
private TxPoint pointInfo(TransferPoint p, boolean boarding) {
var r = new TxPoint();
if (p instanceof StopTransferPoint) {
r.loc = p.getStop().getName();
return r;
}
var ptn = index.getPatternForTrip().get(p.getTrip());
var trip = p.getTrip();
var route = trip.getRoute();

r.tripId = trip.getId().getId();
r.trip = route.getName() + " " + route.getMode() + " " + route.getLongName()
+ " " + trip.getTripHeadsign();
r.c = null;

if(p instanceof TripTransferPoint) {
var tp = (TripTransferPoint)p;
var trip = tp.getTrip();
var route = trip.getRoute();
var ptn = index.getPatternForTrip().get(trip);
r.operator = trip.getOperator().getId().getId();
r.type = "Trip";
r.entityId = trip.getId().getId();
r.route = route.getName() + " " + route.getMode() + " " + route.getLongName();
r.trip = trip.getTripHeadsign();
var stop = ptn.getStop(tp.getStopPositionInPattern());
addLocation(r, ptn, stop, trip, boarding);
}
else if(p instanceof RouteStopTransferPoint) {
var rp = (RouteStopTransferPoint)p;
var route = rp.getRoute();
var ptn = index.getPatternsForRoute().get(route).stream().findFirst().orElse(null);
r.operator = route.getOperator().getId().getId();
r.type = "Route";
r.entityId = route.getId().getId();
r.route = route.getName() + " " + route.getMode() + " " + route.getLongName();
addLocation(r, ptn, rp.getStop(), null, boarding);
}
else if(p instanceof RouteStationTransferPoint) {
var rp = (RouteStationTransferPoint)p;
var route = rp.getRoute();
r.operator = route.getOperator().getId().getId();
r.type = "Route";
r.entityId = route.getId().getId();
r.route = route.getName() + " " + route.getMode() + " " + route.getLongName();
r.loc += rp.getStation().getName();
r.coordinate = rp.getStation().getCoordinate();
}
else if(p instanceof StopTransferPoint) {
var sp = (StopTransferPoint)p;
StopLocation stop = sp.getStop();
r.type = "Stop";
r.entityId = stop.getId().getId();
r.loc = stop.getName();
r.coordinate = stop.getCoordinate();
}
else if(p instanceof StationTransferPoint) {
var sp = (StationTransferPoint)p;
Station station = sp.getStation();
r.type = "Station";
r.entityId = station.getId().getId();
r.loc = station.getName();
r.coordinate = station.getCoordinate();
}

r.specificity = p.getSpecificityRanking();
r.coordinate = null;
return r;
}

private static void addLocation(
TxPoint r,
TripPattern pattern,
StopLocation stop,
Trip trip,
boolean boarding
) {
if(pattern == null) {
r.loc += stop.getName() + " [Pattern no found]";
return;
}
int stopPosition = pattern.findStopPosition(stop);
r.coordinate = stop.getCoordinate();

if (ptn.getStops().size() > p.getStopPosition()) {
int pos = p.getStopPosition();
var stop = ptn.getStops().get(pos);
var tt = ptn.getScheduledTimetable().getTripTimes(trip);
r.loc += stop.getName() + " [" + pos + "]" + " " + stop.getCoordinate();
r.time = arrival ? tt.getScheduledArrivalTime(pos) : tt.getScheduledDepartureTime(pos);
r.c = stop.getCoordinate().asJtsCoordinate();
if(stopPosition<0) {
r.loc += "[Stop not found in pattern: " + stop.getName() + "]";
return;
}
else {
r.loc += "[Stop index not found: " + p.getStopPosition() + "]";
r.loc += stop.getName() + " [" + stopPosition + "]";

if(trip != null) {
var tt = pattern.getScheduledTimetable().getTripTimes(trip);
r.time = boarding
? tt.getScheduledDepartureTime(stopPosition)
: tt.getScheduledArrivalTime(stopPosition)
;
}
r.loc += " " + p.getSpecificityRanking();
return r;
}

static class TxPoint {
private String operator = "";
private String type = "";
private String entityId = "";
private String loc = "";
private String tripId = "";
private String trip = "";
private Coordinate c = null;
private String route = "";
private Integer specificity = null;
private WgsCoordinate coordinate = null;
private int time = NOT_SET;

String location() {
return coordinate == null ? loc : loc + " " + coordinate;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package org.opentripplanner.ext.siri;

import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.Route;
import org.opentripplanner.model.Station;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.Trip;
import org.opentripplanner.model.TripPattern;
import org.opentripplanner.routing.RoutingService;
Expand All @@ -18,14 +23,6 @@
import uk.org.siri.siri20.VehicleActivityStructure;
import uk.org.siri.siri20.VehicleModesEnumeration;

import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* This class is used for matching TripDescriptors without trip_ids to scheduled GTFS data and to
* feed back that information into a new TripDescriptor with proper trip_id.
Expand Down Expand Up @@ -237,7 +234,7 @@ private static void initCache(RoutingService index) {
}
}
}
String lastStopId = tripPattern.getStops().get(tripPattern.getStops().size()-1).getId().getId();
String lastStopId = tripPattern.lastStop().getId().getId();

TripTimes tripTimes = tripPattern.getScheduledTimetable().getTripTimes(trip);
if (tripTimes != null) {
Expand Down
Loading