Upgrade origin-src to google transit feed 1.2.6
[bus.git] / origin-src / transitfeed-1.2.6 / examples / google_random_queries.py
blob:a/origin-src/transitfeed-1.2.6/examples/google_random_queries.py -> blob:b/origin-src/transitfeed-1.2.6/examples/google_random_queries.py
#!/usr/bin/python2.5 #!/usr/bin/python2.5
   
# Copyright (C) 2007 Google Inc. # Copyright (C) 2007 Google Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
# You may obtain a copy of the License at # You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
   
   
"""Output Google Transit URLs for queries near stops. """Output Google Transit URLs for queries near stops.
   
The output can be used to speed up manual testing. Load the output from this The output can be used to speed up manual testing. Load the output from this
file and then open many of the links in new tabs. In each result check that the file and then open many of the links in new tabs. In each result check that the
polyline looks okay (no unnecassary loops, no jumps to a far away location) and polyline looks okay (no unnecassary loops, no jumps to a far away location) and
look at the time of each leg. Also check the route names and headsigns are look at the time of each leg. Also check the route names and headsigns are
formatted correctly and not redundant. formatted correctly and not redundant.
""" """
   
from datetime import datetime from datetime import datetime
from datetime import timedelta from datetime import timedelta
import math import math
import optparse import optparse
import os.path import os.path
import random import random
import sys import sys
import transitfeed import transitfeed
import urllib import urllib
import urlparse import urlparse
   
   
def Distance(lat0, lng0, lat1, lng1): def Distance(lat0, lng0, lat1, lng1):
""" """
Compute the geodesic distance in meters between two points on the Compute the geodesic distance in meters between two points on the
surface of the Earth. The latitude and longitude angles are in surface of the Earth. The latitude and longitude angles are in
degrees. degrees.
   
Approximate geodesic distance function (Haversine Formula) assuming Approximate geodesic distance function (Haversine Formula) assuming
a perfect sphere of radius 6367 km (see "What are some algorithms a perfect sphere of radius 6367 km (see "What are some algorithms
for calculating the distance between 2 points?" in the GIS Faq at for calculating the distance between 2 points?" in the GIS Faq at
http://www.census.gov/geo/www/faq-index.html). The approximate http://www.census.gov/geo/www/faq-index.html). The approximate
radius is adequate for our needs here, but a more sophisticated radius is adequate for our needs here, but a more sophisticated
geodesic function should be used if greater accuracy is required geodesic function should be used if greater accuracy is required
(see "When is it NOT okay to assume the Earth is a sphere?" in the (see "When is it NOT okay to assume the Earth is a sphere?" in the
same faq). same faq).
""" """
deg2rad = math.pi / 180.0 deg2rad = math.pi / 180.0
lat0 = lat0 * deg2rad lat0 = lat0 * deg2rad
lng0 = lng0 * deg2rad lng0 = lng0 * deg2rad
lat1 = lat1 * deg2rad lat1 = lat1 * deg2rad
lng1 = lng1 * deg2rad lng1 = lng1 * deg2rad
dlng = lng1 - lng0 dlng = lng1 - lng0
dlat = lat1 - lat0 dlat = lat1 - lat0
a = math.sin(dlat*0.5) a = math.sin(dlat*0.5)
b = math.sin(dlng*0.5) b = math.sin(dlng*0.5)
a = a * a + math.cos(lat0) * math.cos(lat1) * b * b a = a * a + math.cos(lat0) * math.cos(lat1) * b * b
c = 2.0 * math.atan2(math.sqrt(a), math.sqrt(1.0 - a)) c = 2.0 * math.atan2(math.sqrt(a), math.sqrt(1.0 - a))
return 6367000.0 * c return 6367000.0 * c
   
   
def AddNoiseToLatLng(lat, lng): def AddNoiseToLatLng(lat, lng):
"""Add up to 500m of error to each coordinate of lat, lng.""" """Add up to 500m of error to each coordinate of lat, lng."""
m_per_tenth_lat = Distance(lat, lng, lat + 0.1, lng) m_per_tenth_lat = Distance(lat, lng, lat + 0.1, lng)
m_per_tenth_lng = Distance(lat, lng, lat, lng + 0.1) m_per_tenth_lng = Distance(lat, lng, lat, lng + 0.1)
lat_per_100m = 1 / m_per_tenth_lat * 10 lat_per_100m = 1 / m_per_tenth_lat * 10
lng_per_100m = 1 / m_per_tenth_lng * 10 lng_per_100m = 1 / m_per_tenth_lng * 10
return (lat + (lat_per_100m * 5 * (random.random() * 2 - 1)), return (lat + (lat_per_100m * 5 * (random.random() * 2 - 1)),
lng + (lng_per_100m * 5 * (random.random() * 2 - 1))) lng + (lng_per_100m * 5 * (random.random() * 2 - 1)))
   
   
def GetRandomLocationsNearStops(schedule): def GetRandomLocationsNearStops(schedule):
"""Return a list of (lat, lng) tuples.""" """Return a list of (lat, lng) tuples."""
locations = [] locations = []
for s in schedule.GetStopList(): for s in schedule.GetStopList():
locations.append(AddNoiseToLatLng(s.stop_lat, s.stop_lon)) locations.append(AddNoiseToLatLng(s.stop_lat, s.stop_lon))
return locations return locations
   
   
def GetRandomDatetime(): def GetRandomDatetime():
"""Return a datetime in the next week.""" """Return a datetime in the next week."""
seconds_offset = random.randint(0, 60 * 60 * 24 * 7) seconds_offset = random.randint(0, 60 * 60 * 24 * 7)
dt = datetime.today() + timedelta(seconds=seconds_offset) dt = datetime.today() + timedelta(seconds=seconds_offset)
return dt.replace(second=0, microsecond=0) return dt.replace(second=0, microsecond=0)
   
   
def FormatLatLng(lat_lng): def FormatLatLng(lat_lng):
"""Format a (lat, lng) tuple into a string for maps.google.com.""" """Format a (lat, lng) tuple into a string for maps.google.com."""
return "%0.6f,%0.6f" % lat_lng return "%0.6f,%0.6f" % lat_lng
   
   
def LatLngsToGoogleUrl(source, destination, dt): def LatLngsToGoogleUrl(source, destination, dt):
"""Return a URL for routing between two (lat, lng) at a datetime.""" """Return a URL for routing between two (lat, lng) at a datetime."""
params = {"saddr": FormatLatLng(source), params = {"saddr": FormatLatLng(source),
"daddr": FormatLatLng(destination), "daddr": FormatLatLng(destination),
"time": dt.strftime("%I:%M%p"), "time": dt.strftime("%I:%M%p"),
"date": dt.strftime("%Y-%m-%d"), "date": dt.strftime("%Y-%m-%d"),
"dirflg": "r", "dirflg": "r",
"ie": "UTF8", "ie": "UTF8",
"oe": "UTF8"} "oe": "UTF8"}
url = urlparse.urlunsplit(("http", "maps.google.com", "/maps", url = urlparse.urlunsplit(("http", "maps.google.com", "/maps",
urllib.urlencode(params), "")) urllib.urlencode(params), ""))
return url return url
   
   
def LatLngsToGoogleLink(source, destination): def LatLngsToGoogleLink(source, destination):
"""Return a string "<a ..." for a trip at a random time.""" """Return a string "<a ..." for a trip at a random time."""
dt = GetRandomDatetime() dt = GetRandomDatetime()
return "<a href='%s'>from:%s to:%s on %s</a>" % ( return "<a href='%s'>from:%s to:%s on %s</a>" % (
LatLngsToGoogleUrl(source, destination, dt), LatLngsToGoogleUrl(source, destination, dt),
FormatLatLng(source), FormatLatLng(destination), FormatLatLng(source), FormatLatLng(destination),
dt.ctime()) dt.ctime())
   
   
def WriteOutput(title, locations, limit, f): def WriteOutput(title, locations, limit, f):
"""Write html to f for up to limit trips between locations. """Write html to f for up to limit trips between locations.
   
Args: Args:
title: String used in html title title: String used in html title
locations: list of (lat, lng) tuples locations: list of (lat, lng) tuples
limit: maximum number of queries in the html limit: maximum number of queries in the html
f: a file object f: a file object
""" """
output_prefix = """ output_prefix = """
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>%(title)s</title> <title>%(title)s</title>
</head> </head>
<body> <body>
Random queries for %(title)s<p> Random queries for %(title)s<p>
This list of random queries should speed up important manual testing. Here are This list of random queries should speed up important manual testing. Here are
some things to check when looking at the results of a query. some things to check when looking at the results of a query.
<ul> <ul>
<li> Check the agency attribution under the trip results: <li> Check the agency attribution under the trip results:
<ul> <ul>
<li> has correct name and spelling of the agency <li> has correct name and spelling of the agency
<li> opens a page with general information about the service <li> opens a page with general information about the service
</ul> </ul>
<li> For each alternate trip check that each of these is reasonable: <li> For each alternate trip check that each of these is reasonable:
<ul> <ul>
<li> the total time of the trip <li> the total time of the trip
<li> the time for each leg. Bad data frequently results in a leg going a long <li> the time for each leg. Bad data frequently results in a leg going a long
way in a few minutes. way in a few minutes.
<li> the icons and mode names (Tram, Bus, etc) are correct for each leg <li> the icons and mode names (Tram, Bus, etc) are correct for each leg
<li> the route names and headsigns are correctly formatted and not <li> the route names and headsigns are correctly formatted and not
redundant. redundant.
For a good example see <a For a good example see <a
href="http://code.google.com/transit/spec/transit_feed_specification.html#transitScreenshots">the href="http://code.google.com/transit/spec/transit_feed_specification.html#transitScreenshots">the
screenshots in the Google Transit Feed Specification</a>. screenshots in the Google Transit Feed Specification</a>.
<li> the shape line on the map looks correct. Make sure the polyline does <li> the shape line on the map looks correct. Make sure the polyline does
not zig-zag, loop, skip stops or jump far away unless the trip does the not zig-zag, loop, skip stops or jump far away unless the trip does the
same thing. same thing.
<li> the route is active on the day the trip planner returns <li> the route is active on the day the trip planner returns
</ul> </ul>
</ul> </ul>
If you find a problem be sure to save the URL. This file is generated randomly. If you find a problem be sure to save the URL. This file is generated randomly.
<ol> <ol>
""" % locals() """ % locals()
   
output_suffix = """ output_suffix = """
</ol> </ol>
</body> </body>
</html> </html>
""" % locals() """ % locals()
   
f.write(transitfeed.EncodeUnicode(output_prefix)) f.write(transitfeed.EncodeUnicode(output_prefix))
for source, destination in zip(locations[0:limit], locations[1:limit + 1]): for source, destination in zip(locations[0:limit], locations[1:limit + 1]):
f.write(transitfeed.EncodeUnicode("<li>%s\n" % f.write(transitfeed.EncodeUnicode("<li>%s\n" %
LatLngsToGoogleLink(source, destination))) LatLngsToGoogleLink(source, destination)))
f.write(transitfeed.EncodeUnicode(output_suffix)) f.write(transitfeed.EncodeUnicode(output_suffix))
   
   
def ParentAndBaseName(path): def ParentAndBaseName(path):
"""Given a path return only the parent name and file name as a string.""" """Given a path return only the parent name and file name as a string."""
dirname, basename = os.path.split(path) dirname, basename = os.path.split(path)
dirname = dirname.rstrip(os.path.sep) dirname = dirname.rstrip(os.path.sep)
if os.path.altsep: if os.path.altsep:
dirname = dirname.rstrip(os.path.altsep) dirname = dirname.rstrip(os.path.altsep)
_, parentname = os.path.split(dirname) _, parentname = os.path.split(dirname)
return os.path.join(parentname, basename) return os.path.join(parentname, basename)
   
   
def main(): def main():
  usage = \
  """%prog [options] <input GTFS.zip>
   
  Create an HTML page of random URLs for the Google Maps transit trip
  planner. The queries go between places near stops listed in a <input GTFS.zip>.
  By default 50 random URLs are saved to google_random_queries.html.
   
  For more information see
  http://code.google.com/p/googletransitdatafeed/wiki/GoogleRandomQueries
  """
   
parser = optparse.OptionParser( parser = optparse.OptionParser(
usage="usage: %prog [options] feed_filename output_filename", usage=usage,
version="%prog "+transitfeed.__version__) version="%prog "+transitfeed.__version__)
parser.add_option("-l", "--limit", dest="limit", type="int", parser.add_option("-l", "--limit", dest="limit", type="int",
help="Maximum number of URLs to generate") help="Maximum number of URLs to generate")
parser.add_option('-o', '--output', dest='output', metavar='FILE', parser.add_option("-o", "--output", dest="output", metavar="HTML_OUTPUT_PATH",
help='write html output to FILE') help="write HTML output to HTML_OUTPUT_PATH")
parser.set_defaults(output="google_random_queries.html", limit=50) parser.set_defaults(output="google_random_queries.html", limit=50)
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if len(args) != 1: if len(args) != 1:
print >>sys.stderr, parser.format_help() print >>sys.stderr, parser.format_help()
print >>sys.stderr, "\n\nYou must provide the path of a single feed\n\n" print >>sys.stderr, "\n\nYou must provide the path of a single feed\n\n"
sys.exit(2) sys.exit(2)
feed_path = args[0] feed_path = args[0]
   
# ProblemReporter prints problems on console. # ProblemReporter prints problems on console.
loader = transitfeed.Loader(feed_path, problems=transitfeed.ProblemReporter(), loader = transitfeed.Loader(feed_path, problems=transitfeed.ProblemReporter(),
load_stop_times=False) load_stop_times=False)
schedule = loader.Load() schedule = loader.Load()
locations = GetRandomLocationsNearStops(schedule) locations = GetRandomLocationsNearStops(schedule)
random.shuffle(locations) random.shuffle(locations)
agencies = ", ".join([a.agency_name for a in schedule.GetAgencyList()]) agencies = ", ".join([a.agency_name for a in schedule.GetAgencyList()])
title = "%s (%s)" % (agencies, ParentAndBaseName(feed_path)) title = "%s (%s)" % (agencies, ParentAndBaseName(feed_path))
   
WriteOutput(title, WriteOutput(title,
locations, locations,
options.limit, options.limit,
open(options.output, "w")) open(options.output, "w"))
print ("Load %s in your web browser. It contains more instructions." % print ("Load %s in your web browser. It contains more instructions." %
options.output) options.output)
   
   
if __name__ == "__main__": if __name__ == "__main__":
main() main()