Package org.onebusaway.transit_data_federation.bundle.tasks

Source Code of org.onebusaway.transit_data_federation.bundle.tasks.GenerateNarrativesTask$ShapeIdAndDistance

/**
* 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.bundle.tasks;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.onebusaway.collections.Counter;
import org.onebusaway.collections.MappingLibrary;
import org.onebusaway.container.refresh.RefreshService;
import org.onebusaway.gtfs.model.Agency;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.Route;
import org.onebusaway.gtfs.model.Stop;
import org.onebusaway.gtfs.model.StopTime;
import org.onebusaway.gtfs.model.Trip;
import org.onebusaway.gtfs.services.GtfsRelationalDao;
import org.onebusaway.transit_data_federation.bundle.services.UniqueService;
import org.onebusaway.transit_data_federation.impl.RefreshableResources;
import org.onebusaway.transit_data_federation.impl.narrative.NarrativeProviderImpl;
import org.onebusaway.transit_data_federation.impl.narrative.NarrativeServiceImpl;
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.model.ProjectedPoint;
import org.onebusaway.transit_data_federation.model.ShapePoints;
import org.onebusaway.transit_data_federation.model.modifications.Modifications;
import org.onebusaway.transit_data_federation.model.narrative.AgencyNarrative;
import org.onebusaway.transit_data_federation.model.narrative.RouteCollectionNarrative;
import org.onebusaway.transit_data_federation.model.narrative.StopNarrative;
import org.onebusaway.transit_data_federation.model.narrative.StopTimeNarrative;
import org.onebusaway.transit_data_federation.model.narrative.TripNarrative;
import org.onebusaway.transit_data_federation.services.FederatedTransitDataBundle;
import org.onebusaway.transit_data_federation.services.blocks.BlockIndexService;
import org.onebusaway.transit_data_federation.services.blocks.BlockStopTimeIndex;
import org.onebusaway.transit_data_federation.services.narrative.NarrativeService;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockStopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.RouteCollectionEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.RouteEntry;
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.TransitGraphDao;
import org.onebusaway.transit_data_federation.services.transit_graph.TripEntry;
import org.onebusaway.utility.ObjectSerializationLibrary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import cern.colt.list.DoubleArrayList;
import cern.jet.stat.Descriptive;

/**
* Precomputes all the link narrative objects that will power
* {@link NarrativeService} and powered by a link {@link NarrativeProviderImpl}
* and {@link NarrativeServiceImpl}
*
* @author bdferris
* @see NarrativeService
* @see NarrativeServiceImpl
* @see NarrativeProviderImpl
*/
public class GenerateNarrativesTask implements Runnable {

  private Logger _log = LoggerFactory.getLogger(GenerateNarrativesTask.class);

  private FederatedTransitDataBundle _bundle;

  private GtfsRelationalDao _gtfsDao;

  private TransitGraphDao _transitGraphDao;

  private BlockIndexService _blockIndexService;

  private Modifications _modifications;

  private ShapePointHelper _shapePointsHelper;

  private UniqueService _uniqueService;

  private RefreshService _refreshService;

  private double _stopDirectionStandardDeviationThreshold = 0.7;

  @Autowired
  public void setBundle(FederatedTransitDataBundle bundle) {
    _bundle = bundle;
  }

  @Autowired
  public void setGtfsDao(GtfsRelationalDao gtfsDao) {
    _gtfsDao = gtfsDao;
  }

  @Autowired
  public void setTransitGraphDao(TransitGraphDao transitGraphDao) {
    _transitGraphDao = transitGraphDao;
  }

  @Autowired
  public void setBlockIndexService(BlockIndexService blockIndexService) {
    _blockIndexService = blockIndexService;
  }

  @Autowired
  public void setModifications(Modifications modifications) {
    _modifications = modifications;
  }

  @Autowired
  public void setShapePointHelper(ShapePointHelper shapePointHelper) {
    _shapePointsHelper = shapePointHelper;
  }

  @Autowired
  public void setUniqueService(UniqueService uniqueService) {
    _uniqueService = uniqueService;
  }

  @Autowired
  public void setRefreshService(RefreshService refreshService) {
    _refreshService = refreshService;
  }

  public void setStopDirectionStandardDeviationThreshold(
      double stopDirectionStandardDeviationThreshold) {
    _stopDirectionStandardDeviationThreshold = stopDirectionStandardDeviationThreshold;
  }

  @Override
  public void run() {

    NarrativeProviderImpl provider = new NarrativeProviderImpl();

    generateAgencyNarratives(provider);
    generateRouteNarratives(provider);
    generateShapePointNarratives(provider);
    generateStopNarratives(provider);
    generateTripNarratives(provider);

    try {
      ObjectSerializationLibrary.writeObject(
          _bundle.getNarrativeProviderPath(), provider);
      _refreshService.refresh(RefreshableResources.NARRATIVE_DATA);
    } catch (IOException e) {
      throw new IllegalStateException(e);
    }
  }

  public void generateAgencyNarratives(NarrativeProviderImpl provider) {

    for (Agency agency : _gtfsDao.getAllAgencies()) {

      AgencyNarrative.Builder narrative = AgencyNarrative.builder();
      narrative.setLang(deduplicate(agency.getLang()));
      narrative.setName(deduplicate(agency.getName()));
      narrative.setPhone(deduplicate(agency.getPhone()));
      narrative.setTimezone(deduplicate(agency.getTimezone()));
      narrative.setUrl(deduplicate(agency.getUrl()));

      String disclaimer = _modifications.getModificationForTypeAndId(
          AgencyNarrative.class, agency.getId(), "disclaimer");
      if (disclaimer != null)
        narrative.setDisclaimer(disclaimer);

      Boolean privateService = _modifications.getModificationForTypeAndId(
          AgencyNarrative.class, agency.getId(), "privatService");
      if (privateService != null)
        narrative.setPrivateService(privateService);

      provider.setNarrativeForAgency(agency.getId(), narrative.create());
    }
  }

  public void generateRouteNarratives(NarrativeProviderImpl provider) {

    for (RouteCollectionEntry routeCollectionEntry : _transitGraphDao.getAllRouteCollections()) {
      List<Route> routes = new ArrayList<Route>();
      Counter<Route> tripCounts = new Counter<Route>();
      for (RouteEntry routeEntry : routeCollectionEntry.getChildren()) {
        Route route = _gtfsDao.getRouteForId(routeEntry.getId());
        routes.add(route);
        int tripCount = routeEntry.getTrips().size();
        tripCounts.increment(route, tripCount);
      }

      RouteCollectionNarrative.Builder builder = RouteCollectionNarrative.builder();
      setPropertiesOfRouteCollectionFromRoutes(routes, tripCounts, builder);
      provider.setNarrativeForRouteCollectionId(routeCollectionEntry.getId(),
          builder.create());
    }
  }

  public void generateShapePointNarratives(NarrativeProviderImpl provider) {

    List<AgencyAndId> shapeIds = _gtfsDao.getAllShapeIds();
    _log.info("shapes to process=" + shapeIds.size());
    int index = 0;

    for (AgencyAndId shapeId : shapeIds) {
      if (index % 10 == 0)
        _log.info("shapes=" + index);
      index++;
      ShapePoints shapePoints = _shapePointsHelper.getShapePointsForShapeId(shapeId);
      provider.setShapePointsForId(shapeId, shapePoints);
    }
  }

  public void generateStopNarratives(NarrativeProviderImpl provider) {

    Map<AgencyAndId, List<ProjectedPoint>> shapePointCache = new HashMap<AgencyAndId, List<ProjectedPoint>>();

    int index = 0;

    Collection<Stop> allStops = _gtfsDao.getAllStops();
    Map<AgencyAndId, Stop> stopsById = MappingLibrary.mapToValue(allStops, "id");

    for (StopEntry stopEntry : _transitGraphDao.getAllStops()) {

      if (index % 10 == 0)
        _log.info("stops=" + index);
      index++;

      Stop stop = stopsById.get(stopEntry.getId());

      StopNarrative.Builder narrative = StopNarrative.builder();
      narrative.setCode(deduplicate(stop.getCode()));
      narrative.setDescription(deduplicate(stop.getDesc()));
      narrative.setName(deduplicate(stop.getName()));
      narrative.setUrl(deduplicate(stop.getUrl()));

      String direction = computeStopDirection(provider, shapePointCache, stop,
          stopEntry);
      narrative.setDirection(deduplicate(direction));

      provider.setNarrativeForStop(stopEntry.getId(), narrative.create());
    }
  }

  public void generateTripNarratives(NarrativeProviderImpl provider) {

    int tripIndex = 0;
    Collection<Trip> trips = _gtfsDao.getAllTrips();

    for (Trip trip : trips) {

      if (tripIndex % 200 == 0) {
        _log.info("trips=" + tripIndex + " of " + trips.size());
      }

      tripIndex++;

      TripNarrative tripNarrative = getTripNarrative(trip);
      provider.setNarrativeForTripId(trip.getId(), tripNarrative);

      List<StopTime> stopTimes = _gtfsDao.getStopTimesForTrip(trip);
      int stopTimeIndex = 0;
      for (StopTime stopTime : stopTimes) {
        StopTimeNarrative stopTimeNarrative = getStopTimeNarrative(stopTime);
        provider.setNarrativeForStopTimeEntry(trip.getId(), stopTimeIndex++,
            stopTimeNarrative);
      }
    }
  }

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

  private void setPropertiesOfRouteCollectionFromRoutes(List<Route> routes,
      Counter<Route> tripCounts, RouteCollectionNarrative.Builder target) {

    Counter<String> shortNames = new Counter<String>();
    Counter<String> longNames = new Counter<String>();
    Counter<String> descriptions = new Counter<String>();
    Counter<String> colors = new Counter<String>();
    Counter<String> textColors = new Counter<String>();
    Counter<String> urls = new Counter<String>();
    Counter<Integer> types = new Counter<Integer>();

    for (Route route : routes) {

      int count = tripCounts.getCount(route);

      addValueToCounterIfValid(route.getShortName(), shortNames, count);
      addValueToCounterIfValid(route.getLongName(), longNames, count);
      addValueToCounterIfValid(route.getDesc(), descriptions, count);
      addValueToCounterIfValid(route.getColor(), colors, count);
      addValueToCounterIfValid(route.getTextColor(), textColors, count);
      addValueToCounterIfValid(route.getUrl(), urls, count);

      types.increment(route.getType(), count);
    }

    if (shortNames.size() > 0)
      target.setShortName(deduplicate(shortNames.getMax()));

    if (longNames.size() > 0)
      target.setLongName(deduplicate(longNames.getMax()));

    if (descriptions.size() > 0)
      target.setDescription(deduplicate(descriptions.getMax()));

    if (colors.size() > 0)
      target.setColor(deduplicate(colors.getMax()));

    if (textColors.size() > 0)
      target.setTextColor(deduplicate(textColors.getMax()));

    if (urls.size() > 0)
      target.setUrl(deduplicate(urls.getMax()));

    target.setType(deduplicate(types.getMax()));
  }

  private <T> void addValueToCounterIfValid(String value,
      Counter<String> counts, int count) {
    value = trim(value);
    if (value != null && value.length() > 0)
      counts.increment(value, count);
  }

  private String computeStopDirection(NarrativeProviderImpl provider,
      Map<AgencyAndId, List<ProjectedPoint>> shapePointCache, Stop stop,
      StopEntry stopEntry) {

    String direction = translateGtfsDirection(stop.getDirection());

    if (direction != null)
      return direction;

    Collection<PointAndOrientation> orientations = getAllOrientationsForStop(
        provider, stopEntry);

    DoubleArrayList ys = new DoubleArrayList();
    DoubleArrayList xs = new DoubleArrayList();

    for (PointAndOrientation po : orientations) {
      double orientation = Math.toRadians(po.getOrientation());
      double x = Math.cos(orientation);
      double y = Math.sin(orientation);
      xs.add(x);
      ys.add(y);
    }

    if (ys.isEmpty())
      return null;

    if (ys.size() == 1) {
      double theta = Math.atan2(ys.get(0), xs.get(0));
      return getAngleAsDirection(theta);
    }

    double yMu = Descriptive.mean(ys);
    double xMu = Descriptive.mean(xs);

    /**
     * Check for undefined case where angles are directly opposite
     */
    if (yMu == 0.0 && xMu == 0.0)
      return null;

    double thetaMu = Math.atan2(yMu, xMu);

    double yVariance = Descriptive.sampleVariance(ys, yMu);
    double xVariance = Descriptive.sampleVariance(xs, xMu);

    double yStdDev = Descriptive.sampleStandardDeviation(ys.size(), yVariance);
    double xStdDev = Descriptive.sampleStandardDeviation(xs.size(), xVariance);

    if (yStdDev > _stopDirectionStandardDeviationThreshold
        || xStdDev > _stopDirectionStandardDeviationThreshold) {
      return null;
    }

    DoubleArrayList normalizedThetas = new DoubleArrayList();

    for (PointAndOrientation po : orientations) {
      double orientation = Math.toRadians(po.getOrientation());
      double delta = orientation - thetaMu;
      delta = normalizeDelta(delta);
      orientation = thetaMu + delta;
      normalizedThetas.add(orientation);
    }

    normalizedThetas.sort();
    double thetaMedian = Descriptive.median(normalizedThetas);

    return getAngleAsDirection(thetaMedian);
  }

  private double normalizeDelta(double delta) {
    while (delta < -Math.PI)
      delta += 2 * Math.PI;
    while (delta >= Math.PI)
      delta -= 2 * Math.PI;
    return delta;
  }

  private String translateGtfsDirection(String direction) {

    if (direction == null)
      return null;

    direction = direction.toLowerCase();

    if (direction.equals("north"))
      return "N";
    else if (direction.equals("east"))
      return "E";
    else if (direction.equals("south"))
      return "S";
    else if (direction.equals("west"))
      return "W";
    else if (direction.equals("northeast"))
      return "NE";
    else if (direction.equals("southeast"))
      return "SE";
    else if (direction.equals("southwest"))
      return "SW";
    else if (direction.equals("northwest"))
      return "NW";

    try {
      double orientation = Double.parseDouble(direction);
      orientation = Math.toRadians(orientation);
      return getAngleAsDirection(orientation);
    } catch (NumberFormatException ex) {

    }

    return null;
  }

  private Collection<PointAndOrientation> getAllOrientationsForStop(
      NarrativeProviderImpl provider, StopEntry stop) {
    List<BlockStopTimeIndex> stopTimeIndices = _blockIndexService.getStopTimeIndicesForStop(stop);

    List<PointAndOrientation> pos = new ArrayList<PointAndOrientation>();
    Map<ShapeIdAndDistance, PointAndOrientation> orientationsByKey = new HashMap<ShapeIdAndDistance, PointAndOrientation>();

    for (BlockStopTimeIndex stopTimeIndex : stopTimeIndices) {
      for (BlockStopTimeEntry blockStopTime : stopTimeIndex.getStopTimes()) {

        StopTimeEntry stopTime = blockStopTime.getStopTime();
        TripEntry trip = stopTime.getTrip();
        AgencyAndId shapeId = trip.getShapeId();

        if (shapeId == null)
          continue;

        ShapePoints shapePoints = provider.getShapePointsForId(shapeId);

        if (shapePoints == null)
          continue;

        int shapePointIndex = stopTime.getShapePointIndex();

        if (shapePointIndex == -1)
          continue;

        ShapeIdAndDistance key = new ShapeIdAndDistance(shapeId,
            stopTime.getShapeDistTraveled());

        PointAndOrientation orientation = orientationsByKey.get(key);

        if (orientation == null) {

          int indexFrom = Math.max(0, shapePointIndex - 5);
          int indexTo = Math.min(shapePoints.getSize(), shapePointIndex + 5);

          ShapePointIndex shapePointIndexMethod = new DistanceTraveledShapePointIndex(
              stopTime.getShapeDistTraveled(), indexFrom, indexTo);

          orientation = shapePointIndexMethod.getPointAndOrientation(shapePoints);

          if (orientation == null)
            continue;

          orientationsByKey.put(key, orientation);
        }

        pos.add(orientation);
      }
    }

    return orientationsByKey.values();
  }

  private StopTimeNarrative getStopTimeNarrative(StopTime stopTime) {
    StopTimeNarrative.Builder builder = StopTimeNarrative.builder();
    builder.setRouteShortName(deduplicate(stopTime.getRouteShortName()));
    builder.setStopHeadsign(deduplicate(stopTime.getStopHeadsign()));
    return deduplicate(builder.create());
  }

  private TripNarrative getTripNarrative(Trip trip) {

    String headsign = trip.getTripHeadsign();
    if (headsign == null) {
      Route route = trip.getRoute();
      headsign = route.getLongName();
    }

    TripNarrative.Builder builder = TripNarrative.builder();
    builder.setRouteShortName(deduplicate(trip.getRouteShortName()));
    builder.setTripHeadsign(deduplicate(headsign));
    builder.setTripShortName(deduplicate(trip.getTripShortName()));
    return builder.create();
  }

  private String getAngleAsDirection(double theta) {

    double t = Math.PI / 4;

    int r = (int) Math.floor((theta + t / 2) / t);

    switch (r) {
      case 0:
        return "E";
      case 1:
        return "NE";
      case 2:
        return "N";
      case 3:
        return "NW";
      case 4:
        return "W";
      case -1:
        return "SE";
      case -2:
        return "S";
      case -3:
        return "SW";
      case -4:
        return "W";
      default:
        return "?";
    }
  }

  private String trim(String value) {
    if (value == null)
      return value;
    return value.trim();
  }

  private <T> T deduplicate(T object) {
    if (object == null)
      return null;
    return _uniqueService.unique(object);
  }

  private static class ShapeIdAndDistance {

    private final AgencyAndId _shapeId;

    private final double _distanceAlongShape;

    public ShapeIdAndDistance(AgencyAndId shapeId, double distanceAlongShape) {
      _shapeId = shapeId;
      _distanceAlongShape = distanceAlongShape;
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      long temp;
      temp = Double.doubleToLongBits(_distanceAlongShape);
      result = prime * result + (int) (temp ^ (temp >>> 32));
      result = prime * result + ((_shapeId == null) ? 0 : _shapeId.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (getClass() != obj.getClass())
        return false;
      ShapeIdAndDistance other = (ShapeIdAndDistance) obj;
      if (Double.doubleToLongBits(_distanceAlongShape) != Double.doubleToLongBits(other._distanceAlongShape))
        return false;
      if (_shapeId == null) {
        if (other._shapeId != null)
          return false;
      } else if (!_shapeId.equals(other._shapeId))
        return false;
      return true;
    }

  }
}
TOP

Related Classes of org.onebusaway.transit_data_federation.bundle.tasks.GenerateNarrativesTask$ShapeIdAndDistance

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.