Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@SiarheiFedartsou
Copy link
Member

@SiarheiFedartsou SiarheiFedartsou commented Nov 1, 2025

Issue

#1703

Basically what I am doing is:

  • actor_t now has simple tile(x, y, z) method which returns std::string containing generated tile
  • if z < 12 I just return empty tile - just to avoid thinking about performance in this case
  • if z >= 12 I simply use CandidateSearch::RangeQuery from meili with bbox of tile from request and obtain all edges from that bbox in this way (may be CandidateSearch is not the best choice here, but it seems to do exactly what we need)
  • then some post processing (clipping)
  • tile rendering itself using vtzero - I also enrich it with some metadata

It is for 100% inspired by OSRMs similar method - they have it for years...

Still on very early stage. A lot of things to be done:

  • code is very dirty, partially generated by AI - need to do proper review and refactoring
  • some things may be moved to config
  • tests are to be done
  • we need to think what actually metadata we need to put into it - I think it would be nice to put there as much as we can, but we can start from some set of the things

Tasklist

  • Add tests
  • Add #fixes with the issue number that this PR addresses
  • Update the docs with any new request parameters or changes to behavior described
  • Update the changelog
  • If you made changes to the lua files, update the taginfo too
  • If you made changes to a translation file, update transifex too

Requirements / Relations

Link any requirements here. Other pull requests this PR is based on?

@@ -0,0 +1,303 @@
<!DOCTYPE html>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I quickly built demo server using our very new NodeJS bindings...

@SiarheiFedartsou SiarheiFedartsou changed the title PoC of simple vector tile rendering service Add simple vector tile rendering service Nov 4, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a vector tile rendering service to Valhalla, enabling the generation of Mapbox Vector Tiles (MVT) from Valhalla's graph data. The implementation is inspired by OSRM's similar functionality and provides a new tile(x, y, z) API endpoint.

Key changes:

  • Introduced heimdall module for vector tile generation with configurable zoom levels per road class
  • Added tile() method to actor_t for serving MVT tiles via z/x/y coordinates
  • Integrated vtzero library as a third-party dependency for MVT encoding

Reviewed Changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
valhalla/heimdall/worker.h New worker class for rendering vector tiles with edges and nodes layers
valhalla/heimdall/util.h Utility functions for Web Mercator projection and tile coordinate conversion
src/heimdall/worker.cc Core tile rendering implementation with geometry clipping and property encoding
src/heimdall/util.cc Implementation of tile-to-bbox and coordinate conversion utilities
valhalla/tyr/actor.h Added public tile() method to actor interface
src/tyr/actor.cc Actor implementation delegating to heimdall worker
test/gurka/test_heimdall.cc Gurka-based tests for tile rendering at various zoom levels
test/actor.cc Integration tests using Utrecht tiles dataset
src/bindings/python/valhalla/actor.py Python binding for tile method returning bytes
src/bindings/nodejs/src/valhalla.cc Node.js async binding for tile method
src/bindings/nodejs/examples/tilevis/ Complete tile visualization example with HTTP server and MapLibre integration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@SiarheiFedartsou SiarheiFedartsou marked this pull request as ready for review November 4, 2025 19:07
@SiarheiFedartsou
Copy link
Member Author

I think I am ready for first round of review... Let's decide what should be done to have it merged to master...

@nilsnolde
Copy link
Member

/Users/runner/work/valhalla/valhalla/test/actor.cc:93:3: error: use of undeclared identifier 'EXCEPT_GT'
EXCEPT_GT(tile_data.size(), 600000);

hehe classic:)

Copy link
Member

@nilsnolde nilsnolde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a great start @SiarheiFedartsou ! thanks a lot, this has been on the roadmap forever.. and finally an endpoint where (I hope) we don't have to worry about PBF output:) thanks for switching to maplibre and being generous with docstrings! this took quite a bit of effort to review tbh, but was also fun:) sorry for the tons of comments, I've been pretty nitty, feel free to ignore some of it or push it out into another PR. I think this is already pretty great.

after some demoing it seems level 12 tiles are super heavy with easily 20 MB around berlin for a single one (and there's multiple similar ones). we should probably tweak the min zoom per road class defaults a bit so we don't overload I/O. but of course it's configurable.

also we should add a page to the docs for API reference, so people understand how to use it with GET, what query parameters we offer etc. and mark it BETA for now I'd say. never mind, no HTTP yet..

I wanna implement this in the web app and the qgis plugin, that'll be very helpful when debugging. a few questions or ideas:

  • let's get this into valhalla_service and wire it up with the other HTTP workers; I can do that if you want
  • over time it'd be cool to have a few standard MVT styles/filters/views(whatever's the right term :D), e.g highlight dest-only edges, coloring by road class etc. would we pack them into individual style.json files and use the github raw endpoint for distribution? or is there a smarter way? I guess one could allow for manual style.json's as well, with QGIS one can style pretty easily and export as MBX style.json
  • would an attribute controller be beneficial to decrease the tile size even more? how big are urban tiles typically? (answered my own question: the busiest is by default level 12 with > 20 MB tiles)

@nilsnolde
Copy link
Member

I'd also offer to do the changes myself in case you're overstretched @SiarheiFedartsou, I'm quite eager to merge this :) if you're ok with that, just let me know which change requests you don't agree with.

@SiarheiFedartsou
Copy link
Member Author

I'd also offer to do the changes myself in case you're overstretched @SiarheiFedartsou, I'm quite eager to merge this :) if you're ok with that, just let me know which change requests you don't agree with.

@nilsnolde I was going to look into it by the end of the week, but if you can do it instead - it is even better 🙂 I went through comments - seems that I agree with everything, so please feel free to finish it if you have time for that 🙏 I'd just ask to avoid force pushes just in case 😀

@nilsnolde
Copy link
Member

nilsnolde commented Nov 12, 2025

a bit of a downer: we can't have this as its own module & worker sadly.. it works fine for the actor, but for HTTP we can only have a single module/endpoint connected to prime_server. the easiest is to put it into loki, it's well inline with its scope.

is everyone OK if we merge this as it is (i.e. a heimdall worker) and I'll do another PR which switches everything to loki while implementing HTTP support? since there's only Actor support, this shouldn't have much of an impact. hm, never mind, I'll do another PR right into here I think. it's gonna be too confusing otherwise..

@nilsnolde
Copy link
Member

I tried this with QGIS: doesn't work with prime_server for some reason.. the requests never reach Valhalla. It did work with the example JS server, albeit crazy slow.. Didn't investigate further yet..

Comment on lines +671 to +672
double min_lat_rad = std::atan(std::sinh(kPiD * (1 - 2 * (y + 1) / n)));
double max_lat_rad = std::atan(std::sinh(kPiD * (1 - 2 * y / n)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not gonna touch /tile again before this PR is merged, but for future reference, we might want to copy a few lines from OSRM, which seems to have a fast approx algo to do the projection: https://github.com/Project-OSRM/osrm-backend/blob/01605f7589e6fe68df3fc690ad001b687128aba7/include/util/web_mercator.hpp#L64.

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

Successfully merging this pull request may close these issues.

5 participants