public static int getNextDepartTime(
      RoutingRequest request, int departureTime, Vertex stopVertex) {

    int bestArrivalTime = Integer.MAX_VALUE;

    request.arriveBy = false;

    // find the boards
    for (Edge preboard : stopVertex.getOutgoing()) {
      if (preboard instanceof PreBoardEdge) {
        Vertex departure = preboard.getToVertex(); // this is the departure vertex
        for (Edge board : departure.getOutgoing()) {
          if (board instanceof TransitBoardAlight) {
            State state = new State(board.getFromVertex(), departureTime, request);
            State result = board.traverse(state);
            if (result == null) continue;
            int time = (int) result.getTime();
            if (time < bestArrivalTime) {
              bestArrivalTime = time;
            }
          }
        }
      }
    }

    request.arriveBy = true;
    return bestArrivalTime;
  }
  public void testBoardAlight() throws Exception {
    Vertex stop_a_depart = graph.getVertex("agency:A_depart");
    Vertex stop_b_depart = graph.getVertex("agency:B_depart");

    assertEquals(1, stop_a_depart.getDegreeOut());
    assertEquals(3, stop_b_depart.getDegreeOut());

    for (Edge e : stop_a_depart.getOutgoing()) {
      assertEquals(TransitBoardAlight.class, e.getClass());
      assertTrue(((TransitBoardAlight) e).boarding);
    }

    TransitBoardAlight pb = (TransitBoardAlight) stop_a_depart.getOutgoing().iterator().next();
    Vertex journey_a_1 = pb.getToVertex();

    assertEquals(1, journey_a_1.getDegreeIn());

    for (Edge e : journey_a_1.getOutgoing()) {
      if (e.getToVertex() instanceof TransitStop) {
        assertEquals(TransitBoardAlight.class, e.getClass());
      } else {
        assertEquals(PatternHop.class, e.getClass());
      }
    }
  }
    /**
     * The safest bike lane should have a safety weight no lower than the time weight of a flat
     * street. This method divides the safety lengths by the length ratio of the safest street,
     * ensuring this property.
     *
     * @param graph
     */
    private void applyBikeSafetyFactor(Graph graph) {
      _log.info(
          GraphBuilderAnnotation.register(
              graph,
              Variety.GRAPHWIDE,
              "Multiplying all bike safety values by " + (1 / bestBikeSafety)));
      HashSet<Edge> seenEdges = new HashSet<Edge>();
      for (Vertex vertex : graph.getVertices()) {
        for (Edge e : vertex.getOutgoing()) {
          if (!(e instanceof PlainStreetEdge)) {
            continue;
          }
          PlainStreetEdge pse = (PlainStreetEdge) e;

          if (!seenEdges.contains(e)) {
            seenEdges.add(e);
            pse.setBicycleSafetyEffectiveLength(
                pse.getBicycleSafetyEffectiveLength() / bestBikeSafety);
          }
        }
        for (Edge e : vertex.getIncoming()) {
          if (!(e instanceof PlainStreetEdge)) {
            continue;
          }
          PlainStreetEdge pse = (PlainStreetEdge) e;

          if (!seenEdges.contains(e)) {
            seenEdges.add(e);
            pse.setBicycleSafetyEffectiveLength(
                pse.getBicycleSafetyEffectiveLength() / bestBikeSafety);
          }
        }
      }
    }
Esempio n. 4
0
  public void testPickupDropoff() throws Exception {
    Vertex stop_o = graph.getVertex("agency_O_depart");
    Vertex stop_p = graph.getVertex("agency_P");
    int i = 0;
    for (@SuppressWarnings("unused") Edge e : stop_o.getOutgoing()) {
      ++i;
    }
    assertTrue(i == 3);

    long startTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 19, 12, 0, 0);
    RoutingRequest options = new RoutingRequest();
    options.dateTime = startTime;
    options.setRoutingContext(graph, stop_o, stop_p);
    ShortestPathTree spt = aStar.getShortestPathTree(options);
    GraphPath path = spt.getPath(stop_p, false);
    assertNotNull(path);
    long endTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 19, 12, 10, 0);
    assertEquals(endTime, path.getEndTime());

    startTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 19, 12, 0, 1);
    options.dateTime = startTime;
    options.setRoutingContext(graph, stop_o, stop_p);
    spt = aStar.getShortestPathTree(options);
    path = spt.getPath(stop_p, false);
    assertNotNull(path);
    endTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 19, 15, 10, 0);
    assertEquals(endTime, path.getEndTime());
  }
 public synchronized void initIndexes() {
   if (vertexIndex != null) {
     return;
   }
   graphService.setLoadLevel(LoadLevel.DEBUG);
   Graph graph = graphService.getGraph();
   vertexIndex = new STRtree();
   edgeIndex = new STRtree();
   for (Vertex v : graph.getVertices()) {
     Envelope vertexEnvelope = new Envelope(v.getCoordinate());
     vertexIndex.insert(vertexEnvelope, v);
     for (Edge e : v.getOutgoing()) {
       Envelope envelope;
       Geometry geometry = e.getGeometry();
       if (geometry == null) {
         envelope = vertexEnvelope;
       } else {
         envelope = geometry.getEnvelopeInternal();
       }
       edgeIndex.insert(envelope, e);
     }
   }
   vertexIndex.build();
   edgeIndex.build();
 }
Esempio n. 6
0
  public void testFrequencies() {
    Vertex stop_u = graph.getVertex("agency_U_depart");
    Vertex stop_v = graph.getVertex("agency_V_arrive");

    ShortestPathTree spt;
    GraphPath path;

    RoutingRequest options = new RoutingRequest();
    options.setModes(new TraverseModeSet("TRANSIT"));
    options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 7, 0, 0, 0);
    options.setRoutingContext(graph, stop_u, stop_v);

    // U to V - original stop times - shouldn't be used
    spt = aStar.getShortestPathTree(options);
    path = spt.getPath(stop_v, false);
    assertNotNull(path);
    assertEquals(4, path.states.size());
    long endTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 7, 6, 40, 0);
    assertEquals(endTime, path.getEndTime());

    // U to V - first frequency
    options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 7, 7, 0, 0);
    options.setRoutingContext(graph, stop_u, stop_v);
    spt = aStar.getShortestPathTree(options);
    path = spt.getPath(stop_v, false);
    assertNotNull(path);
    assertEquals(4, path.states.size());
    endTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 7, 7, 40, 0);
    assertEquals(endTime, path.getEndTime());

    // U to V - second frequency
    options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 7, 14, 0, 0);
    options.setRoutingContext(graph, stop_u, stop_v);
    spt = aStar.getShortestPathTree(options);
    path = spt.getPath(stop_v, false);
    assertNotNull(path);
    assertEquals(4, path.states.size());
    endTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 7, 14, 40, 0);
    assertEquals(endTime, path.getEndTime());

    boolean boarded = false;
    for (FrequencyBoard e : filter(stop_u.getOutgoing(), FrequencyBoard.class)) {
      boarded = true;
      FrequencyBoard board = (FrequencyBoard) e;
      FrequencyBasedTripPattern pattern = board.getPattern();
      int previousArrivalTime = pattern.getPreviousArrivalTime(0, 0, false, false, false);
      assertTrue(previousArrivalTime < 0);

      previousArrivalTime = pattern.getPreviousArrivalTime(0, 60 * 60 * 7 - 1, false, false, false);
      assertEquals(60 * 60 * 6, previousArrivalTime);

      previousArrivalTime = pattern.getPreviousArrivalTime(0, 60 * 60 * 11, false, false, false);
      assertEquals(60 * 60 * 10, previousArrivalTime);

      previousArrivalTime = pattern.getPreviousArrivalTime(0, 60 * 60 * 18, false, false, false);
      assertEquals(60 * 60 * 16, previousArrivalTime);
    }
    assertTrue(boarded);
  }
Esempio n. 7
0
 protected List<Edge> getOutgoingMatchableEdges(Vertex vertex) {
   List<Edge> edges = new ArrayList<Edge>();
   for (Edge e : vertex.getOutgoing()) {
     if (!(e instanceof StreetEdge)) continue;
     if (e.getGeometry() == null) continue;
     edges.add(e);
   }
   return edges;
 }
Esempio n. 8
0
  public PatternHop getHopOut(Vertex v) {
    for (TransitBoardAlight e : filter(v.getOutgoing(), TransitBoardAlight.class)) {
      if (!e.isBoarding()) continue;

      for (PatternHop f : filter(e.getToVertex().getOutgoing(), PatternHop.class)) {
        return f;
      }
    }
    return null;
  }
Esempio n. 9
0
  public static DisjointSet<Vertex> getConnectedComponents(Graph graph) {
    DisjointSet<Vertex> components = new DisjointSet<Vertex>();

    for (Vertex v : graph.getVertices()) {
      for (Edge e : v.getOutgoing()) {
        components.union(e.getFromVertex(), e.getToVertex());
      }
    }
    return components;
  }
  public void testWheelchairAccessible() throws Exception {
    Vertex near_a = graph.getVertex("near_1_agency_entrance_a");
    Vertex near_b = graph.getVertex("near_1_agency_entrance_b");
    Vertex near_c = graph.getVertex("near_1_agency_C");
    Vertex near_e = graph.getVertex("near_1_agency_E");

    Vertex stop_d = graph.getVertex("agency:D");
    Vertex split_d = null;
    for (StreetTransitLink e : Iterables.filter(stop_d.getOutgoing(), StreetTransitLink.class)) {
      split_d = e.getToVertex();
    }

    RoutingRequest options = new RoutingRequest();
    options.wheelchairAccessible = true;
    options.dateTime = TestUtils.dateInSeconds("America/New_York", 2009, 8, 18, 0, 0, 0);

    ShortestPathTree spt;
    GraphPath path;

    // stop B is accessible, so there should be a path.
    options.setRoutingContext(graph, near_a, near_b);
    spt = aStar.getShortestPathTree(options);

    path = spt.getPath(near_b, false);
    assertNotNull(path);

    // stop C is not accessible, so there should be no path.
    options.setRoutingContext(graph, near_a, near_c);
    spt = aStar.getShortestPathTree(options);

    path = spt.getPath(near_c, false);
    assertNull(path);

    // stop E has no accessibility information, but we should still be able to route to it.
    options.setRoutingContext(graph, near_a, near_e);
    spt = aStar.getShortestPathTree(options);

    path = spt.getPath(near_e, false);
    assertNotNull(path);

    // from stop A to stop D would normally be trip 1.1 to trip 2.1, arriving at 00:30. But trip
    // 2 is not accessible, so we'll do 1.1 to 3.1, arriving at 01:00
    GregorianCalendar time = new GregorianCalendar(2009, 8, 18, 0, 0, 0);
    time.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    options.dateTime = TestUtils.toSeconds(time);
    options.setRoutingContext(graph, near_a, split_d);
    spt = aStar.getShortestPathTree(options);

    time.add(Calendar.HOUR, 1);
    time.add(Calendar.SECOND, 1); // for the StreetTransitLink
    path = spt.getPath(split_d, false);
    assertNotNull(path);
    assertEquals(TestUtils.toSeconds(time), path.getEndTime());
  }
 /* Somewhat hackish convenience method to grab a hop edge on a particular route leaving a particular stop. */
 private PatternHop getHopEdge(String stopId, String routeId) {
   Vertex stopDepartVertex = graph.getVertex("agency:" + stopId + "_depart");
   for (Edge edge : stopDepartVertex.getOutgoing()) {
     if (edge instanceof TransitBoardAlight) {
       TransitBoardAlight tba = ((TransitBoardAlight) edge);
       if (tba.boarding && tba.getPattern().route.getId().getId().equals(routeId)) {
         for (Edge edge2 : tba.getToVertex().getOutgoing()) {
           if (edge2 instanceof PatternHop) {
             return (PatternHop) edge2;
           }
         }
       }
     }
   }
   return null;
 }
  public void testBoardAlightStopIndex() {
    Vertex stop_b_arrive = graph.getVertex("agency:C_arrive");
    Vertex stop_b_depart = graph.getVertex("agency:C_depart");

    Map<TripPattern, Integer> stopIndex = new HashMap<TripPattern, Integer>();
    for (Edge edge : stop_b_depart.getOutgoing()) {
      TransitBoardAlight tba = (TransitBoardAlight) edge;
      stopIndex.put(tba.getPattern(), tba.getStopIndex());
    }

    for (Edge edge : stop_b_arrive.getIncoming()) {
      TransitBoardAlight tba = (TransitBoardAlight) edge;
      if (stopIndex.containsKey(tba.getPattern()))
        assertEquals((Integer) stopIndex.get(tba.getPattern()), new Integer(tba.getStopIndex()));
    }
  }
 /*
  * Iterate through all vertices and their (outgoing) edges. If they are of 'interesting' types, add them to the corresponding spatial index.
  */
 public synchronized void buildSpatialIndex() {
   vertexIndex = new STRtree();
   edgeIndex = new STRtree();
   Envelope env;
   // int xminx, xmax, ymin, ymax;
   for (Vertex v : graph.getVertices()) {
     Coordinate c = v.getCoordinate();
     env = new Envelope(c);
     vertexIndex.insert(env, v);
     for (Edge e : v.getOutgoing()) {
       if (e.getGeometry() == null) continue;
       if (e instanceof PatternEdge || e instanceof StreetTransitLink || e instanceof StreetEdge) {
         env = e.getGeometry().getEnvelopeInternal();
         edgeIndex.insert(env, e);
       }
     }
   }
   vertexIndex.build();
   edgeIndex.build();
 }
Esempio n. 14
0
 /**
  * Internals of getRegionsForVertex; keeps track of seen vertices to avoid loops.
  *
  * @param regionData
  * @param vertex
  * @param seen
  * @param depth
  * @return
  */
 private static HashSet<Integer> getRegionsForVertex(
     RegionData regionData, Vertex vertex, HashSet<Vertex> seen, int depth) {
   seen.add(vertex);
   HashSet<Integer> regions = new HashSet<Integer>();
   int region = vertex.getGroupIndex();
   if (region >= 0) {
     regions.add(region);
   } else {
     for (Edge e : vertex.getOutgoing()) {
       final Vertex tov = e.getToVertex();
       if (!seen.contains(tov))
         regions.addAll(getRegionsForVertex(regionData, tov, seen, depth + 1));
     }
     for (Edge e : vertex.getIncoming()) {
       final Vertex fromv = e.getFromVertex();
       if (!seen.contains(fromv))
         regions.addAll(getRegionsForVertex(regionData, fromv, seen, depth + 1));
     }
   }
   return regions;
 }
  /**
   * Get edges connected to an vertex
   *
   * @return
   */
  @Secured({"ROLE_USER"})
  @GET
  @Path("/edgesForVertex")
  @Produces({MediaType.APPLICATION_JSON})
  public EdgesForVertex getEdgesForVertex(@QueryParam("vertex") String label) {

    Graph graph = graphService.getGraph();
    Vertex vertex = graph.getVertex(label);
    if (vertex == null) {
      return null;
    }
    EdgeSet incoming = new EdgeSet();
    incoming.addEdges(vertex.getIncoming(), graph);

    EdgeSet outgoing = new EdgeSet();
    outgoing.addEdges(vertex.getOutgoing(), graph);

    EdgesForVertex e4v = new EdgesForVertex();
    e4v.incoming = incoming.withGraph(graph);
    e4v.outgoing = outgoing.withGraph(graph);

    return e4v;
  }
    @SuppressWarnings("unchecked")
    public Void call() throws Exception {
      // LOG.debug("ORIGIN " + origin);
      int oi = stopIndices.get(origin); // origin index
      // first check for walking transfers
      // LOG.debug("    Walk");

      BinHeap<State> heap;
      try {
        heap = (BinHeap<State>) heapPool.borrowObject();
      } catch (Exception e) {
        throw new RuntimeException(e);
      }

      BasicShortestPathTree spt = new BasicShortestPathTree(500000);
      State s0 = new State(origin, options);
      spt.add(s0);
      heap.insert(s0, s0.getWeight());
      while (!heap.empty()) {
        double w = heap.peek_min_key();
        State u = heap.extract_min();
        if (!spt.visit(u)) continue;
        Vertex uVertex = u.getVertex();
        // LOG.debug("heap extract " + u + " weight " + w);
        if (w > MAX_WEIGHT) break;
        if (uVertex instanceof TransitStop) {
          int di = stopIndices.get(uVertex); // dest index
          table[oi][di] = (float) w;
          // LOG.debug("    Dest " + u + " w=" + w);
        }
        for (Edge e : uVertex.getOutgoing()) {
          if (!(e instanceof PreBoardEdge)) {
            State v = e.optimisticTraverse(u);
            if (v != null && spt.add(v)) heap.insert(v, v.getWeight());
          }
        }
      }

      // then check what is accessible in one transit trip
      heap.reset(); // recycle heap
      spt = new BasicShortestPathTree(50000);
      // first handle preboard edges
      Queue<Vertex> q = new ArrayDeque<Vertex>(100);
      q.add(origin);
      while (!q.isEmpty()) {
        Vertex u = q.poll();
        for (Edge e : u.getOutgoing()) {
          if (e instanceof PatternBoard) {
            Vertex v = ((PatternBoard) e).getToVertex();
            // give onboard vertices same index as their
            // corresponding station
            stopIndices.put(v, oi);
            StateEditor se = (new State(u, options)).edit(e);
            se.incrementWeight(OPTIMISTIC_BOARD_COST);
            s0 = se.makeState();
            spt.add(s0);
            heap.insert(s0, s0.getWeight());
            // _log.debug("    board " + tov);
          } else if (e instanceof FreeEdge) { // handle preboard
            Vertex v = ((FreeEdge) e).getToVertex();
            // give onboard vertices same index as their
            // corresponding station
            stopIndices.put(v, oi);
            q.add(v);
          }
        }
      }
      // all boarding edges for this stop have now been traversed
      // LOG.debug("    Transit");
      while (!heap.empty()) {
        // check for transit stops when pulling off of heap
        // and continue when one is found
        // this is enough to prevent reboarding
        // need to mark closed vertices because otherwise cycles may
        // appear (interlining...)
        double w = heap.peek_min_key();
        State u = heap.extract_min();
        if (!spt.visit(u)) continue;
        // LOG.debug("    Extract " + u + " w=" + w);
        Vertex uVertex = u.getVertex();
        if (uVertex instanceof TransitStop) {
          int di = stopIndices.get(uVertex); // dest index
          if (table[oi][di] > w) {
            table[oi][di] = (float) w;
            // LOG.debug("    Dest " + u + "w=" + w);
          }
          continue;
        }
        for (Edge e : uVertex.getOutgoing()) {
          // LOG.debug("        Edge " + e);
          State v = e.optimisticTraverse(u);
          if (v != null && spt.add(v)) heap.insert(v, v.getWeight());
          // else LOG.debug("        (skip)");
        }
      }
      heapPool.returnObject(heap);
      incrementCount();
      return null;
    }
  @Test
  public final void testOnBoardDepartureTime() {
    Coordinate[] coordinates = new Coordinate[5];
    coordinates[0] = new Coordinate(0.0, 0.0);
    coordinates[1] = new Coordinate(0.0, 1.0);
    coordinates[2] = new Coordinate(2.0, 1.0);
    coordinates[3] = new Coordinate(5.0, 1.0);
    coordinates[4] = new Coordinate(5.0, 5.0);

    PatternDepartVertex depart = mock(PatternDepartVertex.class);
    PatternArriveVertex dwell = mock(PatternArriveVertex.class);
    PatternArriveVertex arrive = mock(PatternArriveVertex.class);
    Graph graph = mock(Graph.class);
    RoutingRequest routingRequest = mock(RoutingRequest.class);
    ServiceDay serviceDay = mock(ServiceDay.class);

    when(graph.getTimeZone()).thenReturn(TimeZone.getTimeZone("GMT"));

    GeometryFactory geometryFactory = GeometryUtils.getGeometryFactory();
    CoordinateSequenceFactory coordinateSequenceFactory =
        geometryFactory.getCoordinateSequenceFactory();
    CoordinateSequence coordinateSequence = coordinateSequenceFactory.create(coordinates);
    LineString geometry = new LineString(coordinateSequence, geometryFactory);
    ArrayList<Edge> hops = new ArrayList<Edge>(2);
    RoutingContext routingContext = new RoutingContext(routingRequest, graph, null, arrive);
    AgencyAndId agencyAndId = new AgencyAndId("Agency", "ID");
    Route route = new Route();
    ArrayList<StopTime> stopTimes = new ArrayList<StopTime>(3);
    StopTime stopDepartTime = new StopTime();
    StopTime stopDwellTime = new StopTime();
    StopTime stopArriveTime = new StopTime();
    Stop stopDepart = new Stop();
    Stop stopDwell = new Stop();
    Stop stopArrive = new Stop();
    Trip trip = new Trip();

    routingContext.serviceDays = new ArrayList<ServiceDay>(Collections.singletonList(serviceDay));
    route.setId(agencyAndId);
    stopDepart.setId(agencyAndId);
    stopDwell.setId(agencyAndId);
    stopArrive.setId(agencyAndId);
    stopDepartTime.setStop(stopDepart);
    stopDepartTime.setDepartureTime(0);
    stopDwellTime.setArrivalTime(20);
    stopDwellTime.setStop(stopDwell);
    stopDwellTime.setDepartureTime(40);
    stopArriveTime.setArrivalTime(60);
    stopArriveTime.setStop(stopArrive);
    stopTimes.add(stopDepartTime);
    stopTimes.add(stopDwellTime);
    stopTimes.add(stopArriveTime);
    trip.setId(agencyAndId);
    trip.setTripHeadsign("The right");

    TripTimes tripTimes = new TripTimes(trip, stopTimes, new Deduplicator());
    StopPattern stopPattern = new StopPattern(stopTimes);
    TripPattern tripPattern = new TripPattern(route, stopPattern);

    when(depart.getTripPattern()).thenReturn(tripPattern);
    when(dwell.getTripPattern()).thenReturn(tripPattern);

    PatternHop patternHop0 = new PatternHop(depart, dwell, stopDepart, stopDwell, 0);
    PatternHop patternHop1 = new PatternHop(dwell, arrive, stopDwell, stopArrive, 1);

    hops.add(patternHop0);
    hops.add(patternHop1);

    when(graph.getEdges()).thenReturn(hops);
    when(depart.getCoordinate()).thenReturn(new Coordinate(0, 0));
    when(dwell.getCoordinate()).thenReturn(new Coordinate(0, 0));
    when(arrive.getCoordinate()).thenReturn(new Coordinate(0, 0));
    when(routingRequest.getFrom()).thenReturn(new GenericLocation());
    when(routingRequest.getStartingTransitTripId()).thenReturn(agencyAndId);
    when(serviceDay.secondsSinceMidnight(anyInt())).thenReturn(9);

    patternHop0.setGeometry(geometry);
    tripPattern.add(tripTimes);
    graph.index = new GraphIndex(graph);

    coordinates = new Coordinate[3];
    coordinates[0] = new Coordinate(3.5, 1.0);
    coordinates[1] = new Coordinate(5.0, 1.0);
    coordinates[2] = new Coordinate(5.0, 5.0);

    coordinateSequence = coordinateSequenceFactory.create(coordinates);
    geometry = new LineString(coordinateSequence, geometryFactory);

    Vertex vertex = onBoardDepartServiceImpl.setupDepartOnBoard(routingContext);
    Edge edge = vertex.getOutgoing().toArray(new Edge[1])[0];

    assertEquals(vertex, edge.getFromVertex());
    assertEquals(dwell, edge.getToVertex());
    assertEquals("The right", edge.getDirection());
    assertEquals(geometry, edge.getGeometry());

    assertEquals(coordinates[0].x, vertex.getX(), 0.0);
    assertEquals(coordinates[0].y, vertex.getY(), 0.0);
  }
Esempio n. 18
0
  /**
   * Get polygons covering the components of the graph. The largest component (in terms of number of
   * nodes) will not overlap any other components (it will have holes); the others may overlap each
   * other.
   *
   * @param dateTime
   */
  public static List<Geometry> getComponentPolygons(
      Graph graph, RoutingRequest options, long time) {
    DisjointSet<Vertex> components = getConnectedComponents(graph);

    LinkedListMultimap<Integer, Coordinate> componentCoordinates = LinkedListMultimap.create();
    options.setDummyRoutingContext(graph);
    for (Vertex v : graph.getVertices()) {
      for (Edge e : v.getOutgoing()) {
        State s0 = new State(v, time, options);
        State s1 = e.traverse(s0);
        if (s1 != null) {
          Integer component = components.find(e.getFromVertex());
          Geometry geometry = s1.getBackEdge().getGeometry();
          if (geometry != null) {
            List<Coordinate> coordinates =
                new ArrayList<Coordinate>(Arrays.asList(geometry.getCoordinates()));
            for (int i = 0; i < coordinates.size(); ++i) {
              Coordinate coordinate = new Coordinate(coordinates.get(i));
              coordinate.x = Math.round(coordinate.x * PRECISION) / PRECISION;
              coordinate.y = Math.round(coordinate.y * PRECISION) / PRECISION;
              coordinates.set(i, coordinate);
            }
            componentCoordinates.putAll(component, coordinates);
          }
        }
      }
    }

    // generate convex hull of each component
    List<Geometry> geoms = new ArrayList<Geometry>();
    int mainComponentSize = 0;
    int mainComponentIndex = -1;
    int component = 0;
    for (Integer key : componentCoordinates.keySet()) {
      List<Coordinate> coords = componentCoordinates.get(key);
      Coordinate[] coordArray = new Coordinate[coords.size()];
      ConvexHull hull =
          new ConvexHull(coords.toArray(coordArray), GeometryUtils.getGeometryFactory());
      Geometry geom = hull.getConvexHull();
      // buffer components which are mere lines so that they do not disappear.
      if (geom instanceof LineString) {
        geom = geom.buffer(0.01); // ~10 meters
      } else if (geom instanceof Point) {
        geom = geom.buffer(0.05); // ~50 meters, so that it shows up
      }

      geoms.add(geom);
      if (mainComponentSize < coordArray.length) {
        mainComponentIndex = component;
        mainComponentSize = coordArray.length;
      }
      ++component;
    }

    // subtract small components out of main component
    // (small components are permitted to overlap each other)
    Geometry mainComponent = geoms.get(mainComponentIndex);
    for (int i = 0; i < geoms.size(); ++i) {
      Geometry geom = geoms.get(i);
      if (i == mainComponentIndex) {
        continue;
      }
      mainComponent = mainComponent.difference(geom);
    }
    geoms.set(mainComponentIndex, mainComponent);

    return geoms;
  }
  @Override
  public List<GraphPath> getPaths(RoutingRequest options) {

    if (options.rctx == null) {
      options.setRoutingContext(graphService.getGraph(options.getRouterId()));
      // move into setRoutingContext ?
      options.rctx.pathParsers =
          new PathParser[] {new BasicPathParser(), new NoThruTrafficPathParser()};
    }

    RemainingWeightHeuristic heuristic;
    if (options.getModes().isTransit()) {
      LOG.debug("Transit itinerary requested.");
      // always use the bidirectional heuristic because the others are not precise enough
      heuristic = new BidirectionalRemainingWeightHeuristic(options.rctx.graph);
    } else {
      LOG.debug("Non-transit itinerary requested.");
      heuristic = new DefaultRemainingWeightHeuristic();
    }

    // the states that will eventually be turned into paths and returned
    List<State> returnStates = new LinkedList<State>();

    BinHeap<State> pq = new BinHeap<State>();
    //        List<State> boundingStates = new ArrayList<State>();

    Vertex originVertex = options.rctx.origin;
    Vertex targetVertex = options.rctx.target;

    // increase maxWalk repeatedly in case hard limiting is in use
    WALK:
    for (double maxWalk = options.getMaxWalkDistance(); returnStates.isEmpty(); maxWalk *= 2) {
      if (maxWalk != Double.MAX_VALUE && maxWalk > MAX_WALK) {
        break;
      }
      LOG.debug("try search with max walk {}", maxWalk);
      // increase maxWalk if settings make trip impossible
      if (maxWalk
          < Math.min(
              distanceLibrary.distance(originVertex.getCoordinate(), targetVertex.getCoordinate()),
              originVertex.getDistanceToNearestTransitStop()
                  + targetVertex.getDistanceToNearestTransitStop())) continue WALK;
      options.setMaxWalkDistance(maxWalk);

      // cap search / heuristic weight
      final double AVG_TRANSIT_SPEED = 25; // m/sec
      double cutoff =
          (distanceLibrary.distance(originVertex.getCoordinate(), targetVertex.getCoordinate())
                  * 1.5)
              / AVG_TRANSIT_SPEED; // wait time is irrelevant in the heuristic
      cutoff += options.getMaxWalkDistance() * options.walkReluctance;
      options.maxWeight = cutoff;

      State origin = new State(options);
      // (used to) initialize heuristic outside loop so table can be reused
      heuristic.computeInitialWeight(origin, targetVertex);

      options.maxWeight = cutoff + 30 * 60 * options.waitReluctance;

      // reinitialize states for each retry
      HashMap<Vertex, List<State>> states = new HashMap<Vertex, List<State>>();
      pq.reset();
      pq.insert(origin, 0);
      long startTime = System.currentTimeMillis();
      long endTime = startTime + (int) (_timeouts[0] * 1000);
      LOG.debug("starttime {} endtime {}", startTime, endTime);
      QUEUE:
      while (!pq.empty()) {

        if (System.currentTimeMillis() > endTime) {
          LOG.debug("timeout at {} msec", System.currentTimeMillis() - startTime);
          if (returnStates.isEmpty()) break WALK; // disable walk distance increases
          else {
            storeMemory();
            break WALK;
          }
        }

        //                if (pq.peek_min_key() > options.maxWeight) {
        //                    LOG.debug("max weight {} exceeded", options.maxWeight);
        //                    break QUEUE;
        //                }

        State su = pq.extract_min();

        //                for (State bs : boundingStates) {
        //                    if (eDominates(bs, su)) {
        //                        continue QUEUE;
        //                    }
        //                }

        Vertex u = su.getVertex();

        if (traverseVisitor != null) {
          traverseVisitor.visitVertex(su);
        }

        if (u.equals(targetVertex)) {
          //                    boundingStates.add(su);
          returnStates.add(su);
          if (!options.getModes().isTransit()) break QUEUE;
          // options should contain max itineraries
          if (returnStates.size() >= _maxPaths) break QUEUE;
          if (returnStates.size() < _timeouts.length) {
            endTime = startTime + (int) (_timeouts[returnStates.size()] * 1000);
            LOG.debug(
                "{} path, set timeout to {}",
                returnStates.size(),
                _timeouts[returnStates.size()] * 1000);
          }
          continue QUEUE;
        }

        for (Edge e : options.isArriveBy() ? u.getIncoming() : u.getOutgoing()) {
          STATE:
          for (State new_sv = e.traverse(su); new_sv != null; new_sv = new_sv.getNextResult()) {
            if (traverseVisitor != null) {
              traverseVisitor.visitEdge(e, new_sv);
            }

            double h = heuristic.computeForwardWeight(new_sv, targetVertex);
            if (h == Double.MAX_VALUE) continue;
            //                    for (State bs : boundingStates) {
            //                        if (eDominates(bs, new_sv)) {
            //                            continue STATE;
            //                        }
            //                    }
            Vertex v = new_sv.getVertex();
            List<State> old_states = states.get(v);
            if (old_states == null) {
              old_states = new LinkedList<State>();
              states.put(v, old_states);
            } else {
              for (State old_sv : old_states) {
                if (eDominates(old_sv, new_sv)) {
                  continue STATE;
                }
              }
              Iterator<State> iter = old_states.iterator();
              while (iter.hasNext()) {
                State old_sv = iter.next();
                if (eDominates(new_sv, old_sv)) {
                  iter.remove();
                }
              }
            }
            if (traverseVisitor != null) traverseVisitor.visitEnqueue(new_sv);

            old_states.add(new_sv);
            pq.insert(new_sv, new_sv.getWeight() + h);
          }
        }
      }
    }
    storeMemory();

    // Make the states into paths and return them
    List<GraphPath> paths = new LinkedList<GraphPath>();
    for (State s : returnStates) {
      LOG.debug(s.toStringVerbose());
      paths.add(new GraphPath(s, true));
    }
    // sort by arrival time, though paths are already in order of increasing difficulty
    // Collections.sort(paths, new PathComparator(origin.getOptions().isArriveBy()));
    return paths;
  }