/* 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.edgetype; import java.util.Set; import org.opentripplanner.routing.core.RoutingRequest; import org.opentripplanner.routing.core.State; import org.opentripplanner.routing.core.StateEditor; import org.opentripplanner.routing.core.TraverseMode; import org.opentripplanner.routing.graph.Edge; import org.opentripplanner.routing.graph.Vertex; import org.opentripplanner.routing.vertextype.BikeRentalStationVertex; import com.google.common.collect.Sets; import com.vividsolutions.jts.geom.LineString; /** * Renting or dropping off a rented bike edge. * * @author laurent * */ public abstract class RentABikeAbstractEdge extends Edge { private static final long serialVersionUID = 1L; private Set<String> networks; public RentABikeAbstractEdge(Vertex from, Vertex to, Set<String> networks) { super(from, to); this.networks = networks; } protected State traverseRent(State s0) { RoutingRequest options = s0.getOptions(); /* * If we already have a bike (rented or own) we won't go any faster by having a second one. */ if (!s0.getNonTransitMode().equals(TraverseMode.WALK)) return null; /* * To rent a bike, we need to have BICYCLE in allowed modes. */ if (!options.getModes().contains(TraverseMode.BICYCLE)) return null; BikeRentalStationVertex dropoff = (BikeRentalStationVertex) tov; if (options.isUseBikeRentalAvailabilityInformation() && dropoff.getBikesAvailable() == 0) { return null; } StateEditor s1 = s0.edit(this); s1.incrementWeight(options.isArriveBy() ? options.bikeRentalDropoffCost : options.bikeRentalPickupCost); s1.incrementTimeInSeconds(options.isArriveBy() ? options.bikeRentalDropoffTime : options.bikeRentalPickupTime); s1.setBikeRenting(true); s1.setBikeRentalNetwork(networks); s1.setBackMode(s0.getNonTransitMode()); State s1b = s1.makeState(); return s1b; } protected State traverseDropoff(State s0) { RoutingRequest options = s0.getOptions(); /* * To dropoff a bike, we need to have rented one. */ if (!s0.isBikeRenting() || !hasCompatibleNetworks(networks, s0.getBikeRentalNetworks())) return null; BikeRentalStationVertex pickup = (BikeRentalStationVertex) tov; if (options.isUseBikeRentalAvailabilityInformation() && pickup.getSpacesAvailable() == 0) { return null; } StateEditor s1e = s0.edit(this); s1e.incrementWeight(options.isArriveBy() ? options.bikeRentalPickupCost : options.bikeRentalDropoffCost); s1e.incrementTimeInSeconds(options.isArriveBy() ? options.bikeRentalPickupTime : options.bikeRentalDropoffTime); s1e.setBikeRenting(false); s1e.setBackMode(TraverseMode.WALK); State s1 = s1e.makeState(); return s1; } @Override public double getDistance() { return 0; } @Override public LineString getGeometry() { return null; } @Override public String getName() { return getToVertex().getName(); } @Override public boolean hasBogusName() { return false; } /** * @param stationNetworks The station where we want to drop the bike off. * @param rentedNetworks The set of networks of the station we rented the bike from. * @return true if the bike can be dropped off here, false if not. */ private boolean hasCompatibleNetworks(Set<String> stationNetworks, Set<String> rentedNetworks) { /* * Two stations are compatible if they share at least one network. * Special case for "*" networks (no network defined in OSM). */ if (stationNetworks.contains("*") || rentedNetworks.contains("*")) return true; return !Sets.intersection(stationNetworks, rentedNetworks).isEmpty(); } }