def generate_full_geocode_set(cls, nominatim_host, verbose=False): from shapely.geometry import shape as Shape, mapping as Mapping from shapely.ops import cascaded_union country = cls.regenerate_country_geocode(nominatim_host, verbose) country = { code: { 'geojson': Mapping(Shape(geo['geojson']).simplify(0.005)), 'display_name': geo['display_name'], 'namedetails': geo.get('namedetails', {}) } for code, geo in country.iteritems() if geo.get('geojson') and geo.get('display_name') } with open('cgeo.json', 'wb') as out: dump(country, out) if exists('cgeo.json.xz'): if isfile('cgeo.json.xz'): remove('cgeo.json.xz') else: raise TypeError("cgeo.json.xz exists and is not a file!") Command('xz')('-z9', 'cgeo.json') regions = cls.regenerate_region_geocode(nominatim_host, verbose) regions = { ccode: { rcode: { 'geojson': Mapping(Shape(geo['geojson']).simplify(0.01)), 'display_name': geo['display_name'], 'namedetails': geo.get('namedetails', {}) } for rcode, geo in region.iteritems() if geo.get('geojson') and geo.get('display_name') } for ccode, region in regions.iteritems() } with open('rgeo.json', 'wb') as out: dump(regions, out) if exists('rgeo.json.xz'): if isfile('rgeo.json.xz'): remove('rgeo.json.xz') else: raise TypeError("rgeo.json.xz exists and is not a file!") Command('xz')('-z9', 'rgeo.json') phones = cls.regenerate_phone_geocode(nominatim_host, verbose) phones = { ccode: { acode: cascaded_union(map(Shape, phones[ccode][acode]) ).centroid.coords[0][::-1] for acode in phones[ccode] } for ccode in phones } with open('pgeo.json', 'wb') as out: dump(phones, out) if exists('pgeo.json.xz'): if isfile('pgeo.json.xz'): remove('pgeo.json.xz') else: raise TypeError("pgeo.json.xz exists and is not a file!") Command('xz')('-z9', 'pgeo.json')
# Filter for the selected region. plzs = { plz for plz, bundesland in mapping_plz_bundesland.items() if bundesland == configuration.RESTRICT_REGION } # Only keep the geometries for the selected region. # Afterwards cache the shape data to avoid repeated conversions. geometries = shp.shapeRecords() geometries_filtered = [ geometry for geometry in geometries if geometry.record[0] in plzs ] for geometry in geometries_filtered: setattr(geometry, "boundary", Shape(geometry.shape)) def is_in_region(lat, lon): point = Point(lon, lat) for geometry in geometries_filtered: if point.within(geometry.boundary): return True return False else: # No restrictions requested, so provide a dummy implementation. def is_in_region(lat, lon): return True
def init(): global is_done_loading def _admin_cc(filename): parts = path.basename(filename).split('.', 1)[0].split('-') admin, cc = parts if len(parts) == 2 else (parts[0], None) admin = int(admin[-1]) return admin, cc nearest_points = {0: [], 1: [], 2: []} shapes = {0: [], 1: [], 2: []} cc_shapes = {} id_regions = {} us_states = {} files = glob(path.join(GEOJSON_DIR, 'admin*.json')) if not files: is_done_loading = RuntimeError( 'Missing GeoJSON files. ' 'In development environments, merge in the "json"' 'branch. See CONTRIBUTING.md') raise is_done_loading log.debug('Loading GeoJSON data ...') for filename in files: admin, cc = _admin_cc(filename) with open(filename, encoding='utf-8') as f: collection = json.load(f, encoding='utf-8') for feature in collection['features']: p = feature['properties'] shape = Shape(feature['geometry']) tup = (shape, p) # Add representative lat-lon pair if non-existent if (np.isnan(p.get('latitude', np.nan)) or np.isnan(p.get('longitude', np.nan))): try: r = shape.representative_point() except ValueError: # For GBR, representative point above fails with: # ValueError: No Shapely geometry can be created from null value r = shape.centroid if not r.within(shape): max_poly = max([shape] if isinstance(shape, Polygon) else list(shape), key=lambda polygon: polygon.area) # From https://stackoverflow.com/questions/33311616/find-coordinate-of-closest-point-on-polygon-shapely/33324058#33324058 poly_ext = max_poly.exterior dist = poly_ext.project(r) pt = poly_ext.interpolate(dist) r = Point(pt.coords[0]) assert r.within(shape) p.update(latitude=r.y, longitude=r.x) # Get representative points for the k-d tree points = [] polygons = (shape,) if isinstance(shape, Polygon) else shape for poly in polygons: points.append([poly.centroid.y, poly.centroid.x]) if poly.area > 10: points.extend(xy[::-1] for xy in poly.simplify(1).exterior.coords) nearest_points[admin].extend(points) tups = [tup] * len(points) shapes[admin].extend(tups) id_regions[p['_id']] = tup if admin == 0: cc_shapes[p['adm0_a3']] = tup # Make Admin1 shapes available in Admin2 too. Except for USA # which is the country we have explicit Admin2 shapes for if admin == 1 and cc not in ADMIN2_COUNTRIES: shapes[2].extend(tups) nearest_points[2].extend(points) if admin == 1 and cc == 'USA': us_states[p['hasc'].split('.')[1]] = tup kdtree = {admin: KDTree(np.array(centroids)) for admin, centroids in nearest_points.items()} cc_shapes['NUL'] = (None, NUL) # tuple for Null Island assert all(len(nearest_points[admin]) == len(shapes[admin]) for admin in shapes) global SHAPES, CC_SHAPES, KDTREE, ID_REGIONS, US_STATES SHAPES, CC_SHAPES, KDTREE, ID_REGIONS, US_STATES = shapes, cc_shapes, kdtree, id_regions, us_states is_done_loading = True return
def is_point_within_shape(x: float, y: float, geometry): point = Point(x, y) shape = Shape(geometry) return shape.contains(point)