Search in sources :

Example 56 with StreetEdge

use of org.opentripplanner.routing.edgetype.StreetEdge in project OpenTripPlanner by opentripplanner.

the class SampleFactory method getSample.

@Override
public /**
 * implements SampleSource interface
 */
Sample getSample(double lon, double lat) {
    Coordinate c = new Coordinate(lon, lat);
    // query always returns a (possibly empty) list, but never null
    Envelope env = new Envelope(c);
    // find scaling factor for equirectangular projection
    double xscale = Math.cos(c.y * Math.PI / 180);
    env.expandBy(searchRadiusLat / xscale, searchRadiusLat);
    @SuppressWarnings("unchecked") Collection<Vertex> vertices = graph.streetIndex.getVerticesForEnvelope(env);
    // make sure things are in the radius
    final TIntDoubleMap distances = new TIntDoubleHashMap();
    for (Vertex v : vertices) {
        if (!(v instanceof OsmVertex))
            continue;
        // figure ersatz distance
        double dx = (lon - v.getLon()) * xscale;
        double dy = lat - v.getLat();
        distances.put(v.getIndex(), dx * dx + dy * dy);
    }
    List<Vertex> sorted = new ArrayList<Vertex>();
    for (Vertex input : vertices) {
        if (!(input instanceof OsmVertex && distances.get(input.getIndex()) < searchRadiusLat * searchRadiusLat))
            continue;
        for (StreetEdge e : Iterables.filter(input.getOutgoing(), StreetEdge.class)) {
            if (e.canTraverse(new TraverseModeSet(TraverseMode.WALK))) {
                sorted.add(input);
                break;
            }
        }
    }
    // sort list by distance
    Collections.sort(sorted, new Comparator<Vertex>() {

        @Override
        public int compare(Vertex o1, Vertex o2) {
            double d1 = distances.get(o1.getIndex());
            double d2 = distances.get(o2.getIndex());
            if (d1 < d2)
                return -1;
            else if (d1 > d2)
                return 1;
            else
                return 0;
        }
    });
    Vertex v0, v1;
    if (sorted.isEmpty())
        return null;
    else if (sorted.size() <= 2) {
        v0 = sorted.get(0);
        v1 = sorted.size() > 1 ? sorted.get(1) : null;
    } else {
        int vxi = 0;
        // Group them by distance
        Vertex[] vx = new Vertex[2];
        ArrayList<Vertex> grouped = new ArrayList<>();
        // of at least EPSILON. Once we've done that, break ties using labels (which are OSM IDs).
        for (int i = 0; i < sorted.size(); i++) {
            if (vxi >= 2)
                break;
            if (grouped.isEmpty()) {
                grouped.add(sorted.get(i));
                continue;
            }
            double dlast = distances.get(sorted.get(i - 1).getIndex());
            double dthis = distances.get(sorted.get(i).getIndex());
            if (dthis - dlast < EPSILON) {
                grouped.add(sorted.get(i));
                continue;
            } else {
                // we have a distinct group of vertices
                // sort them by OSM IDs
                // this seems like it would be slow but keep in mind that it will only do any work
                // when there are multiple members of a group, which is relatively rare.
                Collections.sort(grouped, (vv1, vv2) -> vv1.getLabel().compareTo(vv2.getLabel()));
                // then loop over the list until it's empty or we've found two vertices
                int gi = 0;
                while (vxi < 2 && gi < grouped.size()) {
                    vx[vxi++] = grouped.get(gi++);
                }
                // get ready for the next group
                grouped.clear();
            }
        }
        v0 = vx[0];
        v1 = vx[1];
    }
    double d0 = v0 != null ? SphericalDistanceLibrary.distance(v0.getLat(), v0.getLon(), lat, lon) : 0;
    double d1 = v1 != null ? SphericalDistanceLibrary.distance(v1.getLat(), v1.getLon(), lat, lon) : 0;
    return new Sample(v0, (int) d0, v1, (int) d1);
}
Also used : Coordinate(com.vividsolutions.jts.geom.Coordinate) Iterables(com.google.common.collect.Iterables) java.util(java.util) Envelope(com.vividsolutions.jts.geom.Envelope) Vertex(org.opentripplanner.routing.graph.Vertex) TIntDoubleHashMap(gnu.trove.map.hash.TIntDoubleHashMap) OsmVertex(org.opentripplanner.routing.vertextype.OsmVertex) StreetEdge(org.opentripplanner.routing.edgetype.StreetEdge) Sample(org.opentripplanner.analyst.core.Sample) SphericalDistanceLibrary(org.opentripplanner.common.geometry.SphericalDistanceLibrary) LineString(com.vividsolutions.jts.geom.LineString) TraverseModeSet(org.opentripplanner.routing.core.TraverseModeSet) GeometryUtils(org.opentripplanner.common.geometry.GeometryUtils) TIntDoubleMap(gnu.trove.map.TIntDoubleMap) Graph(org.opentripplanner.routing.graph.Graph) SampleSource(org.opentripplanner.analyst.core.SampleSource) TraverseMode(org.opentripplanner.routing.core.TraverseMode) CoordinateSequence(com.vividsolutions.jts.geom.CoordinateSequence) Edge(org.opentripplanner.routing.graph.Edge) Vertex(org.opentripplanner.routing.graph.Vertex) OsmVertex(org.opentripplanner.routing.vertextype.OsmVertex) Sample(org.opentripplanner.analyst.core.Sample) TIntDoubleMap(gnu.trove.map.TIntDoubleMap) StreetEdge(org.opentripplanner.routing.edgetype.StreetEdge) TraverseModeSet(org.opentripplanner.routing.core.TraverseModeSet) Envelope(com.vividsolutions.jts.geom.Envelope) Coordinate(com.vividsolutions.jts.geom.Coordinate) TIntDoubleHashMap(gnu.trove.map.hash.TIntDoubleHashMap) OsmVertex(org.opentripplanner.routing.vertextype.OsmVertex)

Example 57 with StreetEdge

use of org.opentripplanner.routing.edgetype.StreetEdge in project OpenTripPlanner by opentripplanner.

the class SampleFactory method findClosest.

/**
 * DistanceToPoint.computeDistance() uses a LineSegment, which has a closestPoint method.
 * That finds the true distance every time rather than once the closest segment is known,
 * and does not allow for equi-rectangular projection/scaling.
 *
 * Here we want to compare squared distances to all line segments until we find the best one,
 * then do the precise calculations.
 */
public Sample findClosest(List<Edge> edges, Coordinate pt, double xscale) {
    Candidate c = new Candidate();
    // track the best geometry
    Candidate best = new Candidate();
    for (Edge edge : edges) {
        /* LineString.getCoordinates() uses PackedCoordinateSequence.toCoordinateArray() which
             * necessarily builds new Coordinate objects.CoordinateSequence.getOrdinate() reads them 
             * directly. */
        c.edge = edge;
        LineString ls = (LineString) (edge.getGeometry());
        // one of the two a sample gets linked to is effectively random.
        if (!edge.getFromVertex().getLabel().startsWith("osm:node:") || (edge instanceof StreetEdge && ((StreetEdge) edge).isBack()))
            continue;
        CoordinateSequence coordSeq = ls.getCoordinateSequence();
        int numCoords = coordSeq.size();
        for (int seg = 0; seg < numCoords - 1; seg++) {
            c.seg = seg;
            double x0 = coordSeq.getX(seg);
            double y0 = coordSeq.getY(seg);
            double x1 = coordSeq.getX(seg + 1);
            double y1 = coordSeq.getY(seg + 1);
            // use bounding rectangle to find a lower bound on (squared) distance ?
            // this would mean more squaring or roots.
            c.frac = GeometryUtils.segmentFraction(x0, y0, x1, y1, pt.x, pt.y, xscale);
            // project to get closest point
            // note: no need to multiply anything by xscale; the fraction is scaleless.
            c.x = x0 + c.frac * (x1 - x0);
            c.y = y0 + c.frac * (y1 - y0);
            // find ersatz distance to edge (do not take root)
            double dx = (c.x - pt.x) * xscale;
            double dy = c.y - pt.y;
            c.dist2 = dx * dx + dy * dy;
            // replace best segments
            if (c.dist2 < best.dist2) {
                best.setFrom(c);
            }
        }
    // end loop over segments
    }
    // if at least one vertex was found make a sample
    if (best.edge != null) {
        Vertex v0 = best.edge.getFromVertex();
        // Vertex v1 = best.edge.getToVertex();
        Vertex v1 = v0;
        double d = best.distanceTo(pt);
        if (d > searchRadiusM)
            return null;
        double d0 = d + best.distanceAlong();
        // double d1 = d + best.distanceToEnd();
        double d1 = d0;
        Sample s = new Sample(v0, (int) d0, v1, (int) d1);
        // System.out.println(s.toString());
        return s;
    }
    return null;
}
Also used : CoordinateSequence(com.vividsolutions.jts.geom.CoordinateSequence) Vertex(org.opentripplanner.routing.graph.Vertex) OsmVertex(org.opentripplanner.routing.vertextype.OsmVertex) LineString(com.vividsolutions.jts.geom.LineString) Sample(org.opentripplanner.analyst.core.Sample) StreetEdge(org.opentripplanner.routing.edgetype.StreetEdge) StreetEdge(org.opentripplanner.routing.edgetype.StreetEdge) Edge(org.opentripplanner.routing.graph.Edge)

Example 58 with StreetEdge

use of org.opentripplanner.routing.edgetype.StreetEdge in project OpenTripPlanner by opentripplanner.

the class NycFareServiceImpl method getCost.

@Override
public Fare getCost(GraphPath path) {
    final List<AgencyAndId> SIR_PAID_STOPS = makeMtaStopList("S31", "S30");
    final List<AgencyAndId> SUBWAY_FREE_TRANSFER_STOPS = makeMtaStopList("R11", "B08", "629");
    final List<AgencyAndId> SIR_BONUS_STOPS = makeMtaStopList("140", "420", "419", "418", "M22", "M23", "R27", "R26");
    final List<AgencyAndId> SIR_BONUS_ROUTES = makeMtaStopList("M5", "M20", "M15-SBS");
    final List<AgencyAndId> CANARSIE = makeMtaStopList("L29", "303345");
    // List of NYC agencies to set fares for
    final List<String> AGENCIES = new ArrayList<>();
    AGENCIES.add("MTABC");
    AGENCIES.add("MTA NYCT");
    LinkedList<State> states = path.states;
    // create rides
    List<Ride> rides = new ArrayList<Ride>();
    Ride newRide = null;
    final int SUBWAY = 1;
    final int SIR = 2;
    final int LOCAL_BUS = 3;
    final int EXPRESS_BUS = 30;
    final int EXPENSIVE_EXPRESS_BUS = 34;
    final int WALK = -1;
    for (State state : states) {
        Edge backEdge = state.getBackEdge();
        if (backEdge instanceof StreetEdge) {
            if (newRide == null || !newRide.classifier.equals(WALK)) {
                if (rides.size() == 0 || !rides.get(rides.size() - 1).classifier.equals(WALK)) {
                    newRide = new Ride();
                    newRide.classifier = WALK;
                    rides.add(newRide);
                }
            }
            continue;
        }
        // dwells do not affect fare.
        if (backEdge instanceof DwellEdge)
            continue;
        if (!(backEdge instanceof HopEdge)) {
            newRide = null;
            continue;
        }
        AgencyAndId routeId = state.getRoute();
        String agencyId = state.getBackTrip().getRoute().getAgency().getId();
        if (!AGENCIES.contains(agencyId)) {
            continue;
        }
        if (routeId == null) {
            newRide = null;
        } else {
            if (newRide == null || !routeId.equals(newRide.route)) {
                newRide = new Ride();
                rides.add(newRide);
                newRide.firstStop = ((HopEdge) backEdge).getBeginStop();
                newRide.route = routeId;
                Trip trip = state.getBackTrip();
                Route route = trip.getRoute();
                int type = route.getType();
                newRide.classifier = type;
                String shortName = route.getShortName();
                if (shortName == null) {
                    newRide.classifier = SUBWAY;
                } else if (shortName.equals("BxM4C")) {
                    newRide.classifier = EXPENSIVE_EXPRESS_BUS;
                } else if (shortName.startsWith("X") || shortName.startsWith("BxM") || shortName.startsWith("QM") || shortName.startsWith("BM")) {
                    // Express bus
                    newRide.classifier = EXPRESS_BUS;
                }
                newRide.startTime = state.getTimeSeconds();
            }
            newRide.lastStop = ((HopEdge) backEdge).getBeginStop();
        }
    }
    // There are no rides, so there's no fare.
    if (rides.size() == 0) {
        return null;
    }
    NycFareState state = NycFareState.INIT;
    boolean lexFreeTransfer = false;
    boolean canarsieFreeTransfer = false;
    boolean siLocalBus = false;
    boolean sirBonusTransfer = false;
    float totalFare = 0;
    for (Ride ride : rides) {
        AgencyAndId firstStopId = null;
        AgencyAndId lastStopId = null;
        if (ride.firstStop != null) {
            firstStopId = ride.firstStop.getId();
            lastStopId = ride.lastStop.getId();
        }
        switch(state) {
            case INIT:
                lexFreeTransfer = siLocalBus = canarsieFreeTransfer = false;
                if (ride.classifier.equals(WALK)) {
                // walking keeps you in init
                } else if (ride.classifier.equals(SUBWAY)) {
                    state = NycFareState.SUBWAY_PRE_TRANSFER;
                    totalFare += ORDINARY_FARE;
                    if (SUBWAY_FREE_TRANSFER_STOPS.contains(ride.lastStop.getId())) {
                        lexFreeTransfer = true;
                    }
                    if (CANARSIE.contains(ride.lastStop.getId())) {
                        canarsieFreeTransfer = true;
                    }
                } else if (ride.classifier.equals(SIR)) {
                    state = NycFareState.SIR_PRE_TRANSFER;
                    if (SIR_PAID_STOPS.contains(firstStopId) || SIR_PAID_STOPS.contains(lastStopId)) {
                        totalFare += ORDINARY_FARE;
                    }
                } else if (ride.classifier.equals(LOCAL_BUS)) {
                    state = NycFareState.BUS_PRE_TRANSFER;
                    totalFare += ORDINARY_FARE;
                    if (CANARSIE.contains(ride.lastStop.getId())) {
                        canarsieFreeTransfer = true;
                    }
                    siLocalBus = ride.route.getId().startsWith("S");
                } else if (ride.classifier.equals(EXPRESS_BUS)) {
                    state = NycFareState.BUS_PRE_TRANSFER;
                    totalFare += EXPRESS_FARE;
                } else if (ride.classifier.equals(EXPENSIVE_EXPRESS_BUS)) {
                    state = NycFareState.EXPENSIVE_EXPRESS_BUS;
                    totalFare += EXPENSIVE_EXPRESS_FARE;
                }
                break;
            case SUBWAY_PRE_TRANSFER_WALKED:
                if (ride.classifier.equals(SUBWAY)) {
                    // lex and 59/63
                    if (!(lexFreeTransfer && SUBWAY_FREE_TRANSFER_STOPS.contains(ride.firstStop.getId()))) {
                        totalFare += ORDINARY_FARE;
                    }
                    lexFreeTransfer = canarsieFreeTransfer = false;
                    if (SUBWAY_FREE_TRANSFER_STOPS.contains(ride.lastStop.getId())) {
                        lexFreeTransfer = true;
                    }
                    if (CANARSIE.contains(ride.lastStop.getId())) {
                        canarsieFreeTransfer = true;
                    }
                }
            /* FALL THROUGH */
            case SUBWAY_PRE_TRANSFER:
                // hours (if only just)
                if (ride.classifier.equals(WALK)) {
                    state = NycFareState.SUBWAY_PRE_TRANSFER_WALKED;
                } else if (ride.classifier.equals(SIR)) {
                    state = NycFareState.SIR_POST_TRANSFER_FROM_SUBWAY;
                } else if (ride.classifier.equals(LOCAL_BUS)) {
                    if (CANARSIE.contains(ride.firstStop.getId()) && canarsieFreeTransfer) {
                        state = NycFareState.BUS_PRE_TRANSFER;
                    } else {
                        state = NycFareState.INIT;
                    }
                } else if (ride.classifier.equals(EXPRESS_BUS)) {
                    // need to pay the upgrade cost
                    totalFare += EXPRESS_FARE - ORDINARY_FARE;
                } else if (ride.classifier.equals(EXPENSIVE_EXPRESS_BUS)) {
                    // no transfers to the
                    totalFare += EXPENSIVE_EXPRESS_FARE;
                // BxMM4C
                }
                break;
            case BUS_PRE_TRANSFER:
                if (ride.classifier.equals(SUBWAY)) {
                    if (CANARSIE.contains(ride.firstStop.getId()) && canarsieFreeTransfer) {
                        state = NycFareState.SUBWAY_PRE_TRANSFER;
                    } else {
                        state = NycFareState.INIT;
                    }
                } else if (ride.classifier.equals(SIR)) {
                    if (siLocalBus) {
                        // SI local bus to SIR, so it is as if we started on the
                        // SIR (except that when we enter the bus or subway system we need to do
                        // so at certain places)
                        sirBonusTransfer = true;
                        state = NycFareState.SIR_PRE_TRANSFER;
                    } else {
                        // transfers exhausted
                        state = NycFareState.INIT;
                    }
                } else if (ride.classifier.equals(LOCAL_BUS)) {
                    state = NycFareState.INIT;
                } else if (ride.classifier.equals(EXPRESS_BUS)) {
                    // need to pay the upgrade cost
                    totalFare += EXPRESS_FARE - ORDINARY_FARE;
                    state = NycFareState.INIT;
                } else if (ride.classifier.equals(EXPENSIVE_EXPRESS_BUS)) {
                    totalFare += EXPENSIVE_EXPRESS_FARE;
                // no transfers to the BxMM4C
                }
                break;
            case SIR_PRE_TRANSFER:
                if (ride.classifier.equals(SUBWAY)) {
                    if (sirBonusTransfer && !SIR_BONUS_STOPS.contains(ride.firstStop.getId())) {
                        // we were relying on the bonus transfer to be in the "pre-transfer state",
                        // but the bonus transfer does not apply here
                        totalFare += ORDINARY_FARE;
                    }
                    if (CANARSIE.contains(ride.lastStop.getId())) {
                        canarsieFreeTransfer = true;
                    }
                    state = NycFareState.SUBWAY_POST_TRANSFER;
                } else if (ride.classifier.equals(SIR)) {
                    /* should not happen, and unhandled */
                    LOG.warn("Should not transfer from SIR to SIR");
                } else if (ride.classifier.equals(LOCAL_BUS)) {
                    if (!SIR_BONUS_ROUTES.contains(ride.route)) {
                        totalFare += ORDINARY_FARE;
                    }
                    state = NycFareState.BUS_PRE_TRANSFER;
                } else if (ride.classifier.equals(EXPRESS_BUS)) {
                    totalFare += EXPRESS_BUS;
                    state = NycFareState.BUS_PRE_TRANSFER;
                } else if (ride.classifier.equals(EXPENSIVE_EXPRESS_BUS)) {
                    totalFare += EXPENSIVE_EXPRESS_BUS;
                    state = NycFareState.BUS_PRE_TRANSFER;
                }
                break;
            case SIR_POST_TRANSFER_FROM_SUBWAY:
                if (ride.classifier.equals(SUBWAY)) {
                    /* should not happen */
                    totalFare += ORDINARY_FARE;
                    state = NycFareState.SUBWAY_PRE_TRANSFER;
                } else if (ride.classifier.equals(SIR)) {
                    /* should not happen, and unhandled */
                    LOG.warn("Should not transfer from SIR to SIR");
                } else if (ride.classifier.equals(LOCAL_BUS)) {
                    if (!ride.route.getId().startsWith("S")) {
                        totalFare += ORDINARY_FARE;
                        state = NycFareState.BUS_PRE_TRANSFER;
                    } else {
                        state = NycFareState.INIT;
                    }
                } else if (ride.classifier.equals(EXPRESS_BUS)) {
                    // need to pay the full cost
                    totalFare += EXPRESS_FARE;
                    state = NycFareState.INIT;
                } else if (ride.classifier.equals(EXPENSIVE_EXPRESS_BUS)) {
                    /* should not happen */
                    // no transfers to the BxMM4C
                    totalFare += EXPENSIVE_EXPRESS_FARE;
                    state = NycFareState.BUS_PRE_TRANSFER;
                }
                break;
            case SUBWAY_POST_TRANSFER:
                if (ride.classifier.equals(WALK)) {
                    if (!canarsieFreeTransfer) {
                        /* note: if we end up walking to another subway after alighting
			    		 * at Canarsie, we will mistakenly not be charged, but nobody
			    		 * would ever do this */
                        state = NycFareState.INIT;
                    }
                } else if (ride.classifier.equals(SIR)) {
                    totalFare += ORDINARY_FARE;
                    state = NycFareState.SIR_PRE_TRANSFER;
                } else if (ride.classifier.equals(LOCAL_BUS)) {
                    if (!(CANARSIE.contains(ride.firstStop.getId()) && canarsieFreeTransfer)) {
                        totalFare += ORDINARY_FARE;
                    }
                    state = NycFareState.INIT;
                } else if (ride.classifier.equals(SUBWAY)) {
                    // walking transfer
                    totalFare += ORDINARY_FARE;
                    state = NycFareState.SUBWAY_PRE_TRANSFER;
                } else if (ride.classifier.equals(EXPRESS_BUS)) {
                    totalFare += EXPRESS_FARE;
                    state = NycFareState.BUS_PRE_TRANSFER;
                } else if (ride.classifier.equals(EXPENSIVE_EXPRESS_BUS)) {
                    totalFare += EXPENSIVE_EXPRESS_FARE;
                    state = NycFareState.BUS_PRE_TRANSFER;
                }
        }
    }
    Currency currency = Currency.getInstance("USD");
    Fare fare = new Fare();
    fare.addFare(FareType.regular, new WrappedCurrency(currency), (int) Math.round(totalFare * Math.pow(10, currency.getDefaultFractionDigits())));
    return fare;
}
Also used : Trip(org.onebusaway.gtfs.model.Trip) DwellEdge(org.opentripplanner.routing.edgetype.DwellEdge) AgencyAndId(org.onebusaway.gtfs.model.AgencyAndId) ArrayList(java.util.ArrayList) StreetEdge(org.opentripplanner.routing.edgetype.StreetEdge) WrappedCurrency(org.opentripplanner.routing.core.WrappedCurrency) Fare(org.opentripplanner.routing.core.Fare) HopEdge(org.opentripplanner.routing.edgetype.HopEdge) State(org.opentripplanner.routing.core.State) Currency(java.util.Currency) WrappedCurrency(org.opentripplanner.routing.core.WrappedCurrency) HopEdge(org.opentripplanner.routing.edgetype.HopEdge) DwellEdge(org.opentripplanner.routing.edgetype.DwellEdge) StreetEdge(org.opentripplanner.routing.edgetype.StreetEdge) Edge(org.opentripplanner.routing.graph.Edge) Route(org.onebusaway.gtfs.model.Route)

Aggregations

StreetEdge (org.opentripplanner.routing.edgetype.StreetEdge)58 Coordinate (com.vividsolutions.jts.geom.Coordinate)24 IntersectionVertex (org.opentripplanner.routing.vertextype.IntersectionVertex)23 Edge (org.opentripplanner.routing.graph.Edge)22 LineString (com.vividsolutions.jts.geom.LineString)17 Graph (org.opentripplanner.routing.graph.Graph)16 Vertex (org.opentripplanner.routing.graph.Vertex)15 Test (org.junit.Test)13 StreetVertex (org.opentripplanner.routing.vertextype.StreetVertex)9 HashSet (java.util.HashSet)8 StreetTraversalPermission (org.opentripplanner.routing.edgetype.StreetTraversalPermission)8 State (org.opentripplanner.routing.core.State)7 NonLocalizedString (org.opentripplanner.util.NonLocalizedString)7 RoutingRequest (org.opentripplanner.routing.core.RoutingRequest)5 TraverseMode (org.opentripplanner.routing.core.TraverseMode)5 Envelope (com.vividsolutions.jts.geom.Envelope)4 GeometryFactory (com.vividsolutions.jts.geom.GeometryFactory)4 ArrayList (java.util.ArrayList)4 Before (org.junit.Before)4 StreetTransitLink (org.opentripplanner.routing.edgetype.StreetTransitLink)4