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);
}
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;
}
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;
}
Aggregations