Skip to content

Improve bounds management #22

Open

Description

@qlereboursBS

Description

Currently, if you generate a SVG based on bounds, it will contain more than just the bounds you gave, because we have to specify output width and height, and also because zoom level are integers.
It would be awesome be able to let the program choose the output size based on the given bounds (or have a minWidth, minHeight instead).

Current behavior:

The code:

import staticmaps
import s2sphere
import sys

context = staticmaps.Context()
# add bounds on east Canada
context.add_bounds(s2sphere.LatLngRect(
    s2sphere.LatLng.from_degrees(43.26120612479979, -79.859619140625),
    s2sphere.LatLng.from_degrees(49.475263243037986, -63.017578125)
))
context.set_tile_provider(staticmaps.tile_provider_OSM)

svg_image = context.render_svg(2000, 2000)
with open("output.svg", "w", encoding="utf-8") as f:
    svg_image.write(f, pretty=True)

Output file looks like this:

image

SVG file available here:
https://mega.nz/file/wtdARJwJ#4bXTgySf9vcmBBCnliu3blbkRoLW2hTIEcipWPbs4tg

When given bounds are:

image

Expected behavior

I think that we should be able to call the render_svg method with minWidth and minHeight arguments which would let the program choose a better zoom level, to perfectly fit the bounds.
Here is how it could work:

  1. User defines bounds
  2. User defines minWidth and minHeight
  3. The program would determine on it's own which size the output file should be to fit the bounds
  4. It renders the SVG with the viewbox matching the size

I would be ok to work on it, I already tried to do a first version but the mathematics used in the context._determine_zoom function are complicated, I don't know the formulas and I'm not sure to understand the variables.
I know that I can return return self._clamp_zoom(zoom) instead of return self._clamp_zoom(zoom - 1) but I don't know how to determine the output size.

Activity

  1. flopp commented on Nov 16, 2021

    @flopp
    Owner

    That's a valid point. I will look into it.

  2. qlereboursBS commented on Nov 16, 2021

    @qlereboursBS
    Author

    Thank you very much. As I said, if you think that you won't have the time to do it, maybe you can guide me (with some links on how the math works to get the zoom, and how we could get the new output dimensions for instance)

  3. lowtower commented on Nov 16, 2021

    @lowtower
    Contributor

    I haven't looked into the code in detail, just read through the text of pull request #19, but I suspect that it tried to solve the same issue.
    You could check that code.

  4. qlereboursBS commented on Nov 16, 2021

    @qlereboursBS
    Author

    Thanks for your comment, it seems that indeed, it tries to solve the same issue, however it's done only for non-svg outputs, it's done by cropping the image using the min and max X and Y of the rendered objects, which (I think) won't work with SVGs

  5. lowtower commented on Jan 19, 2022

    @lowtower
    Contributor

    Hello @flopp and @qlereboursBS,

    as far as I understand the code:

    • the tile size is fixed to 256 px
    • the default zoom is set to 15
    • with given bounds the zoom is calculated such that the bounds fit best
    • the tiles themselves are not scaled
    • the requested area (bounds) are "simply" centered into the downloaded tiles
    • to achieve the desired behaviour some scaling would have to be done afterwards
      • that is what is done in PR Map #19 for the pillow renderer

    frankfurt_newyork tiles

  6. lowtower commented on Jan 19, 2022

    @lowtower
    Contributor

    Is it possible (for all providers) to set an arbitrary tile size?
    Could it be a solution to calculate the optimum tile size?
    This is the result with tile size = 200px
    frankfurt_newyork tiles t200

  7. lowtower commented on Jan 21, 2022

    @lowtower
    Contributor

    Hello @flopp and @qlereboursBS,

    I have coded a different approach for svg:

    • retrieve all object boundaries
    • scale and transform the svg-groups with tiles and objects afterwards

    You can check it out at my branch https://github.com/lowtower/py-staticmaps/tree/feature/tighten_to_bounds

    Drawbacks up to now:

    • line thickness is not considered
    • marker size is not considered (might get complicated to consider with custom markers)

    Questions:

    • would the consideration of marker size and line thickness be desired?
    • at the moment it is the only behavior. Would it be better to add a command line parameter to switch it on and off?

    I'll have a look at cairo and pillow as well if this is of interest

    frankfurt_newyork

  8. netvandal commented on Mar 8, 2023

    @netvandal

    I'm also interested in the "precision" of the bounds for cairo output in particular.
    Is difficult to at leas add a flag to know ad the end of the process the "real" bound included in the output image?
    Thankyou

  9. lowtower commented on Mar 13, 2023

    @lowtower
    Contributor

    Hello @netvandal,

    I am afraid, I don't get Your point.
    What exactly is Your question?

    In my example above, the map image is "tightened" to the given boundary - plus the "extra" boundaries for the marker object.
    This is for all objects - they have a "positioning point" and "extra" boundaries top, right, bottom and left which are added to the regular boundary to make sure the object is fully covered with the map image.
    If You remove the objects, You should get an image with the "pure" boundaries.

    BTW: the afore mentioned branch in my fork doesn't exist any more, but the feature is included in the main branch, not "master".

    Cheers,
    LT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions