/* 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.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.opentripplanner.common.geometry.DistanceLibrary; import org.opentripplanner.common.geometry.SphericalDistanceLibrary; import org.opentripplanner.graph_builder.services.GraphBuilder; import org.opentripplanner.routing.graph.Edge; import org.opentripplanner.routing.graph.Graph; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vividsolutions.jts.geom.LineString; /** * Print statistics on geometry data for a graph (number of geometry, average number of points, size * distribution, etc...) */ public class GeometryStatisticsGraphBuilderImpl 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(GeometryStatisticsGraphBuilderImpl.class); @Override public void buildGraph(Graph graph, HashMap<Class<?>, Object> extra) { int nGeometry = 0; int nPoints = 0; Map<Integer, AtomicInteger> lenDistribution = new HashMap<Integer, AtomicInteger>(); Map<Integer, AtomicInteger> nptDistribution = new HashMap<Integer, AtomicInteger>(); int maxNptCount = 0; int maxLenCount = 0; for (Edge e : graph.getEdges()) { if (e.getGeometry() != null) { LineString geometry = e.getGeometry(); // Number of points nGeometry++; int n = geometry.getNumPoints(); nPoints += n; AtomicInteger nptCount = nptDistribution.get(n); if (nptCount == null) { nptCount = new AtomicInteger(0); nptDistribution.put(n, nptCount); } if (nptCount.addAndGet(1) > maxNptCount) maxNptCount = nptCount.get(); // Length double lenMeters = distanceLibrary.fastLength(geometry); int lenSlot = (int) Math.round(Math.log(lenMeters) * 2); AtomicInteger lenCount = lenDistribution.get(lenSlot); if (lenCount == null) { lenCount = new AtomicInteger(0); lenDistribution.put(lenSlot, lenCount); } if (lenCount.addAndGet(1) > maxLenCount) maxLenCount = lenCount.get(); } } LOG.info(String.format( "Graph contains %d geometries, total %d points, average %.02f points/geometry.", nGeometry, nPoints, nPoints * 1.0 / nGeometry)); LOG.info("Number of geometry per geometry length (log scale):"); List<Integer> lenSlots = new ArrayList<Integer>(lenDistribution.keySet()); Collections.sort(lenSlots); for (int lenSlot : lenSlots) { double minLen = Math.exp(lenSlot / 2.0); double maxLen = Math.exp((lenSlot + 1) / 2.0); LOG.info(String.format("%9.03f-%9.03f m : %s %d", minLen, maxLen, chart(lenDistribution.get(lenSlot).get(), maxLenCount, 60), lenDistribution .get(lenSlot).get())); } LOG.info("Number of geometry per number of points (linear scale):"); List<Integer> nptSlots = new ArrayList<Integer>(nptDistribution.keySet()); Collections.sort(nptSlots); for (int nptSlot : nptSlots) { LOG.info(String.format("%d : %s %d", nptSlot, chart(nptDistribution.get(nptSlot).get(), maxNptCount, 60), nptDistribution .get(nptSlot).get())); } } private String chart(int x, int xMax, int len) { StringBuffer retval = new StringBuffer(); for (int i = 0; i < Math.round(x * 1.0 * len / xMax); i++) retval.append("*"); return retval.toString(); } @Override public void checkInputs() { // no inputs to check } }