use of org.opentripplanner.routing.vertextype.IntersectionVertex in project OpenTripPlanner by opentripplanner.
the class TestOpenStreetMapGraphBuilder method testBuildGraphDetailed.
/**
* Detailed testing of OSM graph building using a very small chunk of NYC (SOHO-ish).
* @throws Exception
*/
@Test
public void testBuildGraphDetailed() throws Exception {
Graph gg = new Graph();
OpenStreetMapModule loader = new OpenStreetMapModule();
loader.setDefaultWayPropertySetSource(new DefaultWayPropertySetSource());
FileBasedOpenStreetMapProviderImpl provider = new FileBasedOpenStreetMapProviderImpl();
File file = new File(URLDecoder.decode(getClass().getResource("NYC_small.osm.gz").getFile(), "UTF-8"));
provider.setPath(file);
loader.setProvider(provider);
loader.buildGraph(gg, extra);
// These vertices are labeled in the OSM file as having traffic lights.
IntersectionVertex iv1 = (IntersectionVertex) gg.getVertex("osm:node:1919595918");
IntersectionVertex iv2 = (IntersectionVertex) gg.getVertex("osm:node:42442273");
IntersectionVertex iv3 = (IntersectionVertex) gg.getVertex("osm:node:1919595927");
IntersectionVertex iv4 = (IntersectionVertex) gg.getVertex("osm:node:42452026");
assertTrue(iv1.trafficLight);
assertTrue(iv2.trafficLight);
assertTrue(iv3.trafficLight);
assertTrue(iv4.trafficLight);
// These are not.
IntersectionVertex iv5 = (IntersectionVertex) gg.getVertex("osm:node:42435485");
IntersectionVertex iv6 = (IntersectionVertex) gg.getVertex("osm:node:42439335");
IntersectionVertex iv7 = (IntersectionVertex) gg.getVertex("osm:node:42436761");
IntersectionVertex iv8 = (IntersectionVertex) gg.getVertex("osm:node:42442291");
assertFalse(iv5.trafficLight);
assertFalse(iv6.trafficLight);
assertFalse(iv7.trafficLight);
assertFalse(iv8.trafficLight);
Set<P2<Integer>> edgeEndpoints = new HashSet<P2<Integer>>();
for (StreetEdge se : gg.getStreetEdges()) {
P2<Integer> endpoints = new P2<Integer>(se.getFromVertex().getIndex(), se.getToVertex().getIndex());
// Check that we don't get any duplicate edges on this small graph.
if (edgeEndpoints.contains(endpoints)) {
assertFalse(true);
}
edgeEndpoints.add(endpoints);
}
}
use of org.opentripplanner.routing.vertextype.IntersectionVertex in project OpenTripPlanner by opentripplanner.
the class StreetEdge method doTraverse.
/**
* return a StateEditor rather than a State so that we can make parking/mode switch modifications for kiss-and-ride.
*/
private StateEditor doTraverse(State s0, RoutingRequest options, TraverseMode traverseMode) {
boolean walkingBike = options.walkingBike;
boolean backWalkingBike = s0.isBackWalkingBike();
TraverseMode backMode = s0.getBackMode();
Edge backEdge = s0.getBackEdge();
if (backEdge != null) {
// TODO profiling indicates that this is a hot spot.
if (this.isReverseOf(backEdge) || backEdge.isReverseOf(this)) {
return null;
}
}
// Ensure we are actually walking, when walking a bike
backWalkingBike &= TraverseMode.WALK.equals(backMode);
walkingBike &= TraverseMode.WALK.equals(traverseMode);
/* Check whether this street allows the current mode. If not and we are biking, attempt to walk the bike. */
if (!canTraverse(options, traverseMode)) {
if (traverseMode == TraverseMode.BICYCLE) {
return doTraverse(s0, options.bikeWalkingOptions, TraverseMode.WALK);
}
return null;
}
// Automobiles have variable speeds depending on the edge type
double speed = calculateSpeed(options, traverseMode, s0.getTimeInMillis());
double time = getDistance() / speed;
double weight;
// TODO(flamholz): factor out this bike, wheelchair and walking specific logic to somewhere central.
if (options.wheelchairAccessible) {
weight = getSlopeSpeedEffectiveLength() / speed;
} else if (traverseMode.equals(TraverseMode.BICYCLE)) {
time = getSlopeSpeedEffectiveLength() / speed;
switch(options.optimize) {
case SAFE:
weight = bicycleSafetyFactor * getDistance() / speed;
break;
case GREENWAYS:
weight = bicycleSafetyFactor * getDistance() / speed;
if (bicycleSafetyFactor <= GREENWAY_SAFETY_FACTOR) {
// greenways are treated as even safer than they really are
weight *= 0.66;
}
break;
case FLAT:
/* see notes in StreetVertex on speed overhead */
weight = getDistance() / speed + getSlopeWorkCostEffectiveLength();
break;
case QUICK:
weight = getSlopeSpeedEffectiveLength() / speed;
break;
case TRIANGLE:
double quick = getSlopeSpeedEffectiveLength();
double safety = bicycleSafetyFactor * getDistance();
// TODO This computation is not coherent with the one for FLAT
double slope = getSlopeWorkCostEffectiveLength();
weight = quick * options.triangleTimeFactor + slope * options.triangleSlopeFactor + safety * options.triangleSafetyFactor;
weight /= speed;
break;
default:
weight = getDistance() / speed;
}
} else {
if (walkingBike) {
// take slopes into account when walking bikes
time = getSlopeSpeedEffectiveLength() / speed;
}
weight = time;
if (traverseMode.equals(TraverseMode.WALK)) {
// take slopes into account when walking
// FIXME: this causes steep stairs to be avoided. see #1297.
double costs = ElevationUtils.getWalkCostsForSlope(getDistance(), getMaxSlope());
// as the cost walkspeed is assumed to be for 4.8km/h (= 1.333 m/sec) we need to adjust
// for the walkspeed set by the user
double elevationUtilsSpeed = 4.0 / 3.0;
weight = costs * (elevationUtilsSpeed / speed);
// treat cost as time, as in the current model it actually is the same (this can be checked for maxSlope == 0)
time = weight;
/*
// debug code
if(weight > 100){
double timeflat = length / speed;
System.out.format("line length: %.1f m, slope: %.3f ---> slope costs: %.1f , weight: %.1f , time (flat): %.1f %n", length, elevationProfile.getMaxSlope(), costs, weight, timeflat);
}
*/
}
}
if (isStairs()) {
weight *= options.stairsReluctance;
} else {
// TODO: this is being applied even when biking or driving.
weight *= options.walkReluctance;
}
StateEditor s1 = s0.edit(this);
s1.setBackMode(traverseMode);
s1.setBackWalkingBike(walkingBike);
/* Handle no through traffic areas. */
if (this.isNoThruTraffic()) {
// Record transition into no-through-traffic area.
if (backEdge instanceof StreetEdge && !((StreetEdge) backEdge).isNoThruTraffic()) {
s1.setEnteredNoThroughTrafficArea();
}
// If we transitioned into a no-through-traffic area at some point, check if we are exiting it.
if (s1.hasEnteredNoThroughTrafficArea()) {
// on thru _Vertices_. This could certainly be improved somehow.
for (StreetEdge se : Iterables.filter(s1.getVertex().getOutgoing(), StreetEdge.class)) {
if (!se.isNoThruTraffic()) {
// This vertex has at least one through-traffic edge. We can't dominate it with a no-thru state.
return null;
}
}
}
}
/* Compute turn cost. */
StreetEdge backPSE;
if (backEdge != null && backEdge instanceof StreetEdge) {
backPSE = (StreetEdge) backEdge;
RoutingRequest backOptions = backWalkingBike ? s0.getOptions().bikeWalkingOptions : s0.getOptions();
double backSpeed = backPSE.calculateSpeed(backOptions, backMode, s0.getTimeInMillis());
// Units are seconds.
final double realTurnCost;
// Apply turn restrictions
if (options.arriveBy && !canTurnOnto(backPSE, s0, backMode)) {
return null;
} else if (!options.arriveBy && !backPSE.canTurnOnto(this, s0, traverseMode)) {
return null;
}
/*
* This is a subtle piece of code. Turn costs are evaluated differently during
* forward and reverse traversal. During forward traversal of an edge, the turn
* *into* that edge is used, while during reverse traversal, the turn *out of*
* the edge is used.
*
* However, over a set of edges, the turn costs must add up the same (for
* general correctness and specifically for reverse optimization). This means
* that during reverse traversal, we must also use the speed for the mode of
* the backEdge, rather than of the current edge.
*/
if (options.arriveBy && tov instanceof IntersectionVertex) {
// arrive-by search
IntersectionVertex traversedVertex = ((IntersectionVertex) tov);
realTurnCost = backOptions.getIntersectionTraversalCostModel().computeTraversalCost(traversedVertex, this, backPSE, backMode, backOptions, (float) speed, (float) backSpeed);
} else if (!options.arriveBy && fromv instanceof IntersectionVertex) {
// depart-after search
IntersectionVertex traversedVertex = ((IntersectionVertex) fromv);
realTurnCost = options.getIntersectionTraversalCostModel().computeTraversalCost(traversedVertex, backPSE, this, traverseMode, options, (float) backSpeed, (float) speed);
} else {
// In case this is a temporary edge not connected to an IntersectionVertex
LOG.debug("Not computing turn cost for edge {}", this);
realTurnCost = 0;
}
if (!traverseMode.isDriving()) {
// just a tie-breaker
s1.incrementWalkDistance(realTurnCost / 100);
}
long turnTime = (long) Math.ceil(realTurnCost);
time += turnTime;
weight += options.turnReluctance * realTurnCost;
}
if (walkingBike || TraverseMode.BICYCLE.equals(traverseMode)) {
if (!(backWalkingBike || TraverseMode.BICYCLE.equals(backMode))) {
s1.incrementTimeInSeconds(options.bikeSwitchTime);
s1.incrementWeight(options.bikeSwitchCost);
}
}
if (!traverseMode.isDriving()) {
s1.incrementWalkDistance(getDistance());
}
/* On the pre-kiss/pre-park leg, limit both walking and driving, either soft or hard. */
int roundedTime = (int) Math.ceil(time);
if (options.kissAndRide || options.parkAndRide) {
if (options.arriveBy) {
if (!s0.isCarParked())
s1.incrementPreTransitTime(roundedTime);
} else {
if (!s0.isEverBoarded())
s1.incrementPreTransitTime(roundedTime);
}
if (s1.isMaxPreTransitTimeExceeded(options)) {
if (options.softPreTransitLimiting) {
weight += calculateOverageWeight(s0.getPreTransitTime(), s1.getPreTransitTime(), options.maxPreTransitTime, options.preTransitPenalty, options.preTransitOverageRate);
} else
return null;
}
}
/* Apply a strategy for avoiding walking too far, either soft (weight increases) or hard limiting (pruning). */
if (s1.weHaveWalkedTooFar(options)) {
// if we're using a soft walk-limit
if (options.softWalkLimiting) {
// just slap a penalty for the overage onto s1
weight += calculateOverageWeight(s0.getWalkDistance(), s1.getWalkDistance(), options.getMaxWalkDistance(), options.softWalkPenalty, options.softWalkOverageRate);
} else {
// else, it's a hard limit; bail
LOG.debug("Too much walking. Bailing.");
return null;
}
}
s1.incrementTimeInSeconds(roundedTime);
s1.incrementWeight(weight);
return s1;
}
use of org.opentripplanner.routing.vertextype.IntersectionVertex in project OpenTripPlanner by opentripplanner.
the class AreaEdgeList method addVertex.
/**
* Safely add a vertex to this area. This creates edges to all other vertices unless those edges would cross one of the original edges.
*/
public void addVertex(IntersectionVertex newVertex, Graph graph) {
GeometryFactory geometryFactory = GeometryUtils.getGeometryFactory();
if (edges.size() == 0) {
throw new RuntimeException("Can't add a vertex to an empty area");
}
@SuppressWarnings("unchecked") HashSet<IntersectionVertex> verticesCopy = (HashSet<IntersectionVertex>) vertices.clone();
VERTEX: for (IntersectionVertex v : verticesCopy) {
LineString newGeometry = geometryFactory.createLineString(new Coordinate[] { newVertex.getCoordinate(), v.getCoordinate() });
// fall into any holes
if (!originalEdges.union(originalEdges.getBoundary()).contains(newGeometry)) {
continue VERTEX;
}
// check to see if this splits multiple NamedAreas. This code is rather similar to
// code in OSMGBI, but the data structures are different
createSegments(newVertex, v, areas, graph);
}
vertices.add(newVertex);
}
use of org.opentripplanner.routing.vertextype.IntersectionVertex in project OpenTripPlanner by opentripplanner.
the class TestTriangle method testTriangle.
public void testTriangle() {
Coordinate c1 = new Coordinate(-122.575033, 45.456773);
Coordinate c2 = new Coordinate(-122.576668, 45.451426);
StreetVertex v1 = new IntersectionVertex(null, "v1", c1.x, c1.y, (NonLocalizedString) null);
StreetVertex v2 = new IntersectionVertex(null, "v2", c2.x, c2.y, (NonLocalizedString) null);
GeometryFactory factory = new GeometryFactory();
LineString geometry = factory.createLineString(new Coordinate[] { c1, c2 });
double length = 650.0;
StreetWithElevationEdge testStreet = new StreetWithElevationEdge(v1, v2, geometry, "Test Lane", length, StreetTraversalPermission.ALL, false);
// a safe street
testStreet.setBicycleSafetyFactor(0.74f);
Coordinate[] profile = new Coordinate[] { // slope = 0.1
new Coordinate(0, 0), new Coordinate(length / 2, length / 20.0), // slope = -0.1
new Coordinate(length, 0) };
PackedCoordinateSequence elev = new PackedCoordinateSequence.Double(profile);
testStreet.setElevationProfile(elev, false);
SlopeCosts costs = ElevationUtils.getSlopeCosts(elev, true);
double trueLength = costs.lengthMultiplier * length;
double slopeWorkLength = testStreet.getSlopeWorkCostEffectiveLength();
double slopeSpeedLength = testStreet.getSlopeSpeedEffectiveLength();
RoutingRequest options = new RoutingRequest(TraverseMode.BICYCLE);
options.optimize = OptimizeType.TRIANGLE;
options.bikeSpeed = 6.0;
options.walkReluctance = 1;
options.setTriangleSafetyFactor(0);
options.setTriangleSlopeFactor(0);
options.setTriangleTimeFactor(1);
State startState = new State(v1, options);
State result = testStreet.traverse(startState);
double timeWeight = result.getWeight();
double expectedTimeWeight = slopeSpeedLength / options.getSpeed(TraverseMode.BICYCLE);
assertTrue(Math.abs(expectedTimeWeight - timeWeight) < 0.00001);
options.setTriangleSafetyFactor(0);
options.setTriangleSlopeFactor(1);
options.setTriangleTimeFactor(0);
startState = new State(v1, options);
result = testStreet.traverse(startState);
double slopeWeight = result.getWeight();
double expectedSlopeWeight = slopeWorkLength / options.getSpeed(TraverseMode.BICYCLE);
assertTrue(Math.abs(expectedSlopeWeight - slopeWeight) < 0.00001);
assertTrue(length * 1.5 / options.getSpeed(TraverseMode.BICYCLE) < slopeWeight);
assertTrue(length * 1.5 * 10 / options.getSpeed(TraverseMode.BICYCLE) > slopeWeight);
options.setTriangleSafetyFactor(1);
options.setTriangleSlopeFactor(0);
options.setTriangleTimeFactor(0);
startState = new State(v1, options);
result = testStreet.traverse(startState);
double safetyWeight = result.getWeight();
double slopeSafety = costs.slopeSafetyCost;
double expectedSafetyWeight = (trueLength * 0.74 + slopeSafety) / options.getSpeed(TraverseMode.BICYCLE);
assertTrue(Math.abs(expectedSafetyWeight - safetyWeight) < 0.00001);
final double ONE_THIRD = 1 / 3.0;
options.setTriangleSafetyFactor(ONE_THIRD);
options.setTriangleSlopeFactor(ONE_THIRD);
options.setTriangleTimeFactor(ONE_THIRD);
startState = new State(v1, options);
result = testStreet.traverse(startState);
double averageWeight = result.getWeight();
assertTrue(Math.abs(safetyWeight * ONE_THIRD + slopeWeight * ONE_THIRD + timeWeight * ONE_THIRD - averageWeight) < 0.00000001);
}
use of org.opentripplanner.routing.vertextype.IntersectionVertex in project OpenTripPlanner by opentripplanner.
the class SimpleTraversalCostModelTest method testCalculateTurnAngle.
@Test
public void testCalculateTurnAngle() {
// Graph for a fictional grid city with turn restrictions
IntersectionVertex v1 = vertex("maple_1st", new Coordinate(2.0, 2.0), false);
IntersectionVertex v2 = vertex("maple_2nd", new Coordinate(2.0, 1.0), false);
StreetEdge e1 = edge(v1, v2, 1.0, false);
// Edge has same first and last angle.
assertEquals(90, e1.getInAngle());
assertEquals(90, e1.getOutAngle());
// 2 new ones
IntersectionVertex v3 = vertex("test2", new Coordinate(1.0, 1.0), false);
// Second edge
StreetEdge e2 = edge(v2, v3, 1.0, false);
assertEquals(0, e2.getInAngle());
assertEquals(0, e2.getOutAngle());
// Difference should be about 90.
int diff = (e1.getOutAngle() - e2.getInAngle());
assertEquals(90, diff);
int turnAngle = costModel.calculateTurnAngle(e1, e2, options);
assertEquals(270, turnAngle);
}
Aggregations