Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
ee342bd
lua: use non-member functions for interop
cldellow Nov 18, 2023
b322166
spike: use different tag map
cldellow Dec 3, 2023
5c807a9
make Find(...) and Holds(...) faster
cldellow Dec 3, 2023
3922170
tweak names
cldellow Dec 3, 2023
13b3465
avoid malloc for Attribute with long strings
cldellow Dec 4, 2023
8c179d1
fix make
cldellow Dec 4, 2023
5f30a30
move OutputObjects to mmap store
cldellow Dec 15, 2023
b918769
treat objects at low zoom specially
cldellow Dec 15, 2023
d7caf10
make more explicit that this is unexpected
cldellow Dec 16, 2023
8dff5bf
extend --materialize-geometries to nodes
cldellow Dec 16, 2023
b86fddc
rejig AttributePair layout
cldellow Dec 16, 2023
a54938e
fix initialization order warning
cldellow Dec 16, 2023
fa5a2bf
add PooledString
cldellow Dec 16, 2023
3eb07c2
add tests for attribute store
cldellow Dec 16, 2023
b3eac99
rejig isHot
cldellow Dec 16, 2023
2784903
teach PooledString to work with std::string
cldellow Dec 16, 2023
efe6af9
use PooledString in AttributePair
cldellow Dec 16, 2023
9394bc7
log timings
cldellow Dec 17, 2023
3020011
AppendVector: an append-only chunked vector
cldellow Dec 17, 2023
330b0a7
fix progress when --store present
cldellow Dec 17, 2023
9d97d30
mutex on RelationScan progress output
cldellow Dec 17, 2023
f9993cf
make NodeStore/WayStore shardable
cldellow Dec 17, 2023
b49b1e7
add minimal SortedNodeStore test
cldellow Dec 17, 2023
e81c6ee
stop using internal linkage for atomics
cldellow Dec 17, 2023
1c4174d
SortedNodeStore: abstract TLS behind storage()
cldellow Dec 17, 2023
99b5912
SortedWayStore: abstract TLS behind storage()
cldellow Dec 17, 2023
f225ebd
SortedNodeStore: support multiple instances
cldellow Dec 17, 2023
6c7917b
SortedWayStorage: support multiple instances
cldellow Dec 17, 2023
5d9ca2b
actually fix the low zoom object collection
cldellow Dec 17, 2023
24b73f1
AppendVector tweaks
cldellow Dec 17, 2023
2a05365
more low zoom fixes
cldellow Dec 17, 2023
00bb73b
implement SortedNodeStore::contains
cldellow Dec 17, 2023
e8be59c
implement SortedWayStore::contains
cldellow Dec 17, 2023
792d1b3
use TileCoordinatesSet
cldellow Dec 17, 2023
2df3081
faster covered tile enumeration
cldellow Dec 17, 2023
b9434f2
add ShardedNodeStore
cldellow Dec 18, 2023
e968b40
add ShardedWayStore
cldellow Dec 18, 2023
4bfca70
fewer, more balanced shards
cldellow Dec 18, 2023
ffbd194
skip ReadPhase::Ways passes if node store is empty
cldellow Dec 18, 2023
0affec4
support multiple passes for ReadPhase::Relations
cldellow Dec 18, 2023
3a2c87a
fix check for first way
cldellow Dec 18, 2023
f499e34
adjust shards
cldellow Dec 18, 2023
bbf0957
Relations: fix effectiveShards > 1 check
cldellow Dec 19, 2023
12be586
Merge remote-tracking branch 'origin/master' into lua-interop
cldellow Dec 20, 2023
c56d337
wip: use protozero for osm pbf reading
cldellow Dec 21, 2023
01d4aeb
use protozero::data_view for tags
cldellow Dec 22, 2023
5ab10dc
calculateCentroid: use multiPolygonCached()
cldellow Dec 22, 2023
1d48e43
remove timing
cldellow Dec 22, 2023
5abc57c
add empty() function for OSM entities
cldellow Dec 22, 2023
4130f51
extend --materialize-geometries to LayerAsCentroid
cldellow Dec 22, 2023
d6d3f0e
add `DequeMap`, change AttributeStore to use it
cldellow Dec 23, 2023
b234123
Merge remote-tracking branch 'origin/master' into planet-on-32gb
cldellow Dec 23, 2023
f22cfdf
capture s(this)
cldellow Dec 23, 2023
efd66bb
fix warning
cldellow Dec 23, 2023
db89f8b
fix warning, really
cldellow Dec 23, 2023
60e5261
fewer shards
cldellow Dec 23, 2023
3eb4559
Merge branch 'planet-on-32gb' into protozero
cldellow Dec 24, 2023
6886e6b
fix includes
cldellow Dec 24, 2023
f95e13d
rm osmformat.proto, pbf_blocks.{h,cpp}
cldellow Dec 24, 2023
934ccfe
rejig to remove thread locals
cldellow Dec 24, 2023
4d4a808
make things private
cldellow Dec 24, 2023
1d0bc17
simplify iterators
cldellow Dec 24, 2023
6e330f1
comment out println
cldellow Dec 24, 2023
09abd3a
extract option parsing to own file
cldellow Dec 24, 2023
48305a4
use sensible defaults based on presence of --store
cldellow Dec 24, 2023
411b71e
improve test coverage
cldellow Dec 24, 2023
3d89a78
fixes
cldellow Dec 24, 2023
2ae5d69
Merge branch 'planet-on-32gb' into protozero
cldellow Dec 24, 2023
1edbfd6
update number of shards to 6
cldellow Dec 24, 2023
181c3c7
Merge branch 'planet-on-32gb' into protozero
cldellow Dec 24, 2023
0d5e28f
Merge branch 'protozero' into lua-interop
cldellow Dec 25, 2023
be682a0
try to avoid lock contention on AttributeStore
cldellow Dec 25, 2023
c4631a3
RelationScanStore: more granular locks
cldellow Dec 25, 2023
e872073
AttributePairStore.getPair: add thread-local cache
cldellow Dec 25, 2023
58d49c8
Revert "AttributePairStore.getPair: add thread-local cache"
cldellow Dec 25, 2023
1c16fae
move duplicate attribute handling outside of locks
cldellow Dec 25, 2023
0584403
add thread-local cache for attributepairs
cldellow Dec 25, 2023
fd96943
buffer objects when object index contended
cldellow Dec 25, 2023
657da1a
--store uses lazy geometries; permit overriding
cldellow Dec 26, 2023
576fd37
Merge branch 'planet-on-32gb' into protozero
cldellow Dec 26, 2023
916ff31
fix mac/windows build?
cldellow Dec 26, 2023
fe8840d
Merge branch 'protozero' into lua-interop
cldellow Dec 26, 2023
4901415
fixes for Windows build
cldellow Dec 26, 2023
6d491fc
fix mac build?
cldellow Dec 26, 2023
decd18b
more macos fixes
cldellow Dec 26, 2023
bf29ff0
Merge branch 'protozero' into lua-interop
cldellow Dec 26, 2023
867fd1f
read_pbf -> pbf_processor
cldellow Dec 26, 2023
9594df1
Merge branch 'protozero' into lua-interop
cldellow Dec 26, 2023
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
15 changes: 8 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,6 @@ ADD_CUSTOM_COMMAND(OUTPUT vector_tile.pb.cc vector_tile.pb.h
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out ${CMAKE_BINARY_DIR} -I ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/vector_tile.proto)

ADD_CUSTOM_COMMAND(OUTPUT osmformat.pb.cc osmformat.pb.h
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out ${CMAKE_BINARY_DIR} -I ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/osmformat.proto)

file(GLOB tilemaker_src_files
src/attribute_store.cpp
src/coordinates.cpp
Expand All @@ -97,25 +93,30 @@ file(GLOB tilemaker_src_files
src/mbtiles.cpp
src/mmap_allocator.cpp
src/node_stores.cpp
src/options_parser.cpp
src/osm_lua_processing.cpp
src/osm_mem_tiles.cpp
src/osm_store.cpp
src/output_object.cpp
src/pbf_blocks.cpp
src/pbf_processor.cpp
src/pbf_reader.cpp
src/pmtiles.cpp
src/read_pbf.cpp
src/pooled_string.cpp
src/read_shp.cpp
src/sharded_node_store.cpp
src/sharded_way_store.cpp
src/shared_data.cpp
src/shp_mem_tiles.cpp
src/sorted_node_store.cpp
src/sorted_way_store.cpp
src/tag_map.cpp
src/tile_data.cpp
src/tilemaker.cpp
src/tile_worker.cpp
src/way_stores.cpp
src/write_geometry.cpp
)
add_executable(tilemaker vector_tile.pb.cc osmformat.pb.cc ${tilemaker_src_files})
add_executable(tilemaker vector_tile.pb.cc ${tilemaker_src_files})
target_include_directories(tilemaker PRIVATE include)
target_include_directories(tilemaker PRIVATE ${CMAKE_BINARY_DIR}) # for generated files
target_link_libraries(tilemaker
Expand Down
64 changes: 58 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ INC := -I$(PLATFORM_PATH)/include -isystem ./include -I./src $(LUA_CFLAGS)
all: tilemaker

tilemaker: \
include/osmformat.pb.o \
include/vector_tile.pb.o \
src/attribute_store.o \
src/coordinates_geom.o \
Expand All @@ -106,36 +105,89 @@ tilemaker: \
src/mbtiles.o \
src/mmap_allocator.o \
src/node_stores.o \
src/options_parser.o \
src/osm_lua_processing.o \
src/osm_mem_tiles.o \
src/osm_store.o \
src/output_object.o \
src/pbf_blocks.o \
src/pbf_processor.o \
src/pbf_reader.o \
src/pmtiles.o \
src/read_pbf.o \
src/pooled_string.o \
src/read_shp.o \
src/sharded_node_store.o \
src/sharded_way_store.o \
src/shared_data.o \
src/shp_mem_tiles.o \
src/sorted_node_store.o \
src/sorted_way_store.o \
src/tag_map.o \
src/tile_data.o \
src/tilemaker.o \
src/tile_worker.o \
src/way_stores.o \
src/write_geometry.o
$(CXX) $(CXXFLAGS) -o tilemaker $^ $(INC) $(LIB) $(LDFLAGS)

test: test_sorted_way_store
test: \
test_append_vector \
test_attribute_store \
test_deque_map \
test_pbf_reader \
test_pooled_string \
test_sorted_node_store \
test_sorted_way_store

test_append_vector: \
src/mmap_allocator.o \
test/append_vector.test.o
$(CXX) $(CXXFLAGS) -o test.append_vector $^ $(INC) $(LIB) $(LDFLAGS) && ./test.append_vector

test_attribute_store: \
src/mmap_allocator.o \
src/attribute_store.o \
src/pooled_string.o \
test/attribute_store.test.o
$(CXX) $(CXXFLAGS) -o test.attribute_store $^ $(INC) $(LIB) $(LDFLAGS) && ./test.attribute_store

test_deque_map: \
test/deque_map.test.o
$(CXX) $(CXXFLAGS) -o test.deque_map $^ $(INC) $(LIB) $(LDFLAGS) && ./test.deque_map

test_options_parser: \
src/options_parser.o \
test/options_parser.test.o
$(CXX) $(CXXFLAGS) -o test.options_parser $^ $(INC) $(LIB) $(LDFLAGS) && ./test.options_parser

test_pooled_string: \
src/mmap_allocator.o \
src/pooled_string.o \
test/pooled_string.test.o
$(CXX) $(CXXFLAGS) -o test.pooled_string $^ $(INC) $(LIB) $(LDFLAGS) && ./test.pooled_string

test_sorted_node_store: \
src/external/streamvbyte_decode.o \
src/external/streamvbyte_encode.o \
src/external/streamvbyte_zigzag.o \
src/mmap_allocator.o \
src/sorted_node_store.o \
test/sorted_node_store.test.o
$(CXX) $(CXXFLAGS) -o test.sorted_node_store $^ $(INC) $(LIB) $(LDFLAGS) && ./test.sorted_node_store

test_sorted_way_store: \
src/external/streamvbyte_decode.o \
src/external/streamvbyte_encode.o \
src/external/streamvbyte_zigzag.o \
src/mmap_allocator.o \
src/sorted_way_store.o \
src/sorted_way_store.test.o
test/sorted_way_store.test.o
$(CXX) $(CXXFLAGS) -o test.sorted_way_store $^ $(INC) $(LIB) $(LDFLAGS) && ./test.sorted_way_store

test_pbf_reader: \
src/helpers.o \
src/pbf_reader.o \
test/pbf_reader.test.o
$(CXX) $(CXXFLAGS) -o test.pbf_reader $^ $(INC) $(LIB) $(LDFLAGS) && ./test.pbf_reader

%.o: %.cpp
$(CXX) $(CXXFLAGS) -o $@ -c $< $(INC)
Expand All @@ -153,6 +205,6 @@ install:
install docs/man/tilemaker.1 ${DESTDIR}${MANPREFIX}/man1/

clean:
rm -f tilemaker src/*.o src/external/*.o include/*.o include/*.pb.h
rm -f tilemaker src/*.o src/external/*.o include/*.o include/*.pb.h test/*.o

.PHONY: install
51 changes: 28 additions & 23 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,16 @@ For example:

### Lua processing

Your Lua file needs to supply 5 things:
Your Lua file needs to supply a few things:

1. `node_keys`, a list of those OSM keys which indicate that a node should be processed
2. `init_function(name)` (optional), a function to initialize Lua logic
2. `node_function(node)`, a function to process an OSM node and add it to layers
3. `way_function(way)`, a function to process an OSM way and add it to layers
3. `exit_function` (optional), a function to finalize Lua logic (useful to show statistics)
2. `node_function()`, a function to process an OSM node and add it to layers
3. `way_function()`, a function to process an OSM way and add it to layers
4. (optional) `init_function(name)`, a function to initialize Lua logic
5. (optional) `exit_function`, a function to finalize Lua logic (useful to show statistics)
6. (optional) `relation_scan_function`, a function to determine whether your Lua file wishes to process the given relation
7. (optional) `relation_function`, a function to process an OSM relation and add it to layers
8. (optional) `attribute_function`, a function to remap attributes from shapefiles

`node_keys` is a simple list (or in Lua parlance, a 'table') of OSM tag keys. If a node has one of those keys, it will be processed by `node_function`; if not, it'll be skipped. For example, if you wanted to show highway crossings and railway stations, it should be `{ "highway", "railway" }`. (This avoids the need to process the vast majority of nodes which contain no important tags at all.)

Expand All @@ -127,28 +130,30 @@ Note the order: you write to a layer first, then set attributes after.

To do that, you use these methods:

* `node:Find(key)` or `way:Find(key)`: get the value for a tag, or the empty string if not present. For example, `way:Find("railway")` might return "rail" for a railway, "siding" for a siding, or "" if it isn't a railway at all.
* `node:Holds(key)` or `way:Holds(key)`: returns true if that key exists, false otherwise.
* `node:Layer("layer_name", false)` or `way:Layer("layer_name", is_area)`: write this node/way to the named layer. This is how you put objects in your vector tile. is_area (true/false) specifies whether a way should be treated as an area, or just as a linestring.
* `way:LayerAsCentroid("layer_name")`: write a single centroid point for this way to the named layer (useful for labels and POIs).
* `node:Attribute(key,value,minzoom)` or `node:Attribute(key,value,minzoom)`: add an attribute to the most recently written layer. Argument `minzoom` is optional, use it if you do not want to write the attribute on lower zoom levels.
* `node:AttributeNumeric(key,value,minzoom)`, `node:AttributeBoolean(key,value,minzoom)` (and `way:`...): for numeric/boolean columns.
* `node:Id()` or `way:Id()`: get the OSM ID of the current object.
* `node:ZOrder(number)` or `way:ZOrder(number)`: Set a numeric value (default 0, 1-byte signed integer) used to sort features within a layer. Use this feature to ensure a proper rendering order if the rendering engine itself does not support sorting. Sorting is not supported across layers merged with `write_to`. Features with different z-order are not merged if `combine_below` or `combine_polygons_below` is used.
* `node:MinZoom(zoom)` or `way:MinZoom(zoom)`: set the minimum zoom level (0-15) at which this object will be written. Note that the JSON layer configuration minimum still applies (so `:MinZoom(5)` will have no effect if your layer only starts at z6).
* `way:Length()` and `way:Area()`: return the length (metres)/area (square metres) of the current object. Requires recent Boost.
* `way:Centroid()`: return the lat/lon of the centre of the current object as a two-element Lua table (element 1 is lat, 2 is lon).
* `Find(key)`: get the value for a tag, or the empty string if not present. For example, `Find("railway")` might return "rail" for a railway, "siding" for a siding, or "" if it isn't a railway at all.
* `Holds(key)`: returns true if that key exists, false otherwise.
* `Layer("layer_name", is_area)`: write this node/way to the named layer. This is how you put objects in your vector tile. is_area (true/false) specifies whether a way should be treated as an area, or just as a linestring.
* `LayerAsCentroid("layer_name")`: write a single centroid point for this way to the named layer (useful for labels and POIs).
* `Attribute(key,value,minzoom)`: add an attribute to the most recently written layer. Argument `minzoom` is optional, use it if you do not want to write the attribute on lower zoom levels.
* `AttributeNumeric(key,value,minzoom)`, `AttributeBoolean(key,value,minzoom)`: for numeric/boolean columns.
* `Id()`: get the OSM ID of the current object.
* `ZOrder(number)`: Set a numeric value (default 0, 1-byte signed integer) used to sort features within a layer. Use this feature to ensure a proper rendering order if the rendering engine itself does not support sorting. Sorting is not supported across layers merged with `write_to`. Features with different z-order are not merged if `combine_below` or `combine_polygons_below` is used.
* `MinZoom(zoom)`: set the minimum zoom level (0-15) at which this object will be written. Note that the JSON layer configuration minimum still applies (so `:MinZoom(5)` will have no effect if your layer only starts at z6).
* `Length()` and `Area()`: return the length (metres)/area (square metres) of the current object. Requires recent Boost.
* `Centroid()`: return the lat/lon of the centre of the current object as a two-element Lua table (element 1 is lat, 2 is lon).

The simplest possible function, to include roads/paths and nothing else, might look like this:

function way_function(way)
local highway = way:Find("highway")
```lua
function way_function()
local highway = Find("highway")
if highway~="" then
way:Layer("roads", false)
way:Attribute("name", way:Find("name"))
way:Attribute("type", highway)
Layer("roads", false)
Attribute("name", Find("name"))
Attribute("type", highway)
end
end
```

Take a look at the supplied process.lua for a simple example, or the more complex OpenMapTiles-compatible script in `resources/`. You can specify another filename with the `--process` option.

Expand Down Expand Up @@ -197,11 +202,11 @@ When processing OSM objects with your Lua script, you can perform simple spatial

You can then find out whether a node is within one of these polygons using the `Intersects` method:

if node:Intersects("countries") then print("Looks like it's on land"); end
if Intersects("countries") then print("Looks like it's on land"); end

Or you can find out what country(/ies) the node is within using `FindIntersecting`, which returns a table:

names = node:FindIntersecting("countries")
names = FindIntersecting("countries")
print(table.concat(name,","))

To enable these functions, set `index` to true in your shapefile layer definition. `index_column` is not needed for `Intersects` but required for `FindIntersecting`.
Expand Down
34 changes: 20 additions & 14 deletions docs/RELATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,30 @@ This is a two-stage process: first, when reading relations, indicate that these

To define which relations should be accepted, add a `relation_scan_function`:

function relation_scan_function(relation)
if relation:Find("type")=="route" and relation:Find("route")=="bicycle" then
local network = relation:Find("network")
if network=="ncn" then relation:Accept() end
```lua
function relation_scan_function()
if Find("type")=="route" and Find("route")=="bicycle" then
local network = Find("network")
if network=="ncn" then Accept() end
end
end
```

This function takes the relation as its sole argument. Examine the tags using `relation:Find(key)` as normal. (You can also use `relation:Holds(key)` and `relation:Id()`.) If you want to use this relation, call `relation:Accept()`.
Examine the tags using `Find(key)` as normal. (You can also use `Holds(key)` and `Id()`.) If you want to use this relation, call `Accept()`.

#### Stage 2: accessing relations from ways

Now that you've accepted the relations, they will be available from `way_function`. They are accessed using an iterator (`way:NextRelation()`) which reads each relation for that way in turn, returning nil when there are no more relations available. Once you have accessed a relation with the iterator, you can read its tags with `way:FindInRelation(key)`. For example:
Now that you've accepted the relations, they will be available from `way_function`. They are accessed using an iterator (`NextRelation()`) which reads each relation for that way in turn, returning nil when there are no more relations available. Once you have accessed a relation with the iterator, you can read its tags with `FindInRelation(key)`. For example:

```lua
while true do
local rel = way:NextRelation()
local rel = NextRelation()
if not rel then break end
print ("Part of route "..way:FindInRelation("ref"))
print ("Part of route "..FindInRelation("ref"))
end
```

(Should you need to re-read the relations, you can reset the iterator with `way:RestartRelations()`.)
(Should you need to re-read the relations, you can reset the iterator with `RestartRelations()`.)


### Writing relation geometries
Expand All @@ -52,13 +56,15 @@ First, make sure that you have accepted the relations using `relation_scan_funct

Then write a `relation_function`, which works in the same way as `way_function` would:

function relation_function(relation)
if relation:Find("type")=="route" and relation:Find("route")=="bicycle" then
relation:Layer("bike_routes", false)
relation:Attribute("class", relation:Find("network"))
relation:Attribute("ref", relation:Find("ref"))
```lua
function relation_function()
if Find("type")=="route" and Find("route")=="bicycle" then
Layer("bike_routes", false)
Attribute("class", Find("network"))
Attribute("ref", Find("ref"))
end
end
```


### Not supported
Expand Down
Loading