void grid_renderer<T>::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature); boost::optional<marker_ptr> mark = marker_cache::instance().find(filename,true); if (!mark) return; if (!(*mark)->is_bitmap()) { MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; return; } boost::optional<image_ptr> pat = (*mark)->get_bitmap_data(); if (!pat) return; ras_ptr->reset(); agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_transform()); typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types; vertex_converter<box2d<double>, grid_rasterizer, polygon_pattern_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true) converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter for ( geometry_type & geom : feature.paths()) { if (geom.size() > 2) { converter.apply(geom); } } typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type; typedef typename grid_renderer_base_type::pixfmt_type::color_type color_type; typedef agg::renderer_scanline_bin_solid<grid_renderer_base_type> renderer_type; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); pixfmt_type pixf(buf); grid_renderer_base_type renb(pixf); renderer_type ren(renb); // render id ren.color(color_type(feature.id())); agg::scanline_bin sl; ras_ptr->filling_rule(agg::fill_even_odd); agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache pixmap_.add_feature(feature); }
void agg_renderer<T0,T1>::process(debug_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { debug_symbolizer_mode_enum mode = get<debug_symbolizer_mode_enum>(sym, keys::mode, feature, common_.vars_, DEBUG_SYM_MODE_COLLISION); ras_ptr->reset(); if (gamma_method_ != GAMMA_POWER || gamma_ != 1.0) { ras_ptr->gamma(agg::gamma_power()); gamma_method_ = GAMMA_POWER; gamma_ = 1.0; } if (mode == DEBUG_SYM_MODE_RINGS) { RingRenderer<buffer_type> renderer(*ras_ptr,*current_buffer_,common_.t_,prj_trans); render_ring_visitor<buffer_type> apply(renderer); mapnik::util::apply_visitor(apply,feature.get_geometry()); } else if (mode == DEBUG_SYM_MODE_COLLISION) { for (auto const& n : *common_.detector_) { draw_rect(pixmap_, n.get().box); } } else if (mode == DEBUG_SYM_MODE_VERTEX) { using apply_vertex_mode = apply_vertex_mode<buffer_type>; apply_vertex_mode apply(pixmap_, common_.t_, prj_trans); util::apply_visitor(geometry::vertex_processor<apply_vertex_mode>(apply), feature.get_geometry()); } }
void start_tile_feature(mapnik::feature_impl const& feature) { current_feature_ = current_layer_->add_features(); x_ = y_ = 0; // TODO - encode as sint64: (n << 1) ^ ( n >> 63) // test current behavior with negative numbers 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 = MAPNIK_GET<0>(*itr); mapnik::value const& val = MAPNIK_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()); #if MAPNIK_VERSION >= 300000 MAPNIK_APPLY_VISITOR(visitor, val); #else MAPNIK_APPLY_VISITOR(visitor, val.base()); #endif 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 grid_renderer<T>::process(building_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; using color_type = typename grid_renderer_base_type::pixfmt_type::color_type; using renderer_type = agg::renderer_scanline_bin_solid<grid_renderer_base_type>; using transform_path_type = transform_path_adapter<view_transform, vertex_adapter>; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_); pixfmt_type pixf(buf); grid_renderer_base_type renb(pixf); renderer_type ren(renb); ras_ptr->reset(); double height = get<value_double>(sym, keys::height, feature, common_.vars_, 0.0); render_building_symbolizer( feature, height, [&](path_type const& faces) { vertex_adapter va(faces); transform_path_type faces_path (common_.t_,va,prj_trans); ras_ptr->add_path(faces_path); ren.color(color_type(feature.id())); agg::render_scanlines(*ras_ptr, sl, ren); ras_ptr->reset(); }, [&](path_type const& frame) { vertex_adapter va(frame); transform_path_type path(common_.t_,va,prj_trans); agg::conv_stroke<transform_path_type> stroke(path); ras_ptr->add_path(stroke); ren.color(color_type(feature.id())); agg::render_scanlines(*ras_ptr, sl, ren); ras_ptr->reset(); }, [&](path_type const& roof) { vertex_adapter va(roof); transform_path_type roof_path (common_.t_,va,prj_trans); ras_ptr->add_path(roof_path); ren.color(color_type(feature.id())); agg::render_scanlines(*ras_ptr, sl, ren); }); pixmap_.add_feature(feature); }
void grid_renderer<T>::process(polygon_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { typedef agg::renderer_scanline_bin_solid<grid_renderer_base_type> renderer_type; typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type; typedef typename grid_renderer_base_type::pixfmt_type::color_type color_type; ras_ptr->reset(); agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_transform(), scale_factor_); typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types; vertex_converter<box2d<double>, grid_rasterizer, polygon_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true) converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter for ( geometry_type & geom : feature.paths()) { if (geom.size() > 2) { converter.apply(geom); } } grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); pixfmt_type pixf(buf); grid_renderer_base_type renb(pixf); renderer_type ren(renb); // render id ren.color(color_type(feature.id())); agg::scanline_bin sl; ras_ptr->filling_rule(agg::fill_even_odd); agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache pixmap_.add_feature(feature); }
void cairo_renderer<T>::process(debug_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { cairo_save_restore guard(context_); debug_symbolizer_mode_enum mode = get<debug_symbolizer_mode_enum>(sym, keys::mode, feature, common_.vars_, DEBUG_SYM_MODE_COLLISION); context_.set_operator(src_over); context_.set_color(mapnik::color(255, 0, 0), 1.0); context_.set_line_join(MITER_JOIN); context_.set_line_cap(BUTT_CAP); context_.set_miter_limit(4.0); context_.set_line_width(1.0); if (mode == DEBUG_SYM_MODE_COLLISION) { for (auto & n : *common_.detector_) { render_debug_box(context_, n.get().box); } } else if (mode == DEBUG_SYM_MODE_VERTEX) { using apply_vertex_mode = apply_vertex_mode<cairo_context>; apply_vertex_mode apply(context_, common_.t_, prj_trans); util::apply_visitor(geometry::vertex_processor<apply_vertex_mode>(apply), feature.get_geometry()); } }
void grid_renderer<T>::process(text_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { text_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4> helper( sym, feature, prj_trans, width_, height_, scale_factor_ * (1.0/pixmap_.get_resolution()), t_, font_manager_, *detector_, query_extent_); bool placement_found = false; text_renderer<T> ren(pixmap_, font_manager_, sym.get_halo_rasterizer(), sym.comp_op(), scale_factor_); while (helper.next()) { placement_found = true; placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { ren.prepare_glyphs(placements[ii]); ren.render_id(feature.id(), placements[ii].center); } } if (placement_found) pixmap_.add_feature(feature); }
void render_raster_marker(RendererType ren, RasterizerType & ras, image_data_rgba8 & src, mapnik::feature_impl const& feature, agg::trans_affine const& marker_tr, double opacity) { using color_type = typename RendererType::color_type; agg::scanline_bin sl; double width = src.width(); double height = src.height(); double p[8]; p[0] = 0; p[1] = 0; p[2] = width; p[3] = 0; p[4] = width; p[5] = height; p[6] = 0; p[7] = height; marker_tr.transform(&p[0], &p[1]); marker_tr.transform(&p[2], &p[3]); marker_tr.transform(&p[4], &p[5]); marker_tr.transform(&p[6], &p[7]); ras.move_to_d(p[0],p[1]); ras.line_to_d(p[2],p[3]); ras.line_to_d(p[4],p[5]); ras.line_to_d(p[6],p[7]); ren.color(color_type(feature.id())); agg::render_scanlines(ras, sl, ren); }
void grid_renderer<T>::process(text_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { agg::trans_affine tr; auto transform = get_optional<transform_type>(sym, keys::geometry_transform); if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); text_symbolizer_helper helper( sym, feature, common_.vars_, prj_trans, common_.width_, common_.height_, common_.scale_factor_ * (1.0/pixmap_.get_resolution()), common_.t_, common_.font_manager_, *common_.detector_, common_.query_extent_, tr); bool placement_found = false; composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature, common_.vars_, src_over); grid_text_renderer<T> ren(pixmap_, comp_op, common_.scale_factor_); placements_list const& placements = helper.get(); value_integer feature_id = feature.id(); for (glyph_positions_ptr glyphs : placements) { ren.render(*glyphs, feature_id); placement_found = true; } if (placement_found) { pixmap_.add_feature(feature); } }
void agg_renderer<T>::process(raster_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { raster_ptr const& source = feature.get_raster(); if (source) { // If there's a colorizer defined, use it to color the raster in-place raster_colorizer_ptr colorizer = sym.get_colorizer(); if (colorizer) colorizer->colorize(source,feature); box2d<double> target_ext = box2d<double>(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); box2d<double> ext = t_.forward(target_ext); int start_x = static_cast<int>(ext.minx()); int start_y = static_cast<int>(ext.miny()); int end_x = static_cast<int>(ceil(ext.maxx())); int end_y = static_cast<int>(ceil(ext.maxy())); int raster_width = end_x - start_x; int raster_height = end_y - start_y; if (raster_width > 0 && raster_height > 0) { image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); scaling_method_e scaling_method = sym.get_scaling_method(); double filter_radius = sym.calculate_filter_factor(); double offset_x = ext.minx() - start_x; double offset_y = ext.miny() - start_y; if (!prj_trans.equal()) { reproject_and_scale_raster(target, *source, prj_trans, offset_x, offset_y, sym.get_mesh_size(), filter_radius, scaling_method); } else { if (scaling_method == SCALING_BILINEAR8){ scale_image_bilinear8<image_data_32>(target.data_,source->data_, offset_x, offset_y); } else { double scaling_ratio = ext.width() / source->data_.width(); scale_image_agg<image_data_32>(target.data_, source->data_, scaling_method, scaling_ratio, offset_x, offset_y, filter_radius); } } composite(current_buffer_->data(), target.data_, sym.comp_op(), sym.get_opacity(), start_x, start_y, true); } } }
void agg_renderer<T0,T1>::process(dot_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { double width = 0.0; double height = 0.0; bool has_width = has_key(sym,keys::width); bool has_height = has_key(sym,keys::height); if (has_width && has_height) { width = get<double>(sym, keys::width, feature, common_.vars_, 0.0); height = get<double>(sym, keys::height, feature, common_.vars_, 0.0); } else if (has_width) { width = height = get<double>(sym, keys::width, feature, common_.vars_, 0.0); } else if (has_height) { width = height = get<double>(sym, keys::height, feature, common_.vars_, 0.0); } double rx = width/2.0; double ry = height/2.0; double opacity = get<double>(sym, keys::opacity, feature, common_.vars_, 1.0); color const& fill = get<mapnik::color>(sym, keys::fill, feature, common_.vars_, mapnik::color(128,128,128)); ras_ptr->reset(); agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(),current_buffer_->width() * 4); using blender_type = agg::comp_op_adaptor_rgba_pre<agg::rgba8, agg::order_rgba>; using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>; using renderer_base = agg::renderer_base<pixfmt_comp_type>; using renderer_type = agg::renderer_scanline_aa_solid<renderer_base>; pixfmt_comp_type pixf(buf); pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e>(sym, keys::comp_op, feature, common_.vars_, src_over))); renderer_base renb(pixf); renderer_type ren(renb); agg::scanline_u8 sl; ren.color(agg::rgba8_pre(fill.red(), fill.green(), fill.blue(), int(fill.alpha() * opacity))); agg::ellipse el(0,0,rx,ry); unsigned num_steps = el.num_steps(); for (geometry_type const& geom : feature.paths()) { double x,y,z = 0; unsigned cmd = 1; geom.rewind(0); while ((cmd = geom.vertex(&x, &y)) != mapnik::SEG_END) { if (cmd == SEG_CLOSE) continue; prj_trans.backward(x,y,z); common_.t_.forward(&x,&y); el.init(x,y,rx,ry,num_steps); ras_ptr->add_path(el); agg::render_scanlines(*ras_ptr, sl, ren); } } }
void hit_grid<T>::add_feature(mapnik::feature_impl const& feature) { value_type feature_id = feature.id(); // avoid adding duplicate features (e.g. in the case of both a line symbolizer and a polygon symbolizer) typename feature_key_type::const_iterator feature_pos = f_keys_.find(feature_id); if (feature_pos != f_keys_.end()) { return; } if (ctx_->size() == 0) { context_type::map_type::const_iterator itr = feature.context()->begin(); context_type::map_type::const_iterator end = feature.context()->end(); for ( ;itr!=end; ++itr) { ctx_->add(itr->first,itr->second); } } // NOTE: currently lookup keys must be strings, // but this should be revisited lookup_type lookup_value; if (key_ == id_name_) { mapnik::util::to_string(lookup_value,feature_id); } else { if (feature.has_key(key_)) { lookup_value = feature.get(key_).to_string(); } else { MAPNIK_LOG_DEBUG(grid) << "hit_grid: Should not get here: key '" << key_ << "' not found in feature properties"; } } if (!lookup_value.empty()) { // TODO - consider shortcutting f_keys if feature_id == lookup_value // create a mapping between the pixel id and the feature key f_keys_.emplace(feature_id,lookup_value); // if extra fields have been supplied, push them into grid memory if (!names_.empty()) { // it is ~ 2x faster to copy feature attributes compared // to building up a in-memory cache of feature_ptrs // https://github.com/mapnik/mapnik/issues/1198 mapnik::feature_ptr feature2(mapnik::feature_factory::create(ctx_,feature_id)); feature2->set_data(feature.get_data()); features_.emplace(lookup_value,feature2); } } else { MAPNIK_LOG_DEBUG(grid) << "hit_grid: Warning - key '" << key_ << "' was blank for " << feature; } }
bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms, mapnik::feature_impl & feature, proj_transform const& prj_trans) { // svg renderer supports processing of multiple symbolizers. typedef coord_transform<CoordTransform, geometry_type> path_type; bool process_path = false; // process each symbolizer to collect its (path) information. // path information (attributes from line_ and polygon_ symbolizers) // is collected with the path_attributes_ data member. for (symbolizer const& sym : syms) { if (is_path_based(sym)) { process_path = true; } boost::apply_visitor(symbol_dispatch(*this, feature, prj_trans), sym); } if (process_path) { // generate path output for each geometry of the current feature. for(std::size_t i=0; i<feature.num_geometries(); ++i) { geometry_type & geom = feature.get_geometry(i); if(geom.size() > 0) { path_type path(t_, geom, prj_trans); generator_.generate_path(path, path_attributes_); } } // set the previously collected values back to their defaults // for the feature that will be processed next. path_attributes_.reset(); } return true; }
void grid_renderer<T>::process(shield_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { shield_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4> helper( sym, feature, prj_trans, width_, height_, scale_factor_, t_, font_manager_, *detector_, query_extent_); bool placement_found = false; text_renderer<T> ren(pixmap_, font_manager_, sym.get_halo_rasterizer(), sym.comp_op(), scale_factor_); text_placement_info_ptr placement; while (helper.next()) { placement_found = true; placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { // get_marker_position returns (minx,miny) corner position, // while (currently only) agg_renderer::render_marker newly // expects center position; // until all renderers and shield_symbolizer_helper are // modified accordingly, we must adjust the position here pixel_position pos = helper.get_marker_position(placements[ii]); pos.x += 0.5 * helper.get_marker_width(); pos.y += 0.5 * helper.get_marker_height(); render_marker(feature, pixmap_.get_resolution(), pos, helper.get_marker(), helper.get_image_transform(), sym.get_opacity(), sym.comp_op()); ren.prepare_glyphs(placements[ii]); ren.render_id(feature.id(), placements[ii].center); } } if (placement_found) pixmap_.add_feature(feature); }
void cairo_renderer<T>::process(debug_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { using detector_type = label_collision_detector4; cairo_save_restore guard(context_); debug_symbolizer_mode_enum mode = get<debug_symbolizer_mode_enum>(sym, keys::mode, feature, common_.vars_, DEBUG_SYM_MODE_COLLISION); context_.set_operator(src_over); context_.set_color(mapnik::color(255, 0, 0), 1.0); context_.set_line_join(MITER_JOIN); context_.set_line_cap(BUTT_CAP); context_.set_miter_limit(4.0); context_.set_line_width(1.0); if (mode == DEBUG_SYM_MODE_COLLISION) { typename detector_type::query_iterator itr = common_.detector_->begin(); typename detector_type::query_iterator end = common_.detector_->end(); for ( ;itr!=end; ++itr) { render_debug_box(context_, itr->box); } } else if (mode == DEBUG_SYM_MODE_VERTEX) { for (auto const& geom : feature.paths()) { double x; double y; double z = 0; geom.rewind(0); unsigned cmd = 1; while ((cmd = geom.vertex(&x, &y)) != mapnik::SEG_END) { if (cmd == SEG_CLOSE) continue; prj_trans.backward(x,y,z); common_.t_.forward(&x,&y); context_.move_to(std::floor(x) - 0.5, std::floor(y) + 0.5); context_.line_to(std::floor(x) + 1.5, std::floor(y) + 0.5); context_.move_to(std::floor(x) + 0.5, std::floor(y) - 0.5); context_.line_to(std::floor(x) + 0.5, std::floor(y) + 1.5); context_.stroke(); } } } }
void grid_renderer<T>::process(shield_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { agg::trans_affine tr; auto transform = get_optional<transform_type>(sym, keys::geometry_transform); if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); text_symbolizer_helper helper( sym, feature, common_.vars_, prj_trans, common_.width_, common_.height_, common_.scale_factor_, common_.t_, common_.font_manager_, *common_.detector_, common_.query_extent_, tr); bool placement_found = false; composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature, common_.vars_, src_over); double opacity = get<double>(sym, keys::opacity, feature, common_.vars_, 1.0); grid_text_renderer<T> ren(pixmap_, comp_op, common_.scale_factor_); placements_list const& placements = helper.get(); value_integer feature_id = feature.id(); for (auto const& glyphs : placements) { marker_info_ptr mark = glyphs->get_marker(); if (mark) { render_marker(feature, glyphs->marker_pos(), *mark->marker_, mark->transform_, opacity, comp_op); } ren.render(*glyphs, feature_id); placement_found = true; } if (placement_found) { pixmap_.add_feature(feature); } }
void grid_renderer<T>::process(text_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { box2d<double> clip_box = clipping_extent(common_); agg::trans_affine tr; auto transform = get_optional<transform_type>(sym, keys::geometry_transform); if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); text_symbolizer_helper helper( sym, feature, common_.vars_, prj_trans, common_.width_, common_.height_, common_.scale_factor_, common_.t_, common_.font_manager_, *common_.detector_, clip_box, tr, common_.symbol_cache_); bool placement_found = false; composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature, common_.vars_, src_over); grid_text_renderer<T> ren(pixmap_, comp_op, common_.scale_factor_); auto halo_transform = get_optional<transform_type>(sym, keys::halo_transform); if (halo_transform) { agg::trans_affine halo_affine_transform; evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform, common_.scale_factor_); ren.set_halo_transform(halo_affine_transform); } placements_list const& placements = helper.get(); value_integer feature_id = feature.id(); for (auto const& glyphs : placements) { ren.render(*glyphs, feature_id); placement_found = true; } if (placement_found) { pixmap_.add_feature(feature); } }
void render_building_symbolizer(mapnik::feature_impl const& feature, double height, F1 face_func, F2 frame_func, F3 roof_func) { auto const& geom = feature.get_geometry(); if (geom.is<geometry::polygon<double> >()) { auto const& poly = geom.get<geometry::polygon<double> >(); detail::make_building(poly, height, face_func, frame_func, roof_func); } else if (geom.is<geometry::multi_polygon<double> >()) { auto const& multi_poly = geom.get<geometry::multi_polygon<double> >(); for (auto const& poly : multi_poly) { detail::make_building(poly, height, face_func, frame_func, roof_func); } } }
void grid_renderer<T>::process(shield_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { text_symbolizer_helper helper( sym, feature, common_.vars_, prj_trans, common_.width_, common_.height_, common_.scale_factor_, common_.t_, common_.font_manager_, *common_.detector_, common_.query_extent_); bool placement_found = false; composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature, common_.vars_, src_over); double opacity = get<double>(sym, keys::opacity, feature, common_.vars_, 1.0); grid_text_renderer<T> ren(pixmap_, comp_op, common_.scale_factor_); placements_list const& placements = helper.get(); value_integer feature_id = feature.id(); for (glyph_positions_ptr glyphs : placements) { if (glyphs->marker()) { render_marker(feature, pixmap_.get_resolution(), glyphs->marker_pos(), *(glyphs->marker()->marker), glyphs->marker()->transform, opacity, comp_op); } ren.render(*glyphs, feature_id); placement_found = true; } if (placement_found) { pixmap_.add_feature(feature); } }
void grid_renderer<T>::process(polygon_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { using renderer_type = agg::renderer_scanline_bin_solid<grid_renderer_base_type>; using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; using color_type = typename grid_renderer_base_type::pixfmt_type::color_type; using vertex_converter_type = vertex_converter<transform2_tag, clip_poly_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag, contour_tag>; ras_ptr->reset(); grid_rendering_buffer buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_); render_polygon_symbolizer<vertex_converter_type>( sym, feature, prj_trans, common_, common_.query_extent_, *ras_ptr, [&](color const &, double) { pixfmt_type pixf(buf); grid_renderer_base_type renb(pixf); renderer_type ren(renb); // render id ren.color(color_type(feature.id())); agg::scanline_bin sl; ras_ptr->filling_rule(agg::fill_non_zero); agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache pixmap_.add_feature(feature); }); }
bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms, mapnik::feature_impl & feature, proj_transform const& prj_trans) { // svg renderer supports processing of multiple symbolizers. using path_type = transform_path_adapter<view_transform, geometry_type>; bool process_path = false; // process each symbolizer to collect its (path) information. // path information (attributes from line_ and polygon_ symbolizers) // is collected with the path_attributes_ data member. for (auto const& sym : syms) { if (is_path_based(sym)) { process_path = true; } util::apply_visitor(symbolizer_dispatch<svg_renderer<OutputIterator>>(*this, feature, prj_trans), sym); } if (process_path) { // generate path output for each geometry of the current feature. for (auto & geom : feature.paths()) { if(geom.size() > 0) { path_type path(common_.t_, geom, prj_trans); generate_path(generator_.output_iterator_, path, path_attributes_); } } // set the previously collected values back to their defaults // for the feature that will be processed next. path_attributes_.reset(); } return true; }
void cairo_renderer<T>::process(line_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { composite_mode_e comp_op = get<composite_mode_e, keys::comp_op>(sym, feature, common_.vars_); value_bool clip = get<value_bool, keys::clip>(sym, feature, common_.vars_); value_double offset = get<value_double, keys::offset>(sym, feature, common_.vars_); value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym, feature, common_.vars_); value_double smooth = get<value_double, keys::smooth>(sym, feature, common_.vars_); color stroke = get<color, keys::stroke>(sym, feature, common_.vars_); value_double stroke_opacity = get<value_double, keys::stroke_opacity>(sym, feature, common_.vars_); line_join_enum stroke_join = get<line_join_enum, keys::stroke_linejoin>(sym, feature, common_.vars_); line_cap_enum stroke_cap = get<line_cap_enum, keys::stroke_linecap>(sym, feature, common_.vars_); value_double miterlimit = get<value_double, keys::stroke_miterlimit>(sym, feature, common_.vars_); value_double width = get<value_double, keys::stroke_width>(sym, feature, common_.vars_); auto dash = get_optional<dash_array>(sym, keys::stroke_dasharray, feature, common_.vars_); cairo_save_restore guard(context_); context_.set_operator(comp_op); context_.set_color(stroke, stroke_opacity); context_.set_line_join(stroke_join); context_.set_line_cap(stroke_cap); context_.set_miter_limit(miterlimit); context_.set_line_width(width * common_.scale_factor_); if (dash) { context_.set_dash(*dash, common_.scale_factor_); } agg::trans_affine tr; auto geom_transform = get_optional<transform_type>(sym, keys::geometry_transform); if (geom_transform) { evaluate_transform(tr, feature, common_.vars_, *geom_transform, common_.scale_factor_); } box2d<double> clipping_extent = common_.query_extent_; if (clip) { double padding = (double)(common_.query_extent_.width()/common_.width_); double half_stroke = width/2.0; if (half_stroke > 1) padding *= half_stroke; if (std::fabs(offset) > 0) padding *= std::fabs(offset) * 1.2; padding *= common_.scale_factor_; clipping_extent.pad(padding); } using vertex_converter_type = vertex_converter<clip_line_tag, clip_poly_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag, offset_transform_tag>; vertex_converter_type converter(clipping_extent,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); if (clip) { geometry::geometry_types type = geometry::geometry_type(feature.get_geometry()); if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) converter.template set<clip_poly_tag>(); else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) converter.template set<clip_line_tag>(); } converter.set<transform_tag>(); // always transform if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type, cairo_context>; using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>; apply_vertex_converter_type apply(converter, context_); mapnik::util::apply_visitor(vertex_processor_type(apply),feature.get_geometry()); // stroke context_.set_fill_rule(CAIRO_FILL_RULE_WINDING); context_.stroke(); }
void grid_renderer<T>::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { typedef grid_rendering_buffer buf_type; typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type; typedef typename grid_renderer_base_type::pixfmt_type::color_type color_type; typedef agg::renderer_scanline_bin_solid<grid_renderer_base_type> renderer_type; typedef label_collision_detector4 detector_type; typedef boost::mpl::vector<clip_line_tag,clip_poly_tag,transform_tag,smooth_tag> conv_types; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); if (!filename.empty()) { boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true); if (mark && *mark) { ras_ptr->reset(); agg::trans_affine geom_tr; evaluate_transform(geom_tr, feature, sym.get_transform()); agg::trans_affine tr = agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution())); if ((*mark)->is_vector()) { using namespace mapnik::svg; typedef agg::pod_bvector<path_attributes> svg_attribute_type; typedef svg_renderer_agg<svg_path_adapter, svg_attribute_type, renderer_type, pixfmt_type > svg_renderer_type; typedef vector_markers_rasterizer_dispatch_grid<buf_type, svg_renderer_type, grid_rasterizer, detector_type, mapnik::grid > dispatch_type; boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data(); expression_ptr const& width_expr = sym.get_width(); expression_ptr const& height_expr = sym.get_height(); // special case for simple ellipse markers // to allow for full control over rx/ry dimensions if (filename == "shape://ellipse" && (width_expr || height_expr)) { svg_storage_type marker_ellipse; vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse.source()); svg_path_adapter svg_path(stl_storage); // TODO - clamping to >= 4 pixels build_ellipse(sym, feature, marker_ellipse, svg_path); svg_attribute_type attributes; bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); evaluate_transform(tr, feature, sym.get_image_transform()); box2d<double> bbox = marker_ellipse.bounding_box(); coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; buf_type render_buf(pixmap_.raw_data(), width_, height_, width_); dispatch_type rasterizer_dispatch(render_buf, svg_renderer, *ras_ptr, bbox, marker_trans, sym, *detector_, scale_factor_, feature, pixmap_); vertex_converter<box2d<double>, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) { eGeomType type = feature.paths()[0].type(); if (type == Polygon) converter.template set<clip_poly_tag>(); // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 //else if (type == LineString) // converter.template set<clip_line_tag>(); // don't clip if type==Point } converter.template set<transform_tag>(); //always transform if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter apply_markers_multi(feature, converter, sym); } else { box2d<double> const& bbox = (*mark)->bounding_box(); setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym); evaluate_transform(tr, feature, sym.get_image_transform()); // TODO - clamping to >= 4 pixels coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source()); svg_path_adapter svg_path(stl_storage); svg_attribute_type attributes; bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); buf_type render_buf(pixmap_.raw_data(), width_, height_, width_); dispatch_type rasterizer_dispatch(render_buf, svg_renderer, *ras_ptr, bbox, marker_trans, sym, *detector_, scale_factor_, feature, pixmap_); vertex_converter<box2d<double>, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) { eGeomType type = feature.paths()[0].type(); if (type == Polygon) converter.template set<clip_poly_tag>(); // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 //else if (type == LineString) // converter.template set<clip_line_tag>(); // don't clip if type==Point } converter.template set<transform_tag>(); //always transform if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter apply_markers_multi(feature, converter, sym); } } else // raster markers { setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, sym); evaluate_transform(tr, feature, sym.get_image_transform()); box2d<double> const& bbox = (*mark)->bounding_box(); // - clamp sizes to > 4 pixels of interactivity coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data(); typedef raster_markers_rasterizer_dispatch_grid<buf_type, grid_rasterizer, pixfmt_type, grid_renderer_base_type, renderer_type, detector_type, mapnik::grid > dispatch_type; buf_type render_buf(pixmap_.raw_data(), width_, height_, width_); dispatch_type rasterizer_dispatch(render_buf, *ras_ptr, **marker, marker_trans, sym, *detector_, scale_factor_, feature, pixmap_); vertex_converter<box2d<double>, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) { eGeomType type = feature.paths()[0].type(); if (type == Polygon) converter.template set<clip_poly_tag>(); // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 //else if (type == LineString) // converter.template set<clip_line_tag>(); // don't clip if type==Point } converter.template set<transform_tag>(); //always transform if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter apply_markers_multi(feature, converter, sym); } } } }
void grid_renderer<T>::render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity, composite_mode_e comp_op) { if (marker.is_vector()) { typedef coord_transform<CoordTransform,geometry_type> path_type; typedef agg::renderer_base<mapnik::pixfmt_gray32> ren_base; typedef agg::renderer_scanline_bin_solid<ren_base> renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); ras_ptr->reset(); box2d<double> const& bbox = (*marker.get_vector_data())->bounding_box(); coord<double,2> c = bbox.center(); // center the svg marker on '0,0' agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); // apply symbol transformation to get to map space mtx *= tr; mtx *= agg::trans_affine_scaling(scale_factor_*(1.0/step)); // render the marker at the center of the marker box mtx.translate(pos.x, pos.y); using namespace mapnik::svg; vertex_stl_adapter<svg_path_storage> stl_storage((*marker.get_vector_data())->source()); svg_path_adapter svg_path(stl_storage); svg_renderer_agg<svg_path_adapter, agg::pod_bvector<path_attributes>, renderer, mapnik::pixfmt_gray32> svg_renderer(svg_path, (*marker.get_vector_data())->attributes()); svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), mtx, opacity, bbox); } else { image_data_32 const& data = **marker.get_bitmap_data(); double width = data.width(); double height = data.height(); double cx = 0.5 * width; double cy = 0.5 * height; if (step == 1 && (std::fabs(1.0 - scale_factor_) < 0.001 && tr.is_identity())) { // TODO - support opacity pixmap_.set_rectangle(feature.id(), data, boost::math::iround(pos.x - cx), boost::math::iround(pos.y - cy)); } else { // TODO - remove support for step != or add support for agg scaling with opacity double ratio = (1.0/step); image_data_32 target(ratio * data.width(), ratio * data.height()); mapnik::scale_image_agg<image_data_32>(target,data, SCALING_NEAR, scale_factor_, 0.0, 0.0, 1.0, ratio); pixmap_.set_rectangle(feature.id(), target, boost::math::iround(pos.x - cx), boost::math::iround(pos.y - cy)); } } pixmap_.add_feature(feature); }
void render_building_symbolizer(mapnik::feature_impl &feature, double height, F1 face_func, F2 frame_func, F3 roof_func) { for (auto const& geom : feature.paths()) { if (geom.size() > 2) { const std::unique_ptr<geometry_type> frame(new geometry_type(geometry_type::types::LineString)); const std::unique_ptr<geometry_type> roof(new geometry_type(geometry_type::types::Polygon)); std::deque<segment_t> face_segments; double x0 = 0; double y0 = 0; double x,y; geom.rewind(0); for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END; cm = geom.vertex(&x, &y)) { if (cm == SEG_MOVETO) { frame->move_to(x,y); } else if (cm == SEG_LINETO) { frame->line_to(x,y); face_segments.push_back(segment_t(x0,y0,x,y)); } else if (cm == SEG_CLOSE) { frame->close_path(); } x0 = x; y0 = y; } std::sort(face_segments.begin(),face_segments.end(), y_order); for (auto const& seg : face_segments) { const std::unique_ptr<geometry_type> faces(new geometry_type(geometry_type::types::Polygon)); faces->move_to(std::get<0>(seg),std::get<1>(seg)); faces->line_to(std::get<2>(seg),std::get<3>(seg)); faces->line_to(std::get<2>(seg),std::get<3>(seg) + height); faces->line_to(std::get<0>(seg),std::get<1>(seg) + height); face_func(*faces); // frame->move_to(std::get<0>(seg),std::get<1>(seg)); frame->line_to(std::get<0>(seg),std::get<1>(seg)+height); } geom.rewind(0); for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END; cm = geom.vertex(&x, &y)) { if (cm == SEG_MOVETO) { frame->move_to(x,y+height); roof->move_to(x,y+height); } else if (cm == SEG_LINETO) { frame->line_to(x,y+height); roof->line_to(x,y+height); } else if (cm == SEG_CLOSE) { frame->close_path(); roof->close_path(); } } frame_func(*frame); roof_func(*roof); } } }
void cairo_renderer<T>::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { composite_mode_e comp_op = get<composite_mode_e, keys::comp_op>(sym, feature, common_.vars_); std::string filename = get<std::string, keys::file>(sym, feature, common_.vars_); value_bool clip = get<value_bool, keys::clip>(sym, feature, common_.vars_); value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym, feature, common_.vars_); value_double smooth = get<value_double, keys::smooth>(sym, feature, common_.vars_); value_double opacity = get<value_double, keys::opacity>(sym, feature, common_.vars_); agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional<transform_type>(sym, keys::image_transform); if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); cairo_save_restore guard(context_); context_.set_operator(comp_op); boost::optional<mapnik::marker_ptr> marker = mapnik::marker_cache::instance().find(filename,true); if (!marker || !(*marker)) return; unsigned offset_x=0; unsigned offset_y=0; box2d<double> const& clip_box = clipping_extent(common_); pattern_alignment_enum alignment = get<pattern_alignment_enum, keys::alignment>(sym, feature, common_.vars_); if (alignment == LOCAL_ALIGNMENT) { double x0 = 0.0; double y0 = 0.0; if (feature.num_geometries() > 0) { using clipped_geometry_type = agg::conv_clip_polygon<geometry_type>; using path_type = transform_path_adapter<view_transform,clipped_geometry_type>; clipped_geometry_type clipped(feature.get_geometry(0)); clipped.clip_box(clip_box.minx(), clip_box.miny(), clip_box.maxx(), clip_box.maxy()); path_type path(common_.t_, clipped, prj_trans); path.vertex(&x0, &y0); } offset_x = std::abs(clip_box.width() - x0); offset_y = std::abs(clip_box.height() - y0); } if ((*marker)->is_bitmap()) { cairo_pattern pattern(**((*marker)->get_bitmap_data()), opacity); pattern.set_extend(CAIRO_EXTEND_REPEAT); pattern.set_origin(offset_x, offset_y); context_.set_pattern(pattern); } else { mapnik::rasterizer ras; image_ptr image = render_pattern(ras, **marker, image_tr, 1.0); // cairo_pattern pattern(*image, opacity); pattern.set_extend(CAIRO_EXTEND_REPEAT); pattern.set_origin(offset_x, offset_y); context_.set_pattern(pattern); } agg::trans_affine tr; auto geom_transform = get_optional<transform_type>(sym, keys::geometry_transform); if (geom_transform) { evaluate_transform(tr, feature, common_.vars_, *geom_transform, common_.scale_factor_); } vertex_converter<cairo_context,clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> converter(clip_box, context_,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); //optional clip (default: true) converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter for ( geometry_type & geom : feature.paths()) { if (geom.size() > 2) { converter.apply(geom); } } // fill polygon context_.set_fill_rule(CAIRO_FILL_RULE_EVEN_ODD); context_.fill(); }
coord<unsigned, 2> offset(Sym const & sym, mapnik::feature_impl const & feature, proj_transform const & prj_trans, renderer_common const & common, box2d<double> const & clip_box) { coord<unsigned, 2> off(0, 0); pattern_alignment_enum alignment = get<pattern_alignment_enum, keys::alignment>(sym, feature, common.vars_); if (alignment == LOCAL_ALIGNMENT) { coord<double, 2> alignment(0, 0); apply_local_alignment apply(common.t_, prj_trans, clip_box, alignment.x, alignment.y); util::apply_visitor(geometry::vertex_processor<apply_local_alignment>(apply), feature.get_geometry()); off.x = std::abs(clip_box.width() - alignment.x); off.y = std::abs(clip_box.height() - alignment.y); } return off; }
void cairo_renderer<T>::process(line_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { composite_mode_e comp_op = get<composite_mode_e, keys::comp_op>(sym, feature, common_.vars_); value_bool clip = get<value_bool, keys::clip>(sym, feature, common_.vars_); value_double offset = get<value_double, keys::offset>(sym, feature, common_.vars_); value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym, feature, common_.vars_); value_double smooth = get<value_double, keys::smooth>(sym, feature, common_.vars_); color stroke = get<color, keys::stroke>(sym, feature, common_.vars_); value_double stroke_opacity = get<value_double, keys::stroke_opacity>(sym, feature, common_.vars_); line_join_enum stroke_join = get<line_join_enum, keys::stroke_linejoin>(sym, feature, common_.vars_); line_cap_enum stroke_cap = get<line_cap_enum, keys::stroke_linecap>(sym, feature, common_.vars_); value_double miterlimit = get<value_double, keys::stroke_miterlimit>(sym, feature, common_.vars_); value_double width = get<value_double, keys::stroke_width>(sym, feature, common_.vars_); auto dash = get_optional<dash_array>(sym, keys::stroke_dasharray, feature, common_.vars_); cairo_save_restore guard(context_); context_.set_operator(comp_op); context_.set_color(stroke, stroke_opacity); context_.set_line_join(stroke_join); context_.set_line_cap(stroke_cap); context_.set_miter_limit(miterlimit); context_.set_line_width(width * common_.scale_factor_); if (dash) { context_.set_dash(*dash, common_.scale_factor_); } agg::trans_affine tr; auto geom_transform = get_optional<transform_type>(sym, keys::geometry_transform); if (geom_transform) { evaluate_transform(tr, feature, common_.vars_, *geom_transform, common_.scale_factor_); } box2d<double> clipping_extent = common_.query_extent_; if (clip) { double padding = (double)(common_.query_extent_.width()/common_.width_); double half_stroke = width/2.0; if (half_stroke > 1) padding *= half_stroke; if (std::fabs(offset) > 0) padding *= std::fabs(offset) * 1.2; padding *= common_.scale_factor_; clipping_extent.pad(padding); } vertex_converter<cairo_context, clip_line_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag, offset_transform_tag, dash_tag, stroke_tag> converter(clipping_extent,context_,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); if (clip) converter.set<clip_line_tag>(); // optional clip (default: true) converter.set<transform_tag>(); // always transform if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter for (geometry_type & geom : feature.paths()) { if (geom.size() > 1) { converter.apply(geom); } } // stroke context_.set_fill_rule(CAIRO_FILL_RULE_WINDING); context_.stroke(); }
void cairo_renderer<T>::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { std::string filename = get<std::string, keys::file>(sym, feature, common_.vars_); composite_mode_e comp_op = get<composite_mode_e, keys::comp_op>(sym, feature, common_.vars_); value_bool clip = get<value_bool, keys::clip>(sym, feature, common_.vars_); value_double offset = get<value_double, keys::offset>(sym, feature, common_.vars_); value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym, feature, common_.vars_); value_double smooth = get<value_double, keys::smooth>(sym, feature, common_.vars_); if (filename.empty()) { return; } std::shared_ptr<mapnik::marker const> marker = marker_cache::instance().find(filename, true); if (marker->is<mapnik::marker_null>()) return; unsigned width = marker->width(); unsigned height = marker->height(); cairo_save_restore guard(context_); context_.set_operator(comp_op); // TODO - re-implement at renderer level like polygon_pattern symbolizer cairo_renderer_process_visitor_l visit(common_, sym, feature, width, height); std::shared_ptr<cairo_pattern> pattern = util::apply_visitor(visit, *marker); context_.set_line_width(height); pattern->set_extend(CAIRO_EXTEND_REPEAT); pattern->set_filter(CAIRO_FILTER_BILINEAR); agg::trans_affine tr; auto geom_transform = get_optional<transform_type>(sym, keys::geometry_transform); if (geom_transform) { evaluate_transform(tr, feature, common_.vars_, *geom_transform, common_.scale_factor_); } box2d<double> clipping_extent = common_.query_extent_; if (clip) { double padding = (double)(common_.query_extent_.width()/common_.width_); double half_stroke = width/2.0; if (half_stroke > 1) padding *= half_stroke; if (std::fabs(offset) > 0) padding *= std::fabs(offset) * 1.2; padding *= common_.scale_factor_; clipping_extent.pad(padding); } using rasterizer_type = line_pattern_rasterizer<cairo_context>; rasterizer_type ras(context_, *pattern, width, height); using vertex_converter_type = vertex_converter<clip_line_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag, offset_transform_tag>; vertex_converter_type converter(clipping_extent,sym, common_.t_, prj_trans, tr, feature, common_.vars_, common_.scale_factor_); if (clip) converter.set<clip_line_tag>(); // optional clip (default: true) converter.set<transform_tag>(); // always transform if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type, rasterizer_type>; using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>; apply_vertex_converter_type apply(converter, ras); mapnik::util::apply_visitor(vertex_processor_type(apply), feature.get_geometry()); }
void agg_renderer<T0,T1>::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { std::string filename = get<std::string, keys::file>(sym, feature, common_.vars_); if (filename.empty()) return; std::shared_ptr<mapnik::marker const> marker = marker_cache::instance().find(filename, true); buffer_type & current_buffer = buffers_.top().get(); agg::rendering_buffer buf(current_buffer.bytes(), current_buffer.width(), current_buffer.height(), current_buffer.row_size()); ras_ptr->reset(); value_double gamma = get<value_double, keys::gamma>(sym, feature, common_.vars_); gamma_method_enum gamma_method = get<gamma_method_enum, keys::gamma_method>(sym, feature, common_.vars_); if (gamma != gamma_ || gamma_method != gamma_method_) { set_gamma_method(ras_ptr, gamma, gamma_method); gamma_method_ = gamma_method; gamma_ = gamma; } value_bool clip = get<value_bool, keys::clip>(sym, feature, common_.vars_); value_double opacity = get<double, keys::opacity>(sym, feature, common_.vars_); value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym, feature, common_.vars_); value_double smooth = get<value_double, keys::smooth>(sym, feature, common_.vars_); using color = agg::rgba8; using order = agg::order_rgba; using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>; using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>; using wrap_x_type = agg::wrap_mode_repeat; using wrap_y_type = agg::wrap_mode_repeat; using img_source_type = agg::image_accessor_wrap<agg::pixfmt_rgba32_pre, wrap_x_type, wrap_y_type>; using span_gen_type = agg::span_pattern_rgba<img_source_type>; using ren_base = agg::renderer_base<pixfmt_type>; using renderer_type = agg::renderer_scanline_aa_alpha<ren_base, agg::span_allocator<agg::rgba8>, span_gen_type>; pixfmt_type pixf(buf); pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e, keys::comp_op>(sym, feature, common_.vars_))); ren_base renb(pixf); common_pattern_process_visitor<polygon_pattern_symbolizer, rasterizer> visitor(*ras_ptr, common_, sym, feature); image_rgba8 image(util::apply_visitor(visitor, *marker)); unsigned w = image.width(); unsigned h = image.height(); agg::rendering_buffer pattern_rbuf((agg::int8u*)image.bytes(),w,h,w*4); agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); img_source_type img_src(pixf_pattern); box2d<double> clip_box = clipping_extent(common_); coord<unsigned, 2> offset(detail::offset(sym, feature, prj_trans, common_, clip_box)); span_gen_type sg(img_src, offset.x, offset.y); agg::span_allocator<agg::rgba8> sa; renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); agg::trans_affine tr; auto transform = get_optional<transform_type>(sym, keys::geometry_transform); if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); using vertex_converter_type = vertex_converter<clip_poly_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag>; vertex_converter_type converter(clip_box, sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); // optional affine transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type, rasterizer>; using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>; apply_vertex_converter_type apply(converter, *ras_ptr); mapnik::util::apply_visitor(vertex_processor_type(apply),feature.get_geometry()); agg::scanline_u8 sl; ras_ptr->filling_rule(agg::fill_even_odd); agg::render_scanlines(*ras_ptr, sl, rp); }