/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package org.opentripplanner.routing.core;
import lombok.Setter;
import org.opentripplanner.routing.edgetype.PlainStreetEdge;
import org.opentripplanner.routing.vertextype.IntersectionVertex;
/**
* Abstract turn cost model provides various methods most implementations will use.
*
* @author avi
*/
public abstract class AbstractIntersectionTraversalCostModel implements
IntersectionTraversalCostModel {
/** Factor by which absolute turn angles are divided to get turn costs for non-driving scenarios. */
@Setter
protected Double nonDrivingTurnCostFactor = 1.0 / 20.0;
@Setter
protected Integer minRightTurnAngle = 45;
@Setter
protected Integer maxRightTurnAngle = 135;
@Setter
protected Integer minLeftTurnAngle = 225;
@Setter
protected Integer maxLeftTurnAngle = 315;
/** Returns true if this angle represents a right turn. */
protected boolean isRightTurn(int turnAngle) {
return (turnAngle >= minRightTurnAngle && turnAngle < maxRightTurnAngle);
}
/** Returns true if this angle represents a left turn. */
protected boolean isLeftTurn(int turnAngle) {
return (turnAngle >= minLeftTurnAngle && turnAngle < maxLeftTurnAngle);
}
/**
* Computes the turn cost in seconds for non-driving traversal modes.
*
* TODO(flamholz): this should probably account for whether there is a traffic light?
*/
protected double computeNonDrivingTraversalCost(IntersectionVertex v, PlainStreetEdge from,
PlainStreetEdge to, float fromSpeed, float toSpeed) {
int outAngle = to.getOutAngle();
int inAngle = from.getInAngle();
int turnCost = Math.abs(outAngle - inAngle);
if (turnCost > 180) {
turnCost = 360 - turnCost;
}
// NOTE: This makes the turn cost lower the faster you're going
return (this.nonDrivingTurnCostFactor * turnCost) / toSpeed;
}
/**
* Calculates the turn angle from the incoming/outgoing edges and routing request.
*
* Corrects for the side of the street they are driving on.
*/
protected int calculateTurnAngle(PlainStreetEdge from, PlainStreetEdge to,
RoutingRequest options) {
int angleOutOfIntersection = to.getInAngle();
int angleIntoIntersection = from.getOutAngle();
// Put out to the right of in; i.e. represent everything as one long right turn
// Also ensures that turnAngle is always positive.
if (angleOutOfIntersection < angleIntoIntersection) {
angleOutOfIntersection += 360;
}
int turnAngle = angleOutOfIntersection - angleIntoIntersection;
if (!options.driveOnRight) {
turnAngle = 360 - turnAngle;
}
return turnAngle;
}
/* Concrete subclasses must implement this */
@Override
public abstract double computeTraversalCost(IntersectionVertex v, PlainStreetEdge from,
PlainStreetEdge to, TraverseMode mode, RoutingRequest options, float fromSpeed,
float toSpeed);
}