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

org.opentripplanner.graph_builder.linking.SampleStopLinker Maven / Gradle / Ivy

There is a newer version: 2.6.0
Show newest version
package org.opentripplanner.graph_builder.linking;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import org.opentripplanner.analyst.core.Sample;
import org.opentripplanner.analyst.request.SampleFactory;
import org.opentripplanner.common.geometry.GeometryUtils;
import org.opentripplanner.common.geometry.SphericalDistanceLibrary;
import org.opentripplanner.routing.edgetype.IntersectionTransitLink;
import org.opentripplanner.routing.edgetype.SimpleTransfer;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.vertextype.OsmVertex;
import org.opentripplanner.routing.vertextype.TransitStop;

import java.util.Collection;

/**
 * Link transit stops to the street network in a non-destructive manner; i.e. don't
 * modify the street network. Being non-destructive is important in Analyst; new transit
 * models should not affect the length of existing streets, even slightly (due to float
 * roundoff from splits, etc.) An error of even a few seconds can be significant if it causes
 * the router to miss a transit vehicle or transfer, or causes the stop to move just beyond a
 * hard boundary. 
 * 
 * We do this by using the same linking code that is used
 * for Analyst (the SampleFactory code) which additionally means that this code
 * path is used and tested in multiple applications.
 *
 * This is not currently used. But it could be very useful for patching temporary transit lines in
 * interactively generated scenarios.
 */
public class SampleStopLinker {
    private Graph graph;

    /** keep track of stops that are linked to the same vertices */
    private Multimap links;

    public SampleStopLinker (Graph graph) {
        this.graph = graph;
    }

    /**
     * Link all transit stops. If makeTransfers is true, create direct transfer
     * edges between stops linked to the same pair of vertices. This is important
     * e.g. for transit centers where there are many stops on the same street segment;
     * we don't want to force the user to walk to the end of the street and back.
     * 
     * If you're not generating transfers via the street network there is no need to make
     * transfers at this stage. But if you're not generating transfers via the street network,
     * why are you using this module at all?
     */
    public void link (boolean makeTransfers) {
        if (makeTransfers)
            links = HashMultimap.create();

        SampleFactory sf = graph.getSampleFactory();

        for (TransitStop tstop : Iterables.filter(graph.getVertices(), TransitStop.class)) {
            Sample s = sf.getSample(tstop.getLon(), tstop.getLat());

            // TODO: stop unlinked annotation
            if (s == null)
                continue;

            new IntersectionTransitLink(tstop, (OsmVertex) s.v0, s.d0);
            new IntersectionTransitLink((OsmVertex) s.v0, tstop, s.d0);
            new IntersectionTransitLink(tstop, (OsmVertex) s.v1, s.d1);
            new IntersectionTransitLink((OsmVertex) s.v1, tstop, s.d1);

            if (makeTransfers) {
                // save the sample so we can make direct transfers between stops
                VertexPair vp = new VertexPair(s.v0, s.v1);
                links.put(vp, tstop);
            }
        }

        if (makeTransfers) {
            // make direct transfers between stops
            for (Collection tss : links.asMap().values()) {
                for (TransitStop ts0 : tss) {
                    for (TransitStop ts1 : tss) {
                        // make a geometry
                        GeometryFactory gf = GeometryUtils.getGeometryFactory();
                        LineString geom =
                                gf.createLineString(new Coordinate[] { ts0.getCoordinate(), ts1.getCoordinate() });

                        double dist =
                                SphericalDistanceLibrary.distance(ts0.getLat(), ts0.getLon(), ts1.getLat(), ts1.getLon());

                        // building unidirectional edge, we'll hit this again in the opposite direction
                        new SimpleTransfer(ts1, ts1, dist, geom);
                    }
                }
            }
        }
    }

    /** represents an unordered pair of vertices from a sample */
    private static class VertexPair {
        private final int v1, v2;

        public VertexPair(Vertex v1, Vertex v2) {
            this.v1 = v1.getIndex();
            this.v2 = v2.getIndex();
        }

        public int hashCode() {
            // bidirectional hash code
            return v1 + v2;
        }

        public boolean equals (Object other) {
            if (other instanceof VertexPair) {
                VertexPair vpo = (VertexPair) other;
                // bidirectional comparison
                return vpo.v1 == v1 && vpo.v2 == v2 || vpo.v2 == v1 && vpo.v1 == v2; 
            }

            return false;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy