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

GeoTIFF serialization for isochrones #4594

Merged
merged 29 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4c2c0f0
add gdal to project
chrstnbwnkl Feb 20, 2024
d9e9ba7
geotiff serialization
chrstnbwnkl Feb 20, 2024
2ba6064
docs, changelog
chrstnbwnkl Feb 20, 2024
91bc250
fix run_isochrones, changelog entry
chrstnbwnkl Feb 20, 2024
df965af
clang tidy
chrstnbwnkl Feb 20, 2024
a323501
add to dep install script, add cmake flag to docs
chrstnbwnkl Feb 20, 2024
461870f
tidy complains about this macro
chrstnbwnkl Feb 20, 2024
7c78627
minor fixes, added more tests, cleanup
chrstnbwnkl Feb 20, 2024
d7bd63a
use pkgconfig, try out CI build with GDAL
chrstnbwnkl Feb 21, 2024
8f98664
properly hide geotiff driver
chrstnbwnkl Feb 21, 2024
2ba9886
forgot to add a macro there
chrstnbwnkl Feb 21, 2024
657aa59
tidy
chrstnbwnkl Feb 21, 2024
77424ea
format
chrstnbwnkl Feb 21, 2024
b2fa4cc
Revert "tidy"
chrstnbwnkl Feb 21, 2024
f15cb7e
address all comments; forget about having the geotiff driver inside t…
chrstnbwnkl Feb 21, 2024
b1014ba
missed some things
chrstnbwnkl Feb 21, 2024
32c2405
try to fix ci fails
chrstnbwnkl Feb 21, 2024
5ead044
whoops forgot some
chrstnbwnkl Feb 21, 2024
55e19dc
try to prefer CONFIG mode if available and if not use cmake findgdal
nilsnolde Feb 21, 2024
85bf218
shutting up msvc
chrstnbwnkl Feb 22, 2024
cf60652
tidy
chrstnbwnkl Feb 22, 2024
3937387
tidy again
chrstnbwnkl Feb 22, 2024
f767375
bump cmake to 3.14
chrstnbwnkl Feb 22, 2024
7edd038
includes for boost missing in some tests
chrstnbwnkl Feb 22, 2024
8cba25c
Update src/worker.cc
chrstnbwnkl Feb 22, 2024
004ae9e
Merge branch 'master' into cb-isochrone-geotiff
chrstnbwnkl Feb 27, 2024
d6771b8
set nodata value to numeric max limit
chrstnbwnkl Feb 28, 2024
cc552d7
Merge branch 'master' into cb-isochrone-geotiff
chrstnbwnkl Feb 28, 2024
6da3a08
hopefully the last missing boost header
chrstnbwnkl Feb 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/osx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:

- name: Install dependencies
run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install autoconf automake protobuf cmake ccache libtool sqlite3 libspatialite luajit curl wget czmq lz4 spatialite-tools unzip boost
HOMEBREW_NO_AUTO_UPDATE=1 brew install autoconf automake protobuf cmake ccache libtool sqlite3 libspatialite luajit curl wget czmq lz4 spatialite-tools unzip boost gdal
nilsnolde marked this conversation as resolved.
Show resolved Hide resolved
sudo python -m pip install --break-system-packages requests shapely
git clone https://github.com/kevinkreiser/prime_server --recurse-submodules && cd prime_server && ./autogen.sh && ./configure && make -j$(sysctl -n hw.logicalcpu) && sudo make install

Expand All @@ -58,7 +58,7 @@ jobs:
ccache-osx-

- name: Configure CMake
run: cmake -B build -DENABLE_SINGLE_FILES_WERROR=OFF
run: cmake -B build -DENABLE_SINGLE_FILES_WERROR=OFF -DENABLE_GDAL=ON

- name: Build Valhalla
run: make -C build -j$(sysctl -n hw.logicalcpu)
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
* ADDED: Improved instructions for blind users [#3694](https://github.com/valhalla/valhalla/pull/3694)
* FIXED: Fixed roundoff issue in Tiles Row and Col methods [#4585](https://github.com/valhalla/valhalla/pull/4585)
* ADDED: isochrone proper polygon support & pbf output for isochrone [#4575](https://github.com/valhalla/valhalla/pull/4575)
* ADDED: return isotile grid as geotiff [#4594](https://github.com/valhalla/valhalla/pull/4594)

## Release Date: 2023-05-11 Valhalla 3.4.0
* **Removed**
Expand Down
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ option(ENABLE_SINGLE_FILES_WERROR "Convert compiler warnings to errors for singl
option(PREFER_EXTERNAL_DEPS "Whether to use internally vendored headers or find the equivalent external package" OFF)
# useful to workaround issues likes this https://stackoverflow.com/questions/24078873/cmake-generated-xcode-project-wont-compile
option(ENABLE_STATIC_LIBRARY_MODULES "If ON builds Valhalla modules as STATIC library targets" OFF)
option(ENABLE_GDAL "Whether to include GDAL; currently only used for raster serialization of isotile grid" OFF)

set(LOGGING_LEVEL "" CACHE STRING "Logging level, default is INFO")
set_property(CACHE LOGGING_LEVEL PROPERTY STRINGS "NONE;ALL;ERROR;WARN;INFO;DEBUG;TRACE")
Expand Down Expand Up @@ -203,6 +204,15 @@ if(ENABLE_SERVICES)
endif()
endif()

# gdal
set(gdal_target "")
if (ENABLE_GDAL)
pkg_check_modules(GDAL REQUIRED IMPORTED_TARGET gdal)
add_compile_definitions(ENABLE_GDAL)
set(gdal_target PkgConfig::GDAL)
endif()


## Mjolnir and associated executables
if(ENABLE_DATA_TOOLS)
add_compile_definitions(DATA_TOOLS)
Expand Down
3 changes: 3 additions & 0 deletions cmake/ValhallaPkgConfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ function(configure_valhalla_pc)
if(ENABLE_SERVICES)
list(APPEND REQUIRES libprime_server)
endif()
if(ENABLE_GDAL)
list(APPEND REQUIRES gdal)
endif()
if(WIN32 AND NOT MINGW)
list(APPEND LIBS_PRIVATE -lole32 -lshell32)
else()
Expand Down
8 changes: 5 additions & 3 deletions docs/docs/api/isochrone/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ The isochrone service uses the `auto`, `bicycle`, `pedestrian`, and `multimodal`

## Outputs of the Isochrone service

In the service response, the isochrone contours are returned as [GeoJSON](http://geojson.org/), which can be integrated into mapping applications.
In the service response, the isochrone contours are returned as [GeoJSON](http://geojson.org/), which can be integrated into mapping applications. Alternatively, the grid data that underlies these contours can be returned as a [GeoTIFF](https://www.ogc.org/standard/geotiff/).

The contours are calculated using rasters and are returned as either polygon or line features, depending on your input setting for the `polygons` parameter. If an isochrone request has been named using the optional `&id=` input, then the `id` is returned as a name property for the feature collection within the GeoJSON response. A `metric` attribute lets you know whether it's a `distance` or `time` contour. A warnings array may also be included. This array may contain warning objects informing about deprecated request parameters, clamped values etc. |
The isochrone service returns contours as GeoJSON line or polygon features for the requested intervals (depending on the value of the `polygons` request parameter). These contours are calculated using a two dimensional grid. If the `format` request parameter is set to `geotiff`, the underlying grid data is returned directly instead of the contours derived from it. It will return one band for each requested metric (i.e. one for `time` and one for `distance`). If an isochrone request has been named using the optional `&id=` input, then the `id` is returned as a name property for the feature collection within the GeoJSON response. A `metric` attribute lets you know whether it's a `distance` or `time` contour. A warnings array may also be included. This array may contain warning objects informing about deprecated request parameters, clamped values etc. |

See the [HTTP return codes](../turn-by-turn/api-reference.md#http-status-codes-and-conditions) for more on messages you might receive from the service.

Expand All @@ -63,6 +63,8 @@ Most JavaScript-based GeoJSON renderers, including [Leaflet](http://leafletjs.co

When making a map, drawing the isochrone contours as lines is more straightforward than polygons, and, therefore, currently is the default and recommended method. When deciding between the output as lines and polygons, consider your use case and the additional styling considerations involved with polygons. For example, fills should be rendered as semi-transparent over the other map layers so they are visible, although you may have more flexibility when using a vector-based map. In addition, polygons from multiple contour levels do not have overlapping areas cut out or removed. In other words, the outer contours include the areas of any inner contours, causing the colors and transparencies to blend when multiple contour polygons are drawn at the same time.

(TODO: write something about rendering the GeoTIFF output.)

## Future work on the isochrone service

The Isochrone service is in active development. To report software issues or suggest enhancements, open an issue in the [Valhalla GitHub repository](https://github.com/valhalla/valhalla/issues).
Expand All @@ -75,7 +77,7 @@ Several other options are being considered as future service enhancements. These
* ~~Removing self intersections from polygonal contours.~~
* ~~Allowing multiple locations to compute the region reachable from any of the locations within a specified time.~~
* ~~Generating contours with reverse access logic to see the region that can reach a specific location within the specified time.~~
* Returning raster data for potential animation using OpenGL shaders. This also has analysis use for being able to query thousands of locations to determine the time to each location, including improvements with one-to-many requests to the Valhalla Time-Distance Matrix service.
* ~~Returning raster data for potential animation using OpenGL shaders. This also has analysis use for being able to query thousands of locations to determine the time to each location, including improvements with one-to-many requests to the Valhalla Time-Distance Matrix service.~~

## Data credits

Expand Down
1 change: 1 addition & 0 deletions docs/docs/api/turn-by-turn/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -620,4 +620,5 @@ The codes correspond to code returned from a particular [Valhalla project](https
|**5xx** | **Tyr project codes** |
|500 | Failed to parse intermediate request format |
|501 | Failed to parse TripDirections |
|504 | GeoTIFF serialization not supported by service |
nilsnolde marked this conversation as resolved.
Show resolved Hide resolved
|599 | Unknown |
1 change: 1 addition & 0 deletions docs/docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Important build options include:
| `-DENABLE_ADDRESS_SANITIZER` (`ON` / `OFF`) | Build with address sanitizer (defaults to off).|
| `-DENABLE_UNDEFINED_SANITIZER` (`ON` / `OFF`) | Build with undefined behavior sanitizer (defaults to off).|
| `-DPREFER_SYSTEM_DEPS` (`ON` / `OFF`) | Whether to use internally vendored headers or find the equivalent external package (defaults to off).|
| `-DENABLE_GDAL` (`ON` / `OFF`) | Whether to include GDAL as a dependency (used for GeoTIFF serialization of isochrone grid) (defaults to off).|

### Building with `vcpkg` - any platform

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/thor/isochrones.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The 2-D grid is used to find the isocrhone contours by using a well-known contou

After forming sets of contour polygons, KEVIN -please write a paragraph or 2 to describe how the contours are formed and output!

This 2-D grid of times can be useful for other purposes as well. It provides a very fast way to query a single location to see how long it takes to get there from the test location. Ultimately this could be a way to do very large one-to-many matrices. At this time we do not return the 2-D array of times, but this is a possibility in the future.
This 2-D grid can be useful for other purposes as well. It provides a very fast way to query a single location to see how long it takes to get there from the test location. Ultimately this could be a way to do very large one-to-many matrices.

Where is it?
------------
Expand Down
1 change: 1 addition & 0 deletions proto/options.proto
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ message Options {
gpx = 1;
osrm = 2;
pbf = 3;
geotiff = 4;
}

enum Action {
Expand Down
1 change: 1 addition & 0 deletions scripts/install-linux-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ env DEBIAN_FRONTEND=noninteractive sudo apt install --yes --quiet \
libboost-all-dev \
libcurl4-openssl-dev \
libczmq-dev \
libgdal-dev \
libgeos++-dev \
libgeos-dev \
libluajit-5.1-dev \
Expand Down
6 changes: 6 additions & 0 deletions src/loki/worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@ loki_worker_t::work(const std::list<zmq::message_t>& job,
result.messages.emplace_back(request.SerializeAsString());
break;
case Options::isochrone:
// return early if geotiff was requested but GDAL isn't enabled
#ifndef ENABLE_GDAL
Copy link
Contributor Author

Choose a reason for hiding this comment

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

be prepared to see plenty of these... I'm open to any suggestions that reduce these wherever possible

if (options.format() == Options_Format_geotiff) {
throw valhalla_exception_t{504};
}
#endif
isochrones(request);
result.messages.emplace_back(request.SerializeAsString());
break;
Expand Down
12 changes: 4 additions & 8 deletions src/proto_conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,8 @@ const std::string& ShapeMatch_Enum_Name(const ShapeMatch match) {

bool Options_Format_Enum_Parse(const std::string& format, Options::Format* f) {
static const std::unordered_map<std::string, Options::Format> formats{
{"json", Options::json},
{"gpx", Options::gpx},
{"osrm", Options::osrm},
{"pbf", Options::pbf},
{"json", Options::json}, {"gpx", Options::gpx}, {"osrm", Options::osrm},
{"pbf", Options::pbf}, {"geotiff", Options::geotiff},
};
auto i = formats.find(format);
if (i == formats.cend())
Expand All @@ -282,10 +280,8 @@ bool Options_Format_Enum_Parse(const std::string& format, Options::Format* f) {

const std::string& Options_Format_Enum_Name(const Options::Format match) {
static const std::unordered_map<int, std::string> formats{
{Options::json, "json"},
{Options::gpx, "gpx"},
{Options::osrm, "osrm"},
{Options::pbf, "pbf"},
{Options::json, "json"}, {Options::gpx, "gpx"}, {Options::osrm, "osrm"},
{Options::pbf, "pbf"}, {Options::geotiff, "geotiff"},
};
auto i = formats.find(match);
return i == formats.cend() ? empty_str : i->second;
Expand Down
3 changes: 2 additions & 1 deletion src/thor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ valhalla_module(NAME thor
valhalla::meili
${valhalla_protobuf_targets}
Boost::boost
${libprime_server_targets})
${libprime_server_targets}
${gdal_target})
15 changes: 6 additions & 9 deletions src/thor/isochrone_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,12 @@ std::string thor_worker_t::isochrones(Api& request) {
if (options.action() == Options_Action_expansion)
return "";

// we have parallel vectors of contour properties and the actual geojson features
// this method sorts the contour specifications by metric (time or distance) and then by value
// with the largest values coming first. eg (60min, 30min, 10min, 40km, 10km)
auto contours =
grid->GenerateContours(intervals, options.polygons(), options.denoise(), options.generalize());

// make the final output (pbf or json)
std::string ret = tyr::serializeIsochrones(request, intervals, contours, options.polygons(),
options.show_locations());
// make the final output (pbf or json)
#ifdef ENABLE_GDAL
std::string ret = tyr::serializeIsochrones(request, intervals, grid, geotiff_driver);
#else
std::string ret = tyr::serializeIsochrones(request, intervals, grid);
#endif

return ret;
}
Expand Down
31 changes: 30 additions & 1 deletion src/thor/worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@

#include <boost/property_tree/ptree.hpp>

#ifdef ENABLE_GDAL
#include <gdal_priv.h>
#endif

Copy link
Contributor Author

Choose a reason for hiding this comment

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

tyr has no way to maintain state, so thor_worker_t will hold the geotiff driver and pass an opaque pointer to it to the serializer function (note that GDAL is not thread-safe)

using namespace valhalla;
using namespace valhalla::tyr;
using namespace valhalla::midgard;
Expand Down Expand Up @@ -74,7 +78,12 @@ thor_worker_t::thor_worker_t(const boost::property_tree::ptree& config,
time_distance_bss_matrix_(config.get_child("thor")), isochrone_gen(config.get_child("thor")),
reader(graph_reader ? graph_reader
: std::make_shared<baldr::GraphReader>(config.get_child("mjolnir"))),
matcher_factory(config, reader), controller{} {
matcher_factory(config, reader), controller {
}
#ifdef ENABLE_GDAL
, geotiff_driver(geotiff_driver_t{})
#endif
{

// Select the matrix algorithm based on the conf file (defaults to
// select_optimal if not present)
Expand Down Expand Up @@ -330,5 +339,25 @@ void thor_worker_t::set_interrupt(const std::function<void()>* interrupt_functio
interrupt = interrupt_function;
reader->SetInterrupt(interrupt);
}

#ifdef ENABLE_GDAL
geotiff_driver_t::geotiff_driver_t() {
auto driver_manager = GetGDALDriverManager();
this->geotiff_driver = driver_manager->GetDriverByName("GTiff");
}

geotiff_driver_t::~geotiff_driver_t() {
// GDALDestroyDriverManager();
}

GDALDataset* geotiff_driver_t::CreateDataSet(const char* pszName,
int nXSize,
int nYSize,
int nBands,
GDALDataType eType,
CSLConstList papszOptions) {
return this->geotiff_driver->Create(pszName, nXSize, nYSize, nBands, eType, papszOptions);
}
#endif
} // namespace thor
} // namespace valhalla
6 changes: 5 additions & 1 deletion src/tyr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ set(system_includes
${date_include_dir}
$<$<BOOL:${WIN32}>:${dirent_include_dir}>)



valhalla_module(NAME tyr
SOURCES
${sources}
Expand All @@ -44,4 +46,6 @@ valhalla_module(NAME tyr
valhalla::odin
valhalla::proto
${valhalla_protobuf_targets}
Boost::boost)
Boost::boost
${gdal_target}
)
Loading
Loading