/** * Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onebusaway.transit_data_federation.impl.otp; import java.util.List; import org.onebusaway.geospatial.services.SphericalGeometryLibrary; import org.onebusaway.transit_data_federation.impl.otp.graph.AbstractBlockVertex; import org.onebusaway.transit_data_federation.impl.otp.graph.TransitVertex; import org.onebusaway.transit_data_federation.services.blocks.BlockInstance; import org.onebusaway.transit_data_federation.services.realtime.ArrivalAndDepartureInstance; import org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry; import org.onebusaway.transit_data_federation.services.transit_graph.BlockStopTimeEntry; import org.onebusaway.transit_data_federation.services.transit_graph.StopEntry; import org.onebusaway.transit_data_federation.services.transit_graph.StopTimeEntry; import org.opentripplanner.routing.algorithm.strategies.RemainingWeightHeuristic; import org.opentripplanner.routing.core.EdgeNarrative; import org.opentripplanner.routing.core.State; import org.opentripplanner.routing.core.TraverseOptions; import org.opentripplanner.routing.core.Vertex; public class RemainingWeightHeuristicImpl implements RemainingWeightHeuristic { private TraverseOptions _options; private boolean _useTransit; /** * assume that the max average transit speed over a hop is 10 m/s, which is so * far true for New York and Portland */ private double _maxTransitSpeed = 10.0; @Override public void reset() { _options = null; _useTransit = false; } @Override public double computeInitialWeight(State s, Vertex target) { _options = s.getOptions(); _useTransit = _options.getModes().getTransit(); double maxSpeed = getMaxSpeed(); return distance(s.getVertex(), target) / maxSpeed; } @Override public double computeForwardWeight(State s, Vertex target) { EdgeNarrative narrative = s.getBackEdgeNarrative(); Vertex v = narrative.getToVertex(); return computeWeight(s, target, v); } @Override public double computeReverseWeight(State s, Vertex target) { EdgeNarrative narrative = s.getBackEdgeNarrative(); Vertex v = narrative.getFromVertex(); return computeWeight(s, target, v); } /**** * Private Methods ****/ private double computeWeight(State state, Vertex target, Vertex v) { OBAState obaState = (OBAState) state; if (obaState.getMaxBlockSequence() >= 0 && v instanceof AbstractBlockVertex) { AbstractBlockVertex abv = (AbstractBlockVertex) v; ArrivalAndDepartureInstance instance = abv.getInstance(); BlockInstance blockInstance = instance.getBlockInstance(); BlockConfigurationEntry blockConfig = blockInstance.getBlock(); List<BlockStopTimeEntry> stopTimes = blockConfig.getStopTimes(); int maxBlockSequence = Math.min(obaState.getMaxBlockSequence(), stopTimes.size()); BlockStopTimeEntry blockStopTime = instance.getBlockStopTime(); int sequence = blockStopTime.getBlockSequence(); StopTimeEntry origStopTime = blockStopTime.getStopTime(); double minTime = Double.POSITIVE_INFINITY; while (sequence < maxBlockSequence) { blockStopTime = stopTimes.get(sequence); StopTimeEntry stopTime = blockStopTime.getStopTime(); StopEntry stop = stopTime.getStop(); double d = SphericalGeometryLibrary.distance(stop.getStopLat(), stop.getStopLon(), target.getY(), target.getX()); double transitTime = Math.max(0, stopTime.getArrivalTime() - origStopTime.getDepartureTime()); double walkingTime = d / _options.speed; minTime = Math.min(minTime, transitTime + walkingTime); sequence++; } if (!Double.isInfinite(minTime)) return minTime; } /* * if (v instanceof HasStopTransitVertex) { HasStopTransitVertex hasStop = * (HasStopTransitVertex) v; StopEntry stop = hasStop.getStop(); if * (_heuristic == null) { GraphContext context = hasStop.getContext(); * _heuristic = new MinTravelTimeUsingTransitHeuristic(target, _options, * context, _maxTransitSpeed); } * * int travelTime = _heuristic.getMinTravelTimeFromStopToTarget(stop); * * if (travelTime >= 0) return travelTime; } */ double distanceEstimate = distance(v, target); double maxSpeed = getMaxSpeedForCurrentState(state, v); return distanceEstimate / maxSpeed; } private double getMaxSpeed() { if (!_useTransit) return _options.speed; return _maxTransitSpeed; } private double getMaxSpeedForCurrentState(State state, Vertex v) { /** * If we can't use transit at all, just use our walking speed */ if (!_useTransit) return _options.speed; /** * If we've ever boarded a transit vehicle, but are now off transit, we can * guarantee that we'll never get back on transit. Thus, we can assume * walking speed as our max velocity. */ if (state.isEverBoarded() && !(v instanceof TransitVertex)) return _options.speed; return _maxTransitSpeed; } private double distance(Vertex a, Vertex b) { return SphericalGeometryLibrary.distance(a.getY(), a.getX(), b.getY(), b.getX()); } }