polygon<T> reproject_internal(polygon<T> const& poly, proj_transform const& proj_trans, unsigned int & n_err) { polygon<T> new_poly; linear_ring<T> new_ext(poly.exterior_ring); unsigned int err = proj_trans.forward(new_ext); // If the exterior ring doesn't transform don't bother with the holes. if (err > 0 || new_ext.empty()) { n_err += err; } else { new_poly.set_exterior_ring(std::move(new_ext)); new_poly.interior_rings.reserve(poly.interior_rings.size()); for (auto const& lr : poly.interior_rings) { linear_ring<T> new_lr(lr); err = proj_trans.forward(new_lr); if (err > 0 || new_lr.empty()) { n_err += err; // If there is an error in interior ring drop // it from polygon. continue; } new_poly.add_hole(std::move(new_lr)); } } return new_poly; }
multi_point<T> reproject_internal(multi_point<T> const & mp, proj_transform const& proj_trans, unsigned int & n_err) { multi_point<T> new_mp; if (proj_trans.is_known()) { // If the projection is known we do them all at once because it is faster // since we know that no point will fail reprojection new_mp.assign(mp.begin(), mp.end()); proj_trans.forward(new_mp); } else { new_mp.reserve(mp.size()); for (auto const& p : mp) { point<T> new_p(p); if (!proj_trans.forward(new_p)) { ++n_err; } else { new_mp.emplace_back(std::move(new_p)); } } } return new_mp; }
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); } } }
inline box2d<double> backward(box2d<double> const& e, proj_transform const& prj_trans) const { double x0 = e.minx(); double y0 = e.miny(); double x1 = e.maxx(); double y1 = e.maxy(); double z = 0.0; backward(&x0, &y0); prj_trans.forward(x0, y0, z); backward(&x1, &y1); prj_trans.forward(x1, y1, z); return box2d<double>(x0, y0, x1, y1); }
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); }
point<T> reproject_internal(point<T> const& p, proj_transform const& proj_trans, unsigned int & n_err) { point<T> new_p(p); if (!proj_trans.forward(new_p)) { ++n_err; } return new_p; }
void agg_renderer<T>::process(point_symbolizer const& sym, Feature const& feature, proj_transform const& prj_trans) { std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); boost::optional<mapnik::marker_ptr> marker; if ( !filename.empty() ) { marker = marker_cache::instance()->find(filename, true); } else { marker.reset(boost::make_shared<mapnik::marker>()); } if (marker) { for (unsigned i=0; i<feature.num_geometries(); ++i) { geometry_type const& geom = feature.get_geometry(i); double x; double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) geom.label_position(&x, &y); else geom.label_interior_position(&x, &y); prj_trans.backward(x,y,z); t_.forward(&x,&y); int w = (*marker)->width(); int h = (*marker)->height(); int px = int(floor(x - 0.5 * w)); int py = int(floor(y - 0.5 * h)); box2d<double> label_ext (px, py, px + w, py + h); if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { agg::trans_affine tr; boost::array<double,6> const& m = sym.get_transform(); tr.load_from(&m[0]); render_marker(px,py,**marker,tr, sym.get_opacity()); if (!sym.get_ignore_placement()) detector_.insert(label_ext); metawriter_with_properties writer = sym.get_metawriter(); if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second); } } } }
inline void write_point(CoordTransform const& t, double x, double y, bool last = false) { double z = 0.0; t.backward(&x, &y); trans_->forward(x, y, z); *f_ << "["<<x<<","<<y<<"]"; if (!last) { *f_ << ","; } }
line_string<T> reproject_internal(line_string<T> const& ls, proj_transform const& proj_trans, unsigned int & n_err) { line_string<T> new_ls(ls); unsigned int err = proj_trans.forward(new_ls); if (err > 0) { n_err += err; } return new_ls; }
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 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(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 agg_renderer<T>::process(raster_symbolizer const& sym, mapnik::feature_ptr const& 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 = (int)ext.minx(); int start_y = (int)ext.miny(); int end_x = (int)ceil(ext.maxx()); int end_y = (int)ceil(ext.maxy()); int raster_width = end_x - start_x; int raster_height = end_y - start_y; double err_offs_x = ext.minx() - start_x; double err_offs_y = ext.miny() - start_y; if (raster_width > 0 && raster_height > 0) { double scale_factor = ext.width() / source->data_.width(); image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y, sym.get_mesh_size(), sym.calculate_filter_factor(), scale_factor, sym.get_scaling()); composite(current_buffer_->data(), target.data_, sym.comp_op(), sym.get_opacity(), start_x, start_y, false, false); } } }
void render_group_symbolizer(group_symbolizer const& sym, feature_impl & feature, attributes const& vars, proj_transform const& prj_trans, box2d<double> const& clipping_extent, renderer_common & common, F render_thunks) { // find all column names referenced in the group rules and symbolizers std::set<std::string> columns; group_attribute_collector column_collector(columns, false); column_collector(sym); group_symbolizer_properties_ptr props = get<group_symbolizer_properties_ptr>(sym, keys::group_properties); // create a new context for the sub features of this group context_ptr sub_feature_ctx = std::make_shared<mapnik::context_type>(); // populate new context with column names referenced in the group rules and symbolizers for (auto const& col_name : columns) { sub_feature_ctx->push(col_name); } // keep track of the sub features that we'll want to symbolize // along with the group rules that they matched std::vector< std::pair<group_rule_ptr, feature_ptr> > matches; // create a copied 'virtual' common renderer for processing sub feature symbolizers // create an empty detector for it, so we are sure we won't hit anything virtual_renderer_common virtual_renderer(common); // keep track of which lists of render thunks correspond to // entries in the group_layout_manager. std::vector<render_thunk_list> layout_thunks; size_t num_layout_thunks = 0; // layout manager to store and arrange bboxes of matched features group_layout_manager layout_manager(props->get_layout(), pixel_position(common.width_ / 2.0, common.height_ / 2.0)); // run feature or sub feature through the group rules & symbolizers // for each index value in the range value_integer start = get<value_integer>(sym, keys::start_column); value_integer end = start + get<value_integer>(sym, keys::num_columns); for (value_integer col_idx = start; col_idx < end; ++col_idx) { // create sub feature with indexed column values feature_ptr sub_feature = feature_factory::create(sub_feature_ctx, col_idx); // copy the necessary columns to sub feature for(auto const& col_name : columns) { if (col_name.find('%') != std::string::npos) { if (col_name.size() == 1) { // column name is '%' by itself, so give the index as the value sub_feature->put(col_name, col_idx); } else { // indexed column std::string col_idx_str; if (mapnik::util::to_string(col_idx_str,col_idx)) { std::string col_idx_name = col_name; boost::replace_all(col_idx_name, "%", col_idx_str); sub_feature->put(col_name, feature.get(col_idx_name)); } } } else { // non-indexed column sub_feature->put(col_name, feature.get(col_name)); } } // add a single point geometry at pixel origin double x = common.width_ / 2.0, y = common.height_ / 2.0, z = 0.0; common.t_.backward(&x, &y); prj_trans.forward(x, y, z); // note that we choose a point in the middle of the screen to // try to ensure that we don't get edge artefacts due to any // symbolizers with avoid-edges set: only the avoid-edges of // the group symbolizer itself should matter. geometry::point<double> origin_pt(x,y); sub_feature->set_geometry(origin_pt); // get the layout for this set of properties for (auto const& rule : props->get_rules()) { if (util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*sub_feature,common.vars_), *(rule->get_filter())).to_bool()) { // add matched rule and feature to the list of things to draw matches.emplace_back(rule, sub_feature); // construct a bounding box around all symbolizers for the matched rule bound_box bounds; render_thunk_list thunks; render_thunk_extractor extractor(bounds, thunks, *sub_feature, common.vars_, prj_trans, virtual_renderer, clipping_extent); for (auto const& _sym : *rule) { // TODO: construct layout and obtain bounding box util::apply_visitor(extractor, _sym); } // add the bounding box to the layout manager layout_manager.add_member_bound_box(bounds); layout_thunks.emplace_back(std::move(thunks)); ++num_layout_thunks; break; } } } // create a symbolizer helper group_symbolizer_helper helper(sym, feature, vars, prj_trans, common.width_, common.height_, common.scale_factor_, common.t_, *common.detector_, clipping_extent); for (size_t i = 0; i < matches.size(); ++i) { group_rule_ptr match_rule = matches[i].first; feature_ptr match_feature = matches[i].second; value_unicode_string rpt_key_value = ""; // get repeat key from matched group rule expression_ptr rpt_key_expr = match_rule->get_repeat_key(); // if no repeat key was defined, use default from group symbolizer if (!rpt_key_expr) { rpt_key_expr = get<expression_ptr>(sym, keys::repeat_key); } // evaluate the repeat key with the matched sub feature if we have one if (rpt_key_expr) { rpt_key_value = util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*match_feature,common.vars_), *rpt_key_expr).to_unicode(); } helper.add_box_element(layout_manager.offset_box_at(i), rpt_key_value); } pixel_position_list positions = helper.get(); for (pixel_position const& pos : positions) { for (size_t layout_i = 0; layout_i < num_layout_thunks; ++layout_i) { pixel_position const& offset = layout_manager.offset_at(layout_i); pixel_position render_offset = pos + offset; render_thunks(layout_thunks[layout_i], render_offset); } } }
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); }
void render_point_symbolizer(point_symbolizer const &sym, mapnik::feature_impl &feature, proj_transform const &prj_trans, RendererType &common, F render_marker) { std::string filename = get<std::string>(sym, keys::file, feature, common.vars_); boost::optional<mapnik::marker_ptr> marker = filename.empty() ? std::make_shared<mapnik::marker>() : marker_cache::instance().find(filename, true); if (marker) { double opacity = get<double>(sym,keys::opacity,feature, common.vars_, 1.0); bool allow_overlap = get<bool>(sym, keys::allow_overlap, feature, common.vars_, false); bool ignore_placement = get<bool>(sym, keys::ignore_placement, feature, common.vars_, false); point_placement_enum placement= get<point_placement_enum>(sym, keys::point_placement_type, feature, common.vars_, CENTROID_POINT_PLACEMENT); box2d<double> const& bbox = (*marker)->bounding_box(); coord2d center = bbox.center(); agg::trans_affine tr; auto image_transform = get_optional<transform_type>(sym, keys::image_transform); if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine recenter_tr = recenter * tr; box2d<double> label_ext = bbox * recenter_tr * agg::trans_affine_scaling(common.scale_factor_); for (std::size_t i=0; i<feature.num_geometries(); ++i) { geometry_type const& geom = feature.get_geometry(i); double x; double y; double z=0; if (placement == CENTROID_POINT_PLACEMENT) { if (!label::centroid(geom, x, y)) return; } else { if (!label::interior_position(geom ,x, y)) return; } prj_trans.backward(x,y,z); common.t_.forward(&x,&y); label_ext.re_center(x,y); if (allow_overlap || common.detector_->has_placement(label_ext)) { render_marker(pixel_position(x, y), **marker, tr, opacity); if (!ignore_placement) common.detector_->insert(label_ext); } } } }
void agg_renderer<T>::process(point_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<mapnik::marker_ptr> marker; if ( !filename.empty() ) { marker = marker_cache::instance()->find(filename, true); } else { marker.reset(boost::make_shared<mapnik::marker>()); } if (marker) { box2d<double> const& bbox = (*marker)->bounding_box(); coord2d center = bbox.center(); agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_image_transform()); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine recenter_tr = recenter * tr; box2d<double> label_ext = bbox * recenter_tr; for (unsigned i=0; i<feature.num_geometries(); ++i) { geometry_type const& geom = feature.get_geometry(i); double x; double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) { if (!label::centroid(geom, x, y)) return; } else { if (!label::interior_position(geom ,x, y)) return; } prj_trans.backward(x,y,z); t_.forward(&x,&y); label_ext.re_center(x,y); if (sym.get_allow_overlap() || detector_->has_placement(label_ext)) { render_marker(pixel_position(x, y), **marker, tr, sym.get_opacity(), sym.comp_op()); if (!sym.get_ignore_placement()) detector_->insert(label_ext); } } } }
MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& prj_trans, box2d<double> const& target_ext, box2d<double> const& source_ext, double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor) { using image_type = T; using pixel_type = typename image_type::pixel_type; using pixfmt_pre = typename detail::agg_scaling_traits<image_type>::pixfmt_pre; using color_type = typename detail::agg_scaling_traits<image_type>::color_type; using renderer_base = agg::renderer_base<pixfmt_pre>; using interpolator_type = typename detail::agg_scaling_traits<image_type>::interpolator_type; constexpr std::size_t pixel_size = sizeof(pixel_type); view_transform ts(source.width(), source.height(), source_ext); view_transform tt(target.width(), target.height(), target_ext, offset_x, offset_y); std::size_t mesh_nx = std::ceil(source.width()/double(mesh_size) + 1); std::size_t mesh_ny = std::ceil(source.height()/double(mesh_size) + 1); image_gray64f xs(mesh_nx, mesh_ny, false); image_gray64f ys(mesh_nx, mesh_ny, false); // Precalculate reprojected mesh for(std::size_t j = 0; j < mesh_ny; ++j) { for (std::size_t i=0; i<mesh_nx; ++i) { xs(i,j) = std::min(i*mesh_size,source.width()); ys(i,j) = std::min(j*mesh_size,source.height()); ts.backward(&xs(i,j), &ys(i,j)); } } prj_trans.backward(xs.getData(), ys.getData(), nullptr, mesh_nx*mesh_ny); agg::rasterizer_scanline_aa<> rasterizer; agg::scanline_bin scanline; agg::rendering_buffer buf(target.getBytes(), target.width(), target.height(), target.width() * pixel_size); pixfmt_pre pixf(buf); renderer_base rb(pixf); rasterizer.clip_box(0, 0, target.width(), target.height()); agg::rendering_buffer buf_tile( const_cast<unsigned char*>(source.getBytes()), source.width(), source.height(), source.width() * pixel_size); pixfmt_pre pixf_tile(buf_tile); using img_accessor_type = agg::image_accessor_clone<pixfmt_pre>; img_accessor_type ia(pixf_tile); agg::span_allocator<color_type> sa; // Project mesh cells into target interpolating raster inside each one for (std::size_t j = 0; j < mesh_ny - 1; ++j) { for (std::size_t i = 0; i < mesh_nx - 1; ++i) { double polygon[8] = {xs(i,j), ys(i,j), xs(i+1,j), ys(i+1,j), xs(i+1,j+1), ys(i+1,j+1), xs(i,j+1), ys(i,j+1)}; tt.forward(polygon+0, polygon+1); tt.forward(polygon+2, polygon+3); tt.forward(polygon+4, polygon+5); tt.forward(polygon+6, polygon+7); rasterizer.reset(); rasterizer.move_to_d(std::floor(polygon[0]), std::floor(polygon[1])); rasterizer.line_to_d(std::floor(polygon[2]), std::floor(polygon[3])); rasterizer.line_to_d(std::floor(polygon[4]), std::floor(polygon[5])); rasterizer.line_to_d(std::floor(polygon[6]), std::floor(polygon[7])); std::size_t x0 = i * mesh_size; std::size_t y0 = j * mesh_size; std::size_t x1 = (i+1) * mesh_size; std::size_t y1 = (j+1) * mesh_size; x1 = std::min(x1, source.width()); y1 = std::min(y1, source.height()); agg::trans_affine tr(polygon, x0, y0, x1, y1); if (tr.is_valid()) { interpolator_type interpolator(tr); if (scaling_method == SCALING_NEAR) { using span_gen_type = typename detail::agg_scaling_traits<image_type>::span_image_filter; span_gen_type sg(ia, interpolator); agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg); } else { using span_gen_type = typename detail::agg_scaling_traits<image_type>::span_image_resample_affine; agg::image_filter_lut filter; detail::set_scaling_method(filter, scaling_method, filter_factor); span_gen_type sg(ia, interpolator, filter); agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg); } } } } }
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>(std::floor(ext.minx()+.5)); int start_y = static_cast<int>(std::floor(ext.miny()+.5)); int end_x = static_cast<int>(std::floor(ext.maxx()+.5)); int end_y = static_cast<int>(std::floor(ext.maxy()+.5)); int raster_width = end_x - start_x; int raster_height = end_y - start_y; if (raster_width > 0 && raster_height > 0) { raster target(target_ext, raster_width,raster_height); scaling_method_e scaling_method = sym.get_scaling_method(); double filter_radius = sym.calculate_filter_factor(); bool premultiply_source = !source->premultiplied_alpha_; boost::optional<bool> is_premultiplied = sym.premultiplied(); if (is_premultiplied) { if (*is_premultiplied) premultiply_source = false; else premultiply_source = true; } if (premultiply_source) { agg::rendering_buffer buffer(source->data_.getBytes(), source->data_.width(), source->data_.height(), source->data_.width() * 4); agg::pixfmt_rgba32 pixf(buffer); pixf.premultiply(); } if (!prj_trans.equal()) { double offset_x = ext.minx() - start_x; double offset_y = ext.miny() - start_y; 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_, 0.0, 0.0); } else { double image_ratio_x = ext.width() / source->data_.width(); double image_ratio_y = ext.height() / source->data_.height(); scale_image_agg<image_data_32>(target.data_, source->data_, scaling_method, image_ratio_x, image_ratio_y, 0.0, 0.0, filter_radius); } } composite(current_buffer_->data(), target.data_, sym.comp_op(), sym.get_opacity(), start_x, start_y, false); } } }
void reproject_and_scale_raster(raster & target, raster const& source, proj_transform const& prj_trans, double offset_x, double offset_y, unsigned mesh_size, double filter_radius, scaling_method_e scaling_method) { CoordTransform ts(source.data_.width(), source.data_.height(), source.ext_); CoordTransform tt(target.data_.width(), target.data_.height(), target.ext_, offset_x, offset_y); unsigned i, j; unsigned mesh_nx = ceil(source.data_.width()/double(mesh_size)+1); unsigned mesh_ny = ceil(source.data_.height()/double(mesh_size)+1); ImageData<double> xs(mesh_nx, mesh_ny); ImageData<double> ys(mesh_nx, mesh_ny); // Precalculate reprojected mesh for(j=0; j<mesh_ny; j++) { for (i=0; i<mesh_nx; i++) { xs(i,j) = i*mesh_size; ys(i,j) = j*mesh_size; ts.backward(&xs(i,j), &ys(i,j)); } } prj_trans.backward(xs.getData(), ys.getData(), NULL, mesh_nx*mesh_ny); // Initialize AGG objects typedef agg::pixfmt_rgba32 pixfmt; typedef pixfmt::color_type color_type; typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::pixfmt_rgba32_pre pixfmt_pre; typedef agg::renderer_base<pixfmt_pre> renderer_base_pre; agg::rasterizer_scanline_aa<> rasterizer; agg::scanline_u8 scanline; agg::rendering_buffer buf((unsigned char*)target.data_.getData(), target.data_.width(), target.data_.height(), target.data_.width()*4); pixfmt_pre pixf_pre(buf); renderer_base_pre rb_pre(pixf_pre); rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height()); agg::rendering_buffer buf_tile( (unsigned char*)source.data_.getData(), source.data_.width(), source.data_.height(), source.data_.width() * 4); pixfmt pixf_tile(buf_tile); typedef agg::image_accessor_clone<pixfmt> img_accessor_type; img_accessor_type ia(pixf_tile); agg::span_allocator<color_type> sa; // Initialize filter agg::image_filter_lut filter; switch(scaling_method) { case SCALING_NEAR: break; case SCALING_BILINEAR8: // TODO - impl this or remove? case SCALING_BILINEAR: filter.calculate(agg::image_filter_bilinear(), true); break; case SCALING_BICUBIC: filter.calculate(agg::image_filter_bicubic(), true); break; case SCALING_SPLINE16: filter.calculate(agg::image_filter_spline16(), true); break; case SCALING_SPLINE36: filter.calculate(agg::image_filter_spline36(), true); break; case SCALING_HANNING: filter.calculate(agg::image_filter_hanning(), true); break; case SCALING_HAMMING: filter.calculate(agg::image_filter_hamming(), true); break; case SCALING_HERMITE: filter.calculate(agg::image_filter_hermite(), true); break; case SCALING_KAISER: filter.calculate(agg::image_filter_kaiser(), true); break; case SCALING_QUADRIC: filter.calculate(agg::image_filter_quadric(), true); break; case SCALING_CATROM: filter.calculate(agg::image_filter_catrom(), true); break; case SCALING_GAUSSIAN: filter.calculate(agg::image_filter_gaussian(), true); break; case SCALING_BESSEL: filter.calculate(agg::image_filter_bessel(), true); break; case SCALING_MITCHELL: filter.calculate(agg::image_filter_mitchell(), true); break; case SCALING_SINC: filter.calculate(agg::image_filter_sinc(filter_radius), true); break; case SCALING_LANCZOS: filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; case SCALING_BLACKMAN: filter.calculate(agg::image_filter_blackman(filter_radius), true); break; } // Project mesh cells into target interpolating raster inside each one for(j=0; j<mesh_ny-1; j++) { for (i=0; i<mesh_nx-1; i++) { double polygon[8] = {xs(i,j), ys(i,j), xs(i+1,j), ys(i+1,j), xs(i+1,j+1), ys(i+1,j+1), xs(i,j+1), ys(i,j+1)}; tt.forward(polygon+0, polygon+1); tt.forward(polygon+2, polygon+3); tt.forward(polygon+4, polygon+5); tt.forward(polygon+6, polygon+7); rasterizer.reset(); rasterizer.move_to_d(polygon[0]-1, polygon[1]-1); rasterizer.line_to_d(polygon[2]+1, polygon[3]-1); rasterizer.line_to_d(polygon[4]+1, polygon[5]+1); rasterizer.line_to_d(polygon[6]-1, polygon[7]+1); unsigned x0 = i * mesh_size; unsigned y0 = j * mesh_size; unsigned x1 = (i+1) * mesh_size; unsigned y1 = (j+1) * mesh_size; agg::trans_affine tr(polygon, x0, y0, x1, y1); if (tr.is_valid()) { typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type; interpolator_type interpolator(tr); if (scaling_method == SCALING_NEAR) { typedef agg::span_image_filter_rgba_nn <img_accessor_type, interpolator_type> span_gen_type; span_gen_type sg(ia, interpolator); agg::render_scanlines_aa(rasterizer, scanline, rb_pre, sa, sg); } else { typedef mapnik::span_image_resample_rgba_affine <img_accessor_type> span_gen_type; span_gen_type sg(ia, interpolator, filter); agg::render_scanlines_aa(rasterizer, scanline, rb_pre, sa, sg); } } } } }
void grid_renderer<T>::process(markers_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { typedef coord_transform2<CoordTransform,geometry_type> path_type; typedef agg::renderer_base<mapnik::pixfmt_gray16> 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_gray16 pixf(buf); ren_base renb(pixf); renderer ren(renb); ras_ptr->reset(); agg::trans_affine tr; boost::array<double,6> const& m = sym.get_transform(); tr.load_from(&m[0]); tr = agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution())) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature); marker_placement_e placement_method = sym.get_marker_placement(); marker_type_e marker_type = sym.get_marker_type(); if (!filename.empty()) { boost::optional<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true); if (mark && *mark && (*mark)->is_vector()) { boost::optional<path_ptr> marker = (*mark)->get_vector_data(); box2d<double> const& bbox = (*marker)->bounding_box(); double x1 = bbox.minx(); double y1 = bbox.miny(); double x2 = bbox.maxx(); double y2 = bbox.maxy(); agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2)); tr.transform(&x1,&y1); tr.transform(&x2,&y2); box2d<double> extent(x1,y1,x2,y2); using namespace mapnik::svg; vertex_stl_adapter<svg_path_storage> stl_storage((*marker)->source()); svg_path_adapter svg_path(stl_storage); svg_renderer<svg_path_adapter, agg::pod_bvector<path_attributes>, renderer, mapnik::pixfmt_gray16 > svg_renderer(svg_path,(*marker)->attributes()); bool placed = false; for (unsigned i=0; i<feature->num_geometries(); ++i) { geometry_type & geom = feature->get_geometry(i); if (geom.num_points() <= 1) { std::clog << "### Warning svg markers not supported yet for points within markers_symbolizer\n"; continue; } path_type path(t_,geom,prj_trans); markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_, sym.get_spacing() * scale_factor_, sym.get_max_error(), sym.get_allow_overlap()); double x, y, angle; while (placement.get_point(&x, &y, &angle)) { placed = true; agg::trans_affine matrix = recenter * tr *agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y); svg_renderer.render_id(*ras_ptr, sl, renb, feature->id(), matrix, sym.get_opacity(),bbox); } } if (placed) pixmap_.add_feature(feature); } } else { stroke const& stroke_ = sym.get_stroke(); double strk_width = stroke_.get_width(); double w; double h; unsigned int res = pixmap_.get_resolution(); if (res != 1) { // clamp to at least 4 px otherwise interactive pixels can be too small double min = static_cast<double>(4/pixmap_.get_resolution()); w = std::max(sym.get_width()/res,min); h = std::max(sym.get_height()/res,min); } else { w = sym.get_width()/res; h = sym.get_height()/res; } arrow arrow_; box2d<double> extent; double dx = w + (2*strk_width); double dy = h + (2*strk_width); if (marker_type == ARROW) { extent = arrow_.extent(); double x1 = extent.minx(); double y1 = extent.miny(); double x2 = extent.maxx(); double y2 = extent.maxy(); tr.transform(&x1,&y1); tr.transform(&x2,&y2); extent.init(x1,y1,x2,y2); } else { double x1 = -1 *(dx); double y1 = -1 *(dy); double x2 = dx; double y2 = dy; tr.transform(&x1,&y1); tr.transform(&x2,&y2); extent.init(x1,y1,x2,y2); } double x; double y; double z=0; for (unsigned i=0; i<feature->num_geometries(); ++i) { geometry_type & geom = feature->get_geometry(i); if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) { geom.label_position(&x,&y); prj_trans.backward(x,y,z); t_.forward(&x,&y); int px = int(floor(x - 0.5 * dx)); int py = int(floor(y - 0.5 * dy)); box2d<double> label_ext (px, py, px + dx +1, py + dy +1); if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { agg::ellipse c(x, y, w, h); agg::path_storage marker; marker.concat_path(c); ras_ptr->add_path(marker); // outline if (strk_width) { agg::conv_stroke<agg::path_storage> outline(marker); outline.generator().width(strk_width * scale_factor_); ras_ptr->add_path(outline); } detector_.insert(label_ext); } } else { agg::path_storage marker; if (marker_type == ARROW) marker.concat_path(arrow_); path_type path(t_,geom,prj_trans); markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_, sym.get_spacing() * scale_factor_, sym.get_max_error(), sym.get_allow_overlap()); double x_t, y_t, angle; while (placement.get_point(&x_t, &y_t, &angle)) { agg::trans_affine matrix; if (marker_type == ELLIPSE) { // todo proper bbox - this is buggy agg::ellipse c(x_t, y_t, w, h); marker.concat_path(c); agg::trans_affine matrix; matrix *= agg::trans_affine_translation(-x_t,-y_t); matrix *= agg::trans_affine_rotation(angle); matrix *= agg::trans_affine_translation(x_t,y_t); marker.transform(matrix); } else { matrix = tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x_t, y_t); } agg::conv_transform<agg::path_storage, agg::trans_affine> trans(marker, matrix); // fill ras_ptr->add_path(trans); // outline if (strk_width) { agg::conv_stroke<agg::conv_transform<agg::path_storage, agg::trans_affine> > outline(trans); outline.generator().width(strk_width * scale_factor_); ras_ptr->add_path(outline); } } } } ren.color(mapnik::gray16(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); pixmap_.add_feature(feature); } }
void agg_renderer<T>::process(point_symbolizer const& sym, Feature const& feature, proj_transform const& prj_trans) { typedef agg::pixfmt_rgba32 pixfmt; typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid; double x; double y; double z=0; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); boost::optional<mapnik::image_ptr> data; if (is_svg(filename)) { // SVG using namespace mapnik::svg; boost::optional<path_ptr> marker; ras_ptr->reset(); ras_ptr->gamma(agg::gamma_linear()); agg::scanline_u8 sl; agg::rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_ * 4); pixfmt pixf(buf); renderer_base renb(pixf); renderer_solid ren(renb); box2d<double> extent; marker = marker_cache::instance()->find(filename, true); if (marker && *marker) { box2d<double> const& bbox = (*marker)->bounding_box(); double x1 = bbox.minx(); double y1 = bbox.miny(); double x2 = bbox.maxx(); double y2 = bbox.maxy(); vertex_stl_adapter<svg_path_storage> stl_storage((*marker)->source()); svg_path_adapter svg_path(stl_storage); svg_renderer<svg_path_adapter, agg::pod_bvector<path_attributes> > svg_renderer(svg_path, (*marker)->attributes()); for (unsigned i=0; i<feature.num_geometries(); ++i) { geometry2d const& geom = feature.get_geometry(i); geom.label_position(&x,&y); prj_trans.backward(x,y,z); t_.forward(&x,&y); agg::trans_affine tr; boost::array<double,6> const& m = sym.get_transform(); tr.load_from(&m[0]); tr *= agg::trans_affine_scaling(scale_factor_); tr *= agg::trans_affine_translation(x, y); tr.transform(&x1,&y1); tr.transform(&x2,&y2); extent.init(x1,y1,x2,y2); if (sym.get_allow_overlap() || detector_.has_placement(extent)) { svg_renderer.render(*ras_ptr, sl, ren, tr, renb.clip_box(), sym.get_opacity()); detector_.insert(extent); metawriter_with_properties writer = sym.get_metawriter(); if (writer.first) { writer.first->add_box(extent, feature, t_, writer.second); } } } } } else { if ( filename.empty() ) { // default OGC 4x4 black square data = boost::optional<mapnik::image_ptr>(new image_data_32(4,4)); (*data)->set(0xff000000); } else { data = mapnik::image_cache::instance()->find(filename,true); } if ( data ) { for (unsigned i=0; i<feature.num_geometries(); ++i) { geometry2d const& geom = feature.get_geometry(i); geom.label_position(&x,&y); prj_trans.backward(x,y,z); t_.forward(&x,&y); int w = (*data)->width(); int h = (*data)->height(); int px = int(floor(x - 0.5 * w)); int py = int(floor(y - 0.5 * h)); box2d<double> label_ext (px, py, px + w, py + h); if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { pixmap_.set_rectangle_alpha2(*(*data), px, py, sym.get_opacity()); detector_.insert(label_ext); metawriter_with_properties writer = sym.get_metawriter(); if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second); } } } } }
void render_point_symbolizer(point_symbolizer const &sym, mapnik::feature_impl &feature, proj_transform const &prj_trans, RendererType &common, F render_marker) { std::string filename = get<std::string,keys::file>(sym,feature, common.vars_); std::shared_ptr<mapnik::marker const> mark = filename.empty() ? std::make_shared<mapnik::marker const>(mapnik::marker_rgba8()) : marker_cache::instance().find(filename, true); if (!mark->is<mapnik::marker_null>()) { value_double opacity = get<value_double,keys::opacity>(sym, feature, common.vars_); value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym, feature, common.vars_); value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym, feature, common.vars_); point_placement_enum placement= get<point_placement_enum, keys::point_placement_type>(sym, feature, common.vars_); box2d<double> const& bbox = mark->bounding_box(); coord2d center = bbox.center(); agg::trans_affine tr; auto image_transform = get_optional<transform_type>(sym, keys::image_transform); if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform, common.scale_factor_); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine recenter_tr = recenter * tr; box2d<double> label_ext = bbox * recenter_tr * agg::trans_affine_scaling(common.scale_factor_); mapnik::geometry::geometry<double> const& geometry = feature.get_geometry(); mapnik::geometry::point<double> pt; geometry::geometry_types type = geometry::geometry_type(geometry); if (placement == CENTROID_POINT_PLACEMENT || type == geometry::geometry_types::Point || type == geometry::geometry_types::MultiPoint) { if (!geometry::centroid(geometry, pt)) return; } else if (type == mapnik::geometry::geometry_types::Polygon) { auto const& poly = mapnik::util::get<geometry::polygon<double> >(geometry); geometry::polygon_vertex_adapter<double> va(poly); if (!label::interior_position(va ,pt.x, pt.y)) return; } else { MAPNIK_LOG_WARN(point_symbolizer) << "TODO: unhandled geometry type for point symbolizer"; return; } double x = pt.x; double y = pt.y; double z = 0; prj_trans.backward(x,y,z); common.t_.forward(&x,&y); label_ext.re_center(x,y); if (allow_overlap || common.detector_->has_placement(label_ext)) { render_marker(pixel_position(x, y), *mark, tr, opacity); if (!ignore_placement) common.detector_->insert(label_ext); } } }
void grid_renderer<T>::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { std::string filename = get<std::string>(sym, keys::file, feature, common_.vars_); if (filename.empty()) return; boost::optional<mapnik::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(); bool clip = get<value_bool>(sym, keys::clip, feature, common_.vars_, true); double simplify_tolerance = get<value_double>(sym, keys::simplify_tolerance, feature, common_.vars_, 0.0); double smooth = get<value_double>(sym, keys::smooth, feature, common_.vars_, false); 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 conv_types = boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag>; vertex_converter<box2d<double>, grid_rasterizer, polygon_pattern_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types, feature_impl> converter(common_.query_extent_,*ras_ptr,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); } } 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>; 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); // 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(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(); }
void grid_renderer<T>::process(text_symbolizer const& sym, Feature const& feature, proj_transform const& prj_trans) { typedef coord_transform2<CoordTransform,geometry_type> path_type; bool placement_found = false; text_placement_info_ptr placement_options = sym.get_placement_options()->get_placement_info(); while (!placement_found && placement_options->next()) { expression_ptr name_expr = sym.get_name(); if (!name_expr) return; value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*name_expr); UnicodeString text = result.to_unicode(); if ( sym.get_text_transform() == UPPERCASE) { text = text.toUpper(); } else if ( sym.get_text_transform() == LOWERCASE) { text = text.toLower(); } else if ( sym.get_text_transform() == CAPITALIZE) { text = text.toTitle(NULL); } if ( text.length() <= 0 ) continue; color const& fill = sym.get_fill(); face_set_ptr faces; if (sym.get_fontset().size() > 0) { faces = font_manager_.get_face_set(sym.get_fontset()); } else { faces = font_manager_.get_face_set(sym.get_face_name()); } stroker_ptr strk = font_manager_.get_stroker(); if (!(faces->size() > 0 && strk)) { throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'"); } text_renderer<T> ren(pixmap_, faces, *strk); ren.set_pixel_size(placement_options->text_size * (scale_factor_ * (1.0/pixmap_.get_resolution()))); ren.set_fill(fill); ren.set_halo_fill(sym.get_halo_fill()); ren.set_halo_radius(sym.get_halo_radius() * scale_factor_); ren.set_opacity(sym.get_text_opacity()); // /pixmap_.get_resolution() ? box2d<double> dims(0,0,width_,height_); placement_finder<label_collision_detector4> finder(detector_,dims); string_info info(text); faces->get_string_info(info); unsigned num_geom = feature.num_geometries(); for (unsigned i=0; i<num_geom; ++i) { geometry_type const& geom = feature.get_geometry(i); if (geom.num_points() == 0) continue; // don't bother with empty geometries while (!placement_found && placement_options->next_position_only()) { placement text_placement(info, sym, scale_factor_); text_placement.avoid_edges = sym.get_avoid_edges(); if (sym.get_label_placement() == POINT_PLACEMENT || sym.get_label_placement() == INTERIOR_PLACEMENT) { double label_x, label_y, z=0.0; if (sym.get_label_placement() == POINT_PLACEMENT) geom.label_position(&label_x, &label_y); else geom.label_interior_position(&label_x, &label_y); prj_trans.backward(label_x,label_y, z); t_.forward(&label_x,&label_y); double angle = 0.0; expression_ptr angle_expr = sym.get_orientation(); if (angle_expr) { // apply rotation value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature),*angle_expr); angle = result.to_double(); } finder.find_point_placement(text_placement, placement_options, label_x, label_y, angle, sym.get_line_spacing(), sym.get_character_spacing()); finder.update_detector(text_placement); } else if ( geom.num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT) { path_type path(t_,geom,prj_trans); finder.find_line_placements<path_type>(text_placement, placement_options, path); } if (!text_placement.placements.size()) continue; placement_found = true; for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ii) { double x = text_placement.placements[ii].starting_x; double y = text_placement.placements[ii].starting_y; ren.prepare_glyphs(&text_placement.placements[ii]); ren.render_id(feature.id(),x,y,2); } } } } if (placement_found) pixmap_.add_feature(feature); }
static boost::python::tuple getinitargs(const proj_transform& p) { using namespace boost::python; return boost::python::make_tuple(p.source(),p.dest()); }
void agg_renderer<T>::process(point_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature); boost::optional<mapnik::marker_ptr> marker; if ( !filename.empty() ) { marker = marker_cache::instance()->find(filename, true); } else { marker.reset(boost::make_shared<mapnik::marker>()); } if (marker) { double w = (*marker)->width(); double h = (*marker)->height(); agg::trans_affine tr; boost::array<double,6> const& m = sym.get_transform(); tr.load_from(&m[0]); double px0 = - 0.5 * w; double py0 = - 0.5 * h; double px1 = 0.5 * w; double py1 = 0.5 * h; double px2 = px1; double py2 = py0; double px3 = px0; double py3 = py1; tr.transform(&px0,&py0); tr.transform(&px1,&py1); tr.transform(&px2,&py2); tr.transform(&px3,&py3); box2d<double> label_ext (px0, py0, px1, py1); label_ext.expand_to_include(px2, py2); label_ext.expand_to_include(px3, py3); for (unsigned i=0; i<feature->num_geometries(); ++i) { geometry_type const& geom = feature->get_geometry(i); double x; double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) geom.label_position(&x, &y); else geom.label_interior_position(&x, &y); prj_trans.backward(x,y,z); t_.forward(&x,&y); label_ext.re_center(x,y); if (sym.get_allow_overlap() || detector_->has_placement(label_ext)) { render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**marker,tr, sym.get_opacity()); if (!sym.get_ignore_placement()) detector_->insert(label_ext); metawriter_with_properties writer = sym.get_metawriter(); if (writer.first) writer.first->add_box(label_ext, *feature, t_, writer.second); } } } }
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); std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(filename,true); if (marker->is<mapnik::marker_null>()) 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; using apply_local_alignment = detail::apply_local_alignment; apply_local_alignment apply(common_.t_, prj_trans, clip_box, x0, y0); util::apply_visitor(geometry::vertex_processor<apply_local_alignment>(apply), feature.get_geometry()); offset_x = std::abs(clip_box.width() - x0); offset_y = std::abs(clip_box.height() - y0); } util::apply_visitor(cairo_renderer_process_visitor_p(context_, image_tr, offset_x, offset_y, opacity), *marker); 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_); } 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>(); //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 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()); // fill polygon context_.set_fill_rule(CAIRO_FILL_RULE_EVEN_ODD); context_.fill(); }
void grid_renderer<T>::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; mapnik::marker const& mark = marker_cache::instance().find(filename, true); if (mark.is<mapnik::marker_null>()) return; if (!mark.is<mapnik::marker_rgba8>()) { MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; return; } ras_ptr->reset(); 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_); 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,smooth_tag>; vertex_converter_type converter(common_.query_extent_,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 using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type, grid_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()); 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>; 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); // 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); }