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

org.opentripplanner.routing.spt.GraphPath Maven / Gradle / Ivy

package org.opentripplanner.routing.spt;

import java.util.LinkedList;

import org.locationtech.jts.geom.LineString;
import org.opentripplanner.api.resource.CoordinateArrayListSequence;
import org.opentripplanner.common.geometry.GeometryUtils;
import org.opentripplanner.routing.core.RoutingContext;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Vertex;

/**
 * A shortest path on the graph.
 */
public class GraphPath {
    public LinkedList states;

    public LinkedList edges;

    // needed to track repeat invocations of path-reversing methods
    private boolean back;

    private double walkDistance = 0;

    // don't really need to save this (available through State) but why not
    private RoutingContext rctx;

    /**
     * Construct a GraphPath based on the given state by following back-edge fields all the way back
     * to the origin of the search. This constructs a proper Java list of states (allowing random
     * access etc.) from the predecessor information left in states by the search algorithm.
     * 
     * Optionally re-traverses all edges backward in order to remove excess waiting time from the
     * final itinerary presented to the user. When planning with departure time, the edges will then
     * be re-traversed once more in order to move the waiting time forward in time, towards the end.
     *  @param s
     *            - the state for which a path is requested
     *
     */
    public GraphPath(State s) {
        this.rctx = s.getContext();
        this.back = s.getOptions().arriveBy;

        /* Put path in chronological order */
        State lastState;
        walkDistance = s.getWalkDistance();
        if (back) {
            lastState = s.reverse();
        } else {
            lastState = s;
        }

        /*
         * Starting from latest (time-wise) state, copy states to the head of a list in reverse
         * chronological order. List indices will thus increase forward in time, and backEdges will
         * be chronologically 'back' relative to their state.
         */
        this.states = new LinkedList<>();
        this.edges = new LinkedList<>();
        for (State cur = lastState; cur != null; cur = cur.getBackState()) {
            states.addFirst(cur);
            
            // Record the edge if it exists and this is not the first state in the path.
            if (cur.getBackEdge() != null && cur.getBackState() != null) {
                edges.addFirst(cur.getBackEdge());
            }
        }
    }

    /**
     * Returns the start time of the trip in seconds since the epoch.
     * @return
     */
    public long getStartTime() {
        return states.getFirst().getTimeSeconds();
    }

    /**
     * Returns the end time of the trip in seconds since the epoch.
     * @return
     */
    public long getEndTime() {
        return states.getLast().getTimeSeconds();
    }

    /**
     * Returns the duration of the trip in seconds.
     * @return
     */
    public int getDuration() {
        // test to see if it is the same as getStartTime - getEndTime;
        return (int) states.getLast().getElapsedTimeSeconds();
    }

    /**
     * Returns the total distance of all the edges in this path
     * @return
     */
    public double getDistanceMeters() {
        return edges.stream().mapToDouble(Edge::getDistanceMeters).sum();
    }

    public double getWeight() {
        return states.getLast().getWeight();
    }

    public Vertex getStartVertex() {
        return states.getFirst().getVertex();
    }

    public Vertex getEndVertex() {
        return states.getLast().getVertex();
    }

    /**
     * Returns the geometry for the entire path
     * @return
     */
    public LineString getGeometry() {
        CoordinateArrayListSequence coordinates = new CoordinateArrayListSequence();

        for (Edge edge : edges) {
            LineString geometry = edge.getGeometry();

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

        return GeometryUtils.getGeometryFactory().createLineString(coordinates);
    }

    public String toString() {
    	return "GraphPath(nStates=" + states.size() + ")";
    }

    /**
     * Two paths are equal if they use the same ordered list of trips
     */
    // TODO OTP2 How should this be implemented now that the GraphPath has no trips?
    public boolean equals(Object o) {
        return false;
    }

    // must compare edges, not states, since states are different at each search
    public int hashCode() {
        return this.edges.hashCode();
    }

    /****
     * Private Methods
     ****/

    public double getWalkDistance() {
        return walkDistance;
    }
    
    public RoutingContext getRoutingContext() {
        return rctx;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy