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