Esempio n. 1
0
pixel_position evaluate_displacement(double dx, double dy, directions_e dir)
{
    switch (dir)
    {
    case EXACT_POSITION:
        return pixel_position(dx,dy);
        break;
    case NORTH:
        return pixel_position(0,-std::abs(dy));
        break;
    case EAST:
        return pixel_position(std::abs(dx),0);
        break;
    case SOUTH:
        return pixel_position(0,std::abs(dy));
        break;
    case WEST:
        return pixel_position(-std::abs(dx),0);
        break;
    case NORTHEAST:
        return pixel_position(std::abs(dx),-std::abs(dy));
        break;
    case SOUTHEAST:
        return pixel_position(std::abs(dx),std::abs(dy));
        break;
    case NORTHWEST:
        return pixel_position(-std::abs(dx),-std::abs(dy));
        break;
    case SOUTHWEST:
        return pixel_position(-std::abs(dx),std::abs(dy));
        break;
    }
}
Esempio n. 2
0
    typename const_accessort_t::data_t integrate(const const_accessort_t & image) const
    {
      typename const_accessort_t::data_t result = 0.0;
      ublas::fixed_vector<float_t, SHAPE_DIMENSION> point, normal;

      for(size_t i = 0; i < n_points(); ++i)
      {
        point = (*this)(i, normal);
        
        // explicit cast of floating point values in "vertex" to pixel position!
        ublas::fixed_vector<size_t, const_accessort_t::dimension> pixel_position = ublas::fixed_vector<size_t, const_accessort_t::dimension>(point);
        bool is_valid_pixel = true;
        
        for(size_t i = 0; i < const_accessort_t::dimension; ++i)
        {
          if( ! ( pixel_position(i) < image.size()(i) ) )
          {
            is_valid_pixel = false;
            break;
          }
        }
        
        if(is_valid_pixel)
          result += image[pixel_position] * norm_2(normal);
      }

      return result;
    }
Esempio n. 3
0
box2d<double> placement_finder::get_bbox(text_layout const& layout, glyph_info const& glyph, pixel_position const& pos, rotation const& rot)
{
    /*

      (0/ymax)           (width/ymax)
      ***************
      *             *
      (0/0)*             *
      *             *
      ***************
      (0/ymin)          (width/ymin)
      Add glyph offset in y direction, but not in x direction (as we use the full cluster width anyways)!
    */
    double width = layout.cluster_width(glyph.char_index);
    if (glyph.advance() <= 0) width = -width;
    pixel_position tmp, tmp2;
    tmp.set(0, glyph.ymax());
    tmp = tmp.rotate(rot);
    tmp2.set(width, glyph.ymax());
    tmp2 = tmp2.rotate(rot);
    box2d<double> bbox(tmp.x,  -tmp.y,
                       tmp2.x, -tmp2.y);
    tmp.set(width, glyph.ymin());
    tmp = tmp.rotate(rot);
    bbox.expand_to_include(tmp.x, -tmp.y);
    tmp.set(0, glyph.ymin());
    tmp = tmp.rotate(rot);
    bbox.expand_to_include(tmp.x, -tmp.y);
    pixel_position pos2 = pos + pixel_position(0, glyph.offset.y).rotate(rot);
    bbox.move(pos2.x , -pos2.y);
    return bbox;
}
Esempio n. 4
0
    // arrange group members in x horizontal pairs of 2,
    // one to the left and one to the right of center in each pair
    void operator()(pair_layout const& layout) const
    {
        member_offsets_.resize(member_boxes_.size());
        double y_margin = layout.get_item_margin();
        double x_margin = y_margin / 2.0;

        if (member_boxes_.size() == 1)
        {
            member_offsets_[0] = pixel_position(0, 0) - input_origin_;
            return;
        }

        auto max_diff = layout.get_max_difference();
        auto layout_box = make_horiz_pair(0, 0.0, 0, x_margin, max_diff);
        auto y_shift = 0.5 * layout_box.height();

        for (size_t i = 2; i < member_boxes_.size(); i += 2)
        {
            auto y = layout_box.maxy() + y_margin;
            auto pair_box = make_horiz_pair(i, y, 1, x_margin, max_diff);
            layout_box.expand_to_include(pair_box);
        }

        // layout_box.center corresponds to the center of the first row;
        // shift offsets so that the whole group is centered vertically

        y_shift -= 0.5 * layout_box.height();

        for (auto & offset : member_offsets_)
        {
            offset.y += y_shift;
        }
    }
pixel_position shield_symbolizer_helper<FaceManagerT, DetectorT>::get_marker_position(text_path const& p)
{
    position const& pos = placement_->properties.displacement;
    if (placement_->properties.label_placement == LINE_PLACEMENT) {
        double lx = p.center.x - pos.first;
        double ly = p.center.y - pos.second;
        double px = lx - 0.5*marker_w_;
        double py = ly - 0.5*marker_h_;
        marker_ext_.re_center(lx, ly);
        //label is added to detector by get_line_placement(), but marker isn't
        detector_.insert(marker_ext_);
        return pixel_position(px, py);
    } else {
        //collision_detector is already updated for point placement in get_point_placement()
        return pixel_position(marker_x_, marker_y_);
    }
}
 void add_path(T & path)
 {
     marker_placement_enum placement_method = get<marker_placement_enum>(
         sym_, keys::markers_placement_type, feature_, vars_, MARKER_POINT_PLACEMENT);
     bool ignore_placement = get<bool>(sym_, keys::ignore_placement, feature_, vars_, false);
     bool allow_overlap = get<bool>(sym_, keys::allow_overlap, feature_, vars_, false);
     double opacity = get<double>(sym_, keys::opacity, feature_, vars_, 1.0);
     double spacing = get<double>(sym_, keys::spacing, feature_, vars_, 100.0);
     double max_error = get<double>(sym_, keys::max_error, feature_, vars_, 0.2);
     coord2d center = bbox_.center();
     agg::trans_affine_translation recenter(-center.x, -center.y);
     agg::trans_affine tr = recenter * marker_trans_;
     markers_placement_finder<T, label_collision_detector4> placement_finder(
         placement_method,
         path,
         bbox_,
         tr,
         detector_,
         spacing * scale_factor_,
         max_error,
         allow_overlap);
     double x, y, angle = .0;
     while (placement_finder.get_point(x, y, angle, ignore_placement))
     {
         agg::trans_affine matrix = tr;
         matrix.rotate(angle);
         matrix.translate(x, y);
         render_vector_marker(
             ctx_,
             pixel_position(x, y),
             marker_,
             bbox_,
             attributes_,
             matrix,
             opacity,
             false);
     }
 }
Esempio n. 7
0
    float_t integrate_vector_field
    (const const_vector_accessor_t & vector_field) const
    {
      float_t result = 0.0;
      ublas::fixed_vector<float_t, SHAPE_DIMENSION> point, normal;

      for(size_t i = 0; i < n_points(); ++i)
      {
        point = (*this)(i, normal);
        
        // explicit cast of floating point values in "vertex" to pixel position!
        ublas::fixed_vector<size_t, const_vector_accessor_t::dimension> pixel_position = ublas::fixed_vector<size_t, const_vector_accessor_t::dimension>(point);
        bool is_valid_pixel = true;
        
        for(size_t i = 0; i < const_vector_accessor_t::dimension; ++i)
        {
          if( ! ( pixel_position(i) < vector_field.size()(i) ) )
          {
            is_valid_pixel = false;
            break;
          }
        }
        
        if(is_valid_pixel)
          // Note: unit normal * tangential speed = normal
          result += inner_prod(vector_field[pixel_position], normal);
        else
        {
          ublas::fixed_vector<float_t, SHAPE_DIMENSION> value;
          boundary_discretizer_impl::compute_zero_extension(vector_field, point, value);
          result += inner_prod(value, normal);
        }
      }

      return result;
    }
Esempio n. 8
0
bool placement_finder::find_point_placement(pixel_position const& pos)
{
    glyph_positions_ptr glyphs = std::make_shared<glyph_positions>();
    std::vector<box2d<double> > bboxes;

    glyphs->reserve(layouts_.glyphs_count());
    bboxes.reserve(layouts_.size());

    bool base_point_set = false;
    for (auto const& layout_ptr : layouts_)
    {
        text_layout const& layout = *layout_ptr;
        rotation const& orientation = layout.orientation();

        // Find text origin.
        pixel_position layout_center = pos + layout.displacement();

        if (!base_point_set)
        {
            glyphs->set_base_point(layout_center);
            base_point_set = true;
        }

        box2d<double> bbox = layout.bounds();
        bbox.re_center(layout_center.x, layout_center.y);

        /* For point placements it is faster to just check the bounding box. */
        if (collision(bbox, layouts_.text(), false)) return false;

        if (layout.num_lines()) bboxes.push_back(std::move(bbox));

        pixel_position layout_offset = layout_center - glyphs->get_base_point();
        layout_offset.y = -layout_offset.y;

        // IMPORTANT NOTE:
        //   x and y are relative to the center of the text
        //   coordinate system:
        //   x: grows from left to right
        //   y: grows from bottom to top (opposite of normal computer graphics)

        double x, y;

        // set for upper left corner of text envelope for the first line, top left of first character
        y = layout.height() / 2.0;

        for ( auto const& line : layout)
        {
            y -= line.height(); //Automatically handles first line differently
            x = layout.jalign_offset(line.width());

            for (auto const& glyph : line)
            {
                // place the character relative to the center of the string envelope
                glyphs->emplace_back(glyph, (pixel_position(x, y).rotate(orientation)) + layout_offset, orientation);
                if (glyph.advance())
                {
                    //Only advance if glyph is not part of a multiple glyph sequence
                    x += glyph.advance() + glyph.format->character_spacing * scale_factor_;
                }
            }
        }
    }

    // add_marker first checks for collision and then updates the detector.
    if (has_marker_ && !add_marker(glyphs, pos)) return false;

    for (box2d<double> const& bbox : bboxes)
    {
        detector_.insert(bbox, layouts_.text());
    }
    placements_.push_back(glyphs);

    return true;
}
Esempio n. 9
0
void base_symbolizer_helper::initialize_points()
{
    label_placement_enum how_placed = placement_->properties.label_placement;
    if (how_placed == LINE_PLACEMENT)
    {
        point_placement_ = false;
        return;
    }
    else
    {
        point_placement_ = true;
    }

    double label_x=0.0;
    double label_y=0.0;
    double z=0.0;

    for (auto * geom_ptr : geometries_to_process_)
    {
        geometry_type const& geom = *geom_ptr;
        if (how_placed == VERTEX_PLACEMENT)
        {
            geom.rewind(0);
            for(unsigned i = 0; i < geom.size(); ++i)
            {
                geom.vertex(&label_x, &label_y);
                prj_trans_.backward(label_x, label_y, z);
                t_.forward(&label_x, &label_y);
                points_.push_back(pixel_position(label_x, label_y));
            }
        }
        else
        {
            // https://github.com/mapnik/mapnik/issues/1423
            bool success = false;
            // https://github.com/mapnik/mapnik/issues/1350
            if (geom.type() == geometry_type::types::LineString)
            {
                success = label::middle_point(geom, label_x,label_y);
            }
            else if (how_placed == POINT_PLACEMENT)
            {
                success = label::centroid(geom, label_x, label_y);
            }
            else if (how_placed == INTERIOR_PLACEMENT)
            {
                success = label::interior_position(geom, label_x, label_y);
            }
            else
            {
                MAPNIK_LOG_ERROR(symbolizer_helpers) << "ERROR: Unknown placement type in initialize_points()";
            }
            if (success)
            {
                prj_trans_.backward(label_x, label_y, z);
                t_.forward(&label_x, &label_y);
                points_.push_back(pixel_position(label_x, label_y));
            }
        }
    }
    point_itr_ = points_.begin();
}
Esempio n. 10
0
void cairo_context::add_text(glyph_positions const& pos,
                             cairo_face_manager & manager,
                             composite_mode_e comp_op,
                             composite_mode_e halo_comp_op,
                             double scale_factor)
{
    pixel_position const& base_point = pos.get_base_point();
    const double sx = base_point.x;
    const double sy = base_point.y;

    for (auto const& glyph_pos : pos)
    {
        glyph_info const& glyph = glyph_pos.glyph;
        glyph.face->set_character_sizes(glyph.format->text_size * scale_factor);
    }

    //render halo
    double halo_radius = 0;
    set_operator(halo_comp_op);
    for (auto const& glyph_pos : pos)
    {
        glyph_info const& glyph = glyph_pos.glyph;
        halo_radius = glyph.format->halo_radius * scale_factor;
        // make sure we've got reasonable values.
        if (halo_radius <= 0.0 || halo_radius > 1024.0) continue;
        double text_size = glyph.format->text_size * scale_factor;
        cairo_matrix_t matrix;
        matrix.xx = text_size * glyph_pos.rot.cos;
        matrix.xy = text_size * glyph_pos.rot.sin;
        matrix.yx = text_size * -glyph_pos.rot.sin;
        matrix.yy = text_size * glyph_pos.rot.cos;
        matrix.x0 = 0;
        matrix.y0 = 0;
        set_font_matrix(matrix);
        set_font_face(manager, glyph.face);
        pixel_position new_pos = glyph_pos.pos + glyph.offset.rotate(glyph_pos.rot);
        glyph_path(glyph.glyph_index, pixel_position(sx + new_pos.x, sy - new_pos.y));
        set_line_width(2.0 * halo_radius);
        set_line_join(ROUND_JOIN);
        set_color(glyph.format->halo_fill, glyph.format->halo_opacity);
        stroke();
    }
    set_operator(comp_op);
    for (auto const& glyph_pos : pos)
    {
        glyph_info const& glyph = glyph_pos.glyph;
        double text_size = glyph.format->text_size * scale_factor;
        cairo_matrix_t matrix;
        matrix.xx = text_size * glyph_pos.rot.cos;
        matrix.xy = text_size * glyph_pos.rot.sin;
        matrix.yx = text_size * -glyph_pos.rot.sin;
        matrix.yy = text_size * glyph_pos.rot.cos;
        matrix.x0 = 0;
        matrix.y0 = 0;
        set_font_matrix(matrix);
        set_font_face(manager, glyph.face);
        pixel_position new_pos = glyph_pos.pos + glyph.offset.rotate(glyph_pos.rot);
        set_color(glyph.format->fill, glyph.format->text_opacity);
        show_glyph(glyph.glyph_index, pixel_position(sx + new_pos.x, sy - new_pos.y));
    }

}
Esempio n. 11
0
bool placement_finder::find_point_placement(pixel_position const& pos)
{
    glyph_positions_ptr glyphs = std::make_shared<glyph_positions>();
    std::vector<box2d<double> > bboxes;

    glyphs->reserve(layouts_.glyphs_count());
    bboxes.reserve(layouts_.size());
    box2d<double> bbox;

    double max_line_width = 0.0;
    double first_line_height = -1.0;
    bool base_point_set = false;
    for (auto const& layout_ptr : layouts_)
    {
        text_layout const& layout = *layout_ptr;
        rotation const& orientation = layout.orientation();

        // Find text origin.
        pixel_position layout_center = pos + layout.displacement();

        if (!base_point_set)
        {
            glyphs->set_base_point(layout_center);
            base_point_set = true;
        }

        bbox = layout.bounds();
        bbox.re_center(layout_center.x, layout_center.y);

        /* For point placements it is faster to just check the bounding box. */
        if (collision(bbox, layouts_.text(), false)) return false;

        if (layout.num_lines()) bboxes.push_back(std::move(bbox));

        pixel_position layout_offset = layout_center - glyphs->get_base_point();
        layout_offset.y = -layout_offset.y;

        // IMPORTANT NOTE:
        //   x and y are relative to the center of the text
        //   coordinate system:
        //   x: grows from left to right
        //   y: grows from bottom to top (opposite of normal computer graphics)

        double x, y;

        // set for upper left corner of text envelope for the first line, top left of first character
        y = layout.height() / 2.0;

        for ( auto const& line : layout)
        {
            y -= line.height(); //Automatically handles first line differently
            x = layout.jalign_offset(line.width());
            if(line.width() > max_line_width)
            {
                max_line_width = line.width();
            }
            if(first_line_height <= 0.0 )
            {
                first_line_height = line.line_height() / scale_factor_;
            }
            for (auto const& glyph : line)
            {
                // place the character relative to the center of the string envelope
                glyphs->emplace_back(glyph, (pixel_position(x, y).rotate(orientation)) + layout_offset, orientation);
                if (glyph.advance())
                {
                    //Only advance if glyph is not part of a multiple glyph sequence
                    x += glyph.advance() + glyph.format->character_spacing * scale_factor_;
                }
            }
        }
    }

    // add_marker first checks for collision and then updates the detector.
    if (has_marker_ )
    {
        agg::trans_affine placement_tr;
        if(text_props_->fit_marker && glyphs->size() > 0)
        {
            double padding = 0.1;
            double width_scale = bbox.width() / marker_box_.width() + 2*padding;        // 2 because the text is being padded on both sides.
            double heigh_scale = bbox.height() / marker_box_.height() + 2*padding;      // 2 because the text is being padded on both sides.
            placement_tr.scale(width_scale, heigh_scale);
            //now we will need to shift the bbox it will fit the padding
            placement_tr.translate(- padding, - padding );
        }
        if(!add_marker(glyphs, pos, false, placement_tr))
        {
            return false;
        }
    }



    for (box2d<double> const& bbox : bboxes)
    {
        detector_.insert(bbox, layouts_.text());
    }
    placements_.push_back(glyphs);

    return true;
}
Esempio n. 12
0
 pixel_position operator~() const
 {
     return pixel_position(x, -y);
 }
Esempio n. 13
0
 pixel_position operator- (pixel_position const& other) const
 {
     return pixel_position(x - other.x, y - other.y);
 }
Esempio n. 14
0
pixel_position pixel_position::rotate(rotation const& rot) const
{
    return pixel_position(x * rot.cos - y * rot.sin, x * rot.sin + y * rot.cos);
}
Esempio n. 15
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);
        }
    }
}
Esempio n. 16
0
 pixel_position operator+ (pixel_position const& other) const
 {
     return pixel_position(x + other.x, y + other.y);
 }
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);
            }
        }
    }

}
Esempio n. 18
0
 pixel_position operator* (double other) const
 {
     return pixel_position(x * other, y * other);
 }
Esempio n. 19
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);
            }
        }
    }

}
Esempio n. 20
0
inline pixel_position operator* (double factor, pixel_position const& pos)
{
    return pixel_position(factor * pos.x, factor * pos.y);
}
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);
            }
        }
    }
}