<gh_stars>1-10
"""
GTFSBusTrack.py: Class definitions for working with GTFS schedule data.

These include:

GTFSBusSchedule -- A lightweight BusTrack representing a scheduled trip which 
takes timetable schedule data at face value and applies no processing.

GTFSBusTrack -- A BusTrack (also representing a scheduled trip) that applies 
more involved processing and heuristics to the data provided by the GTFS 
schedule, including shape data.


"""

# Copyright (c) 2010 <NAME>, <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

import dbqueries as db
import gisutils as gis
from BusTrack import BusTrack



class GTFSBusSchedule(BusTrack):
  """
  A BusTrack whose interpolation is mostly meaningless,
  but will return correct location for times listed
  in the GTFS schedule.
  """
  
  def __init__(self, trip_id,offset=0):
    """
    Given the GTFS trip_id, loads and constructs the schedule.
    Optionally, 'offset' seconds will be subtracted from each
    time in the schedule.
    """
    self.trip_id = trip_id
    self.offset = offset
    self.__load()
    BusTrack.__init__(self)

  def __eq__(self,other):
    return self.trip_id==other.trip_id and self.offset==other.offset;

  def __hash__(self):
    return hash(self.trip_id) * 7 - self.offset;

  ## Loads data about this trip from the database
  def __load(self):
    (trip_data,self.stops,self.shape) = db.getGTFSTripData(self.trip_id);
    self.set_attributes(trip_data);
    route_data = db.getGTFSRouteData(self.route_id);
    self.set_attributes(route_data);

  def _loadInterpolation(self):
    """
    Simply takes the GTFS schedule at face value and doesn't
    try to extract any more information out of it, nor apply
    any heuristics to it.
    """
    interpolation = []
    for stop in self.stops:
      interpolation.append( (stop['stop_lat'],
                             stop['stop_lon'],
                             stop['arrival_time_seconds']-self.offset));
      # If the bus sits there for a while, then add a point
      if stop['arrival_time_seconds'] != stop['departure_time_seconds']:
        interpolation.append( (stop['stop_lat'],
                               stop['stop_lon'],
                               stop['departure_time_seconds']-self.offset));
    return interpolation




class GTFSBusTrack(GTFSBusSchedule):
  """
  A BusTrack which interpolates the bus route along a 
  schedule defined by GTFS data, including the schedule
  and the shape (if provided).
  """

  def __init__(self,trip_id,offset=0,use_shape=True):
    """
    Given the GTFS trip_id, loads and constructs the object.
    Optionally, 'offset' seconds will be subtracted from every time
    in the trip.
    """
    self.use_shape = use_shape;
    GTFSBusSchedule.__init__(self,trip_id,offset);


  

  def findMatchingShapeIndex(self,stop,begin_idx=0,tol=20):
    ## Given a stop, finds the first shape segment at
    ## index i >= begin_idx that is within tol meters
    ## of the stop's location.

    last_pt = self.shape[begin_idx]
    min_dist,min_pt = 1e10,None
    for i,pt in enumerate(self.shape[begin_idx+1:]):
      dist = gis.distance_from_segment_meters( (last_pt['shape_pt_lat'],
                                                last_pt['shape_pt_lon']),
                                               (pt['shape_pt_lat'],
                                                pt['shape_pt_lon']),
                                               (stop['stop_lat'],
                                                stop['stop_lon']) );
      if dist <= tol:
        return i+begin_idx; #really it's i+begin_idx+1 - 1
      if dist < min_dist:
        min_dist,min_pt = dist,pt
      last_pt = pt
    print "Returning none (DOH!)"
    print "  Min dist was %f meters" % (min_dist,)
    return None


  def _loadInterpolation(self):
    ## The idea here is to put all the space/time information
    ## we have about this route into order so that we can make
    ## as good an interpolation as possible.
    ##
    ## First, we place the stops into the correct positions
    ## along the shape. Then from the times of the stops we can
    ## guess the times of the points on the shape.
    ##
    ## Note that if there is no shape_dist_traveled data available
    ## for the route, then there will probably be some large
    ## errors between some stops.
    
    # At the end of this, interpolation will be a list of
    # (lat,lon,time) tuples. This will be the basis of our final
    # representation.
    interpolation = []
    segment_idx = 0;

    if self.use_shape:
      segment = self.shape[0]
      interpolation = [  (segment['shape_pt_lat'],
                          segment['shape_pt_lon'],
                          None)  ];
    
    for stop in self.stops:
      # If we're using shape info we need to know where we are along it
      if self.use_shape:
        stop_segment_idx = self.findMatchingShapeIndex(stop,
                                                       begin_idx=segment_idx,
                                                       tol=50);
        if stop_segment_idx is None:
          print "Could not locate stop on shape within 50 meters"
          print " Route %s (%s), trip %s" % (self.route_short_name,
                                             self.route_id,
                                             self.trip_id)
          return

        while segment_idx < stop_segment_idx:
          segment_idx += 1
          segment = self.shape[segment_idx]
          interpolation.append( (segment['shape_pt_lat'],
                                 segment['shape_pt_lon'],
                                 None));

      # Regardless of shape use we put the stop into the interp
      interpolation.append( (stop['stop_lat'],
                             stop['stop_lon'],
                             stop['arrival_time_seconds']-self.offset));
      # If the bus sits there for a while, then add a point
      if stop['arrival_time_seconds'] != stop['departure_time_seconds']:
        interpolation.append( (stop['stop_lat'],
                               stop['stop_lon'],
                               stop['departure_time_seconds']-self.offset));

        
    # Finish up the rest of the shapes, if we're using them
    if self.use_shape:
      while segment_idx+1 < len(self.shape):
        segment_idx += 1
        segment = self.shape[segment_idx];
        interpolation.append( (segment['shape_pt_lat'],
                               segment['shape_pt_lon'],
                               None));
      
    # For debugging purposes
    self.preinterp = [interp for interp in interpolation];
    
    ## At this point we have some problems:
    ##    1) duplicate lat-lon pairs, in the case that a 
    ##       shape point matches with a stop point.
    ##    2) a bunch of tuples with a time value of None
    ##    3) sequences of points at different places but 
    ##       at the same time.
    ## We now endeavor to eliminate these problems, as follows:
    ##    1) Eliminate duplicate lat-lon pairs by keeping the element
    ##       which has time data. Duplicate lat-lon pairs where both
    ##       elements have a time are not eliminated.
    ##    2) Interpolate times for shape points between stop points.
    ##       If there are shape points at the begin/end with no times,
    ##       they will be given times 1 in second increments before/after 
    ##       the first/last stop points.
    ##    3) Interpolate sub-minute times for points occurring at different
    ##       places but at the same time.
    
    ## 1. Eliminate redundancies
    last_point = interpolation[0]
    for point in interpolation[1:]:
      if point[0] == last_point[0] and point[1] == last_point[1]:
        if not (point[2] or last_point[2]):
          print "Duplicate Shape Points????"
        elif not point[2]:
          interpolation.remove(point);
          continue; # don't want to set last_point to the removed one
        elif not last_point[2]:
          interpolation.remove(last_point);
        elif point[2] == last_point[2]:
          print "Duplicate Time Points????"
          interpolation.remove(last_point);
        else:  # point[2] != last_point[2]:
          pass # leave them both in
      last_point = point

    ## 2. Interpolate times for shape points (if we used them)
    if self.use_shape:
      last_timed_idx = None;
      last_timed = None;
      for i,point in enumerate(interpolation):
        # If there are points between here and last_timed that don't have times
        if point[2] and last_timed and i > last_timed_idx+1:
          #print"interpolating between times %d and %d"%(last_timed[2],point[2])
          delta_t = float(point[2] - last_timed[2]) / (i-last_timed_idx)
          interptime = last_timed[2]
          for j,untimed in enumerate(interpolation[last_timed_idx+1:i]):
            interptime += delta_t
            interpolation[j+last_timed_idx+1] = (untimed[0],untimed[1],interptime);
      
        if point[2]:
          if not last_timed:
            #Fabricate times for the first points
            for j in range(i):
              untimed = interpolation[j]
              interpolation[j] = (untimed[0],untimed[1],point[2] - (i-j));
          last_timed = point;
          last_timed_idx = i;
    
      # Now fabricate times for the last points
      for j in range(last_timed_idx+1,len(interpolation)):
        untimed = interpolation[j]
        interpolation[j] = (untimed[0], untimed[1], 
                            last_timed[2] + (j-last_timed_idx));

  
    ## 3. String out same-time-different-place stops across time
    begin_stop, begin_idx = None,None
    end_stop,end_idx = None, None
    for i,point in enumerate(interpolation):
      # if this is a new search for duplicate times
      if not begin_stop:
        begin_stop, begin_idx = point,i
      # if this is a duplicate time
      elif point[2] == begin_stop[2]:
        end_stop, end_idx = point, i
      # if there were no duplicate times
      elif not end_stop:
        begin_stop, begin_idx = point,i
      # if we reached the end of a string of duplicate times
      else:
        num_stops = i - begin_idx;
        # We will try to fit them all within their minute
        if (60 - (begin_stop[2] % 60)) < num_stops:
          raise Exception, "Too many (%d) duplicate times to eliminate"\
              %(num_stops,)
        for j in range(begin_idx+1,end_idx+1):
          pt = interpolation[j]
          interpolation[j] = (pt[0],pt[1],pt[2] + j - begin_idx);
        # Begin the next search
        begin_stop,begin_idx,end_stop = point,i,None

    # yay done
    return interpolation
    

"""
GTFSBusTrack.py: Class definitions for working with GTFS schedule data.

These include:

GTFSBusSchedule -- A lightweight BusTrack representing a scheduled trip which 
takes timetable schedule data at face value and applies no processing.

GTFSBusTrack -- A BusTrack (also representing a scheduled trip) that applies 
more involved processing and heuristics to the data provided by the GTFS 
schedule, including shape data.


"""

# Copyright (c) 2010 <NAME>, <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

import dbqueries as db
import gisutils as gis
from BusTrack import BusTrack



class GTFSBusSchedule(BusTrack):
  """
  A BusTrack whose interpolation is mostly meaningless,
  but will return correct location for times listed
  in the GTFS schedule.
  """
  
  def __init__(self, trip_id,offset=0):
    """
    Given the GTFS trip_id, loads and constructs the schedule.
    Optionally, 'offset' seconds will be subtracted from each
    time in the schedule.
    """
    self.trip_id = trip_id
    self.offset = offset
    self.__load()
    BusTrack.__init__(self)

  def __eq__(self,other):
    return self.trip_id==other.trip_id and self.offset==other.offset;

  def __hash__(self):
    return hash(self.trip_id) * 7 - self.offset;

  ## Loads data about this trip from the database
  def __load(self):
    (trip_data,self.stops,self.shape) = db.getGTFSTripData(self.trip_id);
    self.set_attributes(trip_data);
    route_data = db.getGTFSRouteData(self.route_id);
    self.set_attributes(route_data);

  def _loadInterpolation(self):
    """
    Simply takes the GTFS schedule at face value and doesn't
    try to extract any more information out of it, nor apply
    any heuristics to it.
    """
    interpolation = []
    for stop in self.stops:
      interpolation.append( (stop['stop_lat'],
                             stop['stop_lon'],
                             stop['arrival_time_seconds']-self.offset));
      # If the bus sits there for a while, then add a point
      if stop['arrival_time_seconds'] != stop['departure_time_seconds']:
        interpolation.append( (stop['stop_lat'],
                               stop['stop_lon'],
                               stop['departure_time_seconds']-self.offset));
    return interpolation




class GTFSBusTrack(GTFSBusSchedule):
  """
  A BusTrack which interpolates the bus route along a 
  schedule defined by GTFS data, including the schedule
  and the shape (if provided).
  """

  def __init__(self,trip_id,offset=0,use_shape=True):
    """
    Given the GTFS trip_id, loads and constructs the object.
    Optionally, 'offset' seconds will be subtracted from every time
    in the trip.
    """
    self.use_shape = use_shape;
    GTFSBusSchedule.__init__(self,trip_id,offset);


  

  def findMatchingShapeIndex(self,stop,begin_idx=0,tol=20):
    ## Given a stop, finds the first shape segment at
    ## index i >= begin_idx that is within tol meters
    ## of the stop's location.

    last_pt = self.shape[begin_idx]
    min_dist,min_pt = 1e10,None
    for i,pt in enumerate(self.shape[begin_idx+1:]):
      dist = gis.distance_from_segment_meters( (last_pt['shape_pt_lat'],
                                                last_pt['shape_pt_lon']),
                                               (pt['shape_pt_lat'],
                                                pt['shape_pt_lon']),
                                               (stop['stop_lat'],
                                                stop['stop_lon']) );
      if dist <= tol:
        return i+begin_idx; #really it's i+begin_idx+1 - 1
      if dist < min_dist:
        min_dist,min_pt = dist,pt
      last_pt = pt
    print "Returning none (DOH!)"
    print "  Min dist was %f meters" % (min_dist,)
    return None


  def _loadInterpolation(self):
    ## The idea here is to put all the space/time information
    ## we have about this route into order so that we can make
    ## as good an interpolation as possible.
    ##
    ## First, we place the stops into the correct positions
    ## along the shape. Then from the times of the stops we can
    ## guess the times of the points on the shape.
    ##
    ## Note that if there is no shape_dist_traveled data available
    ## for the route, then there will probably be some large
    ## errors between some stops.
    
    # At the end of this, interpolation will be a list of
    # (lat,lon,time) tuples. This will be the basis of our final
    # representation.
    interpolation = []
    segment_idx = 0;

    if self.use_shape:
      segment = self.shape[0]
      interpolation = [  (segment['shape_pt_lat'],
                          segment['shape_pt_lon'],
                          None)  ];
    
    for stop in self.stops:
      # If we're using shape info we need to know where we are along it
      if self.use_shape:
        stop_segment_idx = self.findMatchingShapeIndex(stop,
                                                       begin_idx=segment_idx,
                                                       tol=50);
        if stop_segment_idx is None:
          print "Could not locate stop on shape within 50 meters"
          print " Route %s (%s), trip %s" % (self.route_short_name,
                                             self.route_id,
                                             self.trip_id)
          return

        while segment_idx < stop_segment_idx:
          segment_idx += 1
          segment = self.shape[segment_idx]
          interpolation.append( (segment['shape_pt_lat'],
                                 segment['shape_pt_lon'],
                                 None));

      # Regardless of shape use we put the stop into the interp
      interpolation.append( (stop['stop_lat'],
                             stop['stop_lon'],
                             stop['arrival_time_seconds']-self.offset));
      # If the bus sits there for a while, then add a point
      if stop['arrival_time_seconds'] != stop['departure_time_seconds']:
        interpolation.append( (stop['stop_lat'],
                               stop['stop_lon'],
                               stop['departure_time_seconds']-self.offset));

        
    # Finish up the rest of the shapes, if we're using them
    if self.use_shape:
      while segment_idx+1 < len(self.shape):
        segment_idx += 1
        segment = self.shape[segment_idx];
        interpolation.append( (segment['shape_pt_lat'],
                               segment['shape_pt_lon'],
                               None));
      
    # For debugging purposes
    self.preinterp = [interp for interp in interpolation];
    
    ## At this point we have some problems:
    ##    1) duplicate lat-lon pairs, in the case that a 
    ##       shape point matches with a stop point.
    ##    2) a bunch of tuples with a time value of None
    ##    3) sequences of points at different places but 
    ##       at the same time.
    ## We now endeavor to eliminate these problems, as follows:
    ##    1) Eliminate duplicate lat-lon pairs by keeping the element
    ##       which has time data. Duplicate lat-lon pairs where both
    ##       elements have a time are not eliminated.
    ##    2) Interpolate times for shape points between stop points.
    ##       If there are shape points at the begin/end with no times,
    ##       they will be given times 1 in second increments before/after 
    ##       the first/last stop points.
    ##    3) Interpolate sub-minute times for points occurring at different
    ##       places but at the same time.
    
    ## 1. Eliminate redundancies
    last_point = interpolation[0]
    for point in interpolation[1:]:
      if point[0] == last_point[0] and point[1] == last_point[1]:
        if not (point[2] or last_point[2]):
          print "Duplicate Shape Points????"
        elif not point[2]:
          interpolation.remove(point);
          continue; # don't want to set last_point to the removed one
        elif not last_point[2]:
          interpolation.remove(last_point);
        elif point[2] == last_point[2]:
          print "Duplicate Time Points????"
          interpolation.remove(last_point);
        else:  # point[2] != last_point[2]:
          pass # leave them both in
      last_point = point

    ## 2. Interpolate times for shape points (if we used them)
    if self.use_shape:
      last_timed_idx = None;
      last_timed = None;
      for i,point in enumerate(interpolation):
        # If there are points between here and last_timed that don't have times
        if point[2] and last_timed and i > last_timed_idx+1:
          #print"interpolating between times %d and %d"%(last_timed[2],point[2])
          delta_t = float(point[2] - last_timed[2]) / (i-last_timed_idx)
          interptime = last_timed[2]
          for j,untimed in enumerate(interpolation[last_timed_idx+1:i]):
            interptime += delta_t
            interpolation[j+last_timed_idx+1] = (untimed[0],untimed[1],interptime);
      
        if point[2]:
          if not last_timed:
            #Fabricate times for the first points
            for j in range(i):
              untimed = interpolation[j]
              interpolation[j] = (untimed[0],untimed[1],point[2] - (i-j));
          last_timed = point;
          last_timed_idx = i;
    
      # Now fabricate times for the last points
      for j in range(last_timed_idx+1,len(interpolation)):
        untimed = interpolation[j]
        interpolation[j] = (untimed[0], untimed[1], 
                            last_timed[2] + (j-last_timed_idx));

  
    ## 3. String out same-time-different-place stops across time
    begin_stop, begin_idx = None,None
    end_stop,end_idx = None, None
    for i,point in enumerate(interpolation):
      # if this is a new search for duplicate times
      if not begin_stop:
        begin_stop, begin_idx = point,i
      # if this is a duplicate time
      elif point[2] == begin_stop[2]:
        end_stop, end_idx = point, i
      # if there were no duplicate times
      elif not end_stop:
        begin_stop, begin_idx = point,i
      # if we reached the end of a string of duplicate times
      else:
        num_stops = i - begin_idx;
        # We will try to fit them all within their minute
        if (60 - (begin_stop[2] % 60)) < num_stops:
          raise Exception, "Too many (%d) duplicate times to eliminate"\
              %(num_stops,)
        for j in range(begin_idx+1,end_idx+1):
          pt = interpolation[j]
          interpolation[j] = (pt[0],pt[1],pt[2] + j - begin_idx);
        # Begin the next search
        begin_stop,begin_idx,end_stop = point,i,None

    # yay done
    return interpolation
GTFSBusTrack.py: Class definitions for working with GTFS schedule data.  These include:  GTFSBusSchedule -- A lightweight BusTrack representing a scheduled trip which  takes timetable schedule data at face value and applies no processing.  GTFSBusTrack -- A BusTrack (also representing a scheduled trip) that applies  more involved processing and heuristics to the data provided by the GTFS  schedule, including shape data. # Copyright (c) 2010 <NAME>, <NAME> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. A BusTrack whose interpolation is mostly meaningless,   but will return correct location for times listed   in the GTFS schedule. Given the GTFS trip_id, loads and constructs the schedule.     Optionally, 'offset' seconds will be subtracted from each     time in the schedule. ## Loads data about this trip from the database Simply takes the GTFS schedule at face value and doesn't     try to extract any more information out of it, nor apply     any heuristics to it. # If the bus sits there for a while, then add a point A BusTrack which interpolates the bus route along a    schedule defined by GTFS data, including the schedule   and the shape (if provided). Given the GTFS trip_id, loads and constructs the object.     Optionally, 'offset' seconds will be subtracted from every time     in the trip. ## Given a stop, finds the first shape segment at ## index i >= begin_idx that is within tol meters ## of the stop's location. #really it's i+begin_idx+1 - 1 ## The idea here is to put all the space/time information ## we have about this route into order so that we can make ## as good an interpolation as possible. ## ## First, we place the stops into the correct positions ## along the shape. Then from the times of the stops we can ## guess the times of the points on the shape. ## ## Note that if there is no shape_dist_traveled data available ## for the route, then there will probably be some large ## errors between some stops. # At the end of this, interpolation will be a list of # (lat,lon,time) tuples. This will be the basis of our final # representation. # If we're using shape info we need to know where we are along it # Regardless of shape use we put the stop into the interp # If the bus sits there for a while, then add a point # Finish up the rest of the shapes, if we're using them # For debugging purposes ## At this point we have some problems: ##    1) duplicate lat-lon pairs, in the case that a ##       shape point matches with a stop point. ##    2) a bunch of tuples with a time value of None ##    3) sequences of points at different places but ##       at the same time. ## We now endeavor to eliminate these problems, as follows: ##    1) Eliminate duplicate lat-lon pairs by keeping the element ##       which has time data. Duplicate lat-lon pairs where both ##       elements have a time are not eliminated. ##    2) Interpolate times for shape points between stop points. ##       If there are shape points at the begin/end with no times, ##       they will be given times 1 in second increments before/after ##       the first/last stop points. ##    3) Interpolate sub-minute times for points occurring at different ##       places but at the same time. ## 1. Eliminate redundancies # don't want to set last_point to the removed one # point[2] != last_point[2]: # leave them both in ## 2. Interpolate times for shape points (if we used them) # If there are points between here and last_timed that don't have times #print"interpolating between times %d and %d"%(last_timed[2],point[2]) #Fabricate times for the first points # Now fabricate times for the last points ## 3. String out same-time-different-place stops across time # if this is a new search for duplicate times # if this is a duplicate time # if there were no duplicate times # if we reached the end of a string of duplicate times # We will try to fit them all within their minute # Begin the next search # yay done