All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.conveyal.gtfs.validator.ReversedTripValidator Maven / Gradle / Ivy

Go to download

A library to load and index GTFS feeds of arbitrary size using disk-backed storage

There is a newer version: 6.2.0
Show newest version
package com.conveyal.gtfs.validator;

import com.conveyal.gtfs.error.MissingShapeError;
import com.conveyal.gtfs.error.ReversedTripShapeError;
import com.conveyal.gtfs.error.SQLErrorStorage;
import com.conveyal.gtfs.error.ShapeMissingCoordinatesError;
import com.conveyal.gtfs.loader.Feed;
import com.conveyal.gtfs.model.*;
import com.conveyal.gtfs.validator.service.GeoUtils;
import com.google.common.collect.Iterables;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import org.mapdb.Fun;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TODO re-implement as a TripValidator
 */
public class ReversedTripValidator extends TripValidator {

    private static Double distanceMultiplier = 1.0;

    private static GeometryFactory geometryFactory = new GeometryFactory();

    public ReversedTripValidator(Feed feed, SQLErrorStorage errorStorage) {
        super(feed, errorStorage);
    }

    @Override
    public void validateTrip(Trip trip, Route route, List stopTimes, List stops) {
        // TODO implement
    }

    public boolean validate(Feed feed, boolean repair) {
        boolean isValid = true;
        int errorLimit = 5000;
        int missingShapeErrorCount = 0;
        int missingCoordinatesErrorCount = 0;
        int reversedTripShapeErrorCount = 0;
        Map> missingShapesMap = new HashMap<>();

        for(Trip trip : feed.trips) {

            String tripId = trip.trip_id;
            if (trip.shape_id == null) {
                isValid = false;
                if (missingShapeErrorCount < errorLimit) {
                    // FIXME store MissingShape errors
                    // feed.errors.add(new MissingShapeError(trip));
                }
                missingShapeErrorCount++;
                continue;
            }
            String shapeId = trip.shape_id;
            Iterable stopTimes = feed.stopTimes.getOrdered(tripId);
            StopTime firstStop = Iterables.get(stopTimes, 0);

            StopTime lastStop = Iterables.getLast(stopTimes);

            ShapePoint firstShape = null; // feed.shape_points.ceilingEntry(Fun.t2(shapeId, null)).getValue();
            Map.Entry, ShapePoint> entry = null; //feed.shape_points.floorEntry(new Fun.Tuple2(shapeId, Fun.HI));
            ShapePoint lastShape = entry.getValue();

            Coordinate firstStopCoord;
            Coordinate lastStopCoord;
            Geometry firstShapeGeom;
            Geometry lastShapeGeom;
            Geometry firstStopGeom;
            Geometry lastStopGeom;
            Coordinate firstShapeCoord;
            Coordinate lastShapeCoord;

            // if coordinate creation fails here, add trip_id to missing shapes list
            try {
                firstStopCoord = new Coordinate(feed.stops.get(firstStop.stop_id).stop_lat, feed.stops.get(firstStop.stop_id).stop_lon);
                lastStopCoord = new Coordinate(feed.stops.get(lastStop.stop_id).stop_lat, feed.stops.get(lastStop.stop_id).stop_lon);

                firstStopGeom = geometryFactory.createPoint(GeoUtils.convertLatLonToEuclidean(firstStopCoord));
                lastStopGeom = geometryFactory.createPoint(GeoUtils.convertLatLonToEuclidean(lastStopCoord));

                firstShapeCoord = new Coordinate(firstShape.shape_pt_lat, firstShape.shape_pt_lon);
                lastShapeCoord = new Coordinate(lastShape.shape_pt_lat, lastShape.shape_pt_lon);

                firstShapeGeom = geometryFactory.createPoint(GeoUtils.convertLatLonToEuclidean(firstShapeCoord));
                lastShapeGeom = geometryFactory.createPoint(GeoUtils.convertLatLonToEuclidean(lastShapeCoord));
            } catch (Exception any) {
                isValid = false;
                List listOfTrips;
                if (missingShapesMap.containsKey(firstShape)) {
                    listOfTrips = missingShapesMap.get(firstShape);
                }
                else {
                    listOfTrips = new ArrayList();
                }
                listOfTrips.add(tripId);
                missingShapesMap.put(firstShape, listOfTrips);
                missingCoordinatesErrorCount++;
                continue;
            }

            Double distanceFirstStopToStart = firstStopGeom.distance(firstShapeGeom);
            Double distanceFirstStopToEnd = firstStopGeom.distance(lastShapeGeom);

            Double distanceLastStopToEnd = lastStopGeom.distance(lastShapeGeom);
            Double distanceLastStopToStart = lastStopGeom.distance(firstShapeGeom);

            // check if first stop is x times closer to end of shape than the beginning or last stop is x times closer to start than the end
            if (distanceFirstStopToStart > (distanceFirstStopToEnd * distanceMultiplier) && distanceLastStopToEnd > (distanceLastStopToStart * distanceMultiplier)) {
                if (reversedTripShapeErrorCount < errorLimit) {
                    // FIXME store ReversedTripShape errors
                    // feed.errors.add(new ReversedTripShapeError(trip));
                }
                reversedTripShapeErrorCount++;
                isValid = false;
            }
        }
        if (missingCoordinatesErrorCount > 0) {
            for (Map.Entry> shapeError : missingShapesMap.entrySet()) {
                String[] tripIdList = shapeError.getValue().toArray(new String[shapeError.getValue().size()]);
                // FIXME store ShapeMissingCoordinates errors
                // feed.errors.add(new ShapeMissingCoordinatesError(shapeError.getKey(), tripIdList));
            }
        }
        return isValid;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy