Package org.opentripplanner.routing.location

Source Code of org.opentripplanner.routing.location.StreetLocation

/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. */

package org.opentripplanner.routing.location;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.common.collect.Iterables;

import org.opentripplanner.common.TurnRestriction;
import org.opentripplanner.common.geometry.DistanceLibrary;
import org.opentripplanner.common.geometry.GeometryUtils;
import org.opentripplanner.common.geometry.PackedCoordinateSequence;
import org.opentripplanner.common.geometry.SphericalDistanceLibrary;
import org.opentripplanner.common.model.P2;
import org.opentripplanner.routing.core.RoutingContext;
import org.opentripplanner.routing.core.TraverseModeSet;
import org.opentripplanner.routing.edgetype.AreaEdge;
import org.opentripplanner.routing.edgetype.FreeEdge;
import org.opentripplanner.routing.edgetype.PartialStreetEdge;
import org.opentripplanner.routing.edgetype.StreetEdge;
import org.opentripplanner.routing.edgetype.StreetWithElevationEdge;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.impl.CandidateEdge;
import org.opentripplanner.routing.util.ElevationUtils;
import org.opentripplanner.routing.vertextype.StreetVertex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;

/**
* Represents a location on a street, somewhere between the two corners. This is used when computing the first and last segments of a trip, for trips
* that start or end between two intersections. Also for situating bus stops in the middle of street segments.
*/
public class StreetLocation extends StreetVertex {

    private static final Logger LOG = LoggerFactory.getLogger(StreetLocation.class);
   
    private static DistanceLibrary distanceLibrary = SphericalDistanceLibrary.getInstance();

    private ArrayList<Edge> extra = new ArrayList<Edge>();

    private boolean wheelchairAccessible;

    private ArrayList<StreetEdge> edges;

    private Graph graph;

    // maybe name should just be pulled from street being split
    public StreetLocation(Graph graph, String id, Coordinate nearestPoint, String name) {
        // calling constructor with null graph means this vertex is temporary
        super(null, id, nearestPoint.x, nearestPoint.y, name);
        this.graph = graph;
    }

    private static final long serialVersionUID = 1L;

    /**
     * Creates a StreetLocation on the given street (set of PlainStreetEdges). How far along is controlled by the location parameter, which represents
     * a distance along the edge between 0 (the from vertex) and 1 (the to vertex).
     *
     * @param graph
     *
     * @param label
     * @param name
     * @param edges A collection of nearby edges, which represent one street.
     * @param nearestPoint
     *
     * @return the new StreetLocation
     */
    public static StreetLocation createStreetLocation(Graph graph, String label, String name,
            Iterable<StreetEdge> edges, Coordinate nearestPoint, Coordinate originalCoordinate) {

        /* linking vertex with epsilon transitions */
        StreetLocation location = createStreetLocation(graph, label, name, edges, nearestPoint);

        /* Extra edges for this area */
        Set<StreetEdge> allEdges = new HashSet<StreetEdge>();
        TraverseModeSet modes = new TraverseModeSet();
        for (StreetEdge street : edges) {
            allEdges.add(street);
            if (street instanceof AreaEdge) {
                for (StreetEdge e : ((AreaEdge) street).getArea().getEdges()) {
                    if (!allEdges.contains(e)) {
                        CandidateEdge ce = new CandidateEdge(e, originalCoordinate, 0, modes);
                        if (ce.endwise() || ce.distance > .0005) {
                            // skip inappropriate area edges
                            continue;
                        }
                        StreetLocation areaSplitter = createStreetLocation(graph, label, name,
                                Arrays.asList(e), ce.nearestPointOnEdge);
                        location.extra.addAll(areaSplitter.getExtra());
                        location.extra.add(new FreeEdge(location, areaSplitter));
                        location.extra.add(new FreeEdge(areaSplitter, location));
                        allEdges.add(e);
                    }
                }
            }
        }
        location.setSourceEdges(allEdges);

        return location;
    }

    /**
     * Creates the StreetLocation along the given edges regardless of how close it is to the endpoints of the edge.
     */
    public static StreetLocation createStreetLocationOnEdges(Graph graph, String label, String name,
            Iterable<StreetEdge> edges, Coordinate nearestPoint) {

        boolean wheelchairAccessible = false;

        StreetLocation location = new StreetLocation(graph, label, nearestPoint, name);
        for (StreetEdge street : edges) {
            Vertex fromv = street.getFromVertex();
            Vertex tov = street.getToVertex();
            wheelchairAccessible |= ((StreetEdge) street).isWheelchairAccessible();
            /* forward edges and vertices */
            Vertex edgeLocation;

            // location is somewhere in the middle of the edge.
            edgeLocation = location;
           
            // creates links from street head -> location -> street tail.
            createHalfLocation(graph, location, label + " to " + tov.getLabel(), name,
                    nearestPoint, street);
        }
        location.setWheelchairAccessible(wheelchairAccessible);
        return location;

    }
   
    public static StreetLocation createStreetLocation(Graph graph, String label, String name,
            Iterable<StreetEdge> edges, Coordinate nearestPoint) {

        boolean wheelchairAccessible = false;

        StreetLocation location = new StreetLocation(graph, label, nearestPoint, name);
        for (StreetEdge street : edges) {
            Vertex fromv = street.getFromVertex();
            Vertex tov = street.getToVertex();
            wheelchairAccessible |= ((StreetEdge) street).isWheelchairAccessible();
            /* forward edges and vertices */
            Vertex edgeLocation;
            if (distanceLibrary.distance(nearestPoint, fromv.getCoordinate()) < 1) {
                // no need to link to area edges caught on-end
                edgeLocation = fromv;
                new FreeEdge(location, edgeLocation);
                new FreeEdge(edgeLocation, location);
            } else if (distanceLibrary.distance(nearestPoint, tov.getCoordinate()) < 1) {
                // no need to link to area edges caught on-end
                edgeLocation = tov;
                new FreeEdge(location, edgeLocation);
                new FreeEdge(edgeLocation, location);
            } else {
                // location is somewhere in the middle of the edge.
                edgeLocation = location;
               
                // creates links from street head -> location -> street tail.
                createHalfLocation(graph, location, label + " to " + tov.getLabel(), name,
                        nearestPoint, street);
            }
        }
        location.setWheelchairAccessible(wheelchairAccessible);
        return location;

    }

    private void setSourceEdges(Iterable<StreetEdge> edges) {
        this.edges = new ArrayList<StreetEdge>();
        for (StreetEdge edge : edges) {
            this.edges.add(edge);
        }
    }

    public List<StreetEdge> getSourceEdges() {
        return edges;
    }

    private static void createHalfLocation(Graph graph, StreetLocation base, String label,
            String name, Coordinate nearestPoint, StreetEdge street) {

        StreetVertex tov = (StreetVertex) street.getToVertex();
        StreetVertex fromv = (StreetVertex) street.getFromVertex();
        Geometry geometry = street.getGeometry();

        P2<LineString> geometries = getGeometry(street, nearestPoint);

        double totalGeomLength = geometry.getLength();
        double lengthRatioIn = geometries.first.getLength() / totalGeomLength;

        double lengthIn = street.getDistance() * lengthRatioIn;
        double lengthOut = street.getDistance() * (1 - lengthRatioIn);

        StreetWithElevationEdge newLeft = new PartialStreetEdge(street, fromv, base,
                geometries.first, name, lengthIn);
        StreetWithElevationEdge newRight = new PartialStreetEdge(street, base, tov,
                geometries.second, name, lengthOut);

        newLeft.setElevationProfile(ElevationUtils.getPartialElevationProfile(
                street.getElevationProfile(), 0, lengthIn), false);
        newLeft.setNoThruTraffic(street.isNoThruTraffic());
        newLeft.setStreetClass(street.getStreetClass());

        newRight.setElevationProfile(ElevationUtils.getPartialElevationProfile(
                street.getElevationProfile(), lengthIn, lengthIn + lengthOut), false);
        newRight.setStreetClass(street.getStreetClass());
        newRight.setNoThruTraffic(street.isNoThruTraffic());
       
        // Copy turn restrictions onto the outgoing half-edge.
        for (TurnRestriction turnRestriction : graph.getTurnRestrictions(street)) {
            graph.addTurnRestriction(newRight, turnRestriction);
        }
        base.extra.add(newLeft);
        base.extra.add(newRight);
    }

    private static P2<LineString> getGeometry(StreetEdge e, Coordinate nearestPoint) {
        Geometry geometry = e.getGeometry();
        return GeometryUtils.splitGeometryAtPoint(geometry, nearestPoint);
    }

    // public void reify(Graph graph) {
    // if (graph.getVertex(label) != null) {
    // // already reified
    // return;
    // }
    //
    // for (Edge e : extra) {
    // graph.addVerticesFromEdge(e);
    // }
    // }

    public List<Edge> getExtra() {
        return extra;
    }

    public void setWheelchairAccessible(boolean wheelchairAccessible) {
        this.wheelchairAccessible = wheelchairAccessible;
    }

    public boolean isWheelchairAccessible() {
        return wheelchairAccessible;
    }

    public boolean equals(Object o) {
        if (o instanceof StreetLocation) {
            StreetLocation other = (StreetLocation) o;
            return other.getCoordinate().equals(getCoordinate());
        }
        return false;
    }

    @Override
    public int hashCode() {
        return getCoordinate().hashCode();
    }

    public void addExtraEdgeTo(Vertex target) {
        extra.add(new FreeEdge(this, target));
        extra.add(new FreeEdge(target, this));
    }

    @Override
    public int removeTemporaryEdges(Graph graph) {
        int nRemoved = 0;
        for (Edge e : getExtra()) {           
            graph.removeTemporaryEdge(e);
            // edges might already be detached
            if (e.detach(graph) != 0) nRemoved += 1;
        }
        return nRemoved;
    }

    /**
     * This finalizer is intended as a failsafe to prevent memory leakage in case someone does
     * not remove temporary edges. It could even be considered an error if it does any work.
     * removeTemporaryEdges is called by both this finalizer and the RoutingContext.destroy()
     * method, which is in turn called by the RoutingRequest.cleanup() method. You need to call
     * one of these after you handle a request and know that you no longer need the context.
     */
    @Override
    public void finalize() {
        if (removeTemporaryEdges(graph) > 0)
            LOG.error("Temporary edges were removed by finalizer: this is a memory leak.");
    }

    /**
     * Temporary edges are traversable to only one routing context. It was too awkward to rework all the edge-splitting
     * code to pass the routing context down into the temporary edge constructors. Therefore we set the context for
     * all temporary edges after they are created.
     */
    public void setTemporaryEdgeVisibility(RoutingContext rctx) {
        for (PartialStreetEdge ppse : Iterables.filter(this.extra, PartialStreetEdge.class)) {
            ppse.visibleTo = rctx;
        }
        // There are other temporary edges (FreeEdges) but it's a rabbit hole...
        // better to fix this be completely redoing how temporary endpoint vertices are created.
    }

}
TOP

Related Classes of org.opentripplanner.routing.location.StreetLocation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.