lib.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import json
  2. import math
  3. import requests
  4. import haversine
  5. # Google API key, with access to Street View Static API
  6. google_api_key = "AIzaSyAqjCYR6Szph0X0H_iD6O1HenFhL9jySOo"
  7. metadata_url = "https://maps.googleapis.com/maps/api/streetview/metadata"
  8. mapcrunch_url = "http://www.mapcrunch.com/_r/"
  9. def generate_coord(max_retries=100000):
  10. """
  11. Returns (latitude, longitude) of usable coord (where google has data).
  12. This function will attempt at most max_retries calls to map crunch to fetch
  13. candidate points, and will exit as soon as a suitable candidate is found.
  14. This function calls the streetview metadata endpoint - there is no quota consumed
  15. """
  16. for _ in range(max_retries):
  17. points_res = requests.get(mapcrunch_url).text
  18. points_js = json.loads(points_res.strip("while(1); "))
  19. for lat, lng in points_js["points"]:
  20. params = {
  21. "key": google_api_key,
  22. "location": f"{lat},{lng}",
  23. }
  24. js = requests.get(metadata_url, params=params).json()
  25. if js["status"] == "OK":
  26. return (lat, lng)
  27. mean_earth_radius_km = (6378 + 6357) / 2
  28. # the farthest you can be from another point on Earth
  29. antipode_dist_km = math.pi * mean_earth_radius_km
  30. min_dist_km = 0.15 # if you're within 150m, you get a perfect score
  31. # if you're more than 1/4 of the Earth away, you get 0
  32. max_dist_km = antipode_dist_km / 2
  33. # this has been tuned by hand based on the max dist to get a nice Gaussian
  34. exp_denom = max_dist_km * max_dist_km / 4
  35. perfect_score = 5000
  36. def score(target, guess):
  37. """
  38. Takes in two (latitude, longitude) pairs and produces an int score.
  39. Score is in the (inclusive) range [0, 5000]
  40. Higher scores are closer.
  41. Returns (score, distance in km)
  42. """
  43. dist_km = haversine.haversine(target, guess)
  44. if dist_km <= min_dist_km:
  45. return perfect_score, dist_km
  46. if dist_km >= max_dist_km:
  47. return 0, dist_km
  48. # Gaussian, with some manual tuning to get good fall off
  49. exponent = -((dist_km - min_dist_km) ^ 2) / exp_denom
  50. return int(perfect_score * math.exp(exponent)), dist_km