public Geometry getGeometry() {
    if (geometry == null) {

      Coordinate c1 = new Coordinate(start.getLon(), start.getLat());
      Coordinate c2 = new Coordinate(end.getLon(), end.getLat());

      geometry = GeometryUtils.getGeometryFactory().createLineString(new Coordinate[] {c1, c2});
    }
    return geometry;
  }
  /**
   * Create an edge. If twoWay, create two edges (back and forth).
   *
   * @param vA
   * @param vB
   * @param length
   * @param back true if this is a reverse edge
   */
  private PlainStreetEdge edge(StreetVertex vA, StreetVertex vB, double length, boolean back) {
    String labelA = vA.getLabel();
    String labelB = vB.getLabel();
    String name = String.format("%s_%s", labelA, labelB);
    Coordinate[] coords = new Coordinate[2];
    coords[0] = vA.getCoordinate();
    coords[1] = vB.getCoordinate();
    LineString geom = GeometryUtils.getGeometryFactory().createLineString(coords);

    StreetTraversalPermission perm = StreetTraversalPermission.ALL;
    return new PlainStreetEdge(vA, vB, geom, name, length, perm, back);
  }
 private void finalizeLeg(
     Leg leg,
     State state,
     List<State> states,
     int start,
     int end,
     CoordinateArrayListSequence coordinates) {
   if (start != -1) {
     leg.walkSteps = getWalkSteps(states.subList(start, end + 1));
   }
   leg.endTime = makeCalendar(state.getBackState());
   Geometry geometry = GeometryUtils.getGeometryFactory().createLineString(coordinates);
   leg.legGeometry = PolylineEncoder.createEncodings(geometry);
   leg.to = makePlace(state, true);
   coordinates.clear();
 }
  private void finalizeLeg(
      Leg leg,
      State state,
      List<State> states,
      int start,
      int end,
      CoordinateArrayListSequence coordinates,
      Itinerary itinerary) {

    // this leg has already been added to the itinerary, so we actually want the penultimate leg, if
    // any
    if (states != null) {
      int extra = 0;
      WalkStep continuation = null;
      if (itinerary.legs.size() >= 2) {
        Leg previousLeg = itinerary.legs.get(itinerary.legs.size() - 2);
        if (previousLeg.walkSteps != null) {
          continuation = previousLeg.walkSteps.get(previousLeg.walkSteps.size() - 1);
          extra = 1;
        }
      }
      if (end == states.size() - 1) {
        extra = 1;
      }

      leg.walkSteps = getWalkSteps(states.subList(start, end + extra), continuation);
    }
    leg.endTime = makeCalendar(state.getBackState());
    Geometry geometry = GeometryUtils.getGeometryFactory().createLineString(coordinates);
    leg.legGeometry = PolylineEncoder.createEncodings(geometry);
    Edge backEdge = state.getBackEdge();
    String name;
    if (backEdge instanceof StreetEdge) {
      name = backEdge.getName();
    } else {
      name = state.getVertex().getName();
    }
    leg.to = makePlace(state, name, true);
    coordinates.clear();
  }
  @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);
  }
  /**
   * 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 void buildGraph(Graph graph, HashMap<Class<?>, Object> extra) {
    final Parser parser[] = new Parser[] {new Parser()};
    GeometryFactory geometryFactory = GeometryUtils.getGeometryFactory();
    EarliestArrivalSPTService earliestArrivalSPTService = new EarliestArrivalSPTService();
    earliestArrivalSPTService.maxDuration = (maxDuration);

    for (TransitStop ts : Iterables.filter(graph.getVertices(), TransitStop.class)) {
      // Only link street linkable stops
      if (!ts.isStreetLinkable()) continue;
      LOG.trace("linking stop '{}' {}", ts.getStop(), ts);

      // Determine the set of pathway/transfer destinations
      Set<TransitStop> pathwayDestinations = new HashSet<TransitStop>();
      for (Edge e : ts.getOutgoing()) {
        if (e instanceof PathwayEdge || e instanceof SimpleTransfer) {
          if (e.getToVertex() instanceof TransitStop) {
            TransitStop to = (TransitStop) e.getToVertex();
            pathwayDestinations.add(to);
          }
        }
      }

      int n = 0;
      RoutingRequest routingRequest = new RoutingRequest(TraverseMode.WALK);
      routingRequest.clampInitialWait = (0L);
      routingRequest.setRoutingContext(graph, ts, null);
      routingRequest.rctx.pathParsers = parser;
      ShortestPathTree spt = earliestArrivalSPTService.getShortestPathTree(routingRequest);

      if (spt != null) {
        for (State state : spt.getAllStates()) {
          Vertex vertex = state.getVertex();
          if (ts == vertex) continue;

          if (vertex instanceof TransitStop) {
            TransitStop other = (TransitStop) vertex;
            if (!other.isStreetLinkable()) continue;
            if (pathwayDestinations.contains(other)) {
              LOG.trace("Skipping '{}', {}, already connected.", other.getStop(), other);
              continue;
            }
            double distance = 0.0;
            GraphPath graphPath = new GraphPath(state, false);
            CoordinateArrayListSequence coordinates = new CoordinateArrayListSequence();

            for (Edge edge : graphPath.edges) {
              if (edge instanceof StreetEdge) {
                LineString geometry = edge.getGeometry();

                if (geometry != null) {
                  if (coordinates.size() == 0) {
                    coordinates.extend(geometry.getCoordinates());
                  } else {
                    coordinates.extend(geometry.getCoordinates(), 1);
                  }
                }

                distance += edge.getDistance();
              }
            }

            if (coordinates.size() < 2) { // Otherwise the walk step generator breaks.
              ArrayList<Coordinate> coordinateList = new ArrayList<Coordinate>(2);
              coordinateList.add(graphPath.states.get(1).getVertex().getCoordinate());
              State lastState = graphPath.states.getLast().getBackState();
              coordinateList.add(lastState.getVertex().getCoordinate());
              coordinates = new CoordinateArrayListSequence(coordinateList);
            }

            LineString geometry =
                geometryFactory.createLineString(
                    new PackedCoordinateSequence.Double(coordinates.toCoordinateArray()));
            LOG.trace("  to stop: '{}' {} ({}m) [{}]", other.getStop(), other, distance, geometry);
            new SimpleTransfer(ts, other, distance, geometry);
            n++;
          }
        }
      }

      LOG.trace("linked to {} others.", n);
      if (n == 0) {
        LOG.warn(graph.addBuilderAnnotation(new StopNotLinkedForTransfers(ts)));
      }
    }
  }