/* 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; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import org.opentripplanner.common.geometry.DistanceLibrary; import org.opentripplanner.common.geometry.SphericalDistanceLibrary; import org.opentripplanner.gbannotation.BogusEdgeGeometry; import org.opentripplanner.gbannotation.BogusVertexGeometry; import org.opentripplanner.gbannotation.VertexShapeError; import org.opentripplanner.graph_builder.services.GraphBuilder; import org.opentripplanner.routing.edgetype.HopEdge; import org.opentripplanner.routing.graph.Edge; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graph.Vertex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; /** * Check the geometry of every edge in the graph for any bogus geometry -- * that is, geometry with coordinates of NaN. * This is mainly good for debugging, but probably worth keeping on for production * because the cost is small compared to the pain of debugging. */ public class CheckGeometryGraphBuilderImpl implements GraphBuilder { private DistanceLibrary distanceLibrary = SphericalDistanceLibrary.getInstance(); /** An set of ids which identifies what stages this graph builder provides (i.e. streets, elevation, transit) */ public List<String> provides() { return Collections.emptyList(); } /** A list of ids of stages which must be provided before this stage */ public List<String> getPrerequisites() { return Arrays.asList("streets"); } private static final Logger LOG = LoggerFactory.getLogger(CheckGeometryGraphBuilderImpl.class); private static final double MAX_VERTEX_SHAPE_ERROR = 150; @Override public void buildGraph(Graph graph, HashMap<Class<?>, Object> extra) { for (Vertex gv : graph.getVertices()) { if (Double.isNaN(gv.getCoordinate().x) || Double.isNaN(gv.getCoordinate().y)) { LOG.warn("Vertex " + gv + " has NaN location; this will cause doom."); LOG.warn(graph.addBuilderAnnotation(new BogusVertexGeometry(gv))); } // TODO: This was filtered to EdgeNarratives before EdgeNarrative removal for (Edge e : gv.getOutgoing()) { Geometry g = e.getGeometry(); if (g == null) { continue; } for (Coordinate c : g.getCoordinates()) { if (Double.isNaN(c.x) || Double.isNaN(c.y)) { LOG.warn(graph.addBuilderAnnotation(new BogusEdgeGeometry(e))); } } if (e instanceof HopEdge) { Coordinate edgeStartCoord = e.getFromVertex().getCoordinate(); Coordinate edgeEndCoord = e.getToVertex().getCoordinate(); Coordinate[] geometryCoordinates = g.getCoordinates(); if (geometryCoordinates.length < 2) { LOG.warn(graph.addBuilderAnnotation(new BogusEdgeGeometry(e))); continue; } Coordinate geometryStartCoord = geometryCoordinates[0]; Coordinate geometryEndCoord = geometryCoordinates[geometryCoordinates.length - 1]; if (getDistanceLibrary().distance(edgeStartCoord, geometryStartCoord) > MAX_VERTEX_SHAPE_ERROR) { LOG.warn(graph.addBuilderAnnotation(new VertexShapeError(e))); } else if (getDistanceLibrary().distance(edgeEndCoord, geometryEndCoord) > MAX_VERTEX_SHAPE_ERROR) { LOG.warn(graph.addBuilderAnnotation(new VertexShapeError(e))); } } } } } @Override public void checkInputs() { //no inputs to check } public DistanceLibrary getDistanceLibrary() { return distanceLibrary; } public void setDistanceLibrary(DistanceLibrary distanceLibrary) { this.distanceLibrary = distanceLibrary; } }