/* * Licensed to GraphHopper GmbH under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * GraphHopper GmbH licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.graphhopper.matching; import com.graphhopper.GraphHopper; import com.graphhopper.PathWrapper; import com.graphhopper.reader.osm.GraphHopperOSM; import com.graphhopper.routing.AlgorithmOptions; import com.graphhopper.routing.Path; import com.graphhopper.routing.util.FlagEncoder; import com.graphhopper.routing.util.HintsMap; import com.graphhopper.routing.weighting.FastestWeighting; import com.graphhopper.util.*; import com.graphhopper.util.shapes.BBox; import java.io.File; import java.io.FilenameFilter; import java.util.Collections; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Peter Karich */ public class MapMatchingMain { public static void main(String[] args) { new MapMatchingMain().start(CmdArgs.read(args)); } private final Logger logger = LoggerFactory.getLogger(getClass()); private void start(CmdArgs args) { String action = args.get("action", "").toLowerCase(); args.put("graph.location", "./graph-cache"); if (action.equals("import")) { String flagEncoders = args.get("vehicle", "").toLowerCase(); if (flagEncoders.isEmpty()) { flagEncoders = args.get("vehicles", "car").toLowerCase(); } args.put("graph.flag_encoders", flagEncoders); args.put("datareader.file", args.get("datasource", "")); // standard should be to remove disconnected islands if (!args.has("prepare.min_one_way_network_size")) { args.put("prepare.min_one_way_network_size", 200); } logger.info("Configuration: " + args); GraphHopper hopper = new GraphHopperOSM().init(args); hopper.getCHFactoryDecorator().setEnabled(false); hopper.importOrLoad(); } else if (action.equals("match")) { GraphHopper hopper = new GraphHopperOSM().init(args); hopper.getCHFactoryDecorator().setEnabled(false); logger.info("loading graph from cache"); hopper.load("./graph-cache"); FlagEncoder firstEncoder = hopper.getEncodingManager().fetchEdgeEncoders().get(0); int gpsAccuracy = args.getInt("gps_accuracy", -1); if (gpsAccuracy < 0) { // backward compatibility since 0.8 gpsAccuracy = args.getInt("gpx_accuracy", 40); } String instructions = args.get("instructions", ""); logger.info("Setup lookup index. Accuracy filter is at " + gpsAccuracy + "m"); AlgorithmOptions opts = AlgorithmOptions.start(). algorithm(Parameters.Algorithms.DIJKSTRA_BI).traversalMode(hopper.getTraversalMode()). weighting(new FastestWeighting(firstEncoder)). maxVisitedNodes(args.getInt("max_visited_nodes", 1000)). // Penalizing inner-link U-turns only works with fastest weighting, since // shortest weighting does not apply penalties to unfavored virtual edges. hints(new HintsMap().put("weighting", "fastest").put("vehicle", firstEncoder.toString())). build(); MapMatching mapMatching = new MapMatching(hopper, opts); mapMatching.setTransitionProbabilityBeta(args.getDouble ("transition_probability_beta", 2.0)); mapMatching.setMeasurementErrorSigma(gpsAccuracy); // do the actual matching, get the GPX entries from a file or via stream String gpxLocation = args.get("gpx", ""); File[] files = getFiles(gpxLocation); logger.info("Now processing " + files.length + " files"); StopWatch importSW = new StopWatch(); StopWatch matchSW = new StopWatch(); Translation tr = new TranslationMap().doImport().get(instructions); for (File gpxFile : files) { try { importSW.start(); List<GPXEntry> inputGPXEntries = new GPXFile().doImport(gpxFile.getAbsolutePath()).getEntries(); importSW.stop(); matchSW.start(); MatchResult mr = mapMatching.doWork(inputGPXEntries); matchSW.stop(); System.out.println(gpxFile); System.out.println("\tmatches:\t" + mr.getEdgeMatches().size() + ", gps entries:" + inputGPXEntries.size()); System.out.println("\tgpx length:\t" + (float) mr.getGpxEntriesLength() + " vs " + (float) mr.getMatchLength()); System.out.println("\tgpx time:\t" + mr.getGpxEntriesMillis() / 1000f + " vs " + mr.getMatchMillis() / 1000f); String outFile = gpxFile.getAbsolutePath() + ".res.gpx"; System.out.println("\texport results to:" + outFile); InstructionList il; if (instructions.isEmpty()) { il = new InstructionList(null); } else { PathWrapper matchGHRsp = new PathWrapper(); Path path = mapMatching.calcPath(mr); new PathMerger().doWork(matchGHRsp, Collections.singletonList(path), tr); il = matchGHRsp.getInstructions(); } new GPXFile(mr, il).doExport(outFile); } catch (Exception ex) { importSW.stop(); matchSW.stop(); logger.error("Problem with file " + gpxFile + " Error: " + ex.getMessage(), ex); } } System.out.println("gps import took:" + importSW.getSeconds() + "s, match took: " + matchSW.getSeconds()); } else if (action.equals("getbounds")) { String gpxLocation = args.get("gpx", ""); File[] files = getFiles(gpxLocation); BBox bbox = BBox.createInverse(false); for (File gpxFile : files) { List<GPXEntry> inputGPXEntries = new GPXFile().doImport(gpxFile.getAbsolutePath()).getEntries(); for (GPXEntry entry : inputGPXEntries) { bbox.update(entry.getLat(), entry.getLon()); } } System.out.println("max bounds: " + bbox); // show download only for small areas if (bbox.maxLat - bbox.minLat < 0.1 && bbox.maxLon - bbox.minLon < 0.1) { double delta = 0.01; System.out.println("Get small areas via\n" + "wget -O extract.osm 'http://overpass-api.de/api/map?bbox=" + (bbox.minLon - delta) + "," + (bbox.minLat - delta) + "," + (bbox.maxLon + delta) + "," + (bbox.maxLat + delta) + "'"); } } else { System.out.println("Usage: Do an import once, then do the matching\n" + "./map-matching action=import datasource=your.pbf\n" + "./map-matching action=match gpx=your.gpx\n" + "./map-matching action=match gpx=.*gpx\n\n" + "Or start in-built matching web service\n" + "./map-matching action=start-server\n\n"); } } File[] getFiles(String gpxLocation) { if (gpxLocation.contains("*")) { int lastIndex = gpxLocation.lastIndexOf(File.separator); final String pattern; File dir = new File("."); if (lastIndex >= 0) { dir = new File(gpxLocation.substring(0, lastIndex)); pattern = gpxLocation.substring(lastIndex + 1); } else { pattern = gpxLocation; } return dir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.matches(pattern); } }); } else { return new File[]{ new File(gpxLocation) }; } } }