Search in sources :

Example 1 with StopCluster

use of org.opentripplanner.profile.StopCluster in project OpenTripPlanner by opentripplanner.

the class IndexAPI method getStopCluster.

/**
 * Return a cluster of stops by its ID.
 * A cluster is not the same thing as a GTFS parent station.
 * Clusters are an unsupported experimental feature that was added to assist in "profile routing".
 * As such the stop clustering method probably only works right with one or two GTFS data sets in the world.
 */
@GET
@Path("/clusters/{clusterId}")
public Response getStopCluster(@PathParam("clusterId") String clusterIdString) {
    index.clusterStopsAsNeeded();
    StopCluster cluster = index.stopClusterForId.get(clusterIdString);
    if (cluster != null) {
        return Response.status(Status.OK).entity(new StopClusterDetail(cluster, true)).build();
    } else {
        return Response.status(Status.NOT_FOUND).entity(MSG_404).build();
    }
}
Also used : StopCluster(org.opentripplanner.profile.StopCluster) StopClusterDetail(org.opentripplanner.index.model.StopClusterDetail) Path(javax.ws.rs.Path) GET(javax.ws.rs.GET)

Example 2 with StopCluster

use of org.opentripplanner.profile.StopCluster in project OpenTripPlanner by opentripplanner.

the class GraphIndex method initializeProfileTransfers.

/**
 * Initialize transfer data needed for profile routing.
 * Find the best transfers between each pair of patterns that pass near one another.
 */
public void initializeProfileTransfers() {
    transfersFromStopCluster = HashMultimap.create();
    // meters
    final double TRANSFER_RADIUS = 500.0;
    Map<P2<TripPattern>, ProfileTransfer.GoodTransferList> transfers = Maps.newHashMap();
    LOG.info("Finding transfers between clusters...");
    for (StopCluster sc0 : stopClusterForId.values()) {
        Set<TripPattern> tripPatterns0 = patternsForStopCluster(sc0);
        // Accounts for area-like (rather than point-like) nature of clusters
        Map<StopCluster, Double> nearbyStopClusters = findNearbyStopClusters(sc0, TRANSFER_RADIUS);
        for (StopCluster sc1 : nearbyStopClusters.keySet()) {
            double distance = nearbyStopClusters.get(sc1);
            Set<TripPattern> tripPatterns1 = patternsForStopCluster(sc1);
            for (TripPattern tp0 : tripPatterns0) {
                for (TripPattern tp1 : tripPatterns1) {
                    if (tp0 == tp1)
                        continue;
                    P2<TripPattern> pair = new P2<TripPattern>(tp0, tp1);
                    ProfileTransfer.GoodTransferList list = transfers.get(pair);
                    if (list == null) {
                        list = new ProfileTransfer.GoodTransferList();
                        transfers.put(pair, list);
                    }
                    list.add(new ProfileTransfer(tp0, tp1, sc0, sc1, (int) distance));
                }
            }
        }
    }
    /* Now filter the transfers down to eliminate long series of transfers in shared trunks. */
    LOG.info("Filtering out long series of transfers on trunks shared between patterns.");
    for (P2<TripPattern> pair : transfers.keySet()) {
        ProfileTransfer.GoodTransferList list = transfers.get(pair);
        // TODO consider using second (think of express-local transfers in NYC)
        TripPattern fromPattern = pair.first;
        Map<StopCluster, ProfileTransfer> transfersByFromCluster = Maps.newHashMap();
        for (ProfileTransfer transfer : list.good) {
            transfersByFromCluster.put(transfer.sc1, transfer);
        }
        List<ProfileTransfer> retainedTransfers = Lists.newArrayList();
        // true whenever a transfer existed for the last stop in the stop pattern
        boolean inSeries = false;
        for (Stop stop : fromPattern.stopPattern.stops) {
            StopCluster cluster = this.stopClusterForStop.get(stop);
            // LOG.info("stop {} cluster {}", stop, cluster.id);
            ProfileTransfer transfer = transfersByFromCluster.get(cluster);
            if (transfer == null) {
                inSeries = false;
                continue;
            }
            if (inSeries)
                continue;
            // Keep this transfer: it's not preceded by another stop with a transfer in this stop pattern
            retainedTransfers.add(transfer);
            inSeries = true;
        }
        // LOG.info("patterns {}, {} transfers", pair, retainedTransfers.size());
        for (ProfileTransfer tr : retainedTransfers) {
            transfersFromStopCluster.put(tr.sc1, tr);
        // LOG.info("   {}", tr);
        }
    }
    /*
         * for (Stop stop : transfersForStop.keys()) { System.out.println("STOP " + stop); for
         * (Transfer transfer : transfersForStop.get(stop)) { System.out.println("    " +
         * transfer.toString()); } }
         */
    LOG.info("Done finding transfers.");
}
Also used : P2(org.opentripplanner.common.model.P2) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) Stop(org.onebusaway.gtfs.model.Stop) StopCluster(org.opentripplanner.profile.StopCluster) TripPattern(org.opentripplanner.routing.edgetype.TripPattern) ProfileTransfer(org.opentripplanner.profile.ProfileTransfer)

Example 3 with StopCluster

use of org.opentripplanner.profile.StopCluster in project OpenTripPlanner by opentripplanner.

the class GraphIndex method clusterByProximityAndName.

/**
 * Cluster stops by proximity and name.
 * This functionality was developed for the Washington, DC area and probably will not work anywhere else in the
 * world. It depends on the exact way stops are named and the way street intersections are named in that geographic
 * region and in the GTFS data sets which represent it. Based on comments, apparently it might work for TriMet
 * as well.
 *
 * We can't use a name similarity comparison, we need exact matches. This is because many street names differ by
 * only one letter or number, e.g. 34th and 35th or Avenue A and Avenue B. Therefore normalizing the names before
 * the comparison is essential. The agency must provide either parent station information or a well thought out stop
 * naming scheme to cluster stops -- no guessing is reasonable without that information.
 */
private void clusterByProximityAndName() {
    // unique index for next parent stop
    int psIdx = 0;
    LOG.info("Clustering stops by geographic proximity and name...");
    // Each stop without a cluster will greedily claim other stops without clusters.
    for (Stop s0 : stopForId.values()) {
        // skip stops that have already been claimed by a cluster
        if (stopClusterForStop.containsKey(s0))
            continue;
        String s0normalizedName = StopNameNormalizer.normalize(s0.getName());
        StopCluster cluster = new StopCluster(String.format("C%03d", psIdx++), s0normalizedName);
        // LOG.info("stop {}", s0normalizedName);
        // No need to explicitly add s0 to the cluster. It will be found in the spatial index query below.
        Envelope env = new Envelope(new Coordinate(s0.getLon(), s0.getLat()));
        env.expandBy(SphericalDistanceLibrary.metersToLonDegrees(CLUSTER_RADIUS, s0.getLat()), SphericalDistanceLibrary.metersToDegrees(CLUSTER_RADIUS));
        for (TransitStop ts1 : stopSpatialIndex.query(env)) {
            Stop s1 = ts1.getStop();
            double geoDistance = SphericalDistanceLibrary.fastDistance(s0.getLat(), s0.getLon(), s1.getLat(), s1.getLon());
            if (geoDistance < CLUSTER_RADIUS) {
                String s1normalizedName = StopNameNormalizer.normalize(s1.getName());
                // LOG.info("       geodist {} stringdist {}", geoDistance, stringDistance);
                if (s1normalizedName.equals(s0normalizedName)) {
                    // Create a bidirectional relationship between the stop and its cluster
                    cluster.children.add(s1);
                    stopClusterForStop.put(s1, cluster);
                }
            }
        }
        cluster.computeCenter();
        stopClusterForId.put(cluster.id, cluster);
    }
}
Also used : TransitStop(org.opentripplanner.routing.vertextype.TransitStop) TransitStop(org.opentripplanner.routing.vertextype.TransitStop) Stop(org.onebusaway.gtfs.model.Stop) Coordinate(com.vividsolutions.jts.geom.Coordinate) StopCluster(org.opentripplanner.profile.StopCluster) Envelope(com.vividsolutions.jts.geom.Envelope)

Example 4 with StopCluster

use of org.opentripplanner.profile.StopCluster in project OpenTripPlanner by opentripplanner.

the class GraphIndex method clusterStopsAsNeeded.

/**
 * Stop clustering is slow to perform and only used in profile routing for the moment.
 * Therefore it is not done automatically, and any method requiring stop clusters should call this method
 * to ensure that the necessary indexes are lazy-initialized.
 */
public synchronized void clusterStopsAsNeeded() {
    if (stopClusterSpatialIndex == null) {
        clusterStops();
        LOG.info("Creating a spatial index for stop clusters.");
        stopClusterSpatialIndex = new HashGridSpatialIndex<>();
        for (StopCluster cluster : stopClusterForId.values()) {
            Envelope envelope = new Envelope(new Coordinate(cluster.lon, cluster.lat));
            stopClusterSpatialIndex.insert(envelope, cluster);
        }
    }
}
Also used : Coordinate(com.vividsolutions.jts.geom.Coordinate) StopCluster(org.opentripplanner.profile.StopCluster) Envelope(com.vividsolutions.jts.geom.Envelope)

Example 5 with StopCluster

use of org.opentripplanner.profile.StopCluster in project OpenTripPlanner by opentripplanner.

the class LuceneIndex method index.

/**
 * Index stations, stops, intersections, streets, and addresses by name and location.
 */
private void index() {
    try {
        long startTime = System.currentTimeMillis();
        /* Create or re-open a disk-backed Lucene Directory under the OTP server base filesystem directory. */
        directory = FSDirectory.open(new File(basePath, "lucene"));
        // TODO reuse the index if it exists?
        // directory = new RAMDirectory(); // only a little faster
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_47, analyzer).setOpenMode(OpenMode.CREATE);
        final IndexWriter writer = new IndexWriter(directory, config);
        for (Stop stop : graphIndex.stopForId.values()) {
            addStop(writer, stop);
        }
        graphIndex.clusterStopsAsNeeded();
        for (StopCluster stopCluster : graphIndex.stopClusterForId.values()) {
            addCluster(writer, stopCluster);
        }
        for (StreetVertex sv : Iterables.filter(graphIndex.vertexForId.values(), StreetVertex.class)) {
            addCorner(writer, sv);
        }
        writer.close();
        long elapsedTime = System.currentTimeMillis() - startTime;
        LOG.info("Built Lucene index in {} msec", elapsedTime);
        // Make the IndexSearcher necessary for querying.
        searcher = new IndexSearcher(DirectoryReader.open(directory));
    } catch (Exception ex) {
        throw new RuntimeException("Lucene indexing failed.", ex);
    }
}
Also used : IndexWriter(org.apache.lucene.index.IndexWriter) Stop(org.onebusaway.gtfs.model.Stop) StopCluster(org.opentripplanner.profile.StopCluster) StreetVertex(org.opentripplanner.routing.vertextype.StreetVertex) File(java.io.File) IOException(java.io.IOException) IndexWriterConfig(org.apache.lucene.index.IndexWriterConfig)

Aggregations

StopCluster (org.opentripplanner.profile.StopCluster)7 Stop (org.onebusaway.gtfs.model.Stop)4 Coordinate (com.vividsolutions.jts.geom.Coordinate)3 Envelope (com.vividsolutions.jts.geom.Envelope)3 TransitStop (org.opentripplanner.routing.vertextype.TransitStop)3 File (java.io.File)1 IOException (java.io.IOException)1 GET (javax.ws.rs.GET)1 Path (javax.ws.rs.Path)1 IndexWriter (org.apache.lucene.index.IndexWriter)1 IndexWriterConfig (org.apache.lucene.index.IndexWriterConfig)1 AgencyAndId (org.onebusaway.gtfs.model.AgencyAndId)1 P2 (org.opentripplanner.common.model.P2)1 StopClusterDetail (org.opentripplanner.index.model.StopClusterDetail)1 ProfileTransfer (org.opentripplanner.profile.ProfileTransfer)1 TripPattern (org.opentripplanner.routing.edgetype.TripPattern)1 StreetVertex (org.opentripplanner.routing.vertextype.StreetVertex)1