/usr/include/vector_tile_backend_pbf.hpp is in mapnik-vector-tile 0.3.2+dfsg-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | #ifndef __MAPNIK_VECTOR_TILE_BACKEND_PBF_H__
#define __MAPNIK_VECTOR_TILE_BACKEND_PBF_H__
// mapnik
#include <mapnik/feature.hpp>
#include <mapnik/version.hpp>
#include <mapnik/value_types.hpp>
// vector tile
#include "vector_tile.pb.h"
// boost
#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>
namespace mapnik { namespace vector {
struct to_tile_value: public boost::static_visitor<>
{
public:
to_tile_value(tile_value * value):
value_(value) {}
void operator () ( value_integer val ) const
{
// TODO: figure out shortest varint encoding.
value_->set_int_value(val);
}
void operator () ( mapnik::value_bool val ) const
{
value_->set_bool_value(val);
}
void operator () ( mapnik::value_double val ) const
{
// TODO: Figure out how we can encode 32 bit floats in some cases.
value_->set_double_value(val);
}
void operator () ( mapnik::value_unicode_string const& val ) const
{
std::string str;
to_utf8(val, str);
value_->set_string_value(str.data(), str.length());
}
void operator () ( mapnik::value_null const& /*val*/ ) const
{
// do nothing
}
private:
tile_value * value_;
};
struct backend_pbf
{
typedef std::map<std::string, unsigned> keys_container;
typedef boost::unordered_map<mapnik::value, unsigned> values_container;
private:
tile & tile_;
unsigned path_multiplier_;
mutable tile_layer * current_layer_;
mutable tile_feature * current_feature_;
keys_container keys_;
values_container values_;
int32_t x_, y_;
public:
explicit backend_pbf(tile & _tile,
unsigned path_multiplier)
: tile_(_tile),
path_multiplier_(path_multiplier),
current_layer_(NULL),
current_feature_(NULL)
{
}
void stop_tile_feature()
{
if (current_feature_)
{
if (current_feature_->geometry_size() == 0 && current_layer_)
{
current_layer_->mutable_features()->RemoveLast();
}
}
}
void start_tile_feature(mapnik::feature_impl const& feature)
{
current_feature_ = current_layer_->add_features();
x_ = y_ = 0;
current_feature_->set_id(feature.id());
feature_kv_iterator itr = feature.begin();
feature_kv_iterator end = feature.end();
for ( ;itr!=end; ++itr)
{
std::string const& name = boost::get<0>(*itr);
mapnik::value const& val = boost::get<1>(*itr);
if (!val.is_null())
{
// Insert the key index
keys_container::const_iterator key_itr = keys_.find(name);
if (key_itr == keys_.end())
{
// The key doesn't exist yet in the dictionary.
current_layer_->add_keys(name.c_str(), name.length());
size_t index = keys_.size();
keys_.insert(keys_container::value_type(name, index));
current_feature_->add_tags(index);
}
else
{
current_feature_->add_tags(key_itr->second);
}
// Insert the value index
values_container::const_iterator val_itr = values_.find(val);
if (val_itr == values_.end())
{
// The value doesn't exist yet in the dictionary.
to_tile_value visitor(current_layer_->add_values());
boost::apply_visitor(visitor, val.base());
size_t index = values_.size();
values_.insert(values_container::value_type(val, index));
current_feature_->add_tags(index);
}
else
{
current_feature_->add_tags(val_itr->second);
}
}
}
}
void start_tile_layer(std::string const& name)
{
// Key/value dictionary is per-layer.
keys_.clear();
values_.clear();
current_layer_ = tile_.add_layers();
current_layer_->set_name(name);
current_layer_->set_version(1);
// We currently use path_multiplier as a factor to scale the coordinates.
// Eventually, we should replace this with the extent specifying the
// bounding box in both dimensions. E.g. an extent of 4096 means that
// the coordinates encoded in this tile should be visible in the range
// from 0..4095.
current_layer_->set_extent(256 * path_multiplier_);
}
void stop_tile_layer()
{
// NOTE: we intentionally do not remove layers without features
// since the re-rendering logic expects a layer entry no matter what
//std::cerr << "stop_tile_layer()" << std::endl;
}
template <typename T>
unsigned add_path(T & path, unsigned tolerance, mapnik::eGeomType type)
{
unsigned count = 0;
if (current_feature_)
{
path.rewind(0);
current_feature_->set_type(mapnik::vector::tile_GeomType(type));
vertex2d vtx(vertex2d::no_init);
int cmd = -1;
int cmd_idx = -1;
const int cmd_bits = 3;
unsigned length = 0;
// See vector_tile.proto for a description of how vertex command
// encoding works.
while ((vtx.cmd = path.vertex(&vtx.x, &vtx.y)) != SEG_END)
{
if (static_cast<int>(vtx.cmd) != cmd)
{
if (cmd_idx >= 0)
{
// Encode the previous length/command value.
current_feature_->set_geometry(cmd_idx, (length << cmd_bits) | (cmd & ((1 << cmd_bits) - 1)));
}
cmd = static_cast<int>(vtx.cmd);
length = 0;
cmd_idx = current_feature_->geometry_size();
current_feature_->add_geometry(0); // placeholder
}
if (cmd == SEG_MOVETO || cmd == SEG_LINETO)
{
// Compute delta to the previous coordinate.
int32_t cur_x = static_cast<int32_t>(std::floor((vtx.x * path_multiplier_)+.5));
int32_t cur_y = static_cast<int32_t>(std::floor((vtx.y * path_multiplier_)+.5));
int32_t dx = cur_x - x_;
int32_t dy = cur_y - y_;
// Omit movements that are no-ops.
unsigned x_floor = static_cast<unsigned>(std::abs(dx));
unsigned y_floor = static_cast<unsigned>(std::abs(dy));
if (x_floor >= tolerance ||
y_floor >= tolerance ||
length == 0)
{
// Manual zigzag encoding.
current_feature_->add_geometry((dx << 1) ^ (dx >> 31));
current_feature_->add_geometry((dy << 1) ^ (dy >> 31));
x_ = cur_x;
y_ = cur_y;
length++;
}
}
else if (cmd == SEG_CLOSE) {
length++;
}
else {
throw std::runtime_error("Unknown command type");
}
++count;
}
// Update the last length/command value.
if (cmd_idx >= 0)
{
current_feature_->set_geometry(cmd_idx, (length << cmd_bits) | (cmd & ((1 << cmd_bits) - 1)));
}
}
return count;
}
};
}} // end ns
#endif // __MAPNIK_VECTOR_TILE_BACKEND_PBF_H__
|