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);
        }
    }
}
Пример #4
0
 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);
            }
        }
    }

}
Пример #8
0
 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;
}
Пример #10
0
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);
        }
    }
}
Пример #11
0
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);
        }
    }
}
Пример #14
0
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);
        }
    }
}
Пример #15
0
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);
}
Пример #16
0
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);
            }
        }
    }
}
Пример #17
0
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);
            }
        }
    }

}
Пример #18
0
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);
                }
            }

        }
    }
}
Пример #19
0
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);
        }
    }
}
Пример #20
0
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);
                }
            }

        }
    }
}
Пример #21
0
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);
    }
}
Пример #22
0
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);
                }
            }
        }
    }
}
Пример #23
0
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();
}
Пример #26
0
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);
}
Пример #27
0
 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);
}