Package org.onebusaway.transit_data_federation.impl.transit_graph

Source Code of org.onebusaway.transit_data_federation.impl.transit_graph.BlockConfigurationEntryImpl$BlockStopTimeList

/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
* Copyright (C) 2011 Google, Inc.
*
* 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.transit_graph;

import java.io.Serializable;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

import org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockEntry;
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.FrequencyEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.ServiceIdActivation;
import org.onebusaway.transit_data_federation.services.transit_graph.StopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.TripEntry;

public class BlockConfigurationEntryImpl implements BlockConfigurationEntry,
    Serializable {

  private static final long serialVersionUID = 1L;

  private final BlockEntry block;

  private final ServiceIdActivation serviceIds;

  private final List<BlockTripEntry> trips;

  private final double totalBlockDistance;

  private final BlockStopTimeList blockStopTimes = new BlockStopTimeList();

  private final int[] tripIndices;

  private final int[] accumulatedStopTimeIndices;

  /**
   * We make this one field non-final because it makes it easier to add
   * Frequency information after the fact.
   */
  private List<FrequencyEntry> frequencies;

  private BlockConfigurationEntryImpl(Builder builder) {
    this.block = builder.block;
    this.serviceIds = builder.serviceIds;
    this.trips = builder.computeBlockTrips(this);
    this.frequencies = builder.frequencies;
    this.totalBlockDistance = builder.computeTotalBlockDistance();
    this.tripIndices = builder.computeTripIndices();
    this.accumulatedStopTimeIndices = builder.computeAccumulatedStopTimeIndices();
  }

  public static Builder builder() {
    return new Builder();
  }

  public void setFrequencies(List<FrequencyEntry> frequencies) {
    this.frequencies = frequencies;
  }

  /****
   * {@link BlockConfigurationEntry} Interface
   ****/

  @Override
  public BlockEntry getBlock() {
    return block;
  }

  @Override
  public ServiceIdActivation getServiceIds() {
    return serviceIds;
  }

  @Override
  public List<BlockTripEntry> getTrips() {
    return trips;
  }

  @Override
  public List<FrequencyEntry> getFrequencies() {
    return frequencies;
  }

  @Override
  public List<BlockStopTimeEntry> getStopTimes() {
    return blockStopTimes;
  }

  @Override
  public double getTotalBlockDistance() {
    return totalBlockDistance;
  }

  @Override
  public int getArrivalTimeForIndex(int index) {
    StopTimeEntry stopTime = getStopTimeForIndex(index);
    return stopTime.getArrivalTime();
  }

  @Override
  public int getDepartureTimeForIndex(int index) {
    StopTimeEntry stopTime = getStopTimeForIndex(index);
    return stopTime.getDepartureTime();
  }

  @Override
  public double getDistanceAlongBlockForIndex(int index) {

    int tripIndex = tripIndices[index];

    BlockTripEntry blockTrip = trips.get(tripIndex);
    TripEntry trip = blockTrip.getTrip();

    List<StopTimeEntry> stopTimes = trip.getStopTimes();
    int stopTimeIndex = index - accumulatedStopTimeIndices[tripIndex];
    StopTimeEntry stopTime = stopTimes.get(stopTimeIndex);

    return blockTrip.getDistanceAlongBlock() + stopTime.getShapeDistTraveled();
  }

  @Override
  public String toString() {
    return "BlockConfiguration [block=" + block.getId() + " serviceIds="
        + serviceIds + "]";
  }

  public static class Builder {

    private BlockEntry block;

    private ServiceIdActivation serviceIds;

    private List<TripEntry> trips;

    private List<FrequencyEntry> frequencies;

    private double[] tripGapDistances;

    private Builder() {

    }

    public void setBlock(BlockEntry block) {
      this.block = block;
    }

    public void setServiceIds(ServiceIdActivation serviceIds) {
      this.serviceIds = serviceIds;
    }

    public List<TripEntry> getTrips() {
      return trips;
    }

    public void setTrips(List<TripEntry> trips) {
      this.trips = trips;
    }

    public List<FrequencyEntry> getFrequencies() {
      return frequencies;
    }

    public void setFrequencies(List<FrequencyEntry> frequencies) {
      this.frequencies = frequencies;
    }

    public void setTripGapDistances(double[] tripGapDistances) {
      this.tripGapDistances = tripGapDistances;
    }

    public BlockConfigurationEntry create() {
      return new BlockConfigurationEntryImpl(this);
    }

    private double computeTotalBlockDistance() {
      double distance = 0;
      for (int i = 0; i < trips.size(); i++) {
        TripEntry trip = trips.get(i);
        distance += trip.getTotalTripDistance() + tripGapDistances[i];
      }
      return distance;
    }

    private int[] computeTripIndices() {
      int n = 0;
      for (TripEntry trip : trips)
        n += trip.getStopTimes().size();
      int[] tripIndices = new int[n];
      int index = 0;
      for (int tripIndex = 0; tripIndex < trips.size(); tripIndex++) {
        TripEntry trip = trips.get(tripIndex);
        for (int i = 0; i < trip.getStopTimes().size(); i++)
          tripIndices[index++] = tripIndex;
      }
      return tripIndices;
    }

    private int[] computeAccumulatedStopTimeIndices() {
      int[] accumulatedStopTimeIndices = new int[trips.size()];
      int n = 0;
      for (int i = 0; i < trips.size(); i++) {
        accumulatedStopTimeIndices[i] = n;
        n += trips.get(i).getStopTimes().size();
      }
      return accumulatedStopTimeIndices;
    }

    private List<BlockTripEntry> computeBlockTrips(
        BlockConfigurationEntryImpl blockConfiguration) {

      ArrayList<BlockTripEntry> blockTrips = new ArrayList<BlockTripEntry>();
      short accumulatedStopTimeIndex = 0;
      int accumulatedSlackTime = 0;
      double distanceAlongBlock = 0;

      BlockTripEntryImpl prevTrip = null;
      StopTimeEntry prevTripStopTime = null;
      double prevTripAvgVelocity = 0;

      for (short i = 0; i < trips.size(); i++) {

        TripEntry tripEntry = trips.get(i);
        List<StopTimeEntry> stopTimes = tripEntry.getStopTimes();

        /**
         * See if there is any slack time in the schedule in the transition
         * between the two trips. We take the distance between the last stop of
         * the previous trip and the first stop of the next trip, along with the
         * average travel velocity from the previous trip, and compute the
         * estimated travel time. Any time that's left over is slack.
         */
        if (prevTripStopTime != null) {
          StopTimeEntry nextStopTime = stopTimes.get(0);
          int slackTime = nextStopTime.getArrivalTime()
              - prevTripStopTime.getDepartureTime();
          double distance = (distanceAlongBlock - (prevTrip.getDistanceAlongBlock() + prevTripStopTime.getShapeDistTraveled()))
              + nextStopTime.getShapeDistTraveled();
          if (prevTripAvgVelocity > 0) {
            int timeToTravel = (int) (distance / prevTripAvgVelocity);
            slackTime -= Math.min(timeToTravel, slackTime);
          }

          accumulatedSlackTime += slackTime;
        }

        BlockTripEntryImpl blockTripEntry = new BlockTripEntryImpl();
        blockTripEntry.setTrip(tripEntry);
        blockTripEntry.setBlockConfiguration(blockConfiguration);
        blockTripEntry.setSequence(i);
        blockTripEntry.setAccumulatedStopTimeIndex(accumulatedStopTimeIndex);
        blockTripEntry.setAccumulatedSlackTime(accumulatedSlackTime);
        blockTripEntry.setDistanceAlongBlock(distanceAlongBlock);

        if (prevTrip != null) {
          prevTrip.setNextTrip(blockTripEntry);
          blockTripEntry.setPreviousTrip(prevTrip);
        }

        blockTrips.add(blockTripEntry);

        accumulatedStopTimeIndex += stopTimes.size();

        if (accumulatedSlackTime < 0)
          throw new IllegalStateException(
              "I didn't think this was possible, but the number of stop times in a particular block exceeded "
                  + Short.MAX_VALUE
                  + " causing a wrap-around in the accumulated stop time index: blockId="
                  + blockConfiguration.getBlock().getId());

        for (StopTimeEntry stopTime : stopTimes)
          accumulatedSlackTime += stopTime.getSlackTime();

        prevTripAvgVelocity = computeAverageTripTravelVelocity(stopTimes);

        distanceAlongBlock += tripEntry.getTotalTripDistance()
            + tripGapDistances[i];

        prevTrip = blockTripEntry;
        prevTripStopTime = stopTimes.get(stopTimes.size() - 1);

      }

      blockTrips.trimToSize();

      return blockTrips;
    }

    private double computeAverageTripTravelVelocity(
        List<StopTimeEntry> stopTimes) {

      int accumulatedTravelTime = 0;
      double accumulatedTravelDistance = 0;
      StopTimeEntry prevStopTime = null;

      for (StopTimeEntry stopTime : stopTimes) {
        if (prevStopTime != null) {
          accumulatedTravelTime += stopTime.getArrivalTime()
              - prevStopTime.getDepartureTime();
          accumulatedTravelDistance += stopTime.getShapeDistTraveled()
              - prevStopTime.getShapeDistTraveled();
        }
        prevStopTime = stopTime;
      }

      if (accumulatedTravelTime == 0)
        return 0;

      return accumulatedTravelDistance / accumulatedTravelTime;
    }
  }

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

  private StopTimeEntry getStopTimeForIndex(int index) {
    int tripIndex = tripIndices[index];

    BlockTripEntry blockTrip = trips.get(tripIndex);
    TripEntry trip = blockTrip.getTrip();

    List<StopTimeEntry> stopTimes = trip.getStopTimes();
    int stopTimeIndex = index - accumulatedStopTimeIndices[tripIndex];
    StopTimeEntry stopTime = stopTimes.get(stopTimeIndex);
    return stopTime;
  }

  private class BlockStopTimeList extends AbstractList<BlockStopTimeEntry>
      implements Serializable {

    private static final long serialVersionUID = 1L;

    @Override
    public int size() {
      return tripIndices.length;
    }

    @Override
    public BlockStopTimeEntry get(int index) {

      int tripIndex = tripIndices[index];

      BlockTripEntry blockTrip = trips.get(tripIndex);
      TripEntry trip = blockTrip.getTrip();

      List<StopTimeEntry> stopTimes = trip.getStopTimes();
      int stopTimeIndex = index - accumulatedStopTimeIndices[tripIndex];
      StopTimeEntry stopTime = stopTimes.get(stopTimeIndex);

      boolean hasNextStop = index + 1 < tripIndices.length;

      return new BlockStopTimeEntryImpl(stopTime, index, blockTrip, hasNextStop);
    }
  }

}
TOP

Related Classes of org.onebusaway.transit_data_federation.impl.transit_graph.BlockConfigurationEntryImpl$BlockStopTimeList

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.