Package org.opentripplanner.model

Source Code of org.opentripplanner.model.StopPattern

package org.opentripplanner.model;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import org.onebusaway.gtfs.model.Stop;
import org.onebusaway.gtfs.model.StopTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This class represents what is called a JourneyPattern in Transmodel: the sequence of stops at
* which a trip (GTFS) or vehicle journey (Transmodel) calls, irrespective of the day on which
* service runs.
*
* An important detail: Routes in GTFS are not a structurally important element, they just serve as
* user-facing information. It is possible for the same journey pattern to appear in more than one
* route.
*
* OTP already has several classes that represent this same thing: A TripPattern in the context of
* routing. It represents all trips with the same stop pattern A ScheduledStopPattern in the GTFS
* loading process. A RouteVariant in the TransitIndex, which has a unique human-readable name and
* belongs to a particular route.
*
* We would like to combine all these different classes into one.
*
* Any two trips with the same stops in the same order, and that operate on the same days, can be
* combined using a TripPattern to simplify the graph. This saves memory and reduces search
* complexity since we only consider the trip that departs soonest for each pattern. AgencyAndId
* calendarId has been removed. See issue #1320.
*
* A StopPattern is very closely related to a TripPattern -- it essentially serves as the unique key for a TripPattern.
* Should the route be included in the StopPattern?
*/
public class StopPattern implements Serializable {

    private static final long serialVersionUID = 20140101L;
   
    /* Constants for the GTFS pick up / drop off type fields. */
    // It would be nice to have an enum for these, but the equivalence with integers is important.
    public static final int PICKDROP_SCHEDULED = 0;
    public static final int PICKDROP_NONE = 1;
    public static final int PICKDROP_CALL_AGENCY = 2;
    public static final int PICKDROP_COORDINATE_WITH_DRIVER = 3;
   
    public final int size; // property could be derived from arrays
    public final Stop[] stops;
    public final int[]  pickups;
    public final int[]  dropoffs;

    public boolean equals(Object other) {
        if (other instanceof StopPattern) {
            StopPattern that = (StopPattern) other;
            return Arrays.equals(this.stops,    that.stops) &&
                   Arrays.equals(this.pickups,  that.pickups) &&
                   Arrays.equals(this.dropoffs, that.dropoffs);
        } else {
            return false;
        }
    }

    public int hashCode() {
        int hash = size;
        hash += Arrays.hashCode(this.stops);
        hash *= 31;
        hash += Arrays.hashCode(this.pickups);
        hash *= 31;
        hash += Arrays.hashCode(this.dropoffs);
        return hash;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("StopPattern: ");
        for (int i = 0, j = stops.length; i < j; ++i) {
            sb.append(String.format("%s_%d%d ", stops[i].getCode(), pickups[i], dropoffs[i]));
        }
        return sb.toString();
    }

    private StopPattern (int size) {
        this.size = size;
        stops     = new Stop[size];
        pickups   = new int[size];
        dropoffs  = new int[size];
    }

    /** Assumes that stopTimes are already sorted by time. */
    public StopPattern (List<StopTime> stopTimes) {
        this (stopTimes.size());
        if (size == 0) return;
        for (int i = 0; i < size; ++i) {
            StopTime stopTime = stopTimes.get(i);
            stops[i] = stopTime.getStop();
            // should these just be booleans? anything but 1 means pick/drop is allowed.
            // pick/drop messages could be stored in individual trips
            pickups[i] = stopTime.getPickupType();
            dropoffs[i] = stopTime.getDropOffType();
        }
        /*
         * TriMet GTFS has many trips that differ only in the pick/drop status of their initial and
         * final stops. This may have something to do with interlining. They are turning pickups off
         * on the final stop of a trip to indicate that there is no interlining, because they supply
         * block IDs for all trips, even those followed by dead runs. See issue 681. Enabling
         * dropoffs at the initial stop and pickups at the final merges similar patterns while
         * having no effect on routing.
         */
        dropoffs[0] = 0;
        pickups[size - 1] = 0;
    }

    /**
     * @param stopId in agency_id format
     */
    public boolean containsStop (String stopId) {
        if (stopId == null) return false;
        for (Stop stop : stops) if (stopId.equals(stop.getId().toString())) return true;
        return false;
    }

    private static final Logger LOG = LoggerFactory.getLogger(StopPattern.class);

    /**
     * In most cases we want to use identity equality for StopPatterns. There is a single StopPattern instance for each
     * semantic StopPattern, and we don't want to calculate complicated hashes or equality values during normal
     * execution. However, in some cases we want a way to consistently identify trips across versions of a GTFS feed, when the
     * feed publisher cannot ensure stable trip IDs. Therefore we define some additional hash functions.
     */
    public HashCode semanticHash(HashFunction hashFunction) {
        Hasher hasher = hashFunction.newHasher();
        for (int s = 0; s < size; s++) {
            Stop stop = stops[s];
            // Truncate the lat and lon to 6 decimal places in case they move slightly between feed versions
            hasher.putLong((long) (stop.getLat() * 1000000));
            hasher.putLong((long) (stop.getLon() * 1000000));
        }
        // Use hops rather than stops because drop-off at stop 0 and pick-up at last stop are not important
        // and have changed between OTP versions.
        for (int hop = 0; hop < size - 1; hop++) {
            hasher.putInt(pickups[hop]);
            hasher.putInt(dropoffs[hop + 1]);
        }
        return hasher.hash();
    }

}
TOP

Related Classes of org.opentripplanner.model.StopPattern

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.