/* 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.analyst.request; import java.util.List; import javax.annotation.PostConstruct; import org.opentripplanner.analyst.core.Sample; import org.opentripplanner.analyst.core.SampleSource; import org.opentripplanner.routing.graph.Edge; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graph.Vertex; import org.opentripplanner.routing.services.GraphService; import org.opentripplanner.routing.vertextype.StreetVertex; import org.opentripplanner.common.IterableLibrary; import org.opentripplanner.common.geometry.HashGrid; import org.opentripplanner.common.geometry.HashGrid.RasterizedSegment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.vividsolutions.jts.geom.Coordinate; public class HashGridSampler implements SampleSource { private static final Logger LOG = LoggerFactory.getLogger(HashGridSampler.class); private static final double SEARCH_RADIUS_M = 100; @Autowired private GraphService graphService; private HashGrid index; @PostConstruct public void initialize() { index = new HashGrid(50, 2000, 2000); Graph graph = graphService.getGraph(); LOG.debug("Rasterizing streets into index..."); for (StreetVertex vertex : IterableLibrary.filter(graph.getVertices(), StreetVertex.class)) { for (Edge e: vertex.getOutgoing()) { index.rasterize(e.getGeometry(), e); } } LOG.debug("Done rasterizing streets into index."); //System.out.println(index.densityMap()); } @Override /** implements SampleSource interface */ public Sample getSample(double lon, double lat) { Coordinate coord = new Coordinate(lon, lat); // Point p = geometryFactory.createPoint(c); // track best two turn vertices RasterizedSegment s0 = null; RasterizedSegment s1 = null; Coordinate c0 = null; Coordinate c1 = null; double d0 = Double.MAX_VALUE; double d1 = Double.MAX_VALUE; // query List<Object> os = index.query(lon, lat, SEARCH_RADIUS_M); // query always returns a (possibly empty) list, but never null. // find two closest among nearby geometries for (Object o : os) { RasterizedSegment s = (RasterizedSegment) o; // inspired by a private method buried deep in JTS DistanceOp Coordinate c = s.closestPoint(coord); //double d = DistanceLibrary.fastDistance(c, coord); double d = c.distance(coord); if (d > SEARCH_RADIUS_M) continue; if (d < d1) { if (d < d0) { s1 = s0; c1 = c0; d1 = d0; s0 = s; c0 = c; d0 = d; } else { s1 = s; c1 = c; d1 = d; } } } // if at least one segment was found make a sample if (s0 != null) { int t0 = timeToVertex(s0, c0, d0); int t1 = timeToVertex(s1, c1, d1); Sample s = new Sample((Vertex)s0.payload, t0, (Vertex)s1.payload, t1); return s; } return null; } private static int timeToVertex(RasterizedSegment segment, Coordinate coordOnSegment, double distToSegment) { if (segment == null) return -1; double distOnSegment = segment.p0.distance(coordOnSegment); double dist = distOnSegment + distToSegment + segment.distAlongLinestring; int t = (int) (dist / 1.33); return t; } }