/* 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.graph_builder.impl.map; import java.util.ArrayList; import java.util.List; import org.opentripplanner.common.geometry.DistanceLibrary; import org.opentripplanner.common.geometry.SphericalDistanceLibrary; import org.opentripplanner.routing.core.State; import org.opentripplanner.routing.core.TraverseMode; import org.opentripplanner.routing.core.RoutingRequest; import org.opentripplanner.routing.edgetype.StreetEdge; import org.opentripplanner.routing.graph.Edge; import org.opentripplanner.routing.graph.Vertex; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.linearref.LinearLocation; public abstract class MatchState { private static final RoutingRequest traverseOptions = new RoutingRequest(TraverseMode.CAR); protected static final double NEW_SEGMENT_PENALTY = 0.1; protected static final double NO_TRAVERSE_PENALTY = 20; private static DistanceLibrary distanceLibrary = SphericalDistanceLibrary.getInstance(); public double currentError; public double accumulatedError; public MatchState parent; protected Edge edge; private double distanceAlongRoute = 0; public MatchState(MatchState parent, Edge edge, double distanceAlongRoute) { this.distanceAlongRoute = distanceAlongRoute; this.parent = parent; this.edge = edge; if (parent != null) { this.accumulatedError = parent.accumulatedError + parent.currentError; this.distanceAlongRoute += parent.distanceAlongRoute; } } public abstract List<MatchState> getNextStates(); public Edge getEdge() { return edge; } public double getTotalError() { return accumulatedError + currentError; } protected boolean carsCanTraverse(Edge edge) { // should be done with a method on edge (canTraverse already exists on turnEdge) State s0 = new State(edge.getFromVertex(), traverseOptions); State s1 = edge.traverse(s0); return s1 != null; } protected List<Edge> getOutgoingMatchableEdges(Vertex vertex) { List<Edge> edges = new ArrayList<Edge>(); for (Edge e : vertex.getOutgoing()) { if (!(e instanceof StreetEdge)) continue; if (e.getGeometry() == null) continue; edges.add(e); } return edges; } public double getDistanceAlongRoute() { return distanceAlongRoute; } /* computes the distance, in meters, along a geometry */ protected static double distanceAlongGeometry(Geometry geometry, LinearLocation startIndex, LinearLocation endIndex) { if (endIndex == null) { endIndex = LinearLocation.getEndLocation(geometry); } double total = 0; LinearIterator it = new LinearIterator(geometry, startIndex); LinearLocation index = startIndex; Coordinate previousCoordinate = startIndex.getCoordinate(geometry); it.next(); index = it.getLocation(); while (index.compareTo(endIndex) < 0) { Coordinate thisCoordinate = index.getCoordinate(geometry); double distance = distanceLibrary.fastDistance(previousCoordinate, thisCoordinate); total += distance; previousCoordinate = thisCoordinate; if (!it.hasNext()) break; it.next(); index = it.getLocation(); } //now, last bit of last segment Coordinate finalCoordinate = endIndex.getCoordinate(geometry); total += distanceLibrary.distance(previousCoordinate, finalCoordinate); return total; } protected static double distance(Coordinate from, Coordinate to) { return distanceLibrary.fastDistance(from, to); } }