virtual void on_draw() { typedef agg::renderer_base<pixfmt_type> base_ren_type; pixfmt_type pf(rbuf_window()); base_ren_type ren_base(pf); ren_base.clear(agg::rgba(1, 1, 1)); render(); agg::render_ctrl(m_ras, m_sl, ren_base, m_polygons); agg::render_ctrl(m_ras, m_sl, ren_base, m_operation); }
void agg_renderer<T>::process(line_pattern_symbolizer const& sym, mapnik::feature_ptr const& feature, proj_transform const& prj_trans) { typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type; typedef coord_transform2<CoordTransform,clipped_geometry_type> path_type; typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type; typedef agg::renderer_base<agg::pixfmt_rgba32_plain> renderer_base; typedef agg::renderer_outline_image<renderer_base, pattern_type> renderer_type; typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type; agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4); agg::pixfmt_rgba32_plain pixf(buf); 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()) { std::clog << "### Warning only images (not '" << filename << "') are supported in the line_pattern_symbolizer\n"; return; } boost::optional<image_ptr> pat = (*mark)->get_bitmap_data(); if (!pat) return; box2d<double> ext = query_extent_ * 1.1; renderer_base ren_base(pixf); agg::pattern_filter_bilinear_rgba8 filter; pattern_source source(*(*pat)); pattern_type pattern (filter,source); renderer_type ren(ren_base, pattern); // TODO - should be sensitive to buffer size ren.clip_box(0,0,width_,height_); rasterizer_type ras(ren); //metawriter_with_properties writer = sym.get_metawriter(); for (unsigned i=0;i<feature->num_geometries();++i) { geometry_type & geom = feature->get_geometry(i); if (geom.num_points() > 1) { clipped_geometry_type clipped(geom); clipped.clip_box(ext.minx(),ext.miny(),ext.maxx(),ext.maxy()); path_type path(t_,clipped,prj_trans); ras.add_path(path); //if (writer.first) writer.first->add_line(path, *feature, t_, writer.second); } } }
virtual void on_draw() { typedef agg::renderer_base<agg::pixfmt_bgr24> base_ren_type; agg::pixfmt_bgr24 pf(rbuf_window()); base_ren_type ren_base(pf); ren_base.clear(agg::rgba(1,1,1)); agg::scanline_u8 sl; agg::rasterizer_scanline_aa<> ras; render_clipper(sl, ras); agg::render_ctrl(ras, sl, ren_base, m_polygons); agg::render_ctrl(ras, sl, ren_base, m_operation); }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> base_ren_type; pixfmt pf(rbuf_window()); base_ren_type ren_base(pf); ren_base.clear(agg::rgba(1,1,1)); agg::scanline_u8 sl; agg::rasterizer_scanline_aa<> ras; render_gouraud(sl, ras); ras.gamma(agg::gamma_none()); agg::render_ctrl(ras, sl, ren_base, m_dilation); agg::render_ctrl(ras, sl, ren_base, m_gamma); agg::render_ctrl(ras, sl, ren_base, m_alpha); }
void agg_renderer<T>::process(line_pattern_symbolizer const& sym, Feature const& feature, proj_transform const& prj_trans) { typedef coord_transform2<CoordTransform,geometry_type> path_type; typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type; typedef agg::renderer_base<agg::pixfmt_rgba32_plain> renderer_base; typedef agg::renderer_outline_image<renderer_base, pattern_type> renderer_type; typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type; agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4); agg::pixfmt_rgba32_plain pixf(buf); std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature); boost::optional<marker_ptr> mark = marker_cache::instance()->find(filename,true); if (!mark || !(*mark)->is_bitmap()) return; boost::optional<image_ptr> pat = (*mark)->get_bitmap_data(); if (!pat) return; renderer_base ren_base(pixf); agg::pattern_filter_bilinear_rgba8 filter; pattern_source source(*(*pat)); pattern_type pattern (filter,source); renderer_type ren(ren_base, pattern); ren.clip_box(0,0,width_,height_); rasterizer_type ras(ren); metawriter_with_properties writer = sym.get_metawriter(); for (unsigned i=0;i<feature.num_geometries();++i) { geometry_type const& geom = feature.get_geometry(i); if (geom.num_points() > 1) { path_type path(t_,geom,prj_trans); ras.add_path(path); if (writer.first) writer.first->add_line(path, feature, t_, writer.second); } } }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> base_ren_type; typedef agg::renderer_scanline_aa_solid<base_ren_type> renderer_solid; pixfmt pf(rbuf_window()); base_ren_type ren_base(pf); renderer_solid ren_solid(ren_base); ren_base.clear(agg::rgba(1,1,1)); agg::scanline_u8 sl; agg::rasterizer_scanline_aa<> ras; agg::rasterizer_scanline_aa<> ras2; agg::render_ctrl(ras, sl, ren_base, m_polygons); agg::render_ctrl(ras, sl, ren_base, m_fill_rule); agg::render_ctrl(ras, sl, ren_base, m_scanline_type); agg::render_ctrl(ras, sl, ren_base, m_operation); render_sbool(ras, ras2); }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline; typedef agg::scanline_u8 scanline; pixfmt pixf(rbuf_window()); renderer_base ren_base(pixf); ren_base.clear(agg::rgba(1.0, 1.0, 0.95)); renderer_scanline ren(ren_base); unsigned i; unsigned w = unsigned(width()); m_gradient.resize(w); agg::rgba8 c1(255, 0, 0, 180); agg::rgba8 c2(0, 0, 255, 180); for(i = 0; i < w; i++) { m_gradient[i] = c1.gradient(c2, i / width()); m_gradient[i].premultiply(); } agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> ras; agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> rasc; agg::scanline_u8 sl; agg::scanline_bin sl_bin; agg::conv_transform<agg::compound_shape> shape(m_shape, m_scale); agg::conv_stroke<agg::conv_transform<agg::compound_shape> > stroke(shape); agg::test_styles style_handler(m_colors, m_gradient.data()); agg::span_allocator<agg::rgba8> alloc; m_shape.approximation_scale(m_scale.scale()); // Fill shape //---------------------- rasc.clip_box(0, 0, width(), height()); rasc.reset(); //rasc.filling_rule(agg::fill_even_odd); start_timer(); for(i = 0; i < m_shape.paths(); i++) { if(m_shape.style(i).left_fill >= 0 || m_shape.style(i).right_fill >= 0) { rasc.styles(m_shape.style(i).left_fill, m_shape.style(i).right_fill); rasc.add_path(shape, m_shape.style(i).path_id); } } agg::render_scanlines_compound(rasc, sl, sl_bin, ren_base, alloc, style_handler); double tfill = elapsed_time(); // Hit-test test bool draw_strokes = true; if(m_hit_x >= 0 && m_hit_y >= 0) { if(rasc.hit_test(m_hit_x, m_hit_y)) { draw_strokes = false; } } // Draw strokes //---------------------- start_timer(); if(draw_strokes) { ras.clip_box(0, 0, width(), height()); stroke.width(sqrt(m_scale.scale())); stroke.line_join(agg::round_join); stroke.line_cap(agg::round_cap); for(i = 0; i < m_shape.paths(); i++) { ras.reset(); if(m_shape.style(i).line >= 0) { ras.add_path(stroke, m_shape.style(i).path_id); ren.color(agg::rgba8(0,0,0, 128)); agg::render_scanlines(ras, sl, ren); } } } double tstroke = elapsed_time(); char buf[256]; agg::gsv_text t; t.size(8.0); t.flip(true); agg::conv_stroke<agg::gsv_text> ts(t); ts.width(1.6); ts.line_cap(agg::round_cap); sprintf(buf, "Fill=%.2fms (%dFPS) Stroke=%.2fms (%dFPS) Total=%.2fms (%dFPS)\n\n" "Space: Next Shape\n\n" "+/- : ZoomIn/ZoomOut (with respect to the mouse pointer)", tfill, int(1000.0 / tfill), tstroke, int(1000.0 / tstroke), tfill+tstroke, int(1000.0 / (tfill+tstroke))); t.start_point(10.0, 20.0); t.text(buf); ras.add_path(ts); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); if(m_gamma.gamma() != 1.0) { pixf.apply_gamma_inv(m_gamma); } }
virtual void on_draw() { pixfmt pf(rbuf_window()); renderer_base ren_base(pf); ren_base.clear(agg::rgba(0.5, 0.75, 0.85)); renderer_scanline ren(ren_base); rasterizer_scanline ras; scanline sl; ras.clip_box(0, 0, width(), height()); // Pattern source. Must have an interface: // width() const // height() const // pixel(int x, int y) const // Any agg::renderer_base<> or derived // is good for the use as a source. //----------------------------------- pattern_src_brightness_to_alpha_rgba8 p1(rbuf_img(0)); agg::pattern_filter_bilinear_rgba8 fltr; // Filtering functor // agg::line_image_pattern is the main container for the patterns. It creates // a copy of the patterns extended according to the needs of the filter. // agg::line_image_pattern can operate with arbitrary image width, but if the // width of the pattern is power of 2, it's better to use the modified // version agg::line_image_pattern_pow2 because it works about 15-25 percent // faster than agg::line_image_pattern (because of using simple masking instead // of expensive '%' operation). typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type; typedef agg::renderer_base<pixfmt> base_ren_type; typedef agg::renderer_outline_image<base_ren_type, pattern_type> renderer_img_type; typedef agg::rasterizer_outline_aa<renderer_img_type, agg::line_coord_sat> rasterizer_img_type; typedef agg::renderer_outline_aa<base_ren_type> renderer_line_type; typedef agg::rasterizer_outline_aa<renderer_line_type, agg::line_coord_sat> rasterizer_line_type; //-- Create with specifying the source //pattern_type patt(fltr, src); //-- Create uninitialized and set the source pattern_type patt(fltr); patt.create(p1); renderer_img_type ren_img(ren_base, patt); rasterizer_img_type ras_img(ren_img); //-- create uninitialized and set parameters agg::line_profile_aa profile; profile.smoother_width(10.0); //optional profile.width(8.0); //mandatory! renderer_line_type ren_line(ren_base, profile); ren_line.color(agg::rgba8(0,0,127)); //mandatory! rasterizer_line_type ras_line(ren_line); ras_line.round_cap(true); //optional //ras_line.line_join(agg::outline_no_join); //optional // Calculate the dilation value so that, the line caps were // drawn correctly. //--------------- double w2 = 9.0;//p1.height() / 2 + 2; // Set the clip box a bit bigger than you expect. You need it // to draw the clipped line caps correctly. The correct result // is achieved with raster clipping. //------------------------ ren_img.scale_x(m_scale_x.value()); ren_img.start_x(m_start_x.value()); ren_img.clip_box (50-w2, 50-w2, width()-50+w2, height()-50+w2); ren_line.clip_box(50-w2, 50-w2, width()-50+w2, height()-50+w2); // First, draw polyline without raster clipping just to show the idea //------------------------ draw_polyline(ras_line, ren_line, m_line1.polygon(), m_line1.num_points()); draw_polyline(ras_img, ren_img, m_line1.polygon(), m_line1.num_points()); // Clear the area, almost opaque, but not completely //------------------------ ren_base.blend_bar(0, 0, (int)width(), (int)height(), agg::rgba(1,1,1), 200); // Set the raster clip box and then, draw again. // In reality there shouldn't be two calls above. // It's done only for demonstration //------------------------ ren_base.clip_box((int)50, (int)50, (int)width()-50, (int)height()-50); // This "copy_bar" is also for demonstration only //------------------------ ren_base.copy_bar(0, 0, (int)width(), (int)height(), agg::rgba(1,1,1)); // Finally draw polyline correctly clipped: We use double clipping, // first is vector clipping, with extended clip box, second is raster // clipping with normal clip box. //------------------------ ren_img.scale_x(m_scale_x.value()); ren_img.start_x(m_start_x.value()); draw_polyline(ras_line, ren_line, m_line1.polygon(), m_line1.num_points()); draw_polyline(ras_img, ren_img, m_line1.polygon(), m_line1.num_points()); // Reset clipping and draw the controls and stuff ren_base.reset_clipping(true); m_line1.line_width(1/m_scale.scale()); m_line1.point_radius(5/m_scale.scale()); agg::render_ctrl(ras, sl, ren_base, m_line1); agg::render_ctrl(ras, sl, ren_base, m_scale_x); agg::render_ctrl(ras, sl, ren_base, m_start_x); char buf[256]; agg::gsv_text t; t.size(10.0); agg::conv_stroke<agg::gsv_text> pt(t); pt.width(1.5); pt.line_cap(agg::round_cap); const double* p = m_line1.polygon(); sprintf(buf, "Len=%.2f", agg::calc_distance(p[0], p[1], p[2], p[3]) * m_scale.scale()); t.start_point(10.0, 30.0); t.text(buf); ras.add_path(pt); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); }
void render_gouraud(Scanline& sl, Ras& ras) { unsigned alpha = int(m_alpha.value() * 255.0); unsigned brc = 255; typedef agg::renderer_base<pixfmt> base_ren_type; #ifdef AGG_GRAY8 typedef agg::span_gouraud_gray8<> gouraud_span_gen_type; #else typedef agg::span_gouraud_rgba8<> gouraud_span_gen_type; #endif typedef agg::span_allocator<gouraud_span_gen_type::color_type> gouraud_span_alloc_type; typedef agg::renderer_scanline_u<base_ren_type, gouraud_span_gen_type> renderer_gouraud; pixfmt pf(rbuf_window()); base_ren_type ren_base(pf); gouraud_span_alloc_type span_alloc; gouraud_span_gen_type span_gen(span_alloc); renderer_gouraud ren_gouraud(ren_base, span_gen); ras.gamma(agg::gamma_linear(0.0, m_gamma.value())); double d = m_dilation.value(); // Single triangle //span_gen.colors(agg::rgba8(255, 0, 0, alpha), // agg::rgba8(0, 255, 0, alpha), // agg::rgba8(0, 0, 255, alpha)); //span_gen.triangle(m_x[0], m_y[0], m_x[1], m_y[1], m_x[2], m_y[2], d); //ras.add_path(span_gen); //ras.render(sl, ren_gouraud); // Six triangles double xc = (m_x[0] + m_x[1] + m_x[2]) / 3.0; double yc = (m_y[0] + m_y[1] + m_y[2]) / 3.0; double x1 = (m_x[1] + m_x[0]) / 2 - (xc - (m_x[1] + m_x[0]) / 2); double y1 = (m_y[1] + m_y[0]) / 2 - (yc - (m_y[1] + m_y[0]) / 2); double x2 = (m_x[2] + m_x[1]) / 2 - (xc - (m_x[2] + m_x[1]) / 2); double y2 = (m_y[2] + m_y[1]) / 2 - (yc - (m_y[2] + m_y[1]) / 2); double x3 = (m_x[0] + m_x[2]) / 2 - (xc - (m_x[0] + m_x[2]) / 2); double y3 = (m_y[0] + m_y[2]) / 2 - (yc - (m_y[0] + m_y[2]) / 2); span_gen.colors(agg::rgba8(255, 0, 0, alpha), agg::rgba8(0, 255, 0, alpha), agg::rgba8(brc, brc, brc, alpha)); span_gen.triangle(m_x[0], m_y[0], m_x[1], m_y[1], xc, yc, d); ras.add_path(span_gen); ras.render(sl, ren_gouraud); span_gen.colors(agg::rgba8(0, 255, 0, alpha), agg::rgba8(0, 0, 255, alpha), agg::rgba8(brc, brc, brc, alpha)); span_gen.triangle(m_x[1], m_y[1], m_x[2], m_y[2], xc, yc, d); ras.add_path(span_gen); ras.render(sl, ren_gouraud); span_gen.colors(agg::rgba8(0, 0, 255, alpha), agg::rgba8(255, 0, 0, alpha), agg::rgba8(brc, brc, brc, alpha)); span_gen.triangle(m_x[2], m_y[2], m_x[0], m_y[0], xc, yc, d); ras.add_path(span_gen); ras.render(sl, ren_gouraud); brc = 255-brc; span_gen.colors(agg::rgba8(255, 0, 0, alpha), agg::rgba8(0, 255, 0, alpha), agg::rgba8(brc, brc, brc, alpha)); span_gen.triangle(m_x[0], m_y[0], m_x[1], m_y[1], x1, y1, d); ras.add_path(span_gen); ras.render(sl, ren_gouraud); span_gen.colors(agg::rgba8(0, 255, 0, alpha), agg::rgba8(0, 0, 255, alpha), agg::rgba8(brc, brc, brc, alpha)); span_gen.triangle(m_x[1], m_y[1], m_x[2], m_y[2], x2, y2, d); ras.add_path(span_gen); ras.render(sl, ren_gouraud); span_gen.colors(agg::rgba8(0, 0, 255, alpha), agg::rgba8(255, 0, 0, alpha), agg::rgba8(brc, brc, brc, alpha)); span_gen.triangle(m_x[2], m_y[2], m_x[0], m_y[0], x3, y3, d); ras.add_path(span_gen); ras.render(sl, ren_gouraud); }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> base_ren_type; pixfmt pf(rbuf_window()); base_ren_type ren_base(pf); ren_base.clear(agg::rgba(1, 1, 1)); agg::scanline_u8 sl; agg::rasterizer_scanline_aa<> ras; // Draw some background agg::ellipse ell; srand(1234); unsigned i; unsigned w = unsigned(width()); unsigned h = unsigned(height()); for (i = 0; i < 100; i++) { ell.init(rand() % w, rand() % h, rand() % 60 + 5, rand() % 60 + 5, 50); ras.add_path(ell); agg::render_scanlines_aa_solid( ras, sl, ren_base, agg::rgba(rand() / double(RAND_MAX), rand() / double(RAND_MAX), rand() / double(RAND_MAX), rand() / double(RAND_MAX) / 2.0)); } double parallelogram[6]; parallelogram[0] = m_x[0]; parallelogram[1] = m_y[0]; parallelogram[2] = m_x[1]; parallelogram[3] = m_y[1]; parallelogram[4] = m_x[2]; parallelogram[5] = m_y[2]; // Gradient shape function (linear, radial, custom, etc) //----------------- typedef agg::gradient_circle gradient_func_type; // Alpha gradient shape function (linear, radial, custom, etc) //----------------- typedef agg::gradient_xy gradient_alpha_func_type; // Span interpolator. This object is used in all span generators // that operate with transformations during iterating of the spans, // for example, image transformers use the interpolator too. //----------------- typedef agg::span_interpolator_linear<> interpolator_type; // Span allocator is an object that allocates memory for // the array of colors that will be used to render the // color spans. One object can be shared between different // span generators. //----------------- typedef agg::span_allocator<color_type> span_allocator_type; // Gradient colors array adaptor //----------------- typedef agg::pod_auto_array<color_type, 256> gradient_colors_type; // Finally, the gradient span generator working with the color_type // color type. //----------------- typedef agg::span_gradient<color_type, interpolator_type, gradient_func_type, gradient_colors_type> span_gradient_type; // Gradient alpha array adaptor //----------------- typedef agg::pod_auto_array<color_type::value_type, 256> gradient_alpha_type; // The alpha gradient span converter working with the color_type // color type. //----------------- typedef agg::span_gradient_alpha< color_type, interpolator_type, gradient_alpha_func_type, gradient_alpha_type> span_gradient_alpha_type; // Span converter type //----------------- typedef agg::span_converter<span_gradient_type, span_gradient_alpha_type> span_conv_type; // The gradient objects declarations //---------------- gradient_func_type gradient_func; // The gradient function gradient_alpha_func_type alpha_func; // The gradient function agg::trans_affine gradient_mtx; // Gradient affine transformer agg::trans_affine alpha_mtx; // Alpha affine transformer interpolator_type span_interpolator( gradient_mtx); // Span gradient interpolator interpolator_type span_interpolator_alpha( alpha_mtx); // Span alpha interpolator span_allocator_type span_allocator; // Span Allocator gradient_colors_type color_array; // The gradient colors // Declare the gradient span itself. // The last two arguments are so called "d1" and "d2" // defining two distances in pixels, where the gradient starts // and where it ends. The actual meaning of "d1" and "d2" depands // on the gradient function. //---------------- span_gradient_type span_gradient(span_interpolator, gradient_func, color_array, 0, 150); // Declare the gradient span itself. // The last two arguments are so called "d1" and "d2" // defining two distances in pixels, where the gradient starts // and where it ends. The actual meaning of "d1" and "d2" depands // on the gradient function. //---------------- gradient_alpha_type alpha_array; span_gradient_alpha_type span_gradient_alpha( span_interpolator_alpha, alpha_func, alpha_array, 0, 100); // Span converter declaration span_conv_type span_conv(span_gradient, span_gradient_alpha); // Finally we can draw a circle. //---------------- gradient_mtx *= agg::trans_affine_scaling(0.75, 1.2); gradient_mtx *= agg::trans_affine_rotation(-agg::pi / 3.0); gradient_mtx *= agg::trans_affine_translation(width() / 2, height() / 2); gradient_mtx.invert(); alpha_mtx.parl_to_rect(parallelogram, -100, -100, 100, 100); fill_color_array(color_array, agg::rgba(0, 0.19, 0.19), agg::rgba(0.7, 0.7, 0.19), agg::rgba(0.31, 0, 0)); // Fill Alpha array //---------------- for (i = 0; i < 256; i++) { alpha_array[i] = color_type::from_double(m_alpha.value(i / 255.0)); } ell.init(width() / 2, height() / 2, 150, 150, 100); ras.add_path(ell); // Render the circle with gradient plus alpha-gradient agg::render_scanlines_aa(ras, sl, ren_base, span_allocator, span_conv); // Draw the control points and the parallelogram //----------------- agg::rgba color_pnt(0, 0.4, 0.4, 0.31); ell.init(m_x[0], m_y[0], 5, 5, 20); ras.add_path(ell); agg::render_scanlines_aa_solid(ras, sl, ren_base, color_pnt); ell.init(m_x[1], m_y[1], 5, 5, 20); ras.add_path(ell); agg::render_scanlines_aa_solid(ras, sl, ren_base, color_pnt); ell.init(m_x[2], m_y[2], 5, 5, 20); ras.add_path(ell); agg::render_scanlines_aa_solid(ras, sl, ren_base, color_pnt); agg::vcgen_stroke stroke; stroke.add_vertex(m_x[0], m_y[0], agg::path_cmd_move_to); stroke.add_vertex(m_x[1], m_y[1], agg::path_cmd_line_to); stroke.add_vertex(m_x[2], m_y[2], agg::path_cmd_line_to); stroke.add_vertex(m_x[0] + m_x[2] - m_x[1], m_y[0] + m_y[2] - m_y[1], agg::path_cmd_line_to); stroke.add_vertex(0, 0, agg::path_cmd_end_poly | agg::path_flags_close); ras.add_path(stroke); agg::render_scanlines_aa_solid(ras, sl, ren_base, agg::rgba(0, 0, 0)); agg::render_ctrl(ras, sl, ren_base, m_alpha); }
virtual void on_draw() { typedef agg::renderer_base<pixfmt_pre> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline; typedef agg::scanline_u8 scanline; pixfmt_pre pixf(rbuf_window()); renderer_base ren_base(pixf); ren_base.clear(agg::rgba(1.0, 1.0, 0.95)); renderer_scanline ren(ren_base); agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> ras; agg::scanline_u8 sl; agg::conv_transform<agg::compound_shape> shape(m_shape, m_scale); agg::conv_stroke<agg::conv_transform<agg::compound_shape> > stroke(shape); m_shape.approximation_scale(m_scale.scale()); unsigned i; agg::path_storage tmp_path; ras.clip_box(0, 0, width(), height()); // This is an alternative method of Flash rasterization. // We decompose the compound shape into separate paths // and select the ones that fit the given style (left or right). // So that, we form a sub-shape and draw it as a whole. // // Here the regular scanline rasterizer is used, but it doesn't // automatically close the polygons. So that, the rasterizer // actually works with a set of polylines instead of polygons. // Of course, the data integrity must be preserved, that is, // the polylines must eventually form a closed contour // (or a set of closed contours). So that, first we set // auto_close(false); // // The second important thing is that one path can be rasterized // twice, if it has both, left and right fill. Sometimes the // path has equal left and right fill, so that, the same path // will be added twice even for a single sub-shape. If the // rasterizer can tolerate these degenerates you can add them, // but it's also fine just to omit them. // // The third thing is that for one side (left or right) // you should invert the direction of the paths. // // The main disadvantage of this method is imperfect stitching // of the adjacent polygons. The problem can be solved if we use // compositing operation "plus" instead of alpha-blend. But // in this case we are forced to use an RGBA buffer, clean it with // zero, rasterize using "plus" operation, and then alpha-blend // the result over the final scene. It can be too expensive. //------------------------------------------------------------ ras.auto_close(false); //ras.filling_rule(agg::fill_even_odd); start_timer(); for(int s = m_shape.min_style(); s <= m_shape.max_style(); s++) { ras.reset(); for(i = 0; i < m_shape.paths(); i++) { const agg::path_style& style = m_shape.style(i); if(style.left_fill != style.right_fill) { if(style.left_fill == s) { ras.add_path(shape, style.path_id); } if(style.right_fill == s) { tmp_path.remove_all(); tmp_path.concat_path(shape, style.path_id); tmp_path.invert_polygon(0); ras.add_path(tmp_path); } } } agg::render_scanlines_aa_solid(ras, sl, ren_base, m_colors[s]); } double tfill = elapsed_time(); ras.auto_close(true); // Draw strokes //---------------------- start_timer(); stroke.width(sqrt(m_scale.scale())); stroke.line_join(agg::round_join); stroke.line_cap(agg::round_cap); for(i = 0; i < m_shape.paths(); i++) { ras.reset(); if(m_shape.style(i).line >= 0) { ras.add_path(stroke, m_shape.style(i).path_id); ren.color(agg::srgba8(0,0,0, 128)); agg::render_scanlines(ras, sl, ren); } } double tstroke = elapsed_time(); char buf[256]; agg::gsv_text t; t.size(8.0); t.flip(true); agg::conv_stroke<agg::gsv_text> ts(t); ts.width(1.6); ts.line_cap(agg::round_cap); sprintf(buf, "Fill=%.2fms (%dFPS) Stroke=%.2fms (%dFPS) Total=%.2fms (%dFPS)\n\n" "Space: Next Shape\n\n" "+/- : ZoomIn/ZoomOut (with respect to the mouse pointer)", tfill, int(1000.0 / tfill), tstroke, int(1000.0 / tstroke), tfill+tstroke, int(1000.0 / (tfill+tstroke))); t.start_point(10.0, 20.0); t.text(buf); ras.add_path(ts); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); }
virtual void on_draw() { pixfmt pf(rbuf_window()); renderer_base ren_base(pf); ren_base.clear(agg::rgba(1.0, 1.0, 0.95)); renderer_scanline ren(ren_base); rasterizer_scanline ras; scanline sl; // Pattern source. Must have an interface: // width() const // height() const // pixel(int x, int y) const // Any agg::renderer_base<> or derived // is good for the use as a source. //----------------------------------- pattern_src_brightness_to_alpha p1(rbuf_img(0)); pattern_src_brightness_to_alpha p2(rbuf_img(1)); pattern_src_brightness_to_alpha p3(rbuf_img(2)); pattern_src_brightness_to_alpha p4(rbuf_img(3)); pattern_src_brightness_to_alpha p5(rbuf_img(4)); pattern_src_brightness_to_alpha p6(rbuf_img(5)); pattern_src_brightness_to_alpha p7(rbuf_img(6)); pattern_src_brightness_to_alpha p8(rbuf_img(7)); pattern_src_brightness_to_alpha p9(rbuf_img(8)); agg::pattern_filter_bilinear_rgba<color_type> fltr; // Filtering functor // agg::line_image_pattern is the main container for the patterns. It creates // a copy of the patterns extended according to the needs of the filter. // agg::line_image_pattern can operate with arbitrary image width, but if the // width of the pattern is power of 2, it's better to use the modified // version agg::line_image_pattern_pow2 because it works about 15-25 percent // faster than agg::line_image_pattern (because of using simple masking instead // of expensive '%' operation). typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba<color_type> > pattern_type; typedef agg::renderer_base<pixfmt> base_ren_type; typedef agg::renderer_outline_image<base_ren_type, pattern_type> renderer_type; typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type; //-- Create with specifying the source //pattern_type patt(fltr, src); //-- Create uninitialized and set the source pattern_type patt(fltr); renderer_type ren_img(ren_base, patt); rasterizer_type ras_img(ren_img); draw_curve(patt, ras_img, ren_img, p1, m_curve1.curve()); draw_curve(patt, ras_img, ren_img, p2, m_curve2.curve()); draw_curve(patt, ras_img, ren_img, p3, m_curve3.curve()); draw_curve(patt, ras_img, ren_img, p4, m_curve4.curve()); draw_curve(patt, ras_img, ren_img, p5, m_curve5.curve()); draw_curve(patt, ras_img, ren_img, p6, m_curve6.curve()); draw_curve(patt, ras_img, ren_img, p7, m_curve7.curve()); draw_curve(patt, ras_img, ren_img, p8, m_curve8.curve()); draw_curve(patt, ras_img, ren_img, p9, m_curve9.curve()); agg::render_ctrl(ras, sl, ren_base, m_curve1); agg::render_ctrl(ras, sl, ren_base, m_curve2); agg::render_ctrl(ras, sl, ren_base, m_curve3); agg::render_ctrl(ras, sl, ren_base, m_curve4); agg::render_ctrl(ras, sl, ren_base, m_curve5); agg::render_ctrl(ras, sl, ren_base, m_curve6); agg::render_ctrl(ras, sl, ren_base, m_curve7); agg::render_ctrl(ras, sl, ren_base, m_curve8); agg::render_ctrl(ras, sl, ren_base, m_curve9); agg::render_ctrl(ras, sl, ren_base, m_scale_x); agg::render_ctrl(ras, sl, ren_base, m_start_x); }
void grid_node_t::do_process( const render::context_t& context) { Imath::Color4f color( get_value<Imath::Color4f>( param( "bgcol"))); boost::gil::fill_pixels( image_view(), image::pixel_t( color.r, color.g, color.b, color.a)); Imath::V2f size( get_absolute_value<Imath::V2f>( param( "size"))); Imath::V2f translate( get_absolute_value<Imath::V2f>( param( "translate"))); Imath::V2f line_width( get_absolute_value<Imath::V2f>( param( "linewidth"))); color = get_value<Imath::Color4f>( param( "fgcol")); // adjust params size.x = size.x / context.subsample / aspect_ratio(); size.y /= context.subsample; if( size.x == 0 || size.y == 0) return; translate.x = translate.x / context.subsample / aspect_ratio(); translate.y /= context.subsample; line_width.x = line_width.x / context.subsample / aspect_ratio(); line_width.y /= context.subsample; if( line_width.x == 0 || line_width.y == 0) return; // setup agg typedef image::agg_rgba32f_renderer_t ren_base_type; typedef ren_base_type::color_type color_type; typedef agg::renderer_scanline_aa_solid<ren_base_type> renderer_type; ren_base_type ren_base( image_view()); renderer_type ren( ren_base); agg::rasterizer_scanline_aa<> ras; ras.gamma( agg::gamma_none()); agg::scanline_u8 sl; ras.reset(); agg::path_storage path; agg::conv_stroke<agg::path_storage> stroke_conv( path); // Vertical stroke_conv.width( line_width.x); int w = image_view().width(); int h = image_view().height(); Imath::Box2f area( defined().min - translate, defined().max - translate); float x = Imath::Math<float>::floor( area.min.x / size.x) * size.x; for( ; x < area.max.x + line_width.x; x += size.x) { path.move_to( x - area.min.x, 0); path.line_to( x - area.min.x, h); } ras.add_path( stroke_conv); ren.color( image::pixel_t( color.r, color.g, color.b, color.a)); agg::render_scanlines( ras, sl, ren); // Horizontal path.remove_all(); stroke_conv.width( line_width.y); float y = Imath::Math<float>::floor( area.min.y / size.y) * size.y; for( ; y < area.max.y + line_width.y; y += size.y) { path.move_to( 0, y - area.min.y); path.line_to( w, y - area.min.y); } ras.add_path( stroke_conv); ren.color( image::pixel_t( color.r, color.g, color.b, color.a)); agg::render_scanlines( ras, sl, ren); }
void agg_renderer<T0,T1>::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { using color = agg::rgba8; using order = agg::order_rgba; using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>; using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; using pattern_type = agg::line_image_pattern<pattern_filter_type>; using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>; using renderer_base = agg::renderer_base<pixfmt_type>; using renderer_type = agg::renderer_outline_image<renderer_base, pattern_type>; using rasterizer_type = agg::rasterizer_outline_aa<renderer_type>; std::string filename = get<std::string>(sym, keys::file, feature, common_.vars_); if (filename.empty()) return; boost::optional<mapnik::marker_ptr> marker_ptr = marker_cache::instance().find(filename, true); if (!marker_ptr || !(*marker_ptr)) return; boost::optional<image_ptr> pat; // TODO - re-implement at renderer level like polygon_pattern symbolizer double opacity = get<value_double>(sym, keys::opacity, feature, common_.vars_,1.0); if ((*marker_ptr)->is_bitmap()) { pat = (*marker_ptr)->get_bitmap_data(); } else { 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); pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); } if (!pat) return; bool clip = get<value_bool>(sym, keys::clip, feature, common_.vars_, false); double offset = get<value_double>(sym, keys::offset, feature, common_.vars_, 0.0); 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::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); pixfmt_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 ren_base(pixf); agg::pattern_filter_bilinear_rgba8 filter; pattern_source source(*(*pat), opacity); pattern_type pattern (filter,source); renderer_type ren(ren_base, pattern); rasterizer_type ras(ren); 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_); box2d<double> clip_box = clipping_extent(common_); if (clip) { double padding = (double)(common_.query_extent_.width()/pixmap_.width()); double half_stroke = (*marker_ptr)->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_; clip_box.pad(padding); } using conv_types = boost::mpl::vector<clip_line_tag, transform_tag, affine_transform_tag, simplify_tag,smooth_tag, offset_transform_tag>; vertex_converter<box2d<double>, rasterizer_type, line_pattern_symbolizer, view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl> converter(clip_box,ras,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 (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter for (geometry_type & geom : feature.paths()) { if (geom.size() > 1) { converter.apply(geom); } } }
void render_gouraud(Scanline& sl, Ras& ras) { double alpha = m_alpha.value(); double brc = 1; typedef agg::renderer_base<pixfmt> base_ren_type; #ifdef AGG_GRAY8 typedef agg::span_gouraud_gray<color_type> span_gen_type; #else typedef agg::span_gouraud_rgba<color_type> span_gen_type; #endif typedef agg::span_allocator<color_type> span_alloc_type; pixfmt pf(rbuf_window()); base_ren_type ren_base(pf); span_alloc_type span_alloc; span_gen_type span_gen; ras.gamma(agg::gamma_linear(0.0, m_gamma.value())); double d = m_dilation.value(); // Single triangle //span_gen.colors(agg::rgba(1, 0, 0, alpha), // agg::rgba(0, 1, 0, alpha), // agg::rgba(0, 0, 1, alpha)); //span_gen.triangle(m_x[0], m_y[0], m_x[1], m_y[1], m_x[2], m_y[2], d); //ras.add_path(span_gen); //agg::render_scanlines_aa(ras, sl, ren_base, span_alloc, span_gen); // Six triangles double xc = (m_x[0] + m_x[1] + m_x[2]) / 3.0; double yc = (m_y[0] + m_y[1] + m_y[2]) / 3.0; double x1 = (m_x[1] + m_x[0]) / 2 - (xc - (m_x[1] + m_x[0]) / 2); double y1 = (m_y[1] + m_y[0]) / 2 - (yc - (m_y[1] + m_y[0]) / 2); double x2 = (m_x[2] + m_x[1]) / 2 - (xc - (m_x[2] + m_x[1]) / 2); double y2 = (m_y[2] + m_y[1]) / 2 - (yc - (m_y[2] + m_y[1]) / 2); double x3 = (m_x[0] + m_x[2]) / 2 - (xc - (m_x[0] + m_x[2]) / 2); double y3 = (m_y[0] + m_y[2]) / 2 - (yc - (m_y[0] + m_y[2]) / 2); span_gen.colors(agg::rgba(1, 0, 0, alpha), agg::rgba(0, 1, 0, alpha), agg::rgba(brc, brc, brc, alpha)); span_gen.triangle(m_x[0], m_y[0], m_x[1], m_y[1], xc, yc, d); ras.add_path(span_gen); agg::render_scanlines_aa(ras, sl, ren_base, span_alloc, span_gen); span_gen.colors(agg::rgba(0, 1, 0, alpha), agg::rgba(0, 0, 1, alpha), agg::rgba(brc, brc, brc, alpha)); span_gen.triangle(m_x[1], m_y[1], m_x[2], m_y[2], xc, yc, d); ras.add_path(span_gen); agg::render_scanlines_aa(ras, sl, ren_base, span_alloc, span_gen); span_gen.colors(agg::rgba(0, 0, 1, alpha), agg::rgba(1, 0, 0, alpha), agg::rgba(brc, brc, brc, alpha)); span_gen.triangle(m_x[2], m_y[2], m_x[0], m_y[0], xc, yc, d); ras.add_path(span_gen); agg::render_scanlines_aa(ras, sl, ren_base, span_alloc, span_gen); brc = 1-brc; span_gen.colors(agg::rgba(1, 0, 0, alpha), agg::rgba(0, 1, 0, alpha), agg::rgba(brc, brc, brc, alpha)); span_gen.triangle(m_x[0], m_y[0], m_x[1], m_y[1], x1, y1, d); ras.add_path(span_gen); agg::render_scanlines_aa(ras, sl, ren_base, span_alloc, span_gen); span_gen.colors(agg::rgba(0, 1, 0, alpha), agg::rgba(0, 0, 1, alpha), agg::rgba(brc, brc, brc, alpha)); span_gen.triangle(m_x[1], m_y[1], m_x[2], m_y[2], x2, y2, d); ras.add_path(span_gen); agg::render_scanlines_aa(ras, sl, ren_base, span_alloc, span_gen); span_gen.colors(agg::rgba(0, 0, 1, alpha), agg::rgba(1, 0, 0, alpha), agg::rgba(brc, brc, brc, alpha)); span_gen.triangle(m_x[2], m_y[2], m_x[0], m_y[0], x3, y3, d); ras.add_path(span_gen); agg::render_scanlines_aa(ras, sl, ren_base, span_alloc, span_gen); }
void operator() (marker_svg const& marker) const { using color = agg::rgba8; using order = agg::order_rgba; using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>; using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; using pattern_type = agg::line_image_pattern<pattern_filter_type>; using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>; using renderer_base = agg::renderer_base<pixfmt_type>; using renderer_type = agg::renderer_outline_image<renderer_base, pattern_type>; using rasterizer_type = agg::rasterizer_outline_aa<renderer_type>; 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, common_.scale_factor_); mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr; image_rgba8 image(bbox_image.width(), bbox_image.height()); render_pattern<buffer_type>(*ras_ptr_, marker, image_tr, 1.0, image); 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_); agg::rendering_buffer buf(current_buffer_->bytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->row_size()); pixfmt_type pixf(buf); pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e, keys::comp_op>(sym_, feature_, common_.vars_))); renderer_base ren_base(pixf); agg::pattern_filter_bilinear_rgba8 filter; pattern_source source(image, opacity); pattern_type pattern (filter,source); renderer_type ren(ren_base, pattern); double half_stroke = std::max(marker.width()/2.0,marker.height()/2.0); int rast_clip_padding = static_cast<int>(std::round(half_stroke)); ren.clip_box(-rast_clip_padding,-rast_clip_padding,common_.width_+rast_clip_padding,common_.height_+rast_clip_padding); rasterizer_type ras(ren); 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_); box2d<double> clip_box = clipping_extent(common_); if (clip) { double padding = (double)(common_.query_extent_.width()/pixmap_.width()); if (half_stroke > 1) padding *= half_stroke; if (std::fabs(offset) > 0) padding *= std::fabs(offset) * 1.2; padding *= common_.scale_factor_; clip_box.pad(padding); } 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(clip_box,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); if (clip) converter.set<clip_line_tag>(); converter.set<transform_tag>(); //always transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform 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 operator() (marker_rgba8 const& marker) { using color = agg::rgba8; using order = agg::order_rgba; using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>; using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; using pattern_type = agg::line_image_pattern<pattern_filter_type>; using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>; using renderer_base = agg::renderer_base<pixfmt_type>; using renderer_type = agg::renderer_outline_image<renderer_base, pattern_type>; using rasterizer_type = agg::rasterizer_outline_aa<renderer_type>; value_double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_); mapnik::image_rgba8 const& image = marker.get_data(); 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_); agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); pixfmt_type pixf(buf); pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e, keys::comp_op>(sym_, feature_, common_.vars_))); renderer_base ren_base(pixf); agg::pattern_filter_bilinear_rgba8 filter; pattern_source source(image, opacity); pattern_type pattern (filter,source); renderer_type ren(ren_base, pattern); ren.clip_box(0,0,common_.width_,common_.height_); rasterizer_type ras(ren); 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_); box2d<double> clip_box = clipping_extent(common_); if (clip) { double padding = (double)(common_.query_extent_.width()/pixmap_.width()); double half_stroke = marker.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_; clip_box.pad(padding); } vertex_converter<rasterizer_type, clip_line_tag, transform_tag, affine_transform_tag, simplify_tag,smooth_tag, offset_transform_tag> converter(clip_box,ras,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 (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter for (geometry_type const& geom : feature_.paths()) { if (geom.size() > 1) { vertex_adapter va(geom); converter.apply(va); } } }