PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/core/src/main/java/com/graphhopper/routing/util/PrepareRoutingSubnetworks.java

https://gitlab.com/rizwan/graphhopper-bes
Java | 262 lines | 186 code | 29 blank | 47 comment | 21 complexity | 2b4160ae2f60ee3007de9d29c845b4f6 MD5 | raw file
  1. /*
  2. * Licensed to GraphHopper and Peter Karich under one or more contributor
  3. * license agreements. See the NOTICE file distributed with this work for
  4. * additional information regarding copyright ownership.
  5. *
  6. * GraphHopper licenses this file to you under the Apache License,
  7. * Version 2.0 (the "License"); you may not use this file except in
  8. * compliance with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package com.graphhopper.routing.util;
  19. import com.graphhopper.coll.GHBitSet;
  20. import com.graphhopper.coll.GHBitSetImpl;
  21. import com.graphhopper.storage.GraphStorage;
  22. import com.graphhopper.util.EdgeExplorer;
  23. import com.graphhopper.util.EdgeIterator;
  24. import com.graphhopper.util.EdgeIteratorState;
  25. import com.graphhopper.util.XFirstSearch;
  26. import java.util.*;
  27. import java.util.Map.Entry;
  28. import java.util.concurrent.atomic.AtomicInteger;
  29. import org.slf4j.Logger;
  30. import org.slf4j.LoggerFactory;
  31. import gnu.trove.list.array.TIntArrayList;
  32. /**
  33. * Removes nodes which are not part of the largest network. Ie. mostly nodes with no edges at all
  34. * but also small subnetworks which are nearly always bugs in OSM data or indicate otherwise
  35. * disconnected areas e.g. via barriers - see #86.
  36. * <p/>
  37. * @author Peter Karich
  38. */
  39. public class PrepareRoutingSubnetworks
  40. {
  41. private final Logger logger = LoggerFactory.getLogger(getClass());
  42. private final GraphStorage g;
  43. private final EdgeFilter edgeFilter;
  44. private int minNetworkSize = 200;
  45. private int minOnewayNetworkSize = 0;
  46. private int subNetworks = -1;
  47. private final AtomicInteger maxEdgesPerNode = new AtomicInteger(0);
  48. private final EncodingManager encodingManager;
  49. public PrepareRoutingSubnetworks( GraphStorage g, EncodingManager em )
  50. {
  51. this.g = g;
  52. if (em.getVehicleCount() == 0)
  53. throw new IllegalStateException("No vehicles found");
  54. else if (em.getVehicleCount() > 1)
  55. edgeFilter = EdgeFilter.ALL_EDGES;
  56. else
  57. edgeFilter = new DefaultEdgeFilter(em.getSingle());
  58. this.encodingManager = em;
  59. }
  60. public PrepareRoutingSubnetworks setMinNetworkSize( int minNetworkSize )
  61. {
  62. this.minNetworkSize = minNetworkSize;
  63. return this;
  64. }
  65. public PrepareRoutingSubnetworks setMinOnewayNetworkSize( int minOnewayNetworkSize )
  66. {
  67. this.minOnewayNetworkSize = minOnewayNetworkSize;
  68. return this;
  69. }
  70. public void doWork()
  71. {
  72. int del = removeZeroDegreeNodes();
  73. Map<Integer, Integer> map = findSubnetworks();
  74. keepLargeNetworks(map);
  75. int unvisitedDeadEnds = 0;
  76. if ((this.minOnewayNetworkSize > 0) && (this.encodingManager.getVehicleCount() == 1))
  77. unvisitedDeadEnds = removeDeadEndUnvisitedNetworks(this.encodingManager.getSingle());
  78. logger.info("optimize to remove subnetworks (" + map.size() + "), zero-degree-nodes (" + del + "), "
  79. + "unvisited-dead-end-nodes(" + unvisitedDeadEnds + "), "
  80. + "maxEdges/node (" + maxEdgesPerNode.get() + ")");
  81. g.optimize();
  82. subNetworks = map.size();
  83. }
  84. public int getSubNetworks()
  85. {
  86. return subNetworks;
  87. }
  88. public Map<Integer, Integer> findSubnetworks()
  89. {
  90. return findSubnetworks(g.createEdgeExplorer(edgeFilter));
  91. }
  92. private Map<Integer, Integer> findSubnetworks( final EdgeExplorer explorer )
  93. {
  94. final Map<Integer, Integer> map = new HashMap<Integer, Integer>();
  95. final AtomicInteger integ = new AtomicInteger(0);
  96. int locs = g.getNodes();
  97. final GHBitSet bs = new GHBitSetImpl(locs);
  98. for (int start = 0; start < locs; start++)
  99. {
  100. if (g.isNodeRemoved(start) || bs.contains(start))
  101. continue;
  102. new XFirstSearch()
  103. {
  104. int tmpCounter = 0;
  105. @Override
  106. protected GHBitSet createBitSet()
  107. {
  108. return bs;
  109. }
  110. @Override
  111. protected final boolean goFurther( int nodeId )
  112. {
  113. if (tmpCounter > maxEdgesPerNode.get())
  114. maxEdgesPerNode.set(tmpCounter);
  115. tmpCounter = 0;
  116. integ.incrementAndGet();
  117. return true;
  118. }
  119. @Override
  120. protected final boolean checkAdjacent( EdgeIteratorState iter )
  121. {
  122. tmpCounter++;
  123. return true;
  124. }
  125. }.start(explorer, start, false);
  126. map.put(start, integ.get());
  127. integ.set(0);
  128. }
  129. return map;
  130. }
  131. /**
  132. * Deletes all but the largest subnetworks.
  133. */
  134. void keepLargeNetworks( Map<Integer, Integer> map )
  135. {
  136. if (map.size() < 2)
  137. return;
  138. int biggestStart = -1;
  139. int maxCount = -1;
  140. GHBitSetImpl bs = new GHBitSetImpl(g.getNodes());
  141. for (Entry<Integer, Integer> e : map.entrySet())
  142. {
  143. if (biggestStart < 0)
  144. {
  145. biggestStart = e.getKey();
  146. maxCount = e.getValue();
  147. continue;
  148. }
  149. if (maxCount < e.getValue())
  150. {
  151. // new biggest area found. remove old
  152. removeNetwork(biggestStart, maxCount, bs);
  153. biggestStart = e.getKey();
  154. maxCount = e.getValue();
  155. } else
  156. {
  157. removeNetwork(e.getKey(), e.getValue(), bs);
  158. }
  159. }
  160. }
  161. /**
  162. * Deletes the complete subnetwork reachable through start
  163. */
  164. void removeNetwork( int start, int entries, final GHBitSet bs )
  165. {
  166. if (entries >= minNetworkSize)
  167. {
  168. // logger.info("did not remove large network (" + entries + ")");
  169. return;
  170. }
  171. EdgeExplorer explorer = g.createEdgeExplorer(edgeFilter);
  172. new XFirstSearch()
  173. {
  174. @Override
  175. protected GHBitSet createBitSet()
  176. {
  177. return bs;
  178. }
  179. @Override
  180. protected boolean goFurther( int nodeId )
  181. {
  182. g.markNodeRemoved(nodeId);
  183. return super.goFurther(nodeId);
  184. }
  185. }.start(explorer, start, true);
  186. }
  187. /**
  188. * To avoid large processing and a large HashMap remove nodes with no edges up front
  189. * <p/>
  190. * @return removed nodes
  191. */
  192. int removeZeroDegreeNodes()
  193. {
  194. int removed = 0;
  195. int locs = g.getNodes();
  196. EdgeExplorer explorer = g.createEdgeExplorer();
  197. for (int start = 0; start < locs; start++)
  198. {
  199. EdgeIterator iter = explorer.setBaseNode(start);
  200. if (!iter.next())
  201. {
  202. removed++;
  203. g.markNodeRemoved(start);
  204. }
  205. }
  206. return removed;
  207. }
  208. /**
  209. * Clean small networks that will be never be visited by this explorer See #86 For example,
  210. * small areas like parking lots are sometimes connected to the whole network through a one-way road.
  211. * This is clearly an error - but is causes the routing to fail when point get connected to this
  212. * small area. This routines removed all these points from the graph.
  213. * <p/>
  214. * @return number of removed nodes;
  215. */
  216. public int removeDeadEndUnvisitedNetworks( final FlagEncoder encoder )
  217. {
  218. // Partition g into strongly connected components using Tarjan's Algorithm.
  219. final EdgeFilter filter = new DefaultEdgeFilter(encoder, false, true);
  220. List<TIntArrayList> components = new TarjansStronglyConnectedComponentsAlgorithm(g, filter).findComponents();
  221. // remove components less than minimum size
  222. int removed = 0;
  223. for (TIntArrayList component : components) {
  224. if (component.size() < minOnewayNetworkSize) {
  225. for (int i = 0; i < component.size(); i++) {
  226. g.markNodeRemoved(component.get(i));
  227. removed ++;
  228. }
  229. }
  230. }
  231. return removed;
  232. }
  233. }