use of org.opentripplanner.model.FeedScopedId in project OpenTripPlanner by opentripplanner.
the class NodeAdapterTest method asFeedScopedId.
@Test
public void asFeedScopedId() {
NodeAdapter subject = newNodeAdapterForTest("{ key1: 'A:23', key2: 'B:12' }");
assertEquals("A:23", subject.asFeedScopedId("key1", null).toString());
assertEquals("B:12", subject.asFeedScopedId("key2", null).toString());
assertEquals("C:12", subject.asFeedScopedId("missing-key", new FeedScopedId("C", "12")).toString());
}
use of org.opentripplanner.model.FeedScopedId in project OpenTripPlanner by opentripplanner.
the class StreetGraphFinder method findClosestPlaces.
@Override
public List<PlaceAtDistance> findClosestPlaces(double lat, double lon, double radiusMeters, int maxResults, List<TransitMode> filterByModes, List<PlaceType> filterByPlaceTypes, List<FeedScopedId> filterByStops, List<FeedScopedId> filterByRoutes, List<String> filterByBikeRentalStations, List<String> filterByBikeParks, List<String> filterByCarParks, RoutingService routingService) {
PlaceFinderTraverseVisitor visitor = new PlaceFinderTraverseVisitor(routingService, filterByModes, filterByPlaceTypes, filterByStops, filterByRoutes, filterByBikeRentalStations, maxResults);
SearchTerminationStrategy terminationStrategy = visitor.getSearchTerminationStrategy();
findClosestUsingStreets(lat, lon, radiusMeters, visitor, terminationStrategy);
List<PlaceAtDistance> results = visitor.placesFound;
results.sort(Comparator.comparingDouble(pad -> pad.distance));
return results.subList(0, min(results.size(), maxResults));
}
use of org.opentripplanner.model.FeedScopedId in project OpenTripPlanner by opentripplanner.
the class DefaultFareServiceImpl method getBestFareAndId.
private FareAndId getBestFareAndId(FareType fareType, List<Ride> rides, Collection<FareRuleSet> fareRules) {
Set<String> zones = new HashSet<>();
Set<FeedScopedId> routes = new HashSet<>();
Set<FeedScopedId> trips = new HashSet<>();
int transfersUsed = -1;
Ride firstRide = rides.get(0);
long startTime = firstRide.startTime;
String startZone = firstRide.startZone;
String endZone = firstRide.endZone;
// stops don't really have an agency id, they have the per-feed default id
String feedId = firstRide.firstStop.getId().getFeedId();
long lastRideStartTime = firstRide.startTime;
long lastRideEndTime = firstRide.endTime;
for (Ride ride : rides) {
if (!ride.firstStop.getId().getFeedId().equals(feedId)) {
LOG.debug("skipped multi-feed ride sequence {}", rides);
return new FareAndId(Float.POSITIVE_INFINITY, null);
}
lastRideStartTime = ride.startTime;
lastRideEndTime = ride.endTime;
endZone = ride.endZone;
routes.add(ride.route);
zones.addAll(ride.zones);
trips.add(ride.trip);
transfersUsed += 1;
}
FareAttribute bestAttribute = null;
float bestFare = Float.POSITIVE_INFINITY;
long tripTime = lastRideStartTime - startTime;
long journeyTime = lastRideEndTime - startTime;
// find the best fare that matches this set of rides
for (FareRuleSet ruleSet : fareRules) {
FareAttribute attribute = ruleSet.getFareAttribute();
// check only if the fare is not mapped to an agency
if (!attribute.getId().getFeedId().equals(feedId))
continue;
if (ruleSet.matches(startZone, endZone, zones, routes, trips)) {
// TODO Maybe move the code below in FareRuleSet::matches() ?
if (attribute.isTransfersSet() && attribute.getTransfers() < transfersUsed) {
continue;
}
// as trimet does
if (attribute.isTransferDurationSet() && tripTime > attribute.getTransferDuration()) {
continue;
}
if (attribute.isJourneyDurationSet() && journeyTime > attribute.getJourneyDuration()) {
continue;
}
float newFare = getFarePrice(attribute, fareType);
if (newFare < bestFare) {
bestAttribute = attribute;
bestFare = newFare;
}
}
}
LOG.debug("{} best for {}", bestAttribute, rides);
if (bestFare == Float.POSITIVE_INFINITY) {
LOG.debug("No fare for a ride sequence: {}", rides);
}
return new FareAndId(bestFare, bestAttribute == null ? null : bestAttribute.getId());
}
use of org.opentripplanner.model.FeedScopedId in project OpenTripPlanner by opentripplanner.
the class DefaultFareServiceImpl method populateFare.
/**
* Builds the Fare object for the given currency, fareType and fareRules.
* <p>
* Besides calculating the lowest fare, we also break down the fare and which routes
* correspond to which components. Note that even if we cannot get a lowest fare
* (if some rides don't have fare rules), there will still be a breakdown for those
* parts which have fares.
* <p>
* As an example, given the rides A-B and B-C. Where A-B and B-C have fares of 10
* each, 2 fare detail objects are added, one with fare 10 for A-B and one with fare 10
* for B-C.
* <p>
* If we add the rule for A-C with a fare of 15, we will get 1 fare detail object
* with fare 15, which lists both A-B and B-C as routes involved.
* <p>
* If our only rule were A-B with a fare of 10, we would have no lowest fare, but
* we will still have one fare detail with fare 10 for the route A-B. B-C will not
* just not be listed at all.
*/
protected boolean populateFare(Fare fare, Currency currency, FareType fareType, List<Ride> rides, Collection<FareRuleSet> fareRules) {
FareSearch r = performSearch(fareType, rides, fareRules);
List<FareComponent> details = new ArrayList<FareComponent>();
int count = 0;
int start = 0;
int end = rides.size() - 1;
while (start <= end) {
// even if not all legs have fares
while (start <= end && r.endOfComponent[start] < 0) {
++start;
}
if (start > end) {
break;
}
int via = r.next[start][r.endOfComponent[start]];
float cost = r.resultTable[start][via];
FeedScopedId fareId = r.fareIds[start][via];
FareComponent detail = new FareComponent(fareId, getMoney(currency, cost));
for (int i = start; i <= via; ++i) {
detail.addRoute(rides.get(i).route);
}
details.add(detail);
++count;
start = via + 1;
}
fare.addFare(fareType, getMoney(currency, r.resultTable[0][rides.size() - 1]));
fare.addFareDetails(fareType, details);
return count > 0;
}
use of org.opentripplanner.model.FeedScopedId in project OpenTripPlanner by opentripplanner.
the class DutchFareServiceImpl method getLowestCost.
@Override
protected float getLowestCost(FareType fareType, List<Ride> rides, Collection<FareRuleSet> fareRules) {
float cost = 0f;
int units = 0;
int prevSumUnits = 0;
boolean mustHaveCheckedOut = false;
String startTariefEenheden = null;
String endTariefEenheden = null;
FeedScopedId lastAgencyId = null;
String lastFareZone = null;
long alightedEasyTrip = 0;
long alightedTariefEenheden = 0;
for (Ride ride : rides) {
LOG.trace(String.format("%s %s %s %s %s %s", ride.startZone, ride.endZone, ride.firstStop, ride.lastStop, ride.route, ride.agency));
if (ride.agency.getFeedId().equals("IFF")) {
LOG.trace("1. Trains");
/* In Reizen op Saldo we will try to fares as long as possible. */
/* If our previous agency isn't this agency, then we must have checked out */
mustHaveCheckedOut |= !ride.agency.equals(lastAgencyId);
/* When a user has checked out, we first calculate the units made until then. */
if (mustHaveCheckedOut && lastAgencyId != null) {
LOG.trace("2. Must have checked out from a station");
UnitsFareZone unitsFareZone = getUnitsByZones(lastAgencyId, startTariefEenheden, endTariefEenheden, fareRules);
if (unitsFareZone == null)
return Float.POSITIVE_INFINITY;
lastFareZone = unitsFareZone.fareZone;
units += unitsFareZone.units;
startTariefEenheden = ride.startZone;
mustHaveCheckedOut = false;
}
/* The entrance Fee applies if the transfer time ends before the new trip starts. */
if ((alightedTariefEenheden + TRANSFER_DURATION) < ride.startTime) {
LOG.trace("3. Exceeded Transfer Time");
cost += getCostByUnits(lastFareZone, units, prevSumUnits, fareRules);
if (cost == Float.POSITIVE_INFINITY)
return cost;
startTariefEenheden = ride.startZone;
units = 0;
prevSumUnits = 0;
mustHaveCheckedOut = false;
} else if (!ride.agency.equals(lastAgencyId)) {
LOG.trace("4. Swiched Rail Agency");
cost += getCostByUnits(lastFareZone, units, prevSumUnits, fareRules);
if (cost == Float.POSITIVE_INFINITY)
return cost;
prevSumUnits += units;
units = 0;
startTariefEenheden = ride.startZone;
}
alightedTariefEenheden = ride.endTime;
endTariefEenheden = ride.endZone;
lastAgencyId = ride.agency;
} else {
LOG.trace("5. Easy Trip");
/* We are now on Easy Trip, so we must have checked-out from Reizen op Saldo, if we were on it */
mustHaveCheckedOut = (startTariefEenheden != null);
/* The entranceFee applies if the transfer time ends before the new trip starts. */
boolean entranceFee = ((alightedEasyTrip + TRANSFER_DURATION) < ride.startTime);
/* EasyTrip will always calculate its price per leg */
cost += getEasyTripFareByLineFromTo(ride.route.getId(), ride.startZone, ride.endZone, entranceFee, fareRules);
if (cost == Float.POSITIVE_INFINITY)
return cost;
alightedEasyTrip = ride.endTime;
}
}
LOG.trace("6. Final");
if (lastAgencyId != null) {
UnitsFareZone unitsFareZone = getUnitsByZones(lastAgencyId, startTariefEenheden, endTariefEenheden, fareRules);
if (unitsFareZone == null)
return Float.POSITIVE_INFINITY;
lastFareZone = unitsFareZone.fareZone;
units += unitsFareZone.units;
cost += getCostByUnits(lastFareZone, units, prevSumUnits, fareRules);
}
if (cost == Float.POSITIVE_INFINITY)
return cost;
return cost / 100f;
}
Aggregations