package org.opentripplanner.routing.edgetype; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.opentripplanner.common.geometry.GeometryUtils; import org.opentripplanner.routing.core.RoutingRequest; import org.opentripplanner.routing.core.State; import org.opentripplanner.routing.core.TraverseMode; import org.opentripplanner.routing.core.TraverseModeSet; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.vertextype.IntersectionVertex; import org.opentripplanner.routing.vertextype.StreetVertex; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.LineString; public class PlainStreetEdgeTest { private Graph _graph; private IntersectionVertex v0, v1, v2; private RoutingRequest proto; @Before public void before() { _graph = new Graph(); v0 = vertex("maple_0th", 0.0, 0.0); v1 = vertex("maple_1st", 2.0, 2.0); v2 = vertex("maple_2nd", 1.0, 2.0); v1.setTrafficLight(true); proto = new RoutingRequest(); proto.setCarSpeed(15.0f); proto.setWalkSpeed(1.0); proto.setBikeSpeed(5.0f); proto.setWalkReluctance(1.0); proto.setStairsReluctance(1.0); proto.setTurnReluctance(1.0); proto.setModes(TraverseModeSet.allModes()); } @Test public void testInAndOutAngles() { PlainStreetEdge e1 = edge(v1, v2, 1.0, StreetTraversalPermission.ALL); // Edge has same first and last angle. assertEquals(91, e1.getInAngle()); assertEquals(91, e1.getOutAngle()); // 2 new ones StreetVertex u = vertex("test1", 2.0, 1.0); StreetVertex v = vertex("test2", 2.0, 2.0); // Second edge PlainStreetEdge e2 = edge(u, v, 1.0, StreetTraversalPermission.ALL); assertEquals(180, e2.getInAngle()); assertEquals(180, e2.getOutAngle()); // Difference should be about 90. int diff = (e1.getOutAngle() - e2.getInAngle()); assertEquals(-89, diff); } @Test public void testTraverseAsPedestrian() { PlainStreetEdge e1 = edge(v1, v2, 100.0, StreetTraversalPermission.ALL); e1.setCarSpeed(10.0f); RoutingRequest options = proto.clone(); options.setMode(TraverseMode.WALK); options.setRoutingContext(_graph, v1, v2); State s0 = new State(options); State s1 = e1.traverse(s0); // Should use the speed on the edge. double expectedWeight = e1.getLength() / options.getWalkSpeed(); long expectedDuration = (long) Math.ceil(expectedWeight); assertEquals(expectedDuration, s1.getElapsedTimeSeconds(), 0.0); assertEquals(expectedWeight, s1.getWeight(), 0.0); } @Test public void testTraverseAsCar() { PlainStreetEdge e1 = edge(v1, v2, 100.0, StreetTraversalPermission.ALL); e1.setCarSpeed(10.0f); RoutingRequest options = proto.clone(); options.setMode(TraverseMode.CAR); options.setRoutingContext(_graph, v1, v2); State s0 = new State(options); State s1 = e1.traverse(s0); // Should use the speed on the edge. double expectedWeight = e1.getLength() / e1.getCarSpeed(); long expectedDuration = (long) Math.ceil(expectedWeight); assertEquals(expectedDuration, s1.getElapsedTimeSeconds(), 0.0); assertEquals(expectedWeight, s1.getWeight(), 0.0); } @Test public void testTraverseAsCustomMotorVehicle() { PlainStreetEdge e1 = edge(v1, v2, 100.0, StreetTraversalPermission.ALL); e1.setCarSpeed(10.0f); RoutingRequest options = proto.clone(); options.setMode(TraverseMode.CUSTOM_MOTOR_VEHICLE); options.setRoutingContext(_graph, v1, v2); State s0 = new State(options); State s1 = e1.traverse(s0); // Should use the speed on the edge. double expectedWeight = e1.getLength() / e1.getCarSpeed(); long expectedDuration = (long) Math.ceil(expectedWeight); assertEquals(expectedDuration, s1.getElapsedTimeSeconds(), 0.0); assertEquals(expectedWeight, s1.getWeight(), 0.0); } @Test public void testModeSetCanTraverse() { PlainStreetEdge e = edge(v1, v2, 1.0, StreetTraversalPermission.ALL); TraverseModeSet modes = TraverseModeSet.allModes(); assertTrue(e.canTraverse(modes)); modes = new TraverseModeSet(TraverseMode.BICYCLE, TraverseMode.WALK); assertTrue(e.canTraverse(modes)); e = edge(v1, v2, 1.0, StreetTraversalPermission.ALL_DRIVING); assertFalse(e.canTraverse(modes)); modes = new TraverseModeSet(TraverseMode.CAR, TraverseMode.WALK); assertTrue(e.canTraverse(modes)); } /** * Test the traversal of two edges with different traverse modes. * This test will fail unless the following three conditions are met: * 1. Turn costs are computed based on the back edge's traverse mode during reverse traversal. * 2. Turn costs are computed such that bike walking is taken into account correctly. * 3. Enabling bike mode on a routing request bases the bike walking speed on the walking speed. */ @Test public void testTraverseModeSwitch() { PlainStreetEdge e0 = edge(v0, v1, 50.0, StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE); PlainStreetEdge e1 = edge(v1, v2, 18.4, StreetTraversalPermission.PEDESTRIAN); RoutingRequest forward = proto.clone(); forward.setMode(TraverseMode.BICYCLE); forward.setRoutingContext(_graph, v0, v2); State s0 = new State(forward); State s1 = e0.traverse(s0); State s2 = e1.traverse(s1); RoutingRequest reverse = proto.clone(); reverse.setMode(TraverseMode.BICYCLE); reverse.setArriveBy(true); reverse.setRoutingContext(_graph, v0, v2); State s3 = new State(reverse); State s4 = e1.traverse(s3); State s5 = e0.traverse(s4); assertEquals(42, s2.getElapsedTimeSeconds()); assertEquals(42, s5.getElapsedTimeSeconds()); } /**** * Private Methods ****/ private IntersectionVertex vertex(String label, double lat, double lon) { IntersectionVertex v = new IntersectionVertex(_graph, label, lat, lon); return v; } /** * Create an edge. If twoWay, create two edges (back and forth). * * @param vA * @param vB * @param length * @param back true if this is a reverse edge */ private PlainStreetEdge edge(StreetVertex vA, StreetVertex vB, double length, StreetTraversalPermission perm) { String labelA = vA.getLabel(); String labelB = vB.getLabel(); String name = String.format("%s_%s", labelA, labelB); Coordinate[] coords = new Coordinate[2]; coords[0] = vA.getCoordinate(); coords[1] = vB.getCoordinate(); LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords); return new PlainStreetEdge(vA, vB, geom, name, length, perm, false); } }