Package org.onebusaway.transit_data_federation.impl.blocks

Source Code of org.onebusaway.transit_data_federation.impl.blocks.ScheduledBlockLocationServiceImpl

/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.transit_data_federation.impl.blocks;

import java.util.List;

import org.onebusaway.geospatial.model.CoordinatePoint;
import org.onebusaway.geospatial.services.SphericalGeometryLibrary;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.transit_data_federation.impl.shapes.DistanceTraveledShapePointIndex;
import org.onebusaway.transit_data_federation.impl.shapes.PointAndOrientation;
import org.onebusaway.transit_data_federation.impl.shapes.ShapePointIndex;
import org.onebusaway.transit_data_federation.impl.time.GenericBinarySearch;
import org.onebusaway.transit_data_federation.model.ShapePoints;
import org.onebusaway.transit_data_federation.services.blocks.ScheduledBlockLocation;
import org.onebusaway.transit_data_federation.services.blocks.ScheduledBlockLocationService;
import org.onebusaway.transit_data_federation.services.shapes.ShapePointService;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockStopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockTripEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.StopEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.StopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.TripEntry;
import org.onebusaway.utility.InterpolationLibrary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
class ScheduledBlockLocationServiceImpl implements
    ScheduledBlockLocationService {

  private ShapePointService _shapePointService;

  @Autowired
  public void setShapePointService(ShapePointService shapePointService) {
    _shapePointService = shapePointService;
  }

  /****
   * {@link ScheduledBlockLocationService} Interface
   ****/

  @Override
  public ScheduledBlockLocation getScheduledBlockLocationFromDistanceAlongBlock(
      BlockConfigurationEntry blockConfig, double distanceAlongBlock) {

    if (distanceAlongBlock < 0.0
        || distanceAlongBlock > blockConfig.getTotalBlockDistance())
      return null;

    List<BlockStopTimeEntry> stopTimes = blockConfig.getStopTimes();
    int n = stopTimes.size();

    int stopTimeIndex = GenericBinarySearch.search(blockConfig, n,
        distanceAlongBlock, IndexAdapters.BLOCK_CONFIG_DISTANCE_INSTANCE);

    return getScheduledBlockLocationFromDistanceAlongBlockAndStopTimeIndex(
        stopTimes, distanceAlongBlock, stopTimeIndex);
  }

  @Override
  public ScheduledBlockLocation getScheduledBlockLocationFromDistanceAlongBlock(
      ScheduledBlockLocation previousLocation, double distanceAlongBlock) {

    if (previousLocation.getDistanceAlongBlock() > distanceAlongBlock)
      throw new IllegalStateException(
          "previousLocation's distanceAlongBlock must be before the requested distanceAlongBlock");

    BlockTripEntry trip = previousLocation.getActiveTrip();
    BlockConfigurationEntry blockConfig = trip.getBlockConfiguration();

    List<BlockStopTimeEntry> stopTimes = blockConfig.getStopTimes();

    int indexFrom = previousLocation.getStopTimeIndex();
    int indexTo = indexFrom + 1;

    while (indexTo < stopTimes.size()) {
      double d = blockConfig.getDistanceAlongBlockForIndex(indexTo);
      if (distanceAlongBlock <= d)
        break;
      indexTo++;
    }

    int stopTimeIndex = GenericBinarySearch.searchRange(blockConfig, indexFrom,
        indexTo, distanceAlongBlock,
        IndexAdapters.BLOCK_CONFIG_DISTANCE_INSTANCE);

    return getScheduledBlockLocationFromDistanceAlongBlockAndStopTimeIndex(
        stopTimes, distanceAlongBlock, stopTimeIndex);
  }

  @Override
  public ScheduledBlockLocation getScheduledBlockLocationFromScheduledTime(
      BlockConfigurationEntry blockConfig, int scheduleTime) {

    List<BlockStopTimeEntry> stopTimes = blockConfig.getStopTimes();
    int n = stopTimes.size();
    int index = GenericBinarySearch.search(blockConfig, n, scheduleTime,
        IndexAdapters.BLOCK_STOP_TIME_DEPARTURE_INSTANCE);

    return getScheduledBlockLocationFromScheduleTimeAndStopTimeIndex(stopTimes,
        scheduleTime, index);
  }

  @Override
  public ScheduledBlockLocation getScheduledBlockLocationFromScheduledTime(
      ScheduledBlockLocation previousLocation, int scheduleTime) {

    if (previousLocation.getScheduledTime() > scheduleTime)
      throw new IllegalStateException(
          "previousLocation's scheduledTime must be before the requested scheduleTime");

    BlockTripEntry trip = previousLocation.getActiveTrip();
    BlockConfigurationEntry blockConfig = trip.getBlockConfiguration();

    List<BlockStopTimeEntry> stopTimes = blockConfig.getStopTimes();

    int index = previousLocation.getStopTimeIndex();

    while (index < stopTimes.size()) {
      int t = blockConfig.getDepartureTimeForIndex(index);
      if (scheduleTime <= t)
        break;
      index++;
    }

    return getScheduledBlockLocationFromScheduleTimeAndStopTimeIndex(stopTimes,
        scheduleTime, index);
  }

  /****
   * Private Methods
   ****/

  private ScheduledBlockLocation getScheduledBlockLocationFromDistanceAlongBlockAndStopTimeIndex(
      List<BlockStopTimeEntry> stopTimes, double distanceAlongBlock,
      int stopTimeIndex) {

    int n = stopTimes.size();

    // Are we out beyond our last stop-time?
    if (stopTimeIndex == n) {

      // If we only have one stop time, we can't interpolate the schedule time
      if (n == 1)
        return null;
     
      BlockStopTimeEntry blockFrom = stopTimes.get(n - 2);
      BlockStopTimeEntry blockTo = stopTimes.get(n - 1);
     
      if(n == 2)
        return interpolateLocation(blockFrom, blockTo, distanceAlongBlock, stopTimeIndex);
     
      BlockStopTimeEntry previousBlock =  stopTimes.get(n - 3);
     
      return interpolateLocation(previousBlock, blockFrom, blockTo, distanceAlongBlock, stopTimeIndex);
    }

    // Are we before out first stop-time?
    if (stopTimeIndex == 0) {

      // If we only have one stop time, we can't interpolate the schedule time
      if (n == 1)
        return null;

      BlockStopTimeEntry blockFrom = stopTimes.get(0);
      BlockStopTimeEntry blockTo = stopTimes.get(1);

      return interpolateLocation(blockFrom, blockTo, distanceAlongBlock,
          stopTimeIndex);
    }

    BlockStopTimeEntry blockBefore = stopTimes.get(stopTimeIndex - 1);
    BlockStopTimeEntry blockAfter = stopTimes.get(stopTimeIndex);

    StopTimeEntry before = blockBefore.getStopTime();
    StopTimeEntry after = blockAfter.getStopTime();

    double ratio = (distanceAlongBlock - blockBefore.getDistanceAlongBlock())
        / (blockAfter.getDistanceAlongBlock() - blockBefore.getDistanceAlongBlock());

    int scheduleTime = (int) (before.getDepartureTime() + (after.getArrivalTime() - before.getDepartureTime())
        * ratio);

    return getScheduledBlockLocationFromScheduleTimeAndStopTimeIndex(stopTimes,
        scheduleTime, stopTimeIndex);
  }

  private ScheduledBlockLocation getScheduledBlockLocationFromScheduleTimeAndStopTimeIndex(
      List<BlockStopTimeEntry> stopTimes, int scheduleTime, int stopTimeIndex) {

    // Did we have a direct hit?
    if (0 <= stopTimeIndex && stopTimeIndex < stopTimes.size()) {

      BlockStopTimeEntry blockStopTime = stopTimes.get(stopTimeIndex);
      StopTimeEntry stopTime = blockStopTime.getStopTime();
      BlockStopTimeEntry previousBlockStopTime = null;
     
      if(stopTimeIndex > 0){
       previousBlockStopTime = stopTimes.get(stopTimeIndex - 1);
      }
     
      /**
       * Is the vehicle currently at a layover at the stop?
       */
      if (stopTime.getArrivalTime() <= scheduleTime
          && scheduleTime <= stopTime.getDepartureTime()) {

        return getScheduledBlockLocationWhenAtStopTime(blockStopTime, previousBlockStopTime,
            stopTime, scheduleTime, stopTimeIndex);
      }
    }

    /**
     * If the stopTimeIndex is zero, and we weren't at a layover at the first
     * block stop time (see above), then we are looking for the scheduled
     * location before the scheduled start of the block
     */
    if (stopTimeIndex == 0) {
      return getScheduledBlockLocationBeforeStartOfBlock(stopTimes,
          scheduleTime);
    }

    /**
     * If the stopTimeIndex is beyond the last stop time, we don't attempt to
     * determine a scheduled location, since we're beyond the end of the block
     */
    if (stopTimeIndex == stopTimes.size()) {
      // Out of bounds for these stop times
      return null;
    }

    return getScheduledBlockLocationBetweenStopTimes(stopTimes, scheduleTime,
        stopTimeIndex);
  }

  private ScheduledBlockLocation getScheduledBlockLocationWhenAtStopTime(
      BlockStopTimeEntry blockStopTime, BlockStopTimeEntry previousBlockStopTime,
      StopTimeEntry stopTime, int scheduleTime, int stopTimeIndex) {
    StopEntry stop = stopTime.getStop();

    ScheduledBlockLocation result = new ScheduledBlockLocation();

    int shapePointIndex = stopTime.getShapePointIndex();

    PointAndOrientation po = getLocationAlongShape(blockStopTime.getTrip(),
        blockStopTime.getDistanceAlongBlock(), shapePointIndex,
        shapePointIndex + 1);
    if (po != null) {
      result.setLocation(po.getPoint());
      result.setOrientation(po.getOrientation());
    } else {
      CoordinatePoint location = new CoordinatePoint(stop.getStopLat(),
          stop.getStopLon());
      result.setLocation(location);
      result.setOrientation(0);
    }

    result.setClosestStop(blockStopTime);
    result.setClosestStopTimeOffset(0);
    result.setNextStop(blockStopTime);
    result.setNextStopTimeOffset(0);
    result.setScheduledTime(scheduleTime);
    result.setDistanceAlongBlock(blockStopTime.getDistanceAlongBlock());
    result.setActiveTrip(blockStopTime.getTrip());
    result.setInService(true);
    result.setStopTimeIndex(stopTimeIndex);
   
    // If there is more than 1 stop, grab the previous stop
    if(blockStopTime.hasPreviousStop()){
      result.setPreviousStop(previousBlockStopTime);
   }
   
    return result;
  }

  private ScheduledBlockLocation getScheduledBlockLocationBetweenStopTimes(
      List<BlockStopTimeEntry> stopTimes, int scheduleTime, int stopTimeIndex) {

    BlockStopTimeEntry blockBefore = stopTimes.get(stopTimeIndex - 1);
    BlockStopTimeEntry blockAfter = stopTimes.get(stopTimeIndex);

    StopTimeEntry before = blockBefore.getStopTime();
    StopTimeEntry after = blockAfter.getStopTime();

    ScheduledBlockLocation result = new ScheduledBlockLocation();
    result.setScheduledTime(scheduleTime);
    result.setInService(true);
    result.setStopTimeIndex(stopTimeIndex);

    int fromTime = before.getDepartureTime();
    int toTime = after.getArrivalTime();

    int fromTimeOffset = fromTime - scheduleTime;
    int toTimeOffset = toTime - scheduleTime;

    if (Math.abs(fromTimeOffset) < Math.abs(toTimeOffset)) {
      result.setClosestStop(blockBefore);
      result.setClosestStopTimeOffset(fromTimeOffset);
    } else {
      result.setClosestStop(blockAfter);
      result.setClosestStopTimeOffset(toTimeOffset);
    }
    result.setPreviousStop(blockBefore);
    result.setNextStop(blockAfter);
    result.setNextStopTimeOffset(toTimeOffset);

    double ratio = (scheduleTime - fromTime) / ((double) (toTime - fromTime));

    double fromDistance = blockBefore.getDistanceAlongBlock();
    double toDistance = blockAfter.getDistanceAlongBlock();

    double distanceAlongBlock = ratio * (toDistance - fromDistance)
        + fromDistance;
   
    result.setDistanceAlongBlock(distanceAlongBlock);

    int shapePointIndexFrom = -1;
    int shapePointIndexTo = -1;

    /**
     * Are we between trips? Where is the transition point?
     */
    if (!before.getTrip().equals(after.getTrip())) {

      if (distanceAlongBlock >= blockAfter.getTrip().getDistanceAlongBlock()) {
        result.setActiveTrip(blockAfter.getTrip());
        shapePointIndexFrom = 0;
        shapePointIndexTo = nextShapePointIndex(after);
      } else {
        result.setActiveTrip(blockBefore.getTrip());
        shapePointIndexFrom = before.getShapePointIndex();
        shapePointIndexTo = Integer.MAX_VALUE;
      }
    } else {
      result.setActiveTrip(blockBefore.getTrip());
      shapePointIndexFrom = before.getShapePointIndex();
      shapePointIndexTo = nextShapePointIndex(after);
    }

    BlockTripEntry activeTrip = result.getActiveTrip();

    PointAndOrientation po = getLocationAlongShape(activeTrip,
        distanceAlongBlock, shapePointIndexFrom, shapePointIndexTo);

    if (po != null) {
      result.setLocation(po.getPoint());
      result.setOrientation(po.getOrientation());
      return result;
    }

    StopEntry beforeStop = before.getStop();
    StopEntry afterStop = after.getStop();
    double latFrom = beforeStop.getStopLat();
    double lonFrom = beforeStop.getStopLon();
    double latTo = afterStop.getStopLat();
    double lonTo = afterStop.getStopLon();
    double lat = (latTo - latFrom) * ratio + latFrom;
    double lon = (lonTo - lonFrom) * ratio + lonFrom;

    CoordinatePoint location = new CoordinatePoint(lat, lon);
    result.setLocation(location);

    double orientation = SphericalGeometryLibrary.getOrientation(latFrom,
        lonFrom, latTo, lonTo);
    result.setOrientation(orientation);

    return result;
  }

  private ScheduledBlockLocation getScheduledBlockLocationBeforeStartOfBlock(
      List<BlockStopTimeEntry> stopTimes, int scheduleTime) {

    /**
     * The first block stop time
     */
    BlockStopTimeEntry blockStopTime = stopTimes.get(0);
    StopTimeEntry stopTime = blockStopTime.getStopTime();

    double distanceAlongBlock = Double.NaN;
    boolean inService = false;

    /**
     * If we have more than one stop time in the block (we'd hope!), then we
     * attempt to interpolate the distance along the block
     */
    if (stopTimes.size() > 1) {

      BlockStopTimeEntry secondBlockStopTime = stopTimes.get(1);
      StopTimeEntry secondStopTime = secondBlockStopTime.getStopTime();

      distanceAlongBlock = InterpolationLibrary.interpolatePair(
          stopTime.getDepartureTime(), blockStopTime.getDistanceAlongBlock(),
          secondStopTime.getArrivalTime(),
          secondBlockStopTime.getDistanceAlongBlock(), scheduleTime);

      if (distanceAlongBlock >= 0)
        inService = true;
      else
        distanceAlongBlock = 0.0;
    }

    PointAndOrientation po = null;

    if (!Double.isNaN(distanceAlongBlock))
      po = getLocationAlongShape(blockStopTime.getTrip(), distanceAlongBlock,
          0, nextShapePointIndex(stopTime));

    ScheduledBlockLocation result = new ScheduledBlockLocation();

    if (po != null) {
      result.setLocation(po.getPoint());
      result.setOrientation(po.getOrientation());
    }

    result.setClosestStop(blockStopTime);
    result.setClosestStopTimeOffset(stopTime.getArrivalTime() - scheduleTime);
    result.setPreviousStop(null);
    result.setNextStop(blockStopTime);
    result.setNextStopTimeOffset(stopTime.getArrivalTime() - scheduleTime);
    result.setScheduledTime(scheduleTime);
    result.setDistanceAlongBlock(distanceAlongBlock);
    result.setActiveTrip(blockStopTime.getTrip());
    result.setInService(inService);
    result.setStopTimeIndex(0);
    return result;
  }
 
  private ScheduledBlockLocation interpolateLocation(
      BlockStopTimeEntry blockFrom, BlockStopTimeEntry blockTo,
        double distanceAlongBlock, int stopTimeIndex){
    return interpolateLocation(null, blockFrom, blockTo, distanceAlongBlock, stopTimeIndex);
   
  }
 
  private ScheduledBlockLocation interpolateLocation(
    BlockStopTimeEntry blockPrevious, BlockStopTimeEntry blockFrom, BlockStopTimeEntry blockTo,
      double distanceAlongBlock, int stopTimeIndex) {

    if (distanceAlongBlock < 0.0)
      return null;

    StopTimeEntry from = blockFrom.getStopTime();
    StopTimeEntry to = blockTo.getStopTime();

    double r = (distanceAlongBlock - blockFrom.getDistanceAlongBlock())
        / (blockTo.getDistanceAlongBlock() - blockFrom.getDistanceAlongBlock());
    int scheduledTime = (int) (r
        * (to.getArrivalTime() - from.getDepartureTime()) + from.getDepartureTime());

    if (r > 1)
      scheduledTime += to.getSlackTime();

    BlockTripEntry activeTrip = distanceAlongBlock < blockTo.getDistanceAlongBlock()
        ? blockFrom.getTrip() : blockTo.getTrip();

    BlockStopTimeEntry closestStop = r < 0.5 ? blockFrom : blockTo;

    BlockStopTimeEntry previousStop = null;
    BlockStopTimeEntry nextStop = null;
  
    int shapePointIndexFrom = -1;
    int shapePointIndexTo = -1;

    if (r <= 0) {

      /**
       * Location along the block is before the two stop times
       */
      previousStop = blockPrevious;
      nextStop = blockFrom;
      shapePointIndexFrom = 0;
      shapePointIndexTo = nextShapePointIndex(from);

    } else if (r <= 1.0) {

      /**
       * Location along the block is between the two stop times
       */
      previousStop = blockFrom;
      nextStop = blockTo;
      shapePointIndexFrom = from.getShapePointIndex();
      shapePointIndexTo = nextShapePointIndex(to);

    } else {

      /**
       * Location along the block is after the two stop times
       */
      shapePointIndexFrom = to.getShapePointIndex();
      shapePointIndexTo = Integer.MAX_VALUE;
    }

    ScheduledBlockLocation location = new ScheduledBlockLocation();
    location.setActiveTrip(activeTrip);
    location.setClosestStop(closestStop);
    location.setClosestStopTimeOffset(closestStop.getStopTime().getArrivalTime()
        - scheduledTime);
    location.setPreviousStop(previousStop);
    location.setNextStop(nextStop);
    if (nextStop != null)
      location.setNextStopTimeOffset(nextStop.getStopTime().getArrivalTime()
          - scheduledTime);
    location.setInService(nextStop != null);
    location.setStopTimeIndex(stopTimeIndex);
    location.setDistanceAlongBlock(distanceAlongBlock);
    location.setScheduledTime(scheduledTime);

    /**
     * In this case, distance along block and distance along trip are the same
     * because we are still in the first trip of the block
     */

    PointAndOrientation po = getLocationAlongShape(activeTrip,
        distanceAlongBlock, shapePointIndexFrom, shapePointIndexTo);

    if (po != null) {
      location.setLocation(po.getPoint());
      location.setOrientation(po.getOrientation());
    }

    return location;
  }

  private int nextShapePointIndex(StopTimeEntry stopTime) {
    int index = stopTime.getShapePointIndex();
    if (index != -1)
      index++;
    return index;
  }

  private PointAndOrientation getLocationAlongShape(
      BlockTripEntry activeBlockTrip, double distanceAlongBlock,
      int shapePointIndexFrom, int shapePointIndexTo) {

    TripEntry activeTrip = activeBlockTrip.getTrip();
    AgencyAndId shapeId = activeTrip.getShapeId();

    if (shapeId == null)
      return null;

    ShapePoints shapePoints = _shapePointService.getShapePointsForShapeId(shapeId);

    if (shapePoints == null || shapePoints.isEmpty())
      return null;

    /**
     * We allow callers of this method to specify an arbitrarily high
     * shapePointIndexTo, knowing we'll bound it by the max number of points
     */
    shapePointIndexFrom = Math.min(shapePointIndexFrom, shapePoints.getSize());
    shapePointIndexTo = Math.min(shapePointIndexTo, shapePoints.getSize());

    double distanceAlongTrip = distanceAlongBlock
        - activeBlockTrip.getDistanceAlongBlock();

    ShapePointIndex shapePointIndexMethod = new DistanceTraveledShapePointIndex(
        distanceAlongTrip, shapePointIndexFrom, shapePointIndexTo);
    return shapePointIndexMethod.getPointAndOrientation(shapePoints);
  }
}
TOP

Related Classes of org.onebusaway.transit_data_federation.impl.blocks.ScheduledBlockLocationServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.