Skip to content

Commit 756f7a4

Browse files
committed
refactor: Make to kinds of ViaLocation in request: PassThrough and Visit
1 parent a534f33 commit 756f7a4

File tree

12 files changed

+402
-167
lines changed

12 files changed

+402
-167
lines changed

src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaLocationMapper.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.util.List;
66
import java.util.Map;
7+
import org.opentripplanner.routing.api.request.PassThroughViaLocation;
78
import org.opentripplanner.routing.api.request.ViaLocation;
89
import org.opentripplanner.transit.model.framework.FeedScopedId;
910

@@ -12,15 +13,18 @@ class ViaLocationMapper {
1213
static List<ViaLocation> toPassThroughLocations(
1314
final List<Map<String, Object>> passThroughPoints
1415
) {
15-
return passThroughPoints.stream().map(ViaLocationMapper::mapViaLocation).collect(toList());
16+
return passThroughPoints
17+
.stream()
18+
.map(ViaLocationMapper::mapPassThroughViaLocation)
19+
.collect(toList());
1620
}
1721

18-
private static ViaLocation mapViaLocation(Map<String, Object> inputMap) {
22+
private static ViaLocation mapPassThroughViaLocation(Map<String, Object> inputMap) {
1923
final String name = (String) inputMap.get("name");
2024
final List<FeedScopedId> stopLocationIds =
2125
((List<String>) inputMap.get("placeIds")).stream()
2226
.map(TransitIdMapper::mapIDToDomain)
2327
.toList();
24-
return ViaLocation.passThroughLocation(name, stopLocationIds);
28+
return new PassThroughViaLocation(name, stopLocationIds);
2529
}
2630
}

src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.RaptorCostConverter;
2424
import org.opentripplanner.routing.api.request.DebugEventType;
2525
import org.opentripplanner.routing.api.request.RouteRequest;
26-
import org.opentripplanner.routing.api.request.ViaConnection;
2726
import org.opentripplanner.routing.api.request.ViaLocation;
2827
import org.opentripplanner.routing.api.request.framework.CostLinearFunction;
2928
import org.opentripplanner.transit.model.network.grouppriority.DefaultTransitGroupPriorityCalculator;
@@ -123,7 +122,7 @@ private RaptorRequest<T> doMap() {
123122
// Note! If a pass-through-point exists, then the transit-group-priority feature is disabled
124123

125124
// TODO - We need handle via locations that are not pass-through-points here
126-
if (request.getViaLocations().stream().allMatch(ViaLocation::allowAsPassThroughPoint)) {
125+
if (request.getViaLocations().stream().allMatch(ViaLocation::isPassThroughLocation)) {
127126
mcBuilder.withPassThroughPoints(mapPassThroughPoints());
128127
r.relaxGeneralizedCostAtDestination().ifPresent(mcBuilder::withRelaxCostAtDestination);
129128
} else if (!pt.relaxTransitGroupPriority().isNormal()) {
@@ -192,10 +191,9 @@ private List<PassThroughPoint> mapPassThroughPoints() {
192191
}
193192

194193
private PassThroughPoint mapPassThroughPoints(ViaLocation location) {
195-
var feedIds = location.connections().stream().map(ViaConnection::locationId).toList();
196194
return new PassThroughPoint(
197195
location.label(),
198-
lookUpStopIndex.lookupStopLocationIndexes(feedIds)
196+
lookUpStopIndex.lookupStopLocationIndexes(location.stopLocationIds())
199197
);
200198
}
201199

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.opentripplanner.routing.api.request;
2+
3+
import java.util.Collection;
4+
import java.util.List;
5+
import java.util.Objects;
6+
import javax.annotation.Nullable;
7+
import org.opentripplanner.transit.model.framework.FeedScopedId;
8+
9+
public abstract class AbstractViaLocation implements ViaLocation {
10+
11+
private final String label;
12+
private final List<FeedScopedId> stopLocationIds;
13+
14+
public AbstractViaLocation(String label, Collection<FeedScopedId> stopLocationIds) {
15+
this.label = label;
16+
this.stopLocationIds = List.copyOf(stopLocationIds);
17+
}
18+
19+
@Nullable
20+
@Override
21+
public String label() {
22+
return label;
23+
}
24+
25+
@Override
26+
public List<FeedScopedId> stopLocationIds() {
27+
return stopLocationIds;
28+
}
29+
30+
@Override
31+
public boolean equals(Object o) {
32+
if (this == o) return true;
33+
if (o == null || getClass() != o.getClass()) return false;
34+
AbstractViaLocation that = (AbstractViaLocation) o;
35+
return (
36+
Objects.equals(label, that.label) && Objects.equals(stopLocationIds, that.stopLocationIds)
37+
);
38+
}
39+
40+
@Override
41+
public int hashCode() {
42+
return Objects.hash(label, stopLocationIds);
43+
}
44+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.opentripplanner.routing.api.request;
2+
3+
import java.util.Collection;
4+
import javax.annotation.Nullable;
5+
import org.opentripplanner.framework.tostring.ToStringBuilder;
6+
import org.opentripplanner.transit.model.framework.FeedScopedId;
7+
8+
/**
9+
* One of the listed stop locations or one of its children must be visited. An on-board
10+
* intermediate stop visit is ok, as well as boarding or alighting at one of the stops.
11+
*/
12+
public class PassThroughViaLocation extends AbstractViaLocation {
13+
14+
@SuppressWarnings("DataFlowIssue")
15+
public PassThroughViaLocation(@Nullable String label, Collection<FeedScopedId> stopLocationIds) {
16+
super(label, stopLocationIds);
17+
if (stopLocationIds.isEmpty()) {
18+
throw new IllegalArgumentException(
19+
"A pass through via location must have at least one stop location. Label: " + label
20+
);
21+
}
22+
}
23+
24+
@Override
25+
public boolean isPassThroughLocation() {
26+
return true;
27+
}
28+
29+
@Override
30+
public String toString() {
31+
return ToStringBuilder
32+
.of(PassThroughViaLocation.class)
33+
.addObj("label", label())
34+
.addCol("stopLocationIds", stopLocationIds())
35+
.toString();
36+
}
37+
}
Lines changed: 30 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,56 @@
11
package org.opentripplanner.routing.api.request;
22

33
import java.time.Duration;
4-
import java.util.Collection;
54
import java.util.List;
6-
import java.util.Objects;
75
import javax.annotation.Nullable;
8-
import org.opentripplanner.framework.time.DurationUtils;
9-
import org.opentripplanner.framework.tostring.ToStringBuilder;
6+
import org.opentripplanner.framework.geometry.WgsCoordinate;
107
import org.opentripplanner.transit.model.framework.FeedScopedId;
118

129
/**
13-
* Defines a via location which the journey must route through.
10+
* Defines a via location which the journey must route through. At least one stop location or
11+
* coordinate must exist. When routing, the via-location is visited if at least one of the stops
12+
* or coordinates is visited, before the journey continues. There is no need to visit any other
13+
* stop location or coordinate.
14+
* <p>
15+
* The stop locations and coordinates are distinct locations. In earlier versions of OTP the
16+
* coordinates were used as a fallback for when a stop was not found. But in this version, a
17+
* {@link org.opentripplanner.transit.model.framework.EntityNotFoundException} is thrown if
18+
* one of the stops does not exist. The search does NOT try to be smart and recover from an
19+
* entity no found exception.
1420
*/
15-
public final class ViaLocation {
16-
17-
private static final Duration MINIMUM_WAIT_TIME_MAX_LIMIT = Duration.ofHours(24);
18-
19-
private final String label;
20-
private final boolean allowAsPassThroughPoint;
21-
private final Duration minimumWaitTime;
22-
private final List<ViaConnection> connections;
23-
24-
@SuppressWarnings("DataFlowIssue")
25-
private ViaLocation(
26-
@Nullable String label,
27-
boolean allowAsPassThroughPoint,
28-
@Nullable Duration minimumWaitTime,
29-
Collection<ViaConnection> connections
30-
) {
31-
this.label = label;
32-
this.allowAsPassThroughPoint = allowAsPassThroughPoint;
33-
this.minimumWaitTime =
34-
DurationUtils.requireNonNegative(
35-
minimumWaitTime == null ? Duration.ZERO : minimumWaitTime,
36-
MINIMUM_WAIT_TIME_MAX_LIMIT,
37-
"minimumWaitTime"
38-
);
39-
this.connections = List.copyOf(connections);
40-
41-
if (allowAsPassThroughPoint && !minimumWaitTime.isZero()) {
42-
throw new IllegalArgumentException(
43-
"'allowAsPassThroughPoint' can not be used with minimumWaitTime for " + label + "."
44-
);
45-
}
46-
if (allowAsPassThroughPoint && connections.stream().anyMatch(ViaConnection::hasCoordinate)) {
47-
throw new IllegalArgumentException(
48-
"'allowAsPassThroughPoint' can not be used with coordinates for " + label + "."
49-
);
50-
}
51-
}
52-
21+
public interface ViaLocation {
5322
/**
54-
* A pass-through-location instructs the router to visit the location either by boarding,
55-
* alighting or on-board a transit.
56-
* @param label The name/label for this location. This is used for debugging and logging and is pass-through information.
57-
* @param locationIds The ID for the stop, station or multimodal station or groupOfStopPlace.
23+
* Get an optional name/label of for debugging and logging. Not used in business logic.
5824
*/
59-
public static ViaLocation passThroughLocation(
60-
@Nullable String label,
61-
List<FeedScopedId> locationIds
62-
) {
63-
return new ViaLocation(label, true, Duration.ZERO, ViaConnection.connections(locationIds));
64-
}
25+
@Nullable
26+
String label();
6527

6628
/**
67-
* If set to {@code true} this location can be visited as a pass-through-point. Only
68-
* collections of stops are supported, not coordinates. Also, the minWaitTime must be
69-
* zero(0).
29+
* The minimum wait time is used to force the trip to stay the given duration at the via location
30+
* before the trip is continued. This cannot be used together with allow-pass-through, since a
31+
* pass-through stop is visited on-board.
7032
*/
71-
public boolean allowAsPassThroughPoint() {
72-
return allowAsPassThroughPoint;
33+
default Duration minimumWaitTime() {
34+
return Duration.ZERO;
7335
}
7436

7537
/**
76-
* The minimum wait time is used to force the trip to stay the given duration at the via
77-
* location before the trip is continued. This cannot be used together with allow-pass-through,
78-
* since a pass-through stop is visited on-board.
38+
* Returns {@code true} if this location is a pass-through-point. Only stops can be visited and
39+
* the {@code minimumWaitTime} must be zero.
7940
*/
80-
public Duration minimumWaitTime() {
81-
return minimumWaitTime;
82-
}
41+
boolean isPassThroughLocation();
8342

8443
/**
85-
* Get an optional name/label of for debugging and logging.
44+
* A list of stop witch can be used as via location together with the {@code coordinates}.A stop
45+
* location can be a stop, a station, a multimodal station or a group of stations.
8646
*/
87-
@Nullable
88-
public String label() {
89-
return label;
90-
}
47+
List<FeedScopedId> stopLocationIds();
9148

9249
/**
93-
* Get the one or multiple locations of which only one is required to route through.
50+
* Get the one or multiple stop locations. This is optional to implement, an empty
51+
* list is returned if this is not available.
9452
*/
95-
public List<ViaConnection> connections() {
96-
return connections;
97-
}
98-
99-
@Override
100-
public boolean equals(Object o) {
101-
if (this == o) return true;
102-
if (o == null || getClass() != o.getClass()) return false;
103-
ViaLocation that = (ViaLocation) o;
104-
return (
105-
allowAsPassThroughPoint == that.allowAsPassThroughPoint &&
106-
Objects.equals(minimumWaitTime, that.minimumWaitTime) &&
107-
Objects.equals(label, that.label) &&
108-
Objects.equals(connections, that.connections)
109-
);
110-
}
111-
112-
@Override
113-
public int hashCode() {
114-
return Objects.hash(allowAsPassThroughPoint, minimumWaitTime, label, connections);
115-
}
116-
117-
@Override
118-
public String toString() {
119-
return ToStringBuilder
120-
.of(ViaLocation.class)
121-
.addBoolIfTrue(label, label != null)
122-
.addBoolIfTrue("allowAsPassThroughPoint", allowAsPassThroughPoint)
123-
.addDuration("minimumWaitTime", minimumWaitTime, Duration.ZERO)
124-
.addObj("connections", connections)
125-
.toString();
53+
default List<WgsCoordinate> coordinates() {
54+
return List.of();
12655
}
12756
}

0 commit comments

Comments
 (0)