[Python] Google Maps API - How to calculate the zoom level for a given coordinates

Discussão em 'Python' iniciado por Stack, Outubro 25, 2024.

  1. Stack

    Stack Membro Participativo

    I have the following code:

    def calculate_zoom_level(lat_diff, long_diff, map_width, map_height):
    # Earth's circumference in degrees
    WORLD_DIM = 256 # Tile size in pixels
    ZOOM_MAX = 12 # Maximum zoom level (as used in the provided example)
    MIN_DIFF = 0.000001 # Small value to prevent zero division

    # A formula based on the map's bounds and dimensions to calculate zoom
    def zoom_level(diff, map_dim):
    # Avoid division by zero by using a minimum difference threshold
    if diff == 0:
    diff = MIN_DIFF
    PADDING = 1.5 # Padding factor to leave space around the markers
    return math.log2((360 / diff) * (map_dim / WORLD_DIM)) - PADDING

    # Calculate zoom based on both latitude and longitude
    lat_based_zoom = zoom_level(lat_diff, map_height)
    long_based_zoom = zoom_level(long_diff, map_width)

    # Take the smaller zoom level for fitting both dimensions into the map
    zoom = min(lat_based_zoom, long_based_zoom)

    # Further zoom out if necessary (based on location differences)
    if lat_diff < 0.1 and long_diff < 0.1:
    zoom -= 1 # Zoom out if locations are very close

    # Constrain the zoom level to the maximum zoom specified (maxZoom = 12)
    zoom = max(7, min(zoom, ZOOM_MAX))

    return round(zoom)

    def load_polygon_coordinates():
    with open('cleaned_fine.json', 'r', encoding='utf-8') as file:
    polygon_data = json.load(file)
    return polygon_data


    def generate_map_url(locations, polygons):
    base_url = "https://maps.googleapis.com/maps/api/staticmap?"

    # Extract latitudes and longitudes and convert them to floats
    lats, longs = zip(*[(float(lat), float(long)) for lat, long in locations])

    # Calculate bounds
    min_lat, max_lat = min(lats), max(lats)
    min_long, max_long = min(longs), max(longs)

    # Set the center of the map to the midpoint of the bounds
    center_lat = (min_lat + max_lat) / 2
    center_long = (min_long + max_long) / 2

    # Define the map dimensions (width and height in pixels)
    map_width = 640
    map_height = 530

    # Calculate zoom level dynamically
    zoom = calculate_zoom_level(max_lat - min_lat, max_long - min_long, map_width, map_height)

    # Generate the markers for locations
    markers = '|'.join([f'color:red|{lat},{long}' for lat, long in locations])

    # Attempt to create polygon paths
    paths = []
    for polygon in polygons:
    if len(polygon) >= 3: # A polygon must have at least 3 points to form a closed shape
    path = '|'.join([f'{lat},{long}' for lat, long in polygon])
    # Ensure the polygon is closed by repeating the first point at the end
    if polygon[0] != polygon[-1]:
    path += f'|{polygon[0][0]},{polygon[0][1]}'
    paths.append(f'color:0x00000000|weight:2|fillcolor:red|{path}')

    # Set parameters for the static map API
    params = {
    'center': f'{center_lat},{center_long}',
    'zoom': zoom,
    'size': f'{map_width}x{map_height}',
    'markers': markers,
    'language': 'he',
    'key': ''
    }

    # If no valid polygons are available, ensure only red markers are used
    if paths:
    params['path'] = paths

    # Generate the map URL
    url = base_url + urllib.parse.urlencode(params, doseq=True)

    # Attempt to fetch the image to check if it generates correctly
    try:
    response = requests.get(url)
    img = Image.open(BytesIO(response.content)) # This can raise the error you're seeing
    except Exception as e:
    print(f"Error generating map image: {e}")
    # If there's an error, fallback to markers only
    params.pop('path', None) # Remove path if it exists
    url = base_url + urllib.parse.urlencode(params, doseq=True)

    return url


    The problem here is that sometimes there is too much zoom out on areas that are close to each other anyway. I expect that, according to the coordinates, the zoom will be reduced according to the areas it receives, and that it will not be cut in the middle or something, it will simply display the map in its entirety but only the important part, and not just a large zoom out regardless of the proximity of the locations to each other. I am attaching 2 pictures for you here. picture_1 picture_2 The picture with the number 1 written on it is the example of the map I expect it to be

    The picture with the number 2 on it is my current map (with this code)

    I expect it to be like picture number 1, dynamic zoom depending on the locations

    Continue reading...

Compartilhe esta Página