1
0
Fork 0
mirror of https://github.com/systemed/tilemaker synced 2025-02-21 13:24:09 +01:00
tilemaker/src/osm_mem_tiles.cpp
2024-04-01 17:24:47 +01:00

134 lines
3.5 KiB
C++

#include "osm_mem_tiles.h"
#include "node_store.h"
#include "way_store.h"
using namespace std;
thread_local GeometryCache<Linestring> linestringCache;
OsmMemTiles::OsmMemTiles(
size_t threadNum,
uint indexZoom,
bool includeID,
const NodeStore& nodeStore,
const WayStore& wayStore
)
: TileDataSource(threadNum, indexZoom, includeID),
nodeStore(nodeStore),
wayStore(wayStore)
{
}
LatpLon OsmMemTiles::buildNodeGeometry(
NodeID const objectID,
const TileBbox &bbox
) const {
if (objectID < OSM_THRESHOLD) {
return TileDataSource::buildNodeGeometry(objectID, bbox);
}
if (IS_NODE(objectID))
return nodeStore.at(OSM_ID(objectID));
if (IS_WAY(objectID)) {
Linestring& ls = getOrBuildLinestring(objectID);
Point centroid;
Polygon p;
geom::assign_points(p, ls);
geom::centroid(p, centroid);
return LatpLon{(int32_t)(centroid.y()*10000000.0), (int32_t)(centroid.x()*10000000.0)};
}
throw std::runtime_error("OsmMemTiles::buildNodeGeometry: unsupported objectID");
}
Geometry OsmMemTiles::buildWayGeometry(
const OutputGeometryType geomType,
const NodeID objectID,
const TileBbox &bbox
) {
if (objectID < OSM_THRESHOLD || (geomType == POLYGON_ && IS_WAY(objectID))) {
return TileDataSource::buildWayGeometry(geomType, objectID, bbox);
}
if (geomType == LINESTRING_ && IS_WAY(objectID)) {
Linestring& ls = getOrBuildLinestring(objectID);
MultiLinestring out;
if(ls.empty())
return out;
Linestring current_ls;
geom::append(current_ls, ls[0]);
for(size_t i = 1; i < ls.size(); ++i) {
if(!geom::intersects(Linestring({ ls[i-1], ls[i] }), bbox.clippingBox)) {
if(current_ls.size() > 1)
out.push_back(std::move(current_ls));
current_ls.clear();
}
geom::append(current_ls, ls[i]);
}
if(current_ls.size() > 1)
out.push_back(std::move(current_ls));
MultiLinestring result;
geom::intersection(out, bbox.getExtendBox(), result);
return result;
}
throw std::runtime_error("buildWayGeometry: unexpected objectID: " + std::to_string(objectID));
}
void OsmMemTiles::populateLinestring(Linestring& ls, NodeID objectID) const {
std::vector<LatpLon> nodes = wayStore.at(OSM_ID(objectID));
for (const LatpLon& node : nodes) {
boost::geometry::range::push_back(ls, boost::geometry::make<Point>(node.lon/10000000.0, node.latp/10000000.0));
}
}
Linestring& OsmMemTiles::getOrBuildLinestring(NodeID objectID) const {
// Note: this function returns a reference, not a shared_ptr.
//
// This is safe, because this function is the only thing that can
// create/destroy entries in the cache, and the cache is thread-local.
Linestring* cachedEntry = linestringCache.get(objectID);
if (cachedEntry != nullptr)
return *cachedEntry;
std::shared_ptr<Linestring> rv = std::make_shared<Linestring>();
Linestring& ls = *rv;
populateLinestring(ls, objectID);
linestringCache.add(objectID, rv);
return *rv;
}
void OsmMemTiles::populateMultiPolygon(MultiPolygon& dst, NodeID objectID) {
if (objectID < OSM_THRESHOLD)
return TileDataSource::populateMultiPolygon(dst, objectID);
// We don't cache the linestrings used for polygons. Polygons from ways seem
// to be dominated by polygons with few points that only span a basezoom tile,
// e.g. building outlines.
//
// There are some exceptions, but some rough measurements showed caching
// hurt overall throughput.
Linestring ls;
populateLinestring(ls, objectID);
Polygon p;
geom::assign_points(p, ls);
dst.push_back(p);
}
void OsmMemTiles::Clear() {
for (auto& entry : objects)
entry.clear();
for (auto& entry : objectsWithIds)
entry.clear();
}