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 }; }
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; }
std::unordered_map<std::string, std::vector<Feature>> Source::Impl::queryRenderedFeatures(const QueryParameters& parameters) const { std::unordered_map<std::string, std::vector<Feature>> result; if (renderTiles.empty() || parameters.geometry.empty()) { return result; } LineString<double> queryGeometry; for (const auto& p : parameters.geometry) { queryGeometry.push_back(TileCoordinate::fromScreenCoordinate( parameters.transformState, 0, { p.x, parameters.transformState.getSize().height - p.y }).p); } mapbox::geometry::box<double> box = mapbox::geometry::envelope(queryGeometry); auto sortRenderTiles = [](const RenderTile& a, const RenderTile& b) { return a.id.canonical.z != b.id.canonical.z ? a.id.canonical.z < b.id.canonical.z : a.id.canonical.y != b.id.canonical.y ? a.id.canonical.y < b.id.canonical.y : a.id.wrap != b.id.wrap ? a.id.wrap < b.id.wrap : a.id.canonical.x < b.id.canonical.x; }; std::vector<std::reference_wrapper<const RenderTile>> sortedTiles; std::transform(renderTiles.cbegin(), renderTiles.cend(), std::back_inserter(sortedTiles), [](const auto& pair) { return std::ref(pair.second); }); std::sort(sortedTiles.begin(), sortedTiles.end(), sortRenderTiles); for (const auto& renderTileRef : sortedTiles) { const RenderTile& renderTile = renderTileRef.get(); GeometryCoordinate tileSpaceBoundsMin = TileCoordinate::toGeometryCoordinate(renderTile.id, box.min); if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT) { continue; } GeometryCoordinate tileSpaceBoundsMax = TileCoordinate::toGeometryCoordinate(renderTile.id, box.max); if (tileSpaceBoundsMax.x < 0 || tileSpaceBoundsMax.y < 0) { continue; } GeometryCoordinates tileSpaceQueryGeometry; tileSpaceQueryGeometry.reserve(queryGeometry.size()); for (const auto& c : queryGeometry) { tileSpaceQueryGeometry.push_back(TileCoordinate::toGeometryCoordinate(renderTile.id, c)); } renderTile.tile.queryRenderedFeatures(result, tileSpaceQueryGeometry, parameters.transformState, parameters.layerIDs); } return result; }
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; }