Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve bounds management #22

Open
qlereboursBS opened this issue Nov 15, 2021 · 9 comments
Open

Improve bounds management #22

qlereboursBS opened this issue Nov 15, 2021 · 9 comments

Comments

@qlereboursBS
Copy link

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.

@flopp
Copy link
Owner

flopp commented Nov 16, 2021

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

@qlereboursBS
Copy link
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)

@lowtower
Copy link
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.

@qlereboursBS
Copy link
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

@lowtower
Copy link
Contributor

lowtower commented Jan 19, 2022

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

@lowtower
Copy link
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

@lowtower
Copy link
Contributor

lowtower commented Jan 21, 2022

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

@netvandal
Copy link

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

@lowtower
Copy link
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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants