|
@@ -1,87 +0,0 @@
|
|
|
-import math
|
|
|
-import random
|
|
|
-
|
|
|
-from .shared import point_has_streetview, PointSource
|
|
|
-from ..scoring import mean_earth_radius_km
|
|
|
-
|
|
|
-initialized = False
|
|
|
-urban_centers_usa = []
|
|
|
-urban_centers_non_usa = []
|
|
|
-
|
|
|
-
|
|
|
-def init():
|
|
|
- """
|
|
|
- Read in the urban centers data files. Should be called before trying to generate points.
|
|
|
- """
|
|
|
- global initialized
|
|
|
- if initialized:
|
|
|
- return
|
|
|
- with open("./data/urban-centers-usa.csv") as infile:
|
|
|
- for line in infile:
|
|
|
- lat, lng = line.split(",")
|
|
|
- urban_centers_usa.append((float(lat.strip()), float(lng.strip())))
|
|
|
- with open("./data/urban-centers-non-usa.csv") as infile:
|
|
|
- for line in infile:
|
|
|
- lat, lng = line.split(",")
|
|
|
- urban_centers_non_usa.append((float(lat.strip()), float(lng.strip())))
|
|
|
- initialized = True
|
|
|
-
|
|
|
-
|
|
|
-def urban_coord(max_retries=10, retries_per_point=30, max_dist_km=25, usa_chance=0.1):
|
|
|
- """
|
|
|
- Returns (latitude, longitude) of usable coord (where google has data) that is near
|
|
|
- a known urban center. Points will be at most max_dist_km kilometers away. This function will
|
|
|
- generate at most retries_per_point points around an urban center, and will try at most
|
|
|
- max_retries urban centers. If none of the generated points have street view data,
|
|
|
- this will return None. Otherwise, it will exit as soon as suitable point is found.
|
|
|
-
|
|
|
- This function calls the streetview metadata endpoint - there is no quota consumed.
|
|
|
- """
|
|
|
-
|
|
|
- src = urban_centers_usa if random.random() <= usa_chance else urban_centers_non_usa
|
|
|
-
|
|
|
- for _ in range(max_retries):
|
|
|
- # logic adapted from https://stackoverflow.com/a/7835325
|
|
|
- # start in a city
|
|
|
- (city_lat, city_lng) = random.choice(src)
|
|
|
- city_lat_rad = math.radians(city_lat)
|
|
|
- sin_lat = math.sin(city_lat_rad)
|
|
|
- cos_lat = math.cos(city_lat_rad)
|
|
|
- city_lng_rad = math.radians(city_lng)
|
|
|
- for _ in range(retries_per_point):
|
|
|
- # turn a random direction, and go random distance
|
|
|
- dist_km = random.random() * max_dist_km
|
|
|
- angle_rad = random.random() * 2 * math.pi
|
|
|
- d_over_radius = dist_km / mean_earth_radius_km
|
|
|
- sin_dor = math.sin(d_over_radius)
|
|
|
- cos_dor = math.cos(d_over_radius)
|
|
|
- pt_lat_rad = math.asin(sin_lat * cos_dor + cos_lat * sin_dor * math.cos(angle_rad))
|
|
|
- pt_lng_rad = city_lng_rad + math.atan2(math.sin(angle_rad) * sin_dor * cos_lat, cos_dor - sin_lat * math.sin(pt_lat_rad))
|
|
|
- pt_lat = math.degrees(pt_lat_rad)
|
|
|
- pt_lng = math.degrees(pt_lng_rad)
|
|
|
- if point_has_streetview(pt_lat, pt_lng):
|
|
|
- return (pt_lat, pt_lng)
|
|
|
-
|
|
|
-
|
|
|
-class UrbanPointSource(PointSource):
|
|
|
- def __init__(self, stock_target=20, max_retries=10, retries_per_point=30, max_dist_km=25, usa_chance=0.1):
|
|
|
- super().__init__(stock_target=stock_target)
|
|
|
- self.max_retries = max_retries
|
|
|
- self.retries_per_point = retries_per_point
|
|
|
- self.max_dist_km = max_dist_km
|
|
|
- self.usa_chance = usa_chance
|
|
|
- if not initialized:
|
|
|
- init()
|
|
|
-
|
|
|
- def _restock_impl(self, n):
|
|
|
- points = []
|
|
|
- while len(points) < n:
|
|
|
- pt = urban_coord(
|
|
|
- max_retries=self.max_retries,
|
|
|
- retries_per_point=self.retries_per_point,
|
|
|
- max_dist_km=self.max_dist_km,
|
|
|
- usa_chance=self.usa_chance
|
|
|
- )
|
|
|
- if pt is not None:
|
|
|
- points.append(pt)
|
|
|
- return points
|