GeometryCollection operator()(const mapbox::geometry::line_string<int16_t>& geom) const { GeometryCoordinates coordinates; coordinates.reserve(geom.size()); for (const auto& point : geom) { coordinates.emplace_back(point); } return { coordinates }; }
GeometryCollection operator()(const mapbox::geometry::multi_line_string<int16_t>& geom) const { GeometryCollection collection; collection.reserve(geom.size()); for (const auto& ring : geom) { GeometryCoordinates coordinates; coordinates.reserve(ring.size()); for (const auto& point : ring) { coordinates.emplace_back(point); } collection.push_back(std::move(coordinates)); } return collection; }
GeometryCollection operator()(const mapbox::geometry::multi_polygon<int16_t>& geom) const { GeometryCollection collection; for (auto& polygon : geom) { for (auto& ring : polygon) { GeometryCoordinates coordinates; coordinates.reserve(ring.size()); for (auto& point : ring) { coordinates.emplace_back(point); } collection.push_back(std::move(coordinates)); } } return collection; }
GeometryCollection VectorTileFeature::getGeometries() const { uint8_t cmd = 1; uint32_t length = 0; int32_t x = 0; int32_t y = 0; const float scale = float(util::EXTENT) / layer.extent; GeometryCollection lines; lines.emplace_back(); GeometryCoordinates* line = &lines.back(); auto g_itr = geometry_iter.begin(); while (g_itr != geometry_iter.end()) { if (length == 0) { uint32_t cmd_length = static_cast<uint32_t>(*g_itr++); cmd = cmd_length & 0x7; length = cmd_length >> 3; } --length; if (cmd == 1 || cmd == 2) { x += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); y += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); if (cmd == 1 && !line->empty()) { // moveTo lines.emplace_back(); line = &lines.back(); } line->emplace_back(::round(x * scale), ::round(y * scale)); } else if (cmd == 7) { // closePolygon if (!line->empty()) { line->push_back((*line)[0]); } } else { throw std::runtime_error("unknown command"); } }
GeometryCollection VectorTileFeature::getGeometries() const { pbf data(geometry_pbf); uint8_t cmd = 1; uint32_t length = 0; int32_t x = 0; int32_t y = 0; GeometryCollection lines; lines.emplace_back(); GeometryCoordinates* line = &lines.back(); while (data.data < data.end) { if (length == 0) { uint32_t cmd_length = data.varint(); cmd = cmd_length & 0x7; length = cmd_length >> 3; } --length; if (cmd == 1 || cmd == 2) { x += data.svarint(); y += data.svarint(); if (cmd == 1 && !line->empty()) { // moveTo lines.emplace_back(); line = &lines.back(); } line->emplace_back(x, y); } else if (cmd == 7) { // closePolygon if (!line->empty()) { line->push_back((*line)[0]); } } else { throw std::runtime_error("unknown command"); } }
static GeometryCoordinates fromClipperPath(const ClipperLib::Path& path) { GeometryCoordinates result; result.reserve(path.size() + 1); result.reserve(path.size()); for (const auto& p : path) { using Coordinate = GeometryCoordinates::coordinate_type; assert(p.x >= std::numeric_limits<Coordinate>::min()); assert(p.x <= std::numeric_limits<Coordinate>::max()); assert(p.y >= std::numeric_limits<Coordinate>::min()); assert(p.y <= std::numeric_limits<Coordinate>::max()); result.emplace_back(Coordinate(p.x), Coordinate(p.y)); } // Clipper does not repeat initial point, but our geometry model requires it. if (!result.empty()) { result.push_back(result.front()); } return result; }
void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile) { static const double baseTolerance = 4; if (!shapeTiler) { const uint64_t maxAmountOfTiles = 1 << maxZoom; const double tolerance = baseTolerance / (maxAmountOfTiles * GeometryTileFeature::defaultExtent); geojsonvt::ProjectedRings rings; std::vector<geojsonvt::LonLat> points; for (size_t i = 0; i < shape.segments[0].size(); ++i) { // first segment for now (no holes) const double constrainedLatitude = util::clamp(shape.segments[0][i].latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX); points.push_back(geojsonvt::LonLat(shape.segments[0][i].longitude, constrainedLatitude)); } if (type == geojsonvt::ProjectedFeatureType::Polygon && (points.front().lon != points.back().lon || points.front().lat != points.back().lat)) { points.push_back(geojsonvt::LonLat(points.front().lon, points.front().lat)); } auto ring = geojsonvt::Convert::projectRing(points, tolerance); rings.push_back(ring); std::vector<geojsonvt::ProjectedFeature> features; features.push_back(geojsonvt::Convert::create(geojsonvt::Tags(), type, rings)); mapbox::geojsonvt::Options options; options.maxZoom = maxZoom; options.buffer = 255u; options.extent = util::EXTENT; options.tolerance = baseTolerance; shapeTiler = std::make_unique<mapbox::geojsonvt::GeoJSONVT>(features, options); } const auto& shapeTile = shapeTiler->getTile(tileID.sourceZ, tileID.x, tileID.y); if (!shapeTile) return; AnnotationTileLayer& layer = *tile.layers.emplace(layerID, std::make_unique<AnnotationTileLayer>()).first->second; for (auto& shapeFeature : shapeTile.features) { FeatureType featureType = FeatureType::Unknown; if (shapeFeature.type == geojsonvt::TileFeatureType::LineString) { featureType = FeatureType::LineString; } else if (shapeFeature.type == geojsonvt::TileFeatureType::Polygon) { featureType = FeatureType::Polygon; } assert(featureType != FeatureType::Unknown); GeometryCollection renderGeometry; for (auto& shapeRing : shapeFeature.tileGeometry.get<geojsonvt::TileRings>()) { GeometryCoordinates renderLine; for (auto& shapePoint : shapeRing) { renderLine.emplace_back(shapePoint.x, shapePoint.y); } renderGeometry.push_back(renderLine); } layer.features.emplace_back( std::make_shared<AnnotationTileFeature>(featureType, renderGeometry)); } }