void render(mapnik::geometry_type & geom, mapnik::box2d<double> const& extent, std::string const& name) { using path_type = mapnik::coord_transform<mapnik::CoordTransform,mapnik::geometry_type>; using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>; using renderer = agg::renderer_scanline_aa_solid<ren_base>; mapnik::image_32 im(256,256); im.set_background(mapnik::color("white")); mapnik::box2d<double> padded_extent = extent; padded_extent.pad(10); mapnik::CoordTransform tr(im.width(),im.height(),padded_extent,0,0); agg::rendering_buffer buf(im.raw_data(),im.width(),im.height(), im.width() * 4); agg::pixfmt_rgba32_plain pixf(buf); ren_base renb(pixf); renderer ren(renb); ren.color(agg::rgba8(127,127,127,255)); agg::rasterizer_scanline_aa<> ras; mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326")); geom.rewind(0); path_type path(tr,geom,prj_trans); ras.add_path(path); agg::scanline_u8 sl; agg::render_scanlines(ras, sl, ren); mapnik::save_to_file(im,name); geom.rewind(0); }
void render(mapnik::geometry_type const& geom, mapnik::box2d<double> const& extent, std::string const& name) { using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::vertex_adapter>; using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>; using renderer = agg::renderer_scanline_aa_solid<ren_base>; mapnik::vertex_adapter va(geom); mapnik::image_rgba8 im(256,256); mapnik::fill(im, mapnik::color("white")); mapnik::box2d<double> padded_extent = extent; padded_extent.pad(10); mapnik::view_transform tr(im.width(),im.height(),padded_extent,0,0); agg::rendering_buffer buf(im.getBytes(),im.width(),im.height(), im.getRowSize()); agg::pixfmt_rgba32_plain pixf(buf); ren_base renb(pixf); renderer ren(renb); ren.color(agg::rgba8(127,127,127,255)); agg::rasterizer_scanline_aa<> ras; mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326")); path_type path(tr,va,prj_trans); ras.add_path(path); agg::scanline_u8 sl; agg::render_scanlines(ras, sl, ren); mapnik::save_to_file(im,name); }
featureset_ptr Map::query_point(unsigned index, double x, double y) const { if (!current_extent_.valid()) { throw std::runtime_error("query_point: map extent is not intialized, you need to set a valid extent before querying"); } if (!current_extent_.intersects(x,y)) { throw std::runtime_error("query_point: x,y coords do not intersect map extent"); } if (index < layers_.size()) { mapnik::layer const& layer = layers_[index]; mapnik::datasource_ptr ds = layer.datasource(); if (ds) { mapnik::projection dest(srs_); mapnik::projection source(layer.srs()); proj_transform prj_trans(source,dest); double z = 0; if (!prj_trans.equal() && !prj_trans.backward(x,y,z)) { throw std::runtime_error("query_point: could not project x,y into layer srs"); } // calculate default tolerance mapnik::box2d<double> map_ex = current_extent_; if (maximum_extent_) { map_ex.clip(*maximum_extent_); } if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS)) { std::ostringstream s; s << "query_point: could not project map extent '" << map_ex << "' into layer srs for tolerance calculation"; throw std::runtime_error(s.str()); } double tol = (map_ex.maxx() - map_ex.minx()) / width_ * 3; featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y), tol); MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")"; if (fs) { return boost::make_shared<filter_featureset<hit_test_filter> >(fs, hit_test_filter(x,y,tol)); } } } else { std::ostringstream s; s << "Invalid layer index passed to query_point: '" << index << "'"; if (!layers_.empty()) s << " for map with " << layers_.size() << " layers(s)"; else s << " (map has no layers)"; throw std::out_of_range(s.str()); } return featureset_ptr(); }
int main() { mapnik::projection merc("+init=epsg:3857",true); mapnik::proj_transform prj_trans(merc,merc); // no-op unsigned tile_size = 256; mapnik::vector_tile_impl::spherical_mercator merc_tiler(tile_size); double minx,miny,maxx,maxy; merc_tiler.xyz(9664,20435,15,minx,miny,maxx,maxy); mapnik::box2d<double> z15_extent(minx,miny,maxx,maxy); mapnik::view_transform tr(tile_size,tile_size,z15_extent,0,0); std::string geojson_file("./test/data/poly.geojson"); mapnik::util::file input(geojson_file); if (!input.open()) { throw std::runtime_error("failed to open geojson"); } mapnik::geometry::geometry<double> geom; std::string json_string(input.data().get(), input.size()); if (!mapnik::json::from_geojson(json_string, geom)) { throw std::runtime_error("failed to parse geojson"); } mapnik::geometry::correct(geom); unsigned count = 0; unsigned count2 = 0; { mapnik::vector_tile_impl::vector_tile_strategy vs(prj_trans, tr, 16); mapnik::progress_timer __stats__(std::clog, "boost::geometry::transform"); for (unsigned i=0;i<10000;++i) { mapnik::geometry::geometry<std::int64_t> new_geom = mapnik::geometry::transform<std::int64_t>(geom, vs); auto const& poly = mapnik::util::get<mapnik::geometry::multi_polygon<std::int64_t>>(new_geom); count += poly.size(); } } { mapnik::vector_tile_impl::vector_tile_strategy vs(prj_trans, tr, 16); mapnik::progress_timer __stats__(std::clog, "transform_visitor with reserve"); mapnik::vector_tile_impl::transform_visitor transit(vs); for (unsigned i=0;i<10000;++i) { mapnik::geometry::geometry<std::int64_t> new_geom = mapnik::util::apply_visitor(transit,geom); auto const& poly = mapnik::util::get<mapnik::geometry::multi_polygon<std::int64_t>>(new_geom); count2 += poly.size(); } if (count != count2) { std::clog << "tests did not run as expected!\n"; return -1; } } return 0; }
featureset_ptr Map::query_map_point(unsigned index, double x, double y) const { if ( index< layers_.size()) { mapnik::layer const& layer = layers_[index]; CoordTransform tr = view_transform(); tr.backward(&x,&y); try { mapnik::projection dest(srs_); mapnik::projection source(layer.srs()); proj_transform prj_trans(source,dest); double z = 0; prj_trans.backward(x,y,z); double minx = current_extent_.minx(); double miny = current_extent_.miny(); double maxx = current_extent_.maxx(); double maxy = current_extent_.maxy(); prj_trans.backward(minx,miny,z); prj_trans.backward(maxx,maxy,z); double tol = (maxx - minx) / width_ * 3; mapnik::datasource_ptr ds = layer.datasource(); if (ds) { #ifdef MAPNIK_DEBUG std::clog << " query at point tol = " << tol << " (" << x << "," << y << ")\n"; #endif featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y)); if (fs) return boost::make_shared<filter_featureset<hit_test_filter> >(fs, hit_test_filter(x,y,tol)); } } catch (...) { #ifdef MAPNIK_DEBUG std::clog << "exception caught in \"query_map_point\"\n"; #endif } } return featureset_ptr(); }
void Map::zoom_all() { try { if (layers_.empty()) { return; } projection proj0(srs_); box2d<double> ext; bool success = false; bool first = true; std::vector<layer>::const_iterator itr = layers_.begin(); std::vector<layer>::const_iterator end = layers_.end(); while (itr != end) { if (itr->active()) { std::string const& layer_srs = itr->srs(); projection proj1(layer_srs); proj_transform prj_trans(proj0,proj1); box2d<double> layer_ext = itr->envelope(); if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS)) { success = true; MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " original ext=" << itr->envelope(); MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " transformed to map srs=" << layer_ext; if (first) { ext = layer_ext; first = false; } else { ext.expand_to_include(layer_ext); } } } ++itr; } if (success) { if (maximum_extent_) { ext.clip(*maximum_extent_); } zoom_to_box(ext); } else { if (maximum_extent_) { MAPNIK_LOG_ERROR(map) << "could not zoom to combined layer extents" << " so falling back to maximum-extent for zoom_all result"; zoom_to_box(*maximum_extent_); } else { std::ostringstream s; s << "could not zoom to combined layer extents " << "using zoom_all because proj4 could not " << "back project any layer extents into the map srs " << "(set map 'maximum-extent' to override layer extents)"; throw std::runtime_error(s.str()); } } } catch (proj_init_error const& ex) { throw mapnik::config_error(std::string("Projection error during map.zoom_all: ") + ex.what()); } }
void Map::zoom_all() { if (maximum_extent_) { zoom_to_box(*maximum_extent_); } else { try { if (!layers_.size() > 0) return; projection proj0(srs_); box2d<double> ext; bool success = false; bool first = true; std::vector<layer>::const_iterator itr = layers_.begin(); std::vector<layer>::const_iterator end = layers_.end(); while (itr != end) { if (itr->isActive()) { std::string const& layer_srs = itr->srs(); projection proj1(layer_srs); proj_transform prj_trans(proj0,proj1); box2d<double> layer_ext = itr->envelope(); // TODO - consider using more robust method: http://trac.mapnik.org/ticket/751 if (prj_trans.backward(layer_ext)) { success = true; #ifdef MAPNIK_DEBUG std::clog << " layer " << itr->name() << " original ext: " << itr->envelope() << "\n"; std::clog << " layer " << itr->name() << " transformed to map srs: " << layer_ext << "\n"; #endif if (first) { ext = layer_ext; first = false; } else { ext.expand_to_include(layer_ext); } } } ++itr; } if (success) { zoom_to_box(ext); } else { std::ostringstream s; s << "could not zoom to combined layer extents " << "using zoom_all because proj4 could not " << "back project any layer extents into the map srs " << "(set map 'maximum-extent' to override layer extents)"; throw std::runtime_error(s.str()); } } catch (proj_init_error & ex) { std::clog << "proj_init_error:" << ex.what() << "\n"; } } }
void feature_style_processor<Processor>::render_material(layer_rendering_material const & mat, Processor & p) { std::vector<feature_type_style const*> const & active_styles = mat.active_styles_; std::vector<featureset_ptr> const & featureset_ptr_list = mat.featureset_ptr_list_; if (featureset_ptr_list.empty()) { // The datasource wasn't queried because of early return // but we have to apply compositing operations on styles for (feature_type_style const* style : active_styles) { p.start_style_processing(*style); p.end_style_processing(*style); } return; } layer const& lay = mat.lay_; std::vector<rule_cache> const & rule_caches = mat.rule_caches_; proj_transform prj_trans(mat.proj0_,mat.proj1_); bool cache_features = lay.cache_features() && active_styles.size() > 1; datasource_ptr ds = lay.datasource(); std::string group_by = lay.group_by(); // Render incrementally when the column that we group by changes value. if (!group_by.empty()) { featureset_ptr features = *featureset_ptr_list.begin(); if (features) { // Cache all features into the memory_datasource before rendering. std::shared_ptr<featureset_buffer> cache = std::make_shared<featureset_buffer>(); feature_ptr feature, prev; while ((feature = features->next())) { if (prev && prev->get(group_by) != feature->get(group_by)) { // We're at a value boundary, so render what we have // up to this point. std::size_t i = 0; for (feature_type_style const* style : active_styles) { cache->prepare(); render_style(p, style, rule_caches[i], cache, prj_trans); ++i; } cache->clear(); } cache->push(feature); prev = feature; } std::size_t i = 0; for (feature_type_style const* style : active_styles) { cache->prepare(); render_style(p, style, rule_caches[i], cache, prj_trans); ++i; } cache->clear(); } } else if (cache_features) { std::shared_ptr<featureset_buffer> cache = std::make_shared<featureset_buffer>(); featureset_ptr features = *featureset_ptr_list.begin(); if (features) { // Cache all features into the memory_datasource before rendering. feature_ptr feature; while ((feature = features->next())) { cache->push(feature); } } std::size_t i = 0; for (feature_type_style const* style : active_styles) { cache->prepare(); render_style(p, style, rule_caches[i], cache, prj_trans); ++i; } } // We only have a single style and no grouping. else { std::size_t i = 0; std::vector<featureset_ptr>::const_iterator featuresets = featureset_ptr_list.cbegin(); for (feature_type_style const* style : active_styles) { featureset_ptr features = *featuresets++; render_style(p, style, rule_caches[i], features, prj_trans); ++i; } } }
void feature_style_processor<Processor>::prepare_layer(layer_rendering_material & mat, feature_style_context_map & ctx_map, Processor & p, double scale, double scale_denom, unsigned width, unsigned height, box2d<double> const& extent, int buffer_size, std::set<std::string>& names) { layer const& lay = mat.lay_; std::vector<std::string> const& style_names = lay.styles(); std::size_t num_styles = style_names.size(); if (num_styles == 0) { MAPNIK_LOG_DEBUG(feature_style_processor) << "feature_style_processor: No style for layer=" << lay.name(); return; } mapnik::datasource_ptr ds = lay.datasource(); if (!ds) { MAPNIK_LOG_DEBUG(feature_style_processor) << "feature_style_processor: No datasource for layer=" << lay.name(); return; } processor_context_ptr current_ctx = ds->get_context(ctx_map); proj_transform prj_trans(mat.proj0_,mat.proj1_); box2d<double> query_ext = extent; // unbuffered box2d<double> buffered_query_ext(query_ext); // buffered double buffer_padding = 2.0 * scale; boost::optional<int> layer_buffer_size = lay.buffer_size(); if (layer_buffer_size) // if layer overrides buffer size, use this value to compute buffered extent { buffer_padding *= *layer_buffer_size; } else { buffer_padding *= buffer_size; } buffered_query_ext.width(query_ext.width() + buffer_padding); buffered_query_ext.height(query_ext.height() + buffer_padding); // clip buffered extent by maximum extent, if supplied boost::optional<box2d<double> > const& maximum_extent = m_.maximum_extent(); if (maximum_extent) { buffered_query_ext.clip(*maximum_extent); } box2d<double> layer_ext = lay.envelope(); const box2d<double> buffered_query_ext_map_srs = buffered_query_ext; bool fw_success = false; bool early_return = false; // first, try intersection of map extent forward projected into layer srs if (prj_trans.forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext)) { fw_success = true; layer_ext.clip(buffered_query_ext); } // if no intersection and projections are also equal, early return else if (prj_trans.equal()) { early_return = true; } // next try intersection of layer extent back projected into map srs else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext_map_srs.intersects(layer_ext)) { layer_ext.clip(buffered_query_ext_map_srs); // forward project layer extent back into native projection if (! prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS)) { MAPNIK_LOG_ERROR(feature_style_processor) << "feature_style_processor: Layer=" << lay.name() << " extent=" << layer_ext << " in map projection " << " did not reproject properly back to layer projection"; } } else { // if no intersection then nothing to do for layer early_return = true; } std::vector<feature_type_style const*> & active_styles = mat.active_styles_; if (early_return) { // check for styles needing compositing operations applied // https://github.com/mapnik/mapnik/issues/1477 for (std::string const& style_name : style_names) { boost::optional<feature_type_style const&> style=m_.find_style(style_name); if (!style) { continue; } if (style->comp_op() || style->image_filters().size() > 0) { if (style->active(scale_denom)) { // we'll have to handle compositing ops active_styles.push_back(&(*style)); } } } return; } // if we've got this far, now prepare the unbuffered extent // which is used as a bbox for clipping geometries if (maximum_extent) { query_ext.clip(*maximum_extent); } box2d<double> & layer_ext2 = mat.layer_ext2_; layer_ext2 = lay.envelope(); if (fw_success) { if (prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS)) { layer_ext2.clip(query_ext); } } else { if (prj_trans.backward(layer_ext2, PROJ_ENVELOPE_POINTS)) { layer_ext2.clip(query_ext); prj_trans.forward(layer_ext2, PROJ_ENVELOPE_POINTS); } } std::vector<rule_cache> & rule_caches = mat.rule_caches_; attribute_collector collector(names); // iterate through all named styles collecting active styles and attribute names for (std::string const& style_name : style_names) { boost::optional<feature_type_style const&> style=m_.find_style(style_name); if (!style) { MAPNIK_LOG_ERROR(feature_style_processor) << "feature_style_processor: Style=" << style_name << " required for layer=" << lay.name() << " does not exist."; continue; } std::vector<rule> const& style_rules = style->get_rules(); bool active_rules = false; rule_cache rc; for(rule const& r : style_rules) { if (r.active(scale_denom)) { rc.add_rule(r); active_rules = true; collector(r); } } if (active_rules) { rule_caches.push_back(std::move(rc)); active_styles.push_back(&(*style)); } } // Don't even try to do more work if there are no active styles. if (active_styles.empty()) { return; } double qw = query_ext.width()>0 ? query_ext.width() : 1; double qh = query_ext.height()>0 ? query_ext.height() : 1; query::resolution_type res(width/qw, height/qh); query q(layer_ext,res,scale_denom,extent); q.set_variables(p.variables()); if (p.attribute_collection_policy() == COLLECT_ALL) { layer_descriptor lay_desc = ds->get_descriptor(); for (attribute_descriptor const& desc : lay_desc.get_descriptors()) { q.add_property_name(desc.get_name()); } } else { for (std::string const& name : names) { q.add_property_name(name); } } q.set_filter_factor(collector.get_filter_factor()); // Also query the group by attribute std::string const& group_by = lay.group_by(); if (!group_by.empty()) { q.add_property_name(group_by); } bool cache_features = lay.cache_features() && active_styles.size() > 1; std::vector<featureset_ptr> & featureset_ptr_list = mat.featureset_ptr_list_; if (!group_by.empty() || cache_features) { featureset_ptr_list.push_back(ds->features_with_context(q,current_ctx)); } else { for(std::size_t i = 0; i < active_styles.size(); ++i) { featureset_ptr_list.push_back(ds->features_with_context(q,current_ctx)); } } }