Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accra creator #66

Merged
merged 11 commits into from
Oct 7, 2017
14 changes: 11 additions & 3 deletions core/osm_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,10 @@ def _build_route_master(self, route_master, members):
return

name = route_master.tags['name']
rm = RouteMaster(route_master.id, ref, name, members)
frequency = None
if "frequency" in route_master.tags:
frequency = route_master.tags['frequency']
rm = RouteMaster(route_master.id, ref, name, members, frequency)
print(rm)
return rm

Expand Down Expand Up @@ -324,6 +327,11 @@ def _build_route_variant(self, route_variant, query_result_set, rm=None):
else:
name = None

if 'travel_time' in route_variant.tags:
travel_time = route_variant.tags['travel_time']
else:
travel_time = None

stops = []

# Add ids for stops of this route variant
Expand All @@ -342,7 +350,8 @@ def _build_route_variant(self, route_variant, query_result_set, rm=None):
stops.append(otype + "/" + str(stop_candidate.ref))

shape = self._generate_shape(route_variant, query_result_set)
rv = Route(route_variant.id, fr, to, stops, rm, ref, name, shape)
rv = Route(route_variant.id, fr, to, stops,
rm, ref, name, shape, travel_time)
print(rv)
return rv

Expand Down Expand Up @@ -522,7 +531,6 @@ def _is_valid_stop_candidate(self, stop):
return False

def _get_names_for_unnamed_stops(self):

"""Intelligently guess stop names for unnamed stops by sourrounding
street names and amenities.

Expand Down
6 changes: 4 additions & 2 deletions core/osm_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ def __repr__(self):

class Route(BaseRoute):

def __init__(self, osm, fr, to, stops, master, ref, name, shape):
def __init__(self, osm, fr, to, stops, master, ref, name, shape, travel_time=None):
BaseRoute.__init__(self, osm, ref, name)
self.fr = fr
self.to = to
self.stops = stops
self.master = master
self.shape = shape
self.travel_time = travel_time
self.duration = None

def __repr__(self):
Expand Down Expand Up @@ -77,9 +78,10 @@ def print_shape_for_leaflet(self):

class RouteMaster(BaseRoute):

def __init__(self, osm, ref, name, routes):
def __init__(self, osm, ref, name, routes, frequency=None):
BaseRoute.__init__(self, osm, ref, name)
self.routes = routes
self.frequency = frequency
for route in self.routes.values():
route.master = self

Expand Down
6 changes: 4 additions & 2 deletions core/osm_stops.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ def __repr__(self):
if self.name is not None:
rep += self.name
if self.lat is not None and self.lon is not None:
rep += " http://www.openstreetmap.org/?mlat=" + str(self.lat) + "&mlon=" + str(self.lon)
rep += " (https://www.openstreetmap.org/" + self.type + "/" + str(self.id) + ")"
rep += " http://www.openstreetmap.org/?mlat=" + \
str(self.lat) + "&mlon=" + str(self.lon)
rep += " (https://www.openstreetmap.org/" + \
self.type + "/" + str(self.id) + ")"
return rep

@staticmethod
Expand Down
2 changes: 2 additions & 0 deletions creators/accra/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env python
# coding=utf-8
35 changes: 35 additions & 0 deletions creators/accra/accra.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"query": {
"bbox": {
"n": "5.7844",
"s": "5.4783",
"e": "0.0611",
"w": "-0.4779"
},
"tags": {
"route": "bus"
}
},
"stops": {
"name_without": "Add a name to the stop with JungleBus app",
"name_auto": "yes"
},
"agency": {
"agency_id": "AM3",
"agency_name": "Accra Tro tro",
"agency_url": "https://ama.gov.gh/welcome/transport/",
"agency_timezone": "Africa/Accra",
"agency_lang": "EN",
"agency_phone": "",
"agency_fare_url": ""
},
"feed_info": {
"publisher_name": "Jungle Bus",
"publisher_url": "http://junglebus.io",
"version": "0.1",
"start_date": "20170901",
"end_date": "20180730"
},
"output_file": "data/accra.zip",
"selector": "accra"
}
13 changes: 13 additions & 0 deletions creators/accra/routes_creator_accra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# coding=utf-8

from creators.routes_creator import RoutesCreator


class RoutesCreatorAccra(RoutesCreator):

def add_routes_to_schedule(self, schedule, data):
# Get routes information
data.get_routes()

# GTFS routes are created in TripsCreator
return
82 changes: 82 additions & 0 deletions creators/accra/stops_creator_accra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# coding=utf-8


from creators.stops_creator import StopsCreator
import math


def get_crow_fly_distance(from_tuple, to_tuple):
"""
Uses the Haversine formmula to compute distance (https://en.wikipedia.org/wiki/Haversine_formula#The_haversine_formula)
"""
lat1, lon1 = from_tuple
lat2, lon2 = to_tuple

lat1 = float(lat1)
lat2 = float(lat2)
lon1 = float(lon1)
lon2 = float(lon2)

radius = 6371 # km

dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(math.radians(lat1)) * \
math.cos(math.radians(lat2)) * math.sin(dlon / 2) * math.sin(dlon / 2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
d = radius * c

return d * 1000 # meters


def create_stop_area(stop_data, schedule):
gtfs_stop_area = schedule.AddStop(
lat=float(stop_data.lat),
lng=float(stop_data.lon),
name=stop_data.name,
stop_id="SA" + str(stop_data.id)
)
gtfs_stop_area.location_type = 1
return gtfs_stop_area


def create_stop_point(stop_data, schedule):
gtfs_stop_point = schedule.AddStop(
lat=float(stop_data.lat),
lng=float(stop_data.lon),
name=stop_data.name,
stop_id=str(stop_data.id)
)
return gtfs_stop_point

def get_stop_id(stop):
return stop.id

class StopsCreatorAccra(StopsCreator):

def add_stops_to_schedule(self, schedule, data):
stops = data.get_stops()
stops_by_name = {}

for a_stop in stops.values():
if a_stop.name not in stops_by_name:
stops_by_name[a_stop.name] = []
stops_by_name[a_stop.name].append(a_stop)

for a_stop_name in stops_by_name:
stop_areas = []

for a_stop_point in sorted(stops_by_name[a_stop_name], key=get_stop_id):
gtfs_stop_point = create_stop_point(a_stop_point, schedule)
stop_point_has_parent_location = False
for a_stop_area in stop_areas:
distance_to_parent_station = get_crow_fly_distance(
(a_stop_area.stop_lat, a_stop_area.stop_lon), (a_stop_point.lat, a_stop_point.lon))
if distance_to_parent_station < 500:
gtfs_stop_point.parent_station = a_stop_area.stop_id
stop_point_has_parent_location = True
break
if not stop_point_has_parent_location:
new_sa = create_stop_area(a_stop_point, schedule)
gtfs_stop_point.parent_station = new_sa.stop_id
stop_areas.append(new_sa)
96 changes: 96 additions & 0 deletions creators/accra/trips_creator_accra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# coding=utf-8

import sys
import json
import re
from datetime import timedelta, datetime
from creators.trips_creator import TripsCreator
from core.osm_routes import Route, RouteMaster


class TripsCreatorAccra(TripsCreator):

def add_trips_to_schedule(self, schedule, data):
self.service_weekday = schedule.GetDefaultServicePeriod()
self.service_weekday.SetStartDate(
self.config['feed_info']['start_date'])
self.service_weekday.SetEndDate(self.config['feed_info']['end_date'])
self.service_weekday.SetWeekdayService(True)
self.service_weekday.SetWeekendService(True)

lines = data.routes
for route_ref, line in sorted(lines.iteritems()):
if type(line).__name__ != "RouteMaster":
continue

line_gtfs = schedule.AddRoute(
short_name=line.ref,
long_name=line.name.decode('utf8'),
# we change the route_long_name with the 'from' and 'to' tags
# of the last route as the route_master name tag contains
# the line code (route_short_name)
route_type="Bus",
route_id=line.id)
line_gtfs.agency_id = schedule.GetDefaultAgency().agency_id
line_gtfs.route_desc = ""
line_gtfs.route_color = "1779c2"
line_gtfs.route_text_color = "ffffff"

route_index = 0
for a_route_ref, a_route in line.routes.iteritems():
trip_gtfs = line_gtfs.AddTrip(schedule)
trip_gtfs.shape_id = TripsCreator.add_shape(
schedule, a_route_ref, a_route)
trip_gtfs.direction_id = route_index % 2
route_index += 1

if a_route.fr and a_route.to:
trip_gtfs.trip_headsign = a_route.to
line_gtfs.route_long_name = a_route.fr.decode(
'utf8') + " ↔ ".decode('utf8') + a_route.to.decode('utf8')

DEFAULT_ROUTE_FREQUENCY = 30
DEFAULT_TRAVEL_TIME = 120

try:
ROUTE_FREQUENCY = int(line.frequency)
if not ROUTE_FREQUENCY > 0:
print("frequency is invalid for route_master " + str(line.id))
ROUTE_FREQUENCY = DEFAULT_ROUTE_FREQUENCY
except Exception as e:
print("frequency not a number for route_master " + str(line.id))
ROUTE_FREQUENCY = DEFAULT_ROUTE_FREQUENCY
trip_gtfs.AddFrequency(
"05:00:00", "22:00:00", ROUTE_FREQUENCY * 60)

try:
TRAVEL_TIME = int(a_route.travel_time)
if not TRAVEL_TIME > 0:
print("travel_time is invalid for route " +
str(lia_routene.id))
TRAVEL_TIME = DEFAULT_TRAVEL_TIME
except Exception as e:
print("travel_time not a number for route " + str(a_route.id))
TRAVEL_TIME = DEFAULT_TRAVEL_TIME

for index_stop, a_stop in enumerate(a_route.stops):
stop_id = a_stop.split('/')[-1]
departure_time = datetime(2008, 11, 22, 6, 0, 0)

if index_stop == 0:
trip_gtfs.AddStopTime(schedule.GetStop(
str(stop_id)), stop_time=departure_time.strftime("%H:%M:%S"))
elif index_stop == len(a_route.stops) - 1:
departure_time += timedelta(minutes=TRAVEL_TIME)
trip_gtfs.AddStopTime(schedule.GetStop(
str(stop_id)), stop_time=departure_time.strftime("%H:%M:%S"))
else:
trip_gtfs.AddStopTime(schedule.GetStop(str(stop_id)))

for secs, stop_time, is_timepoint in trip_gtfs.GetTimeInterpolatedStops():
if not is_timepoint:
stop_time.arrival_secs = secs
stop_time.departure_secs = secs
trip_gtfs.ReplaceStopTimeObject(stop_time)

TripsCreator.interpolate_stop_times(trip_gtfs)
10 changes: 1 addition & 9 deletions creators/fenix/trips_creator_fenix.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def add_trips_by_day(self, schedule, line, service, route, horarios, day):
self.add_trip_stops(schedule, trip, route, start_time, end_time)

# interpolate times, because Navitia can not handle this itself
self.interpolate_stop_times(trip)
TripsCreator.interpolate_stop_times(trip)

def get_exception_service_period(self, schedule, date, day):
date_string = date.strftime("%Y%m%d")
Expand Down Expand Up @@ -292,11 +292,3 @@ def add_trip_stops(schedule, trip, route, start_time, end_time):
trip.AddStopTime(schedule.GetStop(str(stop.id)))
# print "INTER: " + str(stop)
i += 1

@staticmethod
def interpolate_stop_times(trip):
for secs, stop_time, is_timepoint in trip.GetTimeInterpolatedStops():
if not is_timepoint:
stop_time.arrival_secs = secs
stop_time.departure_secs = secs
trip.ReplaceStopTimeObject(stop_time)
16 changes: 1 addition & 15 deletions creators/incofer/trips_creator_incofer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def add_trips_to_schedule(self, schedule, data):
# print("DEBUG. procesando el itinerario", itinerary.name)

# shape for itinerary
shape_id = _add_shape(schedule, itinerary_id, itinerary)
shape_id = TripsCreator.add_shape(schedule, itinerary_id, itinerary)

# service periods | días de opearación (c/u con sus horarios)
operations = self._get_itinerary_operation(itinerary)
Expand Down Expand Up @@ -110,20 +110,6 @@ def _create_service_period(self, schedule, operation):
return schedule.GetServicePeriod(operation)


def _add_shape(schedule, route_id, osm_r):
# get shape id
shape_id = str(route_id)
try:
schedule.GetShape(shape_id)
except KeyError:
shape = transitfeed.Shape(shape_id)
for point in osm_r.shape:
shape.AddPoint(lat=float(point["lat"]), lon=float(point["lon"]))
schedule.AddShapeObject(shape)

return shape_id


def add_trips_for_route(schedule, gtfs_route, itinerary, service_period,
shape_id, estaciones, horarios):
# debug
Expand Down
28 changes: 28 additions & 0 deletions creators/trips_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,31 @@ def __repr__(self):

def add_trips_to_schedule(self, schedule, data):
raise NotImplementedError("Should have implemented this")

@staticmethod
def interpolate_stop_times(trip):
"""
interpolate stop_times, because Navitia does not handle this itself by now
"""
for secs, stop_time, is_timepoint in trip.GetTimeInterpolatedStops():
if not is_timepoint:
stop_time.arrival_secs = secs
stop_time.departure_secs = secs
trip.ReplaceStopTimeObject(stop_time)

@staticmethod
def add_shape(schedule, route_id, osm_r):
"""
create GTFS shape and return shape_id to add on GTFS trip
"""
import transitfeed
shape_id = str(route_id)
try:
schedule.GetShape(shape_id)
except KeyError:
shape = transitfeed.Shape(shape_id)
for point in osm_r.shape:
shape.AddPoint(
lat=float(point["lat"]), lon=float(point["lon"]))
schedule.AddShapeObject(shape)
return shape_id