Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 19 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,20 @@ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
ENDIF ()

find_package(Boost 1.66 REQUIRED COMPONENTS system filesystem program_options)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(Boost_USE_DEBUG_RUNTIME true)
else()
set(Boost_USE_DEBUG_RUNTIME false)
endif()

set(BOOST_HAS_SYSTEM false)

find_package(Boost 1.89 QUIET COMPONENTS filesystem program_options)

if(NOT Boost_FOUND)
find_package(Boost 1.66 REQUIRED COMPONENTS system filesystem program_options)
set(BOOST_HAS_SYSTEM true)
endif()

find_package(libshp REQUIRED)

Expand Down Expand Up @@ -111,6 +124,7 @@ file(GLOB tilemaker_src_files
src/tag_map.cpp
src/tile_coordinates_set.cpp
src/tile_data.cpp
src/tile_sorting.cpp
src/tilemaker.cpp
src/tile_worker.cpp
src/visvalingam.cpp
Expand All @@ -125,7 +139,10 @@ target_link_libraries(tilemaker
shapelib::shp
SQLite::SQLite3
Rapidjson::rapidjson
Boost::system Boost::filesystem Boost::program_options)
Boost::filesystem Boost::program_options)
if(BOOST_HAS_SYSTEM)
target_link_libraries(tilemaker Boost::system)
endif()

include(CheckCxxAtomic)
if(NOT HAVE_CXX11_ATOMIC)
Expand Down
1 change: 1 addition & 0 deletions include/append_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "mmap_allocator.h"
#include <vector>
#include <queue>
#include <cstdint>

// Tilemaker collects OutputObjects in a list that
// - spills to disk
Expand Down
2 changes: 0 additions & 2 deletions include/output_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
#include <string>
#include <map>
#include <memory>
#include "geom.h"
#include "coordinates.h"
#include "attribute_store.h"
#include "osm_store.h"
#include <vtzero/builder.hpp>

enum OutputGeometryType : unsigned int { POINT_, LINESTRING_, MULTILINESTRING_, POLYGON_ };
Expand Down
90 changes: 8 additions & 82 deletions include/tile_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,22 @@
#include <set>
#include <vector>
#include <memory>
#include <boost/sort/sort.hpp>
#include "output_object.h"
#include "append_vector.h"
#include "clip_cache.h"
#include "mmap_allocator.h"
#include "tile_coordinates_set.h"

#define TILE_DATA_ID_SIZE 34
#include "tile_data_base.h"

typedef std::vector<class TileDataSource *> SourceList;

class TileBbox;

// We cluster output objects by z6 tile
#define CLUSTER_ZOOM 6
#define CLUSTER_ZOOM_WIDTH (1 << CLUSTER_ZOOM)
#define CLUSTER_ZOOM_AREA (CLUSTER_ZOOM_WIDTH * CLUSTER_ZOOM_WIDTH)

// TileDataSource indexes which tiles have objects in them. The indexed zoom
// is at most z14; we'll clamp to z14 if the base zoom is higher than z14.
//
// As a result, we need at most 15 bits to store an X/Y coordinate. For efficiency,
// we bucket the world into 4,096 z6 tiles, which each contain some number of
// z14 objects. This lets us use only 8 bits to store an X/Y coordinate.
//
// Because index zoom is lower than base zoom in the case where base zoom is
// z15+, we'll get false positives when looking up objects in the index,
// since, e.g., a single z14 tile covers 4 z15 tiles.
//
// This is OK: when writing the z15 tile, there's a clipping step that will filter
// out the false positives.
typedef uint8_t Z6Offset;

struct OutputObjectXY {
OutputObject oo;
Z6Offset x;
Z6Offset y;
};

struct OutputObjectXYID {
OutputObject oo;
Z6Offset x;
Z6Offset y;
uint64_t id;
};
template<typename OO> void sortOutputObjects(
const unsigned int indexZoom,
const size_t threadNum,
typename AppendVectorNS::AppendVector<OO>::Iterator begin,
typename AppendVectorNS::AppendVector<OO>::Iterator end
);

template<typename OO> void finalizeObjects(
const std::string& name,
Expand Down Expand Up @@ -88,52 +59,7 @@ template<typename OO> void finalizeObjects(
if (objectIt->oo.minZoom < CLUSTER_ZOOM)
lowZoom[i].push_back(*objectIt);

// If the user is doing a a small extract, there are few populated
// entries in `object`.
//
// e.g. Colorado has ~9 z6 tiles, 1 of which has 95% of its output
// objects.
//
// This optimizes for the small extract case by doing:
// - for each vector in objects
// - do a multi-threaded sort of vector
//
// For small extracts, this ensures that all threads are used even if
// only a handful of entries in `objects` are non-empty.
//
// For a global extract, this will have some overhead of repeatedly
// setting up/tearing down threads. In that case, it would be
// better to assign chunks of `objects` to each thread.
//
// That's a future performance improvement, so deferring for now.
boost::sort::block_indirect_sort(
it->begin(),
it->end(),
[indexZoom](const OO& a, const OO& b) {
// Cluster by parent zoom, so that a subsequent search
// can find a contiguous range of entries for any tile
// at zoom 6 or higher.
const size_t aX = a.x;
const size_t aY = a.y;
const size_t bX = b.x;
const size_t bY = b.y;
for (size_t z = CLUSTER_ZOOM; z <= indexZoom; z++) {
const auto aXz = aX / (1 << (indexZoom - z));
const auto bXz = bX / (1 << (indexZoom - z));
if (aXz != bXz)
return aXz < bXz;

const auto aYz = aY / (1 << (indexZoom - z));
const auto bYz = bY / (1 << (indexZoom - z));

if (aYz != bYz)
return aYz < bYz;
}

return false;
},
threadNum
);
sortOutputObjects<OO>(indexZoom, threadNum, it->begin(), it->end());
}

std::cout << std::endl;
Expand Down
42 changes: 42 additions & 0 deletions include/tile_data_base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef _TILE_DATA_BASE_H
#define _TILE_DATA_BASE_H

#include <cstdint>
#include "output_object.h"

#define TILE_DATA_ID_SIZE 34

// We cluster output objects by z6 tile
#define CLUSTER_ZOOM 6
#define CLUSTER_ZOOM_WIDTH (1 << CLUSTER_ZOOM)
#define CLUSTER_ZOOM_AREA (CLUSTER_ZOOM_WIDTH * CLUSTER_ZOOM_WIDTH)

// TileDataSource indexes which tiles have objects in them. The indexed zoom
// is at most z14; we'll clamp to z14 if the base zoom is higher than z14.
//
// As a result, we need at most 15 bits to store an X/Y coordinate. For efficiency,
// we bucket the world into 4,096 z6 tiles, which each contain some number of
// z14 objects. This lets us use only 8 bits to store an X/Y coordinate.
//
// Because index zoom is lower than base zoom in the case where base zoom is
// z15+, we'll get false positives when looking up objects in the index,
// since, e.g., a single z14 tile covers 4 z15 tiles.
//
// This is OK: when writing the z15 tile, there's a clipping step that will filter
// out the false positives.
typedef uint8_t Z6Offset;

struct OutputObjectXY {
OutputObject oo;
Z6Offset x;
Z6Offset y;
};

struct OutputObjectXYID {
OutputObject oo;
Z6Offset x;
Z6Offset y;
uint64_t id;
};

#endif //_TILE_DATA_BASE_H
1 change: 0 additions & 1 deletion src/osm_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <unordered_map>

#include <ciso646>
#include <boost/sort/sort.hpp>
#include "node_store.h"
#include "way_store.h"

Expand Down
23 changes: 6 additions & 17 deletions src/tile_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,11 @@ void populateTilesAtZoom(
}
}

void sortOutputObjectIDs(
const std::vector<bool>& sortOrders,
std::vector<OutputObjectID>& data
);

std::vector<OutputObjectID> TileDataSource::getObjectsForTile(
const std::vector<bool>& sortOrders,
unsigned int zoom,
Expand All @@ -402,23 +407,7 @@ std::vector<OutputObjectID> TileDataSource::getObjectsForTile(
std::vector<OutputObjectID> data;
collectObjectsForTile(zoom, coordinates, data);
collectLargeObjectsForTile(zoom, coordinates, data);

// Lexicographic comparison, with the order of: layer, geomType, attributes, and objectID.
// Note that attributes is preferred to objectID.
// It is to arrange objects with the identical attributes continuously.
// Such objects will be merged into one object, to reduce the size of output.
boost::sort::pdqsort(data.begin(), data.end(), [&sortOrders](const OutputObjectID& x, const OutputObjectID& y) -> bool {
if (x.oo.layer < y.oo.layer) return true;
if (x.oo.layer > y.oo.layer) return false;
if (x.oo.z_order < y.oo.z_order) return sortOrders[x.oo.layer];
if (x.oo.z_order > y.oo.z_order) return !sortOrders[x.oo.layer];
if (x.oo.geomType < y.oo.geomType) return true;
if (x.oo.geomType > y.oo.geomType) return false;
if (x.oo.attributes < y.oo.attributes) return true;
if (x.oo.attributes > y.oo.attributes) return false;
if (x.oo.objectID < y.oo.objectID) return true;
return false;
});
sortOutputObjectIDs(sortOrders, data);
data.erase(unique(data.begin(), data.end()), data.end());
return data;
}
Expand Down
Loading