All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.transit.service.StopModel Maven / Gradle / Ivy

package org.opentripplanner.transit.service;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.locationtech.jts.geom.Envelope;
import org.opentripplanner.transit.model.basic.WgsCoordinate;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.site.AreaStop;
import org.opentripplanner.transit.model.site.GroupOfStations;
import org.opentripplanner.transit.model.site.GroupStop;
import org.opentripplanner.transit.model.site.MultiModalStation;
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.Station;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.model.site.StopLocationsGroup;
import org.opentripplanner.util.lang.CollectionsView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Repository for Stop entities.
 */
public class StopModel implements Serializable {

  private static final Logger LOG = LoggerFactory.getLogger(StopModel.class);

  private final Map regularStopById;
  private final Map stationById;
  private final Map multiModalStationById;
  private final Map groupOfStationsById;
  private final Map areaStopById;
  private final Map groupStopById;

  /** The density center of the graph for determining the initial geographic extent in the client. */
  private final WgsCoordinate stopLocationCenter;

  private transient StopModelIndex index;

  @Inject
  public StopModel() {
    this.regularStopById = Map.of();
    this.stationById = Map.of();
    this.multiModalStationById = Map.of();
    this.groupOfStationsById = Map.of();
    this.areaStopById = Map.of();
    this.groupStopById = Map.of();
    this.stopLocationCenter = null;
    this.index = new StopModelIndex(List.of(), List.of(), List.of(), List.of());
  }

  public StopModel(StopModelBuilder builder) {
    this.regularStopById = builder.regularStopsById().asImmutableMap();
    this.stationById = builder.stationById().asImmutableMap();
    this.multiModalStationById = builder.multiModalStationById().asImmutableMap();
    this.groupOfStationsById = builder.groupOfStationById().asImmutableMap();
    this.areaStopById = builder.areaStopById().asImmutableMap();
    this.groupStopById = builder.groupStopById().asImmutableMap();
    this.stopLocationCenter = builder.calculateTransitCenter();
    reindex();
  }

  public static StopModelBuilder of() {
    return new StopModelBuilder();
  }

  public StopModelBuilder copy() {
    return new StopModelBuilder(this);
  }

  /**
   * Return a regular transit stop if found(not flex stops).
   */
  public RegularStop getRegularStop(FeedScopedId id) {
    return regularStopById.get(id);
  }

  /**
   * Return all regular transit stops, not flex stops and flex group of stops.
   */
  public Collection listRegularStops() {
    return regularStopById.values();
  }

  public Collection findRegularStops(Envelope envelope) {
    return index.findRegularStops(envelope);
  }

  public boolean hasAreaStops() {
    return !areaStopById.isEmpty();
  }

  /**
   * Flex locations are generated by GTFS graph builder, but consumed only after the street graph is
   * built
   */
  @Nullable
  public AreaStop getAreaStop(FeedScopedId id) {
    return areaStopById.get(id);
  }

  public Collection listAreaStops() {
    return areaStopById.values();
  }

  public Collection queryLocationIndex(Envelope envelope) {
    return index.findAreaStops(envelope);
  }

  public Collection listGroupStops() {
    return groupStopById.values();
  }

  public StopLocation stopByIndex(int stopIndex) {
    return index.stopByIndex(stopIndex);
  }

  public int stopIndexSize() {
    return index.stopIndexSize();
  }

  public Optional stopLocationCenter() {
    return Optional.ofNullable(stopLocationCenter);
  }

  /**
   * Return regular transit stop, flex stop or flex group of stops.
   */
  @Nullable
  public StopLocation getStopLocation(FeedScopedId id) {
    return getById(id, regularStopById, areaStopById, groupStopById);
  }

  /**
   * Return all stops including regular transit stops, flex stops and flex group of stops.
   */
  public Collection listStopLocations() {
    return new CollectionsView<>(
      regularStopById.values(),
      areaStopById.values(),
      groupStopById.values()
    );
  }

  @Nullable
  public Station getStationById(FeedScopedId id) {
    return stationById.get(id);
  }

  public Collection listStations() {
    return stationById.values();
  }

  @Nullable
  public MultiModalStation getMultiModalStation(FeedScopedId id) {
    return multiModalStationById.get(id);
  }

  public Collection listMultiModalStations() {
    return multiModalStationById.values();
  }

  @Nullable
  public MultiModalStation getMultiModalStationForStation(Station station) {
    return index.getMultiModalStationForStation(station);
  }

  public Collection listGroupOfStations() {
    return groupOfStationsById.values();
  }

  /**
   * Finds a {@link StopLocationsGroup} by id. Return a station, multimodal station, or group of
   * station.
   */
  @Nullable
  public StopLocationsGroup getStopLocationsGroup(FeedScopedId id) {
    return getById(id, stationById, multiModalStationById, groupOfStationsById);
  }

  /**
   * Returns all {@link StopLocationsGroup}s present, including stations, group of stations and
   * multimodal stations.
   */
  public Collection listStopLocationGroups() {
    return new CollectionsView<>(
      stationById.values(),
      multiModalStationById.values(),
      groupOfStationsById.values()
    );
  }

  /**
   * @param id Id of Stop, Station, MultiModalStation or GroupOfStations
   * @return The coordinate for the transit entity
   */
  @Nullable
  public WgsCoordinate getCoordinateById(FeedScopedId id) {
    // GroupOfStations
    GroupOfStations groupOfStations = groupOfStationsById.get(id);
    if (groupOfStations != null) {
      return groupOfStations.getCoordinate();
    }
    // Multimodal station
    MultiModalStation multiModalStation = multiModalStationById.get(id);
    if (multiModalStation != null) {
      return multiModalStation.getCoordinate();
    }
    // Station
    Station station = stationById.get(id);
    if (station != null) {
      return station.getCoordinate();
    }
    // Single stop (regular transit and flex)
    StopLocation stop = getStopLocation(id);
    return stop == null ? null : stop.getCoordinate();
  }

  /**
   * Return all stops associated with the given id. If a Station, a MultiModalStation, or a
   * GroupOfStations matches the id, then all child stops are returned. If the id matches a regular
   * stops, area stop or stop group, then a list with one item is returned.
   * An empty list is if nothing is found.
   */
  public Collection findStopOrChildStops(FeedScopedId id) {
    StopLocationsGroup stops = getStopLocationsGroup(id);
    if (stops != null) {
      return stops.getChildStops();
    }

    // Single stop (regular transit and flex)
    StopLocation stop = getStopLocation(id);
    return stop == null ? List.of() : List.of(stop);
  }

  /**
   * Call this method after deserializing this class. This will reindex the StopModel.
   */
  public void reindexAfterDeserialization() {
    reindex();
  }

  private void reindex() {
    LOG.info("Index stop model...");
    index =
      new StopModelIndex(
        regularStopById.values(),
        areaStopById.values(),
        groupStopById.values(),
        multiModalStationById.values()
      );
    LOG.info("Index stop model complete.");
  }

  @Nullable
  @SafeVarargs
  private static  V getById(FeedScopedId id, Map... maps) {
    for (Map map : maps) {
      V v = map.get(id);
      if (v != null) {
        return v;
      }
    }
    return null;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy