File size: 2,715 Bytes
f88eda5
8d1a80c
 
f88eda5
 
 
 
 
 
 
 
 
0750d7a
f88eda5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8d1a80c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import math
import httpx

def generate_circle_centers(center_lat, center_lon, radius_km, small_radius_km=10):
    """

        Generate a list of centers of small circles (radius=10km) needed to cover a larger circle.

        Circles are arranged in hexagonal pattern to minimize # of small circles.

        No overlapping among small circles, but some small circles may be outside the larger circle.

        Input:

        - center_lat: Latitude of the center of the larger circle

        - center_lon: Longitude of the center of the larger circle

        - radius_km: Radius of the larger circle in kilometers

        - small_radius_km: Radius of the smaller circles in kilometers (default 10km, more than that wiki api cannot accomodate)



        Output:

        - A list of tuples, each containing the latitude and longitude of a small circle's center. [(lat1, lon1), (lat2, lon2),...]

    """
    R = 6371  # Earth radius

    dx = 2 * small_radius_km
    dy = math.sqrt(3) * small_radius_km
    max_dist = radius_km + small_radius_km

    results = []
    lat_rad = math.radians(center_lat)
    n_y = int(max_dist // dy) + 2

    for row in range(-n_y, n_y + 1):
        y = row * dy
        offset = 0 if row % 2 == 0 else dx / 2
        n_x = int((max_dist + dx) // dx) + 2

        for col in range(-n_x, n_x + 1):
            x = col * dx + offset
            distance = math.sqrt(x ** 2 + y ** 2)

            if distance <= max_dist:
                delta_lat = (y / R) * (180 / math.pi)
                delta_lon = (x / (R * math.cos(lat_rad))) * (180 / math.pi)

                lat = center_lat + delta_lat
                lon = center_lon + delta_lon
                results.append((lat, lon))
    
    return results



async def fetch_url(client: httpx.AsyncClient, url: str):
    """

        Fetch a URL asynchronously using httpx and return the response status and data.

        This function is asynchrounously used to fetch multiple URLs in parallel when search radius > 10km.

        Input:

        - client: httpx.AsyncClient instance

        - url: URL to fetch

        Output:

        - A dictionary with the URL, status code, and data if available.

            - Data includes the JSON format of wiki geosearch response.

        If an error occurs, return a dictionary with the URL and the error message.

    """
    try:
        response = await client.get(url, timeout=10.0)
        return {
            "url": url,
            "status": response.status_code,
            "data": response.json() if response.status_code == 200 else None,
        }
    except Exception as e:
        return {"url": url, "error": str(e)}