/* * 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.reader.osm; import com.carrotsearch.hppc.IntArrayList; import com.graphhopper.GHRequest; import com.graphhopper.GHResponse; import com.graphhopper.GraphHopper; import com.graphhopper.PathWrapper; import com.graphhopper.reader.DataReader; import com.graphhopper.routing.*; import com.graphhopper.routing.ch.CHAlgoFactoryDecorator; import com.graphhopper.routing.ch.PrepareContractionHierarchies; import com.graphhopper.routing.lm.LandmarkStorage; import com.graphhopper.routing.lm.PrepareLandmarks; import com.graphhopper.routing.util.*; import com.graphhopper.routing.weighting.AbstractWeighting; import com.graphhopper.routing.weighting.FastestWeighting; import com.graphhopper.routing.weighting.Weighting; import com.graphhopper.storage.*; import com.graphhopper.util.CmdArgs; import com.graphhopper.util.Helper; import com.graphhopper.util.Instruction; import com.graphhopper.util.Parameters; import com.graphhopper.util.Parameters.Routing; import com.graphhopper.util.shapes.GHPoint; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import static com.graphhopper.util.Parameters.Algorithms.DIJKSTRA; import static com.graphhopper.util.Parameters.Algorithms.DIJKSTRA_BI; import static org.junit.Assert.*; /** * @author Peter Karich */ public class GraphHopperOSMTest { private static final String ghLoc = "./target/tmp/ghosm"; private static final String testOsm = "./src/test/resources/com/graphhopper/reader/osm/test-osm.xml"; private static final String testOsm3 = "./src/test/resources/com/graphhopper/reader/osm/test-osm3.xml"; private GraphHopper instance; @Before public void setUp() { Helper.removeDir(new File(ghLoc)); } @After public void tearDown() { if (instance != null) instance.close(); Helper.removeDir(new File(ghLoc)); } @Test public void testLoadOSM() { GraphHopper closableInstance = new GraphHopperOSM(). setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); closableInstance.importOrLoad(); GHResponse rsp = closableInstance.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)); assertFalse(rsp.hasErrors()); assertEquals(3, rsp.getBest().getPoints().getSize()); closableInstance.close(); // no encoding manager necessary closableInstance = new GraphHopperOSM(). setStoreOnFlush(true); assertTrue(closableInstance.load(ghLoc)); rsp = closableInstance.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)); assertFalse(rsp.hasErrors()); assertEquals(3, rsp.getBest().getPoints().getSize()); closableInstance.close(); try { rsp = closableInstance.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)); assertTrue(false); } catch (Exception ex) { assertEquals("You need to create a new GraphHopper instance as it is already closed", ex.getMessage()); } try { closableInstance.getLocationIndex().findClosest(51.2492152, 9.4317166, EdgeFilter.ALL_EDGES); assertTrue(false); } catch (Exception ex) { assertEquals("You need to create a new LocationIndex instance as it is already closed", ex.getMessage()); } } @Test public void testLoadOSMNoCH() { GraphHopper gh = new GraphHopperOSM().setStoreOnFlush(true).setCHEnabled(false). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); gh.importOrLoad(); assertFalse(gh.getAlgorithmFactory(new HintsMap("fastest")) instanceof PrepareContractionHierarchies); GHResponse rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)); assertFalse(rsp.hasErrors()); assertEquals(3, rsp.getBest().getPoints().getSize()); gh.close(); gh = new GraphHopperOSM().setStoreOnFlush(true).setCHEnabled(false). setEncodingManager(new EncodingManager("car")); assertTrue(gh.load(ghLoc)); rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)); assertFalse(rsp.hasErrors()); assertEquals(3, rsp.getBest().getPoints().getSize()); gh.close(); gh = new GraphHopperOSM(). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm). init(new CmdArgs().put("graph.flag_encoders", "car").put(Parameters.CH.PREPARE + "weightings", "no")); assertFalse(gh.getAlgorithmFactory(new HintsMap("fastest")) instanceof PrepareContractionHierarchies); gh.close(); } @Test public void testLoadingWithDifferentCHConfig_issue471() { // with CH should not be loadable without CH configured GraphHopper gh = new GraphHopperOSM().setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); gh.importOrLoad(); GHResponse rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)); assertFalse(rsp.hasErrors()); assertEquals(3, rsp.getBest().getPoints().getSize()); gh.close(); gh = new GraphHopperOSM().setStoreOnFlush(true).setCHEnabled(false). setEncodingManager(new EncodingManager("car")); try { gh.load(ghLoc); assertTrue(false); } catch (Exception ex) { assertTrue(ex.getMessage(), ex.getMessage().startsWith("Configured graph.ch.weightings:")); } Helper.removeDir(new File(ghLoc)); // without CH should not be loadable with CH enabled gh = new GraphHopperOSM().setStoreOnFlush(true).setCHEnabled(false). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); gh.importOrLoad(); rsp = gh.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4)); assertFalse(rsp.hasErrors()); assertEquals(3, rsp.getBest().getPoints().getSize()); gh.close(); gh = new GraphHopperOSM().setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")); try { gh.load(ghLoc); assertTrue(false); } catch (Exception ex) { assertTrue(ex.getMessage(), ex.getMessage().startsWith("Configured graph.ch.weightings:")); } } @Test public void testAllowMultipleReadingInstances() { GraphHopper instance1 = new GraphHopperOSM().setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); instance1.importOrLoad(); GraphHopper instance2 = new GraphHopperOSM().setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setDataReaderFile(testOsm); instance2.load(ghLoc); GraphHopper instance3 = new GraphHopperOSM().setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setDataReaderFile(testOsm); instance3.load(ghLoc); instance1.close(); instance2.close(); instance3.close(); } @Test public void testDoNotAllowWritingAndLoadingAtTheSameTime() throws Exception { final CountDownLatch latch1 = new CountDownLatch(1); final CountDownLatch latch2 = new CountDownLatch(1); final GraphHopper instance1 = new GraphHopperOSM() { @Override protected DataReader importData() throws IOException { try { latch2.countDown(); latch1.await(3, TimeUnit.SECONDS); } catch (InterruptedException ex) { throw new RuntimeException(ex); } return super.importData(); } }.setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); final AtomicReference<Exception> ar = new AtomicReference<Exception>(); Thread thread = new Thread() { @Override public void run() { try { instance1.importOrLoad(); } catch (Exception ex) { ar.set(ex); } } }; thread.start(); GraphHopper instance2 = new GraphHopperOSM().setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setDataReaderFile(testOsm); try { // let thread reach the CountDownLatch latch2.await(3, TimeUnit.SECONDS); // now importOrLoad should have create a lock which this load call does not like instance2.load(ghLoc); assertTrue(false); } catch (RuntimeException ex) { assertNotNull(ex); assertTrue(ex.getMessage(), ex.getMessage().startsWith("To avoid reading partial data")); } finally { instance2.close(); latch1.countDown(); // make sure the import process wasn't interrupted and no other error happened thread.join(); } if (ar.get() != null) assertNull(ar.get().getMessage(), ar.get()); instance1.close(); } @Test public void testPrepare() { instance = new GraphHopperOSM(). setStoreOnFlush(false). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); instance.getCHFactoryDecorator().setWeightingsAsStrings("shortest"); instance.importOrLoad(); GHResponse rsp = instance.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4). setAlgorithm(DIJKSTRA_BI)); assertFalse(rsp.hasErrors()); assertEquals(Helper.createPointList(51.249215, 9.431716, 52.0, 9.0, 51.2, 9.4), rsp.getBest().getPoints()); assertEquals(3, rsp.getBest().getPoints().getSize()); } @Test public void testSortedGraph_noCH() { instance = new GraphHopperOSM().setStoreOnFlush(false). setSortGraph(true). setEncodingManager(new EncodingManager("car")).setCHEnabled(false). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); instance.importOrLoad(); PathWrapper rsp = instance.route(new GHRequest(51.2492152, 9.4317166, 51.2, 9.4). setAlgorithm(DIJKSTRA_BI)).getBest(); assertFalse(rsp.hasErrors()); assertEquals(3, rsp.getPoints().getSize()); assertEquals(new GHPoint(51.24921503475044, 9.431716451757769), rsp.getPoints().toGHPoint(0)); assertEquals(new GHPoint(52.0, 9.0), rsp.getPoints().toGHPoint(1)); assertEquals(new GHPoint(51.199999850988384, 9.39999970197677), rsp.getPoints().toGHPoint(2)); GHRequest req = new GHRequest(51.2492152, 9.4317166, 51.2, 9.4); boolean old = instance.isEnableInstructions(); req.getHints().put("instructions", true); instance.route(req); assertEquals(old, instance.isEnableInstructions()); req.getHints().put("instructions", false); instance.route(req); assertEquals("route method should not change instance field", old, instance.isEnableInstructions()); } @Test public void testFootAndCar() { // now all ways are imported instance = new GraphHopperOSM().setStoreOnFlush(false). setEncodingManager(new EncodingManager("car,foot")).setCHEnabled(false). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm3); instance.importOrLoad(); assertEquals(5, instance.getGraphHopperStorage().getNodes()); assertEquals(8, instance.getGraphHopperStorage().getAllEdges().getMaxId()); // A to D GHResponse grsp = instance.route(new GHRequest(11.1, 50, 11.3, 51).setVehicle("car")); assertFalse(grsp.hasErrors()); PathWrapper rsp = grsp.getBest(); assertEquals(3, rsp.getPoints().getSize()); // => found A and D assertEquals(50, rsp.getPoints().getLongitude(0), 1e-3); assertEquals(11.1, rsp.getPoints().getLatitude(0), 1e-3); assertEquals(51, rsp.getPoints().getLongitude(2), 1e-3); assertEquals(11.3, rsp.getPoints().getLatitude(2), 1e-3); // A to D not allowed for foot. But the location index will choose a node close to D accessible to FOOT grsp = instance.route(new GHRequest(11.1, 50, 11.3, 51).setVehicle("foot")); assertFalse(grsp.hasErrors()); rsp = grsp.getBest(); assertEquals(2, rsp.getPoints().getSize()); // => found a point on edge A-B assertEquals(11.680, rsp.getPoints().getLatitude(1), 1e-3); assertEquals(50.644, rsp.getPoints().getLongitude(1), 1e-3); // A to E only for foot grsp = instance.route(new GHRequest(11.1, 50, 10, 51).setVehicle("foot")); assertFalse(grsp.hasErrors()); rsp = grsp.getBest(); assertEquals(2, rsp.getPoints().size()); // A D E for car grsp = instance.route(new GHRequest(11.1, 50, 10, 51).setVehicle("car")); assertFalse(grsp.hasErrors()); rsp = grsp.getBest(); assertEquals(3, rsp.getPoints().getSize()); } @Test public void testFailsForWrongConfig() throws IOException { instance = new GraphHopperOSM().init( new CmdArgs(). put("datareader.file", testOsm3). put("datareader.dataaccess", "RAM"). put("graph.flag_encoders", "foot,car"). put(Parameters.CH.PREPARE + "weightings", "no")). setGraphHopperLocation(ghLoc); instance.importOrLoad(); assertEquals(5, instance.getGraphHopperStorage().getNodes()); instance.close(); // different config (flagEncoder list) try { GraphHopper tmpGH = new GraphHopperOSM().init( new CmdArgs(). put("datareader.file", testOsm3). put("datareader.dataaccess", "RAM"). put("graph.flag_encoders", "foot"). put(Parameters.CH.PREPARE + "weightings", "no")). setDataReaderFile(testOsm3); tmpGH.load(ghLoc); assertTrue(false); } catch (Exception ex) { assertTrue(ex.getMessage(), ex.getMessage().startsWith("Encoding does not match")); } // different bytesForFlags should fail to load instance = new GraphHopperOSM().init( new CmdArgs(). put("datareader.file", testOsm3). put("datareader.dataaccess", "RAM"). put("graph.flag_encoders", "foot,car"). put("graph.bytes_for_flags", 8). put(Parameters.CH.PREPARE + "weightings", "no")). setDataReaderFile(testOsm3); try { instance.load(ghLoc); assertTrue(false); } catch (Exception ex) { assertTrue(ex.getMessage(), ex.getMessage().startsWith("Configured graph.bytes_for_flags (8) is not equal to loaded 4")); } // different order is no longer okay, see #350 try { GraphHopper tmpGH = new GraphHopperOSM().init(new CmdArgs(). put("datareader.file", testOsm3). put("datareader.dataaccess", "RAM"). put(Parameters.CH.PREPARE + "weightings", "no"). put("graph.flag_encoders", "car,foot")). setDataReaderFile(testOsm3); tmpGH.load(ghLoc); assertTrue(false); } catch (Exception ex) { assertTrue(ex.getMessage(), ex.getMessage().startsWith("Encoding does not match")); } } @Test public void testNoNPE_ifLoadNotSuccessful() { instance = new GraphHopperOSM(). setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")); try { // loading from empty directory new File(ghLoc).mkdirs(); assertFalse(instance.load(ghLoc)); instance.route(new GHRequest(10, 40, 12, 32)); assertTrue(false); } catch (IllegalStateException ex) { assertEquals("Do a successful call to load or importOrLoad before routing", ex.getMessage()); } } @Test public void testDoesNotCreateEmptyFolderIfLoadingFromNonExistingPath() { instance = new GraphHopperOSM(). setEncodingManager(new EncodingManager("car")); assertFalse(instance.load(ghLoc)); assertFalse(new File(ghLoc).exists()); } @Test public void testFailsForMissingParameters() throws IOException { class GHTmp extends GraphHopperOSM { @Override public DataReader importData() throws IOException { return super.importData(); } } // missing load of graph GHTmp tmp = new GHTmp(); try { tmp.setDataReaderFile(testOsm); tmp.importData(); assertTrue(false); } catch (IllegalStateException ex) { assertEquals("Load graph before importing OSM data", ex.getMessage()); } // missing graph location instance = new GraphHopperOSM(); try { instance.importOrLoad(); assertTrue(false); } catch (IllegalStateException ex) { assertEquals("GraphHopperLocation is not specified. Call setGraphHopperLocation or init before", ex.getMessage()); } // missing OSM file to import instance = new GraphHopperOSM(). setStoreOnFlush(true). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc); try { instance.importOrLoad(); assertTrue(false); } catch (IllegalStateException ex) { assertEquals("Couldn't load from existing folder: " + ghLoc + " but also cannot use file for DataReader as it wasn't specified!", ex.getMessage()); } // missing encoding manager instance = new GraphHopperOSM(). setStoreOnFlush(true). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm3); try { instance.importOrLoad(); assertTrue(false); } catch (IllegalStateException ex) { assertTrue(ex.getMessage(), ex.getMessage().startsWith("Cannot load properties to fetch EncodingManager")); } // Import is possible even if no storeOnFlush is specified BUT here we miss the OSM file instance = new GraphHopperOSM(). setStoreOnFlush(false). setEncodingManager(new EncodingManager("car")). setGraphHopperLocation(ghLoc); try { instance.importOrLoad(); assertTrue(false); } catch (Exception ex) { assertEquals("Couldn't load from existing folder: " + ghLoc + " but also cannot use file for DataReader as it wasn't specified!", ex.getMessage()); } } @Test public void testFootOnly() { // now only footable ways are imported => no A D C and B D E => the other both ways have pillar nodes! instance = new GraphHopperOSM().setStoreOnFlush(false). setEncodingManager(new EncodingManager("foot")). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm3); instance.importOrLoad(); assertEquals(2, instance.getGraphHopperStorage().getNodes()); assertEquals(2, instance.getGraphHopperStorage().getAllEdges().getMaxId()); // A to E only for foot GHResponse grsp = instance.route(new GHRequest(11.1, 50, 11.19, 52).setVehicle("foot")); assertFalse(grsp.hasErrors()); PathWrapper rsp = grsp.getBest(); // the last points snaps to the edge assertEquals(Helper.createPointList(11.1, 50, 10, 51, 11.194015, 51.995013), rsp.getPoints()); } @Test public void testVia() { instance = new GraphHopperOSM().setStoreOnFlush(true). init(new CmdArgs(). put("datareader.file", testOsm3). put("prepare.min_network_size", "1"). put("graph.flag_encoders", "car")). setGraphHopperLocation(ghLoc); instance.importOrLoad(); // A -> B -> C GHPoint first = new GHPoint(11.1, 50); GHPoint second = new GHPoint(12, 51); GHPoint third = new GHPoint(11.2, 51.9); GHResponse rsp12 = instance.route(new GHRequest().addPoint(first).addPoint(second)); assertFalse("should find 1->2", rsp12.hasErrors()); assertEquals(147930.5, rsp12.getBest().getDistance(), .1); GHResponse rsp23 = instance.route(new GHRequest().addPoint(second).addPoint(third)); assertFalse("should find 2->3", rsp23.hasErrors()); assertEquals(176608.9, rsp23.getBest().getDistance(), .1); GHResponse grsp = instance.route(new GHRequest().addPoint(first).addPoint(second).addPoint(third)); assertFalse("should find 1->2->3", grsp.hasErrors()); PathWrapper rsp = grsp.getBest(); assertEquals(rsp12.getBest().getDistance() + rsp23.getBest().getDistance(), rsp.getDistance(), 1e-6); assertEquals(5, rsp.getPoints().getSize()); assertEquals(5, rsp.getInstructions().size()); assertEquals(Instruction.REACHED_VIA, rsp.getInstructions().get(1).getSign()); } @Test public void testGetPathsDirectionEnforcement1() { // Test enforce start direction // Note: This Test does not pass for CH enabled instance = createSquareGraphInstance(false); // Start in middle of edge 4-5 GHPoint start = new GHPoint(0.0015, 0.002); // End at middle of edge 2-3 GHPoint end = new GHPoint(0.002, 0.0005); GHRequest req = new GHRequest().addPoint(start, 180.).addPoint(end); GHResponse response = new GHResponse(); List<Path> paths = instance.calcPaths(req, response); assertFalse(response.hasErrors()); assertArrayEquals(new int[]{9, 5, 8, 3, 10}, paths.get(0).calcNodes().toArray()); } @Test public void testGetPathsDirectionEnforcement2() { // Test enforce south start direction and east end direction instance = createSquareGraphInstance(false); // Start in middle of edge 4-5 GHPoint start = new GHPoint(0.0015, 0.002); // End at middle of edge 2-3 GHPoint end = new GHPoint(0.002, 0.0005); GHRequest req = new GHRequest().addPoint(start, 180.).addPoint(end, 90.); GHResponse response = new GHResponse(); List<Path> paths = instance.calcPaths(req, response); assertFalse(response.hasErrors()); assertArrayEquals(new int[]{9, 5, 8, 1, 2, 10}, paths.get(0).calcNodes().toArray()); // Test uni-directional case req.setAlgorithm(DIJKSTRA); response = new GHResponse(); paths = instance.calcPaths(req, response); assertFalse(response.hasErrors()); assertArrayEquals(new int[]{9, 5, 8, 1, 2, 10}, paths.get(0).calcNodes().toArray()); } @Test public void testGetPathsDirectionEnforcement3() { instance = createSquareGraphInstance(false); // Start in middle of edge 4-5 GHPoint start = new GHPoint(0.0015, 0.002); // End at middle of edge 2-3 GHPoint end = new GHPoint(0.002, 0.0005); // Via Point betweeen 8-7 GHPoint via = new GHPoint(0.0005, 0.001); GHRequest req = new GHRequest().addPoint(start).addPoint(via, 0.).addPoint(end); GHResponse response = new GHResponse(); List<Path> paths = instance.calcPaths(req, response); assertFalse(response.hasErrors()); assertEquals(IntArrayList.from(9, 5, 6, 7, 11), paths.get(0).calcNodes()); } @Test public void testGetPathsDirectionEnforcement4() { // Test straight via routing instance = createSquareGraphInstance(false); // Start in middle of edge 4-5 GHPoint start = new GHPoint(0.0015, 0.002); // End at middle of edge 2-3 GHPoint end = new GHPoint(0.002, 0.0005); // Via Point betweeen 8-3 GHPoint via = new GHPoint(0.0015, 0.001); GHRequest req = new GHRequest().addPoint(start).addPoint(via).addPoint(end); req.getHints().put(Routing.PASS_THROUGH, true); GHResponse response = new GHResponse(); List<Path> paths = instance.calcPaths(req, response); assertFalse(response.hasErrors()); assertEquals(1, response.getAll().size()); assertEquals(IntArrayList.from(9, 4, 3, 10), paths.get(0).calcNodes()); assertEquals(IntArrayList.from(10, 8, 1, 2, 11), paths.get(1).calcNodes()); } @Test public void testGetPathsDirectionEnforcement5() { // Test independence of previous enforcement for subsequent pathes instance = createSquareGraphInstance(false); // Start in middle of edge 4-5 GHPoint start = new GHPoint(0.0015, 0.002); // End at middle of edge 2-3 GHPoint end = new GHPoint(0.002, 0.0005); // First go south and than come from west to via-point at 7-6. Then go back over previously punished (11)-4 edge GHPoint via = new GHPoint(0.000, 0.0015); GHRequest req = new GHRequest().addPoint(start, 0.).addPoint(via, 3.14 / 2).addPoint(end); req.getHints().put(Routing.PASS_THROUGH, true); GHResponse response = new GHResponse(); List<Path> paths = instance.calcPaths(req, response); assertFalse(response.hasErrors()); assertEquals(IntArrayList.from(9, 4, 3, 8, 7, 11), paths.get(0).calcNodes()); assertEquals(IntArrayList.from(11, 6, 5, 9, 4, 3, 10), paths.get(1).calcNodes()); } @Test public void testGetPathsDirectionEnforcement6() { // Test if query results at tower nodes are ignored instance = createSquareGraphInstance(false); // QueryPoints directly on TowerNodes GHPoint start = new GHPoint(0, 0); GHPoint via = new GHPoint(0.002, 0.000); GHPoint end = new GHPoint(0.002, 0.002); GHRequest req = new GHRequest().addPoint(start, 90.).addPoint(via, 270.).addPoint(end, 270.); GHResponse response = new GHResponse(); List<Path> paths = instance.calcPaths(req, response); assertFalse(response.hasErrors()); assertArrayEquals(new int[]{0, 1, 2}, paths.get(0).calcNodes().toArray()); assertArrayEquals(new int[]{2, 3, 4}, paths.get(1).calcNodes().toArray()); } private GraphHopper createSquareGraphInstance(boolean withCH) { CarFlagEncoder carEncoder = new CarFlagEncoder(); EncodingManager encodingManager = new EncodingManager(carEncoder); Weighting weighting = new FastestWeighting(carEncoder); GraphHopperStorage g = new GraphHopperStorage(Collections.singletonList(weighting), new RAMDirectory(), encodingManager, false, new GraphExtension.NoOpExtension()). create(20); // 2---3---4 // / | \ // 1----8----5 // / | / // 0----7---6 NodeAccess na = g.getNodeAccess(); na.setNode(0, 0.000, 0.000); na.setNode(1, 0.001, 0.000); na.setNode(2, 0.002, 0.000); na.setNode(3, 0.002, 0.001); na.setNode(4, 0.002, 0.002); na.setNode(5, 0.001, 0.002); na.setNode(6, 0.000, 0.002); na.setNode(7, 0.000, 0.001); na.setNode(8, 0.001, 0.001); g.edge(0, 1, 100, true); g.edge(1, 2, 100, true); g.edge(2, 3, 100, true); g.edge(3, 4, 100, true); g.edge(4, 5, 100, true); g.edge(5, 6, 100, true); g.edge(6, 7, 100, true); g.edge(7, 0, 100, true); g.edge(1, 8, 110, true); g.edge(3, 8, 110, true); g.edge(5, 8, 110, true); g.edge(7, 8, 110, true); GraphHopper tmp = new GraphHopperOSM(). setCHEnabled(withCH). setEncodingManager(encodingManager); tmp.getCHFactoryDecorator().setWeightingsAsStrings("fastest"); tmp.setGraphHopperStorage(g); tmp.postProcessing(); return tmp; } @Test public void testCustomFactoryForNoneCH() { CarFlagEncoder carEncoder = new CarFlagEncoder(); EncodingManager em = new EncodingManager(carEncoder); // Weighting weighting = new FastestWeighting(carEncoder); instance = new GraphHopperOSM().setStoreOnFlush(false).setCHEnabled(false). setEncodingManager(em). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); final RoutingAlgorithmFactory af = new RoutingAlgorithmFactorySimple(); instance.addAlgorithmFactoryDecorator(new RoutingAlgorithmFactoryDecorator() { @Override public void init(CmdArgs args) { } @Override public RoutingAlgorithmFactory getDecoratedAlgorithmFactory(RoutingAlgorithmFactory algoFactory, HintsMap map) { return af; } @Override public boolean isEnabled() { return true; } }); instance.importOrLoad(); assertTrue(af == instance.getAlgorithmFactory(null)); // test that hints are passed to algorithm opts final AtomicInteger cnt = new AtomicInteger(0); instance.addAlgorithmFactoryDecorator(new RoutingAlgorithmFactoryDecorator() { @Override public void init(CmdArgs args) { } public RoutingAlgorithmFactory getDecoratedAlgorithmFactory(RoutingAlgorithmFactory algoFactory, HintsMap map) { return new RoutingAlgorithmFactorySimple() { @Override public RoutingAlgorithm createAlgo(Graph g, AlgorithmOptions opts) { cnt.addAndGet(1); assertFalse(opts.getHints().getBool("test", true)); return super.createAlgo(g, opts); } }; } @Override public boolean isEnabled() { return true; } }); GHRequest req = new GHRequest(51.2492152, 9.4317166, 51.2, 9.4); req.getHints().put("test", false); instance.route(req); assertEquals(1, cnt.get()); } @Test public void testMultipleCHPreparationsInParallel() { HashMap<String, Integer> shortcutCountMap = new HashMap<String, Integer>(); // try all parallelization modes for (int threadCount = 1; threadCount < 6; threadCount++) { EncodingManager em = new EncodingManager(Arrays.asList(new CarFlagEncoder(), new MotorcycleFlagEncoder(), new MountainBikeFlagEncoder(), new RacingBikeFlagEncoder(), new FootFlagEncoder()), 8); GraphHopper tmpGH = new GraphHopperOSM(). setStoreOnFlush(false). setEncodingManager(em). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); tmpGH.getCHFactoryDecorator().setPreparationThreads(threadCount); tmpGH.importOrLoad(); assertEquals(5, tmpGH.getCHFactoryDecorator().getPreparations().size()); for (RoutingAlgorithmFactory raf : tmpGH.getCHFactoryDecorator().getPreparations()) { PrepareContractionHierarchies pch = (PrepareContractionHierarchies) raf; assertTrue("Preparation wasn't run! [" + threadCount + "]", pch.isPrepared()); String name = AbstractWeighting.weightingToFileName(pch.getWeighting()); Integer singleThreadShortcutCount = shortcutCountMap.get(name); if (singleThreadShortcutCount == null) shortcutCountMap.put(name, pch.getShortcuts()); else assertEquals((int) singleThreadShortcutCount, pch.getShortcuts()); String keyError = Parameters.CH.PREPARE + "error." + name; String valueError = tmpGH.getGraphHopperStorage().getProperties().get(keyError); assertTrue("Properties for " + name + " should NOT contain error " + valueError + " [" + threadCount + "]", valueError.isEmpty()); String key = Parameters.CH.PREPARE + "date." + name; String value = tmpGH.getGraphHopperStorage().getProperties().get(key); assertTrue("Properties for " + name + " did NOT contain finish date [" + threadCount + "]", !value.isEmpty()); } tmpGH.close(); } } @Test public void testMultipleLMPreparationsInParallel() { HashMap<String, Integer> landmarkCount = new HashMap<String, Integer>(); // try all parallelization modes for (int threadCount = 1; threadCount < 6; threadCount++) { EncodingManager em = new EncodingManager(Arrays.asList(new CarFlagEncoder(), new MotorcycleFlagEncoder(), new MountainBikeFlagEncoder(), new RacingBikeFlagEncoder(), new FootFlagEncoder()), 8); GraphHopper tmpGH = new GraphHopperOSM(). setStoreOnFlush(false). setCHEnabled(false). setEncodingManager(em). setGraphHopperLocation(ghLoc). setDataReaderFile(testOsm); tmpGH.getLMFactoryDecorator(). addWeighting("fastest"). setEnabled(true). setPreparationThreads(threadCount); tmpGH.importOrLoad(); assertEquals(5, tmpGH.getLMFactoryDecorator().getPreparations().size()); for (PrepareLandmarks prepLM : tmpGH.getLMFactoryDecorator().getPreparations()) { assertTrue("Preparation wasn't run! [" + threadCount + "]", prepLM.isPrepared()); String name = AbstractWeighting.weightingToFileName(prepLM.getWeighting()); Integer singleThreadShortcutCount = landmarkCount.get(name); if (singleThreadShortcutCount == null) landmarkCount.put(name, prepLM.getSubnetworksWithLandmarks()); else assertEquals((int) singleThreadShortcutCount, prepLM.getSubnetworksWithLandmarks()); String keyError = Parameters.Landmark.PREPARE + "error." + name; String valueError = tmpGH.getGraphHopperStorage().getProperties().get(keyError); assertTrue("Properties for " + name + " should NOT contain error " + valueError + " [" + threadCount + "]", valueError.isEmpty()); String key = Parameters.Landmark.PREPARE + "date." + name; String value = tmpGH.getGraphHopperStorage().getProperties().get(key); assertTrue("Properties for " + name + " did NOT contain finish date [" + threadCount + "]", !value.isEmpty()); } tmpGH.close(); } } @Test public void testGetWeightingForCH() { TestEncoder truck = new TestEncoder("truck"); TestEncoder simpleTruck = new TestEncoder("simple_truck"); // use simple truck first EncodingManager em = new EncodingManager(simpleTruck, truck); CHAlgoFactoryDecorator decorator = new CHAlgoFactoryDecorator(); Weighting fwSimpleTruck = new FastestWeighting(simpleTruck); Weighting fwTruck = new FastestWeighting(truck); RAMDirectory ramDir = new RAMDirectory(); GraphHopperStorage storage = new GraphHopperStorage(Arrays.asList(fwSimpleTruck, fwTruck), ramDir, em, false, new GraphExtension.NoOpExtension()); decorator.addWeighting(fwSimpleTruck); decorator.addWeighting(fwTruck); decorator.addPreparation(new PrepareContractionHierarchies(ramDir, storage, storage.getGraph(CHGraph.class, fwSimpleTruck), fwSimpleTruck, TraversalMode.NODE_BASED)); decorator.addPreparation(new PrepareContractionHierarchies(ramDir, storage, storage.getGraph(CHGraph.class, fwTruck), fwTruck, TraversalMode.NODE_BASED)); HintsMap wMap = new HintsMap("fastest"); wMap.put("vehicle", "truck"); assertEquals("fastest|truck", ((PrepareContractionHierarchies) decorator.getDecoratedAlgorithmFactory(null, wMap)).getWeighting().toString()); wMap.put("vehicle", "simple_truck"); assertEquals("fastest|simple_truck", ((PrepareContractionHierarchies) decorator.getDecoratedAlgorithmFactory(null, wMap)).getWeighting().toString()); // make sure weighting cannot be mixed decorator.addWeighting(fwTruck); decorator.addWeighting(fwSimpleTruck); try { decorator.addPreparation(new PrepareContractionHierarchies(ramDir, storage, storage.getGraph(CHGraph.class, fwSimpleTruck), fwSimpleTruck, TraversalMode.NODE_BASED)); assertTrue(false); } catch (Exception ex) { } } @Test public void testGetMultipleWeightingsForCH() { EncodingManager em = new EncodingManager(Arrays.asList(new CarFlagEncoder()), 8); GraphHopper tmpGH = new GraphHopperOSM(). setStoreOnFlush(false). setEncodingManager(em); tmpGH.getCHFactoryDecorator().setWeightingsAsStrings("fastest", "shortest"); assertEquals(2, tmpGH.getCHFactoryDecorator().getWeightingsAsStrings().size()); } class TestEncoder extends CarFlagEncoder { private final String name; public TestEncoder(String name) { this.name = name; } @Override public String toString() { return name; } } }