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();
}
}
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.");
}
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);
}
}
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);
}
}
}
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);
}
}
Aggregations