use of org.onebusaway.collections.Min in project onebusaway-application-modules by camsys.
the class BlockGeospatialServiceImpl method getBestScheduledBlockLocationForLocation.
public ScheduledBlockLocation getBestScheduledBlockLocationForLocation(BlockInstance blockInstance, CoordinatePoint location, long timestamp, double blockDistanceFrom, double blockDistanceTo) {
BlockConfigurationEntry block = blockInstance.getBlock();
ProjectedPoint targetPoint = ProjectedPointFactory.forward(location);
List<AgencyAndId> shapePointIds = MappingLibrary.map(block.getTrips(), "trip.shapeId");
T2<List<XYPoint>, double[]> tuple = _projectedShapePointService.getProjectedShapePoints(shapePointIds, targetPoint.getSrid());
if (tuple == null) {
throw new IllegalStateException("block had no shape points: " + block.getBlock().getId());
}
List<XYPoint> projectedShapePoints = tuple.getFirst();
double[] distances = tuple.getSecond();
int fromIndex = 0;
int toIndex = distances.length;
if (blockDistanceFrom > 0) {
fromIndex = Arrays.binarySearch(distances, blockDistanceFrom);
if (fromIndex < 0) {
fromIndex = -(fromIndex + 1);
// Include the previous point if we didn't get an exact match
if (fromIndex > 0)
fromIndex--;
}
}
if (blockDistanceTo < distances[distances.length - 1]) {
toIndex = Arrays.binarySearch(distances, blockDistanceTo);
if (toIndex < 0) {
toIndex = -(toIndex + 1);
// Include the previous point if we didn't get an exact match
if (toIndex < distances.length)
toIndex++;
}
}
XYPoint xyPoint = new XYPoint(targetPoint.getX(), targetPoint.getY());
List<PointAndIndex> assignments = _shapePointsLibrary.computePotentialAssignments(projectedShapePoints, distances, xyPoint, fromIndex, toIndex);
Min<ScheduledBlockLocation> best = new Min<ScheduledBlockLocation>();
for (PointAndIndex index : assignments) {
double distanceAlongBlock = index.distanceAlongShape;
if (distanceAlongBlock > block.getTotalBlockDistance())
distanceAlongBlock = block.getTotalBlockDistance();
ScheduledBlockLocation blockLocation = _scheduledBlockLocationService.getScheduledBlockLocationFromDistanceAlongBlock(block, distanceAlongBlock);
if (blockLocation != null) {
int scheduledTime = blockLocation.getScheduledTime();
long scheduleTimestamp = blockInstance.getServiceDate() + scheduledTime * 1000;
double delta = Math.abs(scheduleTimestamp - timestamp);
best.add(delta, blockLocation);
}
}
return best.getMinElement();
}
use of org.onebusaway.collections.Min in project onebusaway-application-modules by camsys.
the class LocationShapePointIndex method getIndex.
@Override
public int getIndex(ShapePoints points) {
Min<Integer> m = new Min<Integer>();
int n = points.getSize();
double[] lats = points.getLats();
double[] lons = points.getLons();
for (int i = 0; i < n; i++) {
double d = distance(_lat, _lon, lats[i], lons[i]);
m.add(d, i);
}
return m.getMinElement();
}
use of org.onebusaway.collections.Min in project onebusaway-application-modules by camsys.
the class ArrivalAndDepartureServiceImpl method getBlockStopTime.
private BlockStopTimeEntry getBlockStopTime(BlockTripInstance blockTripInstance, AgencyAndId stopId, int stopSequence, int timeOfServiceDate) {
/**
* We don't iterate over block stop times directly because there is
* performance penalty with instantiating each. Also note that this will
* currently miss the case where a stop is visited twice in the same trip.
*/
BlockTripEntry blockTrip = blockTripInstance.getBlockTrip();
TripEntry trip = blockTrip.getTrip();
List<StopTimeEntry> stopTimes = trip.getStopTimes();
if (stopSequence > -1) {
/**
* If a stop sequence has been specified, we start our search at the
* specified index, expanding our search until we find the target stop. We
* allow this flexibility in the case of a bookmarked arrival-departure
* where the stop sequence has changed slightly due to the addition or
* subtraction of a previous stop.
*/
int offset = 0;
while (true) {
int before = stopSequence - offset;
if (isMatch(stopTimes, stopId, before)) {
return blockTrip.getStopTimes().get(before);
}
int after = stopSequence + offset;
if (isMatch(stopTimes, stopId, after)) {
return blockTrip.getStopTimes().get(after);
}
if (before < 0 && after >= stopTimes.size())
return null;
offset++;
}
} else {
Min<BlockStopTimeEntry> m = new Min<BlockStopTimeEntry>();
int index = 0;
for (StopTimeEntry stopTime : stopTimes) {
if (stopTime.getStop().getId().equals(stopId)) {
int a = Math.abs(timeOfServiceDate - stopTime.getArrivalTime());
int b = Math.abs(timeOfServiceDate - stopTime.getDepartureTime());
int delta = Math.min(a, b);
m.add(delta, blockTrip.getStopTimes().get(index));
}
index++;
}
if (m.isEmpty())
return null;
return m.getMinElement();
}
}
use of org.onebusaway.collections.Min in project onebusaway-application-modules by camsys.
the class DistanceAlongShapeLibrary method assignmentSanityCheck.
private void assignmentSanityCheck(ShapePoints shapePoints, List<StopTimeEntryImpl> stopTimes, List<List<PointAndIndex>> possibleAssignments) throws DistanceAlongShapeException {
int stIndex = 0;
for (List<PointAndIndex> assignments : possibleAssignments) {
if (assignments.isEmpty()) {
StopTimeEntry stopTime = stopTimes.get(stIndex);
throw new InvalidStopToShapeMappingException(stopTime.getTrip());
}
Min<PointAndIndex> m = new Min<PointAndIndex>();
for (PointAndIndex pindex : assignments) m.add(pindex.distanceFromTarget, pindex);
if (m.getMinValue() > _maxDistanceFromStopToShapePoint) {
StopTimeEntry stopTime = stopTimes.get(stIndex);
PointAndIndex pindex = m.getMinElement();
CoordinatePoint point = shapePoints.getPointForIndex(pindex.index);
throw new StopIsTooFarFromShapeException(stopTime, pindex, point);
}
stIndex++;
}
}
use of org.onebusaway.collections.Min in project onebusaway-application-modules by camsys.
the class ShapePointsLibrary method computePotentialAssignments.
/**
* Here is the idea:
*
* Given a shape as an array of XY Points, a range over those points, and a
* target point, find the closest location(s) along the shape for the target
* point.
*
* The trick is that there may be multiple good assignments, especially for a
* shape that loops back on itself. In this case, we look for assignments
* within our {@link #_localMinimumThreshold} distance. There will typically
* be ranges of assignments that apply and we take the local min within each
* range. We then return each of these local mins as a potential assignment.
*
* There is an additional wrinkle when the section of the shape that loops
* back occurs where all the shape points are within
* {@link #_localMinimumThreshold} of the target point. In this case, we no
* longer consider the local min for the section, but the individual local
* mins within the section. That is to say, if we find a local min and then
* the shape moves away and comes back, we'll consider the second local min as
* a new potential assignment.
*
* If no assignments are found within the {@link #_localMinimumThreshold}
* distance, we just return the global min.
*
* @param projectedShapePoints
* @param shapePointDistance
* @param targetPoint
* @param fromIndex
* @param toIndex
* @return
*/
public List<PointAndIndex> computePotentialAssignments(List<XYPoint> projectedShapePoints, double[] shapePointDistance, XYPoint targetPoint, int fromIndex, int toIndex) {
/**
* The absolute closest assignment
*/
Min<PointAndIndex> min = new Min<PointAndIndex>();
/**
*/
Min<PointAndIndex> localMin = new Min<PointAndIndex>();
List<PointAndIndex> localMins = new ArrayList<PointAndIndex>();
/**
* For our multi-local min within the _localMinimumThreshold detection, we
* keep track of whether the endpoint of the previous segment was further
* away from the target point than the snapped point, indicating the shape
* is moving away from the target point. We also keep track of the distance
* of the target point from the endpoint of the previous segment. If the
* snapped point of the next section is closer to the target point than the
* previous endpoint AND the shape was moving away from the target point in
* the previous section, we establish a new local min.
*/
boolean previousEndpointDistanceGreaterThanSnappedDistance = false;
double previousEndpointDistance = Double.POSITIVE_INFINITY;
for (int i = fromIndex; i < toIndex - 1; i++) {
XYPoint from = projectedShapePoints.get(i);
XYPoint to = projectedShapePoints.get(i + 1);
XYPoint location = GeometryLibrary.projectPointToSegment(targetPoint, from, to);
double d = location.getDistance(targetPoint);
double distanceAlongShape = shapePointDistance[i] + location.getDistance(from);
PointAndIndex pindex = new PointAndIndex(location, i, d, distanceAlongShape);
min.add(d, pindex);
if (d <= _localMinimumThreshold) {
if (previousEndpointDistanceGreaterThanSnappedDistance && d < previousEndpointDistance && !localMin.isEmpty()) {
localMins.add(localMin.getMinElement());
localMin = new Min<PointAndIndex>();
}
localMin.add(d, pindex);
} else if (!localMin.isEmpty()) {
localMins.add(localMin.getMinElement());
localMin = new Min<PointAndIndex>();
}
previousEndpointDistance = to.getDistance(targetPoint);
previousEndpointDistanceGreaterThanSnappedDistance = previousEndpointDistance > d;
}
/**
* If don't have ANY potential assignments, return an empty list
*/
if (min.isEmpty())
return Collections.emptyList();
/**
* Check to see if we have a localMin element that needs to be added to our
* collection of local mins
*/
if (!localMin.isEmpty())
localMins.add(localMin.getMinElement());
/**
* If we don't have ANY local mins (aka assignments that were within our
* _localMinimumThreshold), we just use the best assigment(s) from the
* global min
*/
if (localMins.isEmpty())
localMins.addAll(min.getMinElements());
return localMins;
}
Aggregations