mirror of
https://github.com/systemed/tilemaker
synced 2025-02-21 13:24:09 +01:00
321 lines
9.7 KiB
C++
321 lines
9.7 KiB
C++
/*! \file */
|
|
#ifndef _OSM_LUA_PROCESSING_H
|
|
#define _OSM_LUA_PROCESSING_H
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <map>
|
|
#include "geom.h"
|
|
#include "osm_store.h"
|
|
#include "shared_data.h"
|
|
#include "output_object.h"
|
|
#include "shp_mem_tiles.h"
|
|
#include "osm_mem_tiles.h"
|
|
#include "helpers.h"
|
|
#include "pbf_reader.h"
|
|
#include <protozero/data_view.hpp>
|
|
|
|
#include <boost/container/flat_map.hpp>
|
|
|
|
class TagMap;
|
|
class SignificantTags;
|
|
|
|
// Lua
|
|
extern "C" {
|
|
#include "lua.h"
|
|
#include "lualib.h"
|
|
#include "lauxlib.h"
|
|
}
|
|
|
|
#include "external/kaguya.hpp"
|
|
|
|
// FIXME: why is this global ?
|
|
extern bool verbose;
|
|
|
|
class AttributeStore;
|
|
class AttributeSet;
|
|
|
|
/**
|
|
\brief OsmLuaProcessing - converts OSM objects into OutputObjects.
|
|
|
|
The input objects are generated by PbfReader. The output objects are sent to OsmMemTiles for storage.
|
|
|
|
This class provides a consistent interface for Lua scripts to access.
|
|
*/
|
|
class OsmLuaProcessing {
|
|
|
|
public:
|
|
// ---- initialization routines
|
|
|
|
OsmLuaProcessing(
|
|
OSMStore &osmStore,
|
|
const class Config &configIn,
|
|
class LayerDefinition &layers,
|
|
const std::string &luaFile,
|
|
const class ShpMemTiles &shpMemTiles,
|
|
class OsmMemTiles &osmMemTiles,
|
|
AttributeStore &attributeStore,
|
|
bool materializeGeometries
|
|
);
|
|
~OsmLuaProcessing();
|
|
|
|
// ---- Helpers provided for main routine
|
|
void handleUserSignal(int signum);
|
|
|
|
// Has this object been assigned to any layers?
|
|
bool empty();
|
|
|
|
// Do we have Lua routines for non-MP relations?
|
|
bool canReadRelations();
|
|
bool canPostScanRelations();
|
|
bool canWriteNodes();
|
|
bool canWriteWays();
|
|
bool canWriteRelations();
|
|
|
|
// Shapefile tag remapping
|
|
bool canRemapShapefiles();
|
|
kaguya::LuaTable newTable();
|
|
kaguya::LuaTable remapAttributes(kaguya::LuaTable& in_table, const std::string &layerName);
|
|
|
|
// ---- Data loading methods
|
|
|
|
using tag_map_t = boost::container::flat_map<protozero::data_view, protozero::data_view, DataViewLessThan>;
|
|
|
|
// Scan non-MP relation
|
|
bool scanRelation(WayID id, const TagMap& tags);
|
|
|
|
// Post-scan non-MP relations
|
|
void postScanRelations();
|
|
|
|
/// \brief We are now processing a significant node
|
|
bool setNode(NodeID id, LatpLon node, const TagMap& tags);
|
|
|
|
/// \brief We are now processing a way
|
|
bool setWay(WayID wayId, LatpLonVec const &llVec, const TagMap& tags);
|
|
|
|
/** \brief We are now processing a relation
|
|
* (note that we store relations as ways with artificial IDs, and that
|
|
* we use decrementing positive IDs to give a bit more space for way IDs)
|
|
*/
|
|
void setRelation(
|
|
const std::vector<protozero::data_view>& stringTable,
|
|
const PbfReader::Relation& relation,
|
|
const WayVec& outerWayVec,
|
|
const WayVec& innerWayVec,
|
|
const TagMap& tags,
|
|
bool isNativeMP,
|
|
bool isInnerOuter
|
|
);
|
|
|
|
// ---- Metadata queries called from Lua
|
|
|
|
// Get the ID of the current object
|
|
std::string Id() const;
|
|
|
|
// Gets a table of all the keys of the OSM tags
|
|
kaguya::LuaTable AllKeys(kaguya::State& luaState);
|
|
|
|
// Gets a table of all the OSM tags
|
|
kaguya::LuaTable AllTags(kaguya::State& luaState);
|
|
|
|
// Check if there's a value for a given key
|
|
bool Holds(const std::string& key) const;
|
|
|
|
// Get an OSM tag for a given key (or return empty string if none)
|
|
const std::string Find(const std::string& key) const;
|
|
|
|
// Check if an object has any tags
|
|
bool HasTags() const;
|
|
|
|
// ---- Spatial queries called from Lua
|
|
|
|
// Find intersecting shapefile layer
|
|
std::vector<std::string> FindIntersecting(const std::string &layerName);
|
|
double AreaIntersecting(const std::string &layerName);
|
|
bool Intersects(const std::string &layerName);
|
|
template <typename GeometryT> double intersectsArea(const std::string &layerName, GeometryT &geom) const;
|
|
template <typename GeometryT> std::vector<uint> intersectsQuery(const std::string &layerName, bool once, GeometryT &geom) const;
|
|
|
|
std::vector<std::string> FindCovering(const std::string &layerName);
|
|
bool CoveredBy(const std::string &layerName);
|
|
template <typename GeometryT> std::vector<uint> coveredQuery(const std::string &layerName, bool once, GeometryT &geom) const;
|
|
|
|
// Returns whether it is closed polygon
|
|
bool IsClosed() const;
|
|
|
|
// Returns area
|
|
double Area();
|
|
double multiPolygonArea(const MultiPolygon &mp) const;
|
|
|
|
// Returns length
|
|
double Length();
|
|
|
|
// Return centroid lat/lon
|
|
kaguya::optional<std::vector<double>> Centroid(kaguya::VariadicArgType algorithm);
|
|
|
|
enum class CentroidAlgorithm: char { Centroid = 0, Polylabel = 1 };
|
|
CentroidAlgorithm defaultCentroidAlgorithm() const { return CentroidAlgorithm::Polylabel; }
|
|
CentroidAlgorithm parseCentroidAlgorithm(const std::string& algorithm) const;
|
|
Point calculateCentroid(CentroidAlgorithm algorithm);
|
|
|
|
enum class CorrectGeometryResult: char { Invalid = 0, Valid = 1, Corrected = 2 };
|
|
// ---- Requests from Lua to write this way/node to a vector tile's Layer
|
|
template<class GeometryT>
|
|
CorrectGeometryResult CorrectGeometry(GeometryT &geom)
|
|
{
|
|
geom::validity_failure_type failure = geom::validity_failure_type::no_failure;
|
|
if (isRelation && !geom::is_valid(geom,failure)) {
|
|
if (verbose) std::cout << "Relation " << originalOsmID << " has " << boost_validity_error(failure) << std::endl;
|
|
} else if (isWay && !geom::is_valid(geom,failure)) {
|
|
if (verbose && failure!=22) std::cout << "Way " << originalOsmID << " has " << boost_validity_error(failure) << std::endl;
|
|
}
|
|
|
|
if (failure==boost::geometry::failure_spikes)
|
|
geom::remove_spikes(geom);
|
|
if (failure == boost::geometry::failure_few_points)
|
|
return CorrectGeometryResult::Invalid;
|
|
if (failure) {
|
|
std::time_t start = std::time(0);
|
|
make_valid(geom);
|
|
if (verbose && std::time(0)-start>3) {
|
|
std::cout << (isRelation ? "Relation " : "Way ") << originalOsmID << " took " << (std::time(0)-start) << " seconds to correct" << std::endl;
|
|
}
|
|
return CorrectGeometryResult::Corrected;
|
|
}
|
|
return CorrectGeometryResult::Valid;
|
|
}
|
|
|
|
// Add layer
|
|
void Layer(const std::string &layerName, bool area);
|
|
void LayerAsCentroid(const std::string &layerName, kaguya::VariadicArgType nodeSources);
|
|
|
|
// Set attributes in a vector tile's Attributes table
|
|
void Attribute(const std::string &key, const protozero::data_view val, const char minzoom);
|
|
void AttributeNumeric(const std::string &key, const float val, const char minzoom);
|
|
void AttributeBoolean(const std::string &key, const bool val, const char minzoom);
|
|
void MinZoom(const double z);
|
|
void ZOrder(const double z);
|
|
|
|
// Relation scan support
|
|
|
|
struct OptionalRelation {
|
|
bool done;
|
|
lua_Integer id;
|
|
std::string role;
|
|
};
|
|
OptionalRelation NextRelation();
|
|
void RestartRelations();
|
|
std::string FindInRelation(const std::string &key);
|
|
void Accept();
|
|
void SetTag(const std::string &key, const std::string &value);
|
|
|
|
// Write error if in verbose mode
|
|
void ProcessingError(const std::string &errStr) {
|
|
if (verbose) { std::cerr << errStr << std::endl; }
|
|
}
|
|
|
|
// ---- vector_layers metadata entry
|
|
|
|
void setVectorLayerMetadata(const uint_least8_t layer, const std::string &key, const uint type);
|
|
|
|
SignificantTags GetSignificantNodeKeys();
|
|
SignificantTags GetSignificantWayKeys();
|
|
|
|
// ---- Cached geometries creation
|
|
|
|
const Linestring &linestringCached();
|
|
|
|
const Polygon &polygonCached();
|
|
|
|
const MultiLinestring &multiLinestringCached();
|
|
|
|
const MultiPolygon &multiPolygonCached();
|
|
|
|
inline AttributeStore &getAttributeStore() { return attributeStore; }
|
|
|
|
struct luaProcessingException :std::exception {};
|
|
const TagMap* currentTags;
|
|
bool isPostScanRelation; // processing a relation in postScanRelation
|
|
|
|
private:
|
|
/// Internal: clear current cached state
|
|
inline void reset() {
|
|
outputs.clear();
|
|
currentRelation = nullptr;
|
|
stringTable = nullptr;
|
|
llVecPtr = nullptr;
|
|
outerWayVecPtr = nullptr;
|
|
innerWayVecPtr = nullptr;
|
|
linestringInited = false;
|
|
multiLinestringInited = false;
|
|
polygonInited = false;
|
|
multiPolygonInited = false;
|
|
relationAccepted = false;
|
|
relationList.clear();
|
|
relationSubscript = -1;
|
|
lastStoredGeometryId = 0;
|
|
isWay = false;
|
|
isRelation = false;
|
|
isPostScanRelation = false;
|
|
}
|
|
|
|
void removeAttributeIfNeeded(const std::string& key);
|
|
|
|
const inline Point getPoint() {
|
|
return Point(lon/10000000.0,latp/10000000.0);
|
|
}
|
|
|
|
OSMStore &osmStore; // global OSM store
|
|
|
|
kaguya::State luaState;
|
|
bool supportsRemappingShapefiles;
|
|
bool supportsReadingRelations;
|
|
bool supportsPostScanRelations;
|
|
bool supportsWritingNodes;
|
|
bool supportsWritingWays;
|
|
bool supportsWritingRelations;
|
|
const class ShpMemTiles &shpMemTiles;
|
|
class OsmMemTiles &osmMemTiles;
|
|
AttributeStore &attributeStore; // key/value store
|
|
|
|
int64_t originalOsmID; ///< Original OSM object ID
|
|
bool isWay, isRelation, isClosed; ///< Way, node, relation?
|
|
|
|
bool relationAccepted; // in scanRelation, whether we're using a non-MP relation
|
|
std::vector<std::pair<WayID, uint16_t>> relationList; // in processNode/processWay, list of relations this entity is in, and its role
|
|
int relationSubscript = -1; // in processWay, position in the relation list
|
|
|
|
int32_t lon,latp; ///< Node coordinates
|
|
LatpLonVec const *llVecPtr;
|
|
WayVec const *outerWayVecPtr;
|
|
WayVec const *innerWayVecPtr;
|
|
|
|
Linestring linestringCache;
|
|
bool linestringInited;
|
|
Polygon polygonCache;
|
|
bool polygonInited;
|
|
MultiLinestring multiLinestringCache;
|
|
bool multiLinestringInited;
|
|
MultiPolygon multiPolygonCache;
|
|
bool multiPolygonInited;
|
|
|
|
NodeID lastStoredGeometryId;
|
|
OutputGeometryType lastStoredGeometryType;
|
|
|
|
const class Config &config;
|
|
class LayerDefinition &layers;
|
|
|
|
std::vector<std::pair<OutputObject, AttributeSet>> outputs; // All output objects that have been created
|
|
std::vector<std::string> outputKeys;
|
|
const PbfReader::Relation* currentRelation;
|
|
const boost::container::flat_map<std::string, std::string>* currentPostScanTags; // for postScan only
|
|
const std::vector<protozero::data_view>* stringTable;
|
|
|
|
std::vector<OutputObject> finalizeOutputs();
|
|
|
|
bool materializeGeometries;
|
|
bool wayEmitted;
|
|
};
|
|
|
|
#endif //_OSM_LUA_PROCESSING_H
|