Skip to content

Commit ae61117

Browse files
committed
Refactor tests
1 parent cdc84e2 commit ae61117

File tree

4 files changed

+268
-263
lines changed

4 files changed

+268
-263
lines changed

src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java

+16
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import org.opentripplanner.framework.geometry.SphericalDistanceLibrary;
1010
import org.opentripplanner.framework.geometry.WgsCoordinate;
1111
import org.opentripplanner.framework.i18n.I18NString;
12+
import org.opentripplanner.service.vehiclerental.model.TestFreeFloatingRentalVehicleBuilder;
13+
import org.opentripplanner.service.vehiclerental.street.VehicleRentalPlaceVertex;
14+
import org.opentripplanner.street.model.RentalFormFactor;
1215
import org.opentripplanner.street.model.StreetTraversalPermission;
1316
import org.opentripplanner.street.model.edge.StreetEdge;
1417
import org.opentripplanner.street.model.edge.StreetEdgeBuilder;
@@ -93,4 +96,17 @@ public static StreetEdge streetEdge(
9396
) {
9497
return streetEdge(from, to, 1, permissions);
9598
}
99+
100+
public static VehicleRentalPlaceVertex rentalVertex(RentalFormFactor formFactor) {
101+
var rentalVehicleBuilder = TestFreeFloatingRentalVehicleBuilder.of().withLatitude(-122.575133).withLongitude(45.456773);
102+
if (formFactor == RentalFormFactor.SCOOTER) {
103+
rentalVehicleBuilder.withVehicleScooter();
104+
} else if (formFactor == RentalFormFactor.BICYCLE) {
105+
rentalVehicleBuilder.withVehicleBicycle();
106+
} else if (formFactor == RentalFormFactor.CAR) {
107+
rentalVehicleBuilder.withVehicleCar();
108+
}
109+
return new VehicleRentalPlaceVertex(rentalVehicleBuilder.build());
110+
}
111+
96112
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
package org.opentripplanner.street.model.edge;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import org.junit.jupiter.api.Test;
7+
import org.locationtech.jts.geom.Coordinate;
8+
import org.locationtech.jts.geom.GeometryFactory;
9+
import org.locationtech.jts.geom.LineString;
10+
import org.locationtech.jts.geom.impl.PackedCoordinateSequence;
11+
import org.opentripplanner.routing.api.request.StreetMode;
12+
import org.opentripplanner.routing.core.VehicleRoutingOptimizeType;
13+
import org.opentripplanner.routing.util.ElevationUtils;
14+
import org.opentripplanner.routing.util.SlopeCosts;
15+
import org.opentripplanner.service.vehiclerental.street.StreetVehicleRentalLink;
16+
import org.opentripplanner.service.vehiclerental.street.VehicleRentalEdge;
17+
import org.opentripplanner.service.vehiclerental.street.VehicleRentalPlaceVertex;
18+
import org.opentripplanner.street.model.RentalFormFactor;
19+
import org.opentripplanner.street.model.StreetTraversalPermission;
20+
import org.opentripplanner.street.model._data.StreetModelForTest;
21+
import org.opentripplanner.street.model.vertex.StreetVertex;
22+
import org.opentripplanner.street.search.TraverseMode;
23+
import org.opentripplanner.street.search.request.StreetSearchRequest;
24+
import org.opentripplanner.street.search.state.State;
25+
26+
public class StreetEdgeScooterTraversalTest {
27+
28+
private static final double DELTA = 0.00001;
29+
private static final double SPEED = 6.0;
30+
31+
@Test
32+
public void testTraverseFloatingScooter() {
33+
// This test does not depend on the setup method - and can probably be simplified
34+
Coordinate c1 = new Coordinate(-122.575033, 45.456773);
35+
Coordinate c2 = new Coordinate(-122.576668, 45.451426);
36+
37+
var formFactor = RentalFormFactor.SCOOTER;
38+
var rentalVertex = StreetModelForTest.rentalVertex(formFactor);
39+
var vehicleRentalEdge = VehicleRentalEdge.createVehicleRentalEdge(rentalVertex, formFactor);
40+
41+
StreetVertex v1 = StreetModelForTest.intersectionVertex("v1", c1.x, c1.y);
42+
StreetVertex v2 = StreetModelForTest.intersectionVertex("v2", c2.x, c2.y);
43+
44+
var link = StreetVehicleRentalLink.createStreetVehicleRentalLink(rentalVertex, v1);
45+
46+
GeometryFactory factory = new GeometryFactory();
47+
LineString geometry = factory.createLineString(new Coordinate[] { c1, c2 });
48+
49+
double length = 650.0;
50+
51+
StreetEdge testStreet = new StreetEdgeBuilder<>()
52+
.withFromVertex(v1)
53+
.withToVertex(v2)
54+
.withGeometry(geometry)
55+
.withName("Test Lane")
56+
.withMeterLength(length)
57+
.withPermission(StreetTraversalPermission.ALL)
58+
.buildAndConnect();
59+
60+
var request = StreetSearchRequest.of().withMode(StreetMode.SCOOTER_RENTAL);
61+
62+
request.withPreferences(pref -> pref.withScooter(scooter -> scooter.withSpeed(5)));
63+
64+
State slowResult = traverseStreetFromRental(
65+
testStreet,
66+
vehicleRentalEdge,
67+
link,
68+
rentalVertex,
69+
request.build()
70+
);
71+
request.withPreferences(pref -> pref.withScooter(scooter -> scooter.withSpeed(10)));
72+
73+
State fastResult = traverseStreetFromRental(
74+
testStreet,
75+
vehicleRentalEdge,
76+
link,
77+
rentalVertex,
78+
request.build()
79+
);
80+
81+
// Cost and time should be less when scooter speed is higher.
82+
assertTrue(slowResult.getWeight() > fastResult.getWeight() + DELTA);
83+
assertTrue(slowResult.getElapsedTimeSeconds() > fastResult.getElapsedTimeSeconds());
84+
85+
request.withPreferences(pref -> pref.withScooter(scooter -> scooter.withReluctance(1)));
86+
State lowReluctanceResult = traverseStreetFromRental(
87+
testStreet,
88+
vehicleRentalEdge,
89+
link,
90+
rentalVertex,
91+
request.build()
92+
);
93+
94+
request.withPreferences(pref -> pref.withScooter(scooter -> scooter.withReluctance(5)));
95+
96+
State highReluctanceResult = traverseStreetFromRental(
97+
testStreet,
98+
vehicleRentalEdge,
99+
link,
100+
rentalVertex,
101+
request.build()
102+
);
103+
// Cost should be more when reluctance is higher but the time should be the same.
104+
assertTrue(highReluctanceResult.getWeight() > lowReluctanceResult.getWeight() + DELTA);
105+
106+
assertEquals(
107+
highReluctanceResult.getElapsedTimeSeconds(),
108+
lowReluctanceResult.getElapsedTimeSeconds()
109+
);
110+
}
111+
112+
@Test
113+
public void testWalkingBeforeScooter() {
114+
StreetEdge e1 = StreetModelForTest.streetEdgeBuilder(StreetModelForTest.V1, StreetModelForTest.V2, 100.0, StreetTraversalPermission.ALL)
115+
.withCarSpeed(10.0f)
116+
.buildAndConnect();
117+
118+
var request = StreetSearchRequest
119+
.of()
120+
.withPreferences(pref -> pref.withWalk(walk -> walk.withReluctance(1)))
121+
.withMode(StreetMode.SCOOTER_RENTAL);
122+
123+
State s0 = new State(StreetModelForTest.V1, request.build());
124+
State result = e1.traverse(s0)[0];
125+
126+
request.withPreferences(pref ->
127+
pref.withScooter(scooter -> scooter.withReluctance(5).withSpeed(8.5))
128+
);
129+
130+
s0 = new State(StreetModelForTest.V1, request.build());
131+
var scooterReluctanceResult = e1.traverse(s0)[0];
132+
133+
// Scooter preferences shouldn't affect walking when SCOOTER_RENTAL is used as mode
134+
assertEquals(TraverseMode.WALK, result.currentMode());
135+
assertEquals(result.getWeight(), scooterReluctanceResult.getWeight(), DELTA);
136+
assertEquals(result.getElapsedTimeSeconds(), scooterReluctanceResult.getElapsedTimeSeconds());
137+
}
138+
139+
@Test
140+
public void testScooterOptimizeTriangle() {
141+
// This test does not depend on the setup method - and can probably be simplified
142+
Coordinate c1 = new Coordinate(-122.575033, 45.456773);
143+
Coordinate c2 = new Coordinate(-122.576668, 45.451426);
144+
145+
var formFactor = RentalFormFactor.SCOOTER;
146+
147+
var rentalVertex = StreetModelForTest.rentalVertex(formFactor);
148+
var vehicleRentalEdge = VehicleRentalEdge.createVehicleRentalEdge(rentalVertex, formFactor);
149+
150+
StreetVertex v1 = StreetModelForTest.intersectionVertex("v1", c1.x, c1.y);
151+
StreetVertex v2 = StreetModelForTest.intersectionVertex("v2", c2.x, c2.y);
152+
153+
var link = StreetVehicleRentalLink.createStreetVehicleRentalLink(rentalVertex, v1);
154+
155+
GeometryFactory factory = new GeometryFactory();
156+
LineString geometry = factory.createLineString(new Coordinate[] { c1, c2 });
157+
158+
double length = 650.0;
159+
160+
StreetEdge testStreet = new StreetEdgeBuilder<>()
161+
.withFromVertex(v1)
162+
.withToVertex(v2)
163+
.withGeometry(geometry)
164+
.withName("Test Lane")
165+
.withMeterLength(length)
166+
.withPermission(StreetTraversalPermission.ALL)
167+
// a safe street
168+
.withBicycleSafetyFactor(0.74f)
169+
.buildAndConnect();
170+
171+
Coordinate[] profile = new Coordinate[] {
172+
new Coordinate(0, 0), // slope = 0.1
173+
new Coordinate(length / 2, length / 20.0),
174+
new Coordinate(length, 0), // slope = -0.1
175+
};
176+
PackedCoordinateSequence elev = new PackedCoordinateSequence.Double(profile);
177+
StreetElevationExtensionBuilder
178+
.of(testStreet)
179+
.withElevationProfile(elev)
180+
.withComputed(false)
181+
.build()
182+
.ifPresent(testStreet::setElevationExtension);
183+
184+
SlopeCosts costs = ElevationUtils.getSlopeCosts(elev, true);
185+
double trueLength = costs.lengthMultiplier * length;
186+
double slopeWorkLength = testStreet.getEffectiveBikeDistanceForWorkCost();
187+
double slopeSpeedLength = testStreet.getEffectiveBikeDistance();
188+
189+
var request = StreetSearchRequest.of().withMode(StreetMode.SCOOTER_RENTAL);
190+
191+
request.withPreferences(pref ->
192+
pref
193+
.withScooter(scooter ->
194+
scooter
195+
.withSpeed(SPEED)
196+
.withOptimizeType(VehicleRoutingOptimizeType.TRIANGLE)
197+
.withOptimizeTriangle(it -> it.withTime(1))
198+
.withReluctance(1)
199+
)
200+
.withWalk(walk -> walk.withReluctance(1))
201+
.withCar(car -> car.withReluctance(1))
202+
);
203+
204+
var rentedState = vehicleRentalEdge.traverse(new State(rentalVertex, request.build()));
205+
var startState = link.traverse(rentedState[0])[0];
206+
207+
State result = testStreet.traverse(startState)[0];
208+
double expectedTimeWeight = slopeSpeedLength / SPEED;
209+
assertEquals(TraverseMode.SCOOTER, result.currentMode());
210+
assertEquals(expectedTimeWeight, result.getWeight() - startState.getWeight(), DELTA);
211+
212+
request.withPreferences(p ->
213+
p.withScooter(scooter -> scooter.withOptimizeTriangle(it -> it.withSlope(1)))
214+
);
215+
rentedState = vehicleRentalEdge.traverse(new State(rentalVertex, request.build()));
216+
startState = link.traverse(rentedState[0])[0];
217+
218+
result = testStreet.traverse(startState)[0];
219+
double slopeWeight = result.getWeight();
220+
double expectedSlopeWeight = slopeWorkLength / SPEED;
221+
assertEquals(expectedSlopeWeight, slopeWeight - startState.getWeight(), DELTA);
222+
assertTrue(length * 1.5 / SPEED < slopeWeight);
223+
assertTrue(length * 1.5 * 10 / SPEED > slopeWeight);
224+
225+
request.withPreferences(p ->
226+
p.withScooter(scooter -> scooter.withOptimizeTriangle(it -> it.withSafety(1)))
227+
);
228+
rentedState = vehicleRentalEdge.traverse(new State(rentalVertex, request.build()));
229+
startState = link.traverse(rentedState[0])[0];
230+
231+
result = testStreet.traverse(startState)[0];
232+
double slopeSafety = costs.slopeSafetyCost;
233+
double safetyWeight = result.getWeight();
234+
double expectedSafetyWeight = (trueLength * 0.74 + slopeSafety) / SPEED;
235+
assertEquals(expectedSafetyWeight, safetyWeight - startState.getWeight(), DELTA);
236+
}
237+
238+
private State traverseStreetFromRental(
239+
StreetEdge streetEdge,
240+
VehicleRentalEdge rentalEdge,
241+
StreetVehicleRentalLink link,
242+
VehicleRentalPlaceVertex rentalVertex,
243+
StreetSearchRequest request
244+
) {
245+
var rentedState = rentalEdge.traverse(new State(rentalVertex, request));
246+
var startState = link.traverse(rentedState[0])[0];
247+
return streetEdge.traverse(startState)[0];
248+
}
249+
}

0 commit comments

Comments
 (0)