1
0
Fork 0
mirror of https://github.com/systemed/tilemaker synced 2025-02-21 13:24:09 +01:00
tilemaker/include/osm_lua_processing.h

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