Пример #1
0
datasource_ptr datasource_cache::create(const parameters& params)
{
    boost::optional<std::string> type = params.get<std::string>("type");
    if ( ! type)
    {
        throw config_error(std::string("Could not create datasource. Required ") +
                           "parameter 'type' is missing");
    }

#ifdef MAPNIK_THREADSAFE
    mutex::scoped_lock lock(mutex_);
#endif

    datasource_ptr ds;
    std::map<std::string,boost::shared_ptr<PluginInfo> >::iterator itr=plugins_.find(*type);
    if ( itr == plugins_.end() )
    {
        std::string s("Could not create datasource for type: '");
        s += *type + "'";
        if (plugin_directories_.empty())
        {
            s + " (no datasource plugin directories have been successfully registered)";
        }
        else
        {
            s + " (searched for datasource plugins in '" + plugin_directories() + "')";
        }
        throw config_error(s);
    }

    if ( ! itr->second->handle())
    {
        throw std::runtime_error(std::string("Cannot load library: ") +
                                 lt_dlerror());
    }

    // http://www.mr-edd.co.uk/blog/supressing_gcc_warnings
#ifdef __GNUC__
    __extension__
#endif
    create_ds* create_datasource =
        reinterpret_cast<create_ds*>(lt_dlsym(itr->second->handle(), "create"));

    if (! create_datasource)
    {
        throw std::runtime_error(std::string("Cannot load symbols: ") +
                                 lt_dlerror());
    }

#ifdef MAPNIK_LOG
    MAPNIK_LOG_DEBUG(datasource_cache) << "datasource_cache: Size=" << params.size();

    parameters::const_iterator i = params.begin();
    for (; i != params.end(); ++i)
    {
        MAPNIK_LOG_DEBUG(datasource_cache) << "datasource_cache: -- " << i->first << "=" << i->second;
    }
#endif

    ds = datasource_ptr(create_datasource(params), datasource_deleter());

    MAPNIK_LOG_DEBUG(datasource_cache) << "datasource_cache: Datasource=" << ds << " type=" << type;

    return ds;
}
Пример #2
0
void user_warning_fn(png_structp /*png_ptr*/, png_const_charp warning_msg)
{
    MAPNIK_LOG_DEBUG(png_reader) << "libpng warning: '" << warning_msg << "'";
}
Пример #3
0
bool freetype_engine::register_font_impl(std::string const& file_name,
                                         font_library & library,
                                         freetype_engine::font_file_mapping_type & font_file_mapping)
{
    MAPNIK_LOG_DEBUG(font_engine_freetype) << "registering: " << file_name;
    mapnik::util::file file(file_name);
    if (!file) return false;

    FT_Face face = 0;
    FT_Open_Args args;
    FT_StreamRec streamRec;
    memset(&args, 0, sizeof(args));
    memset(&streamRec, 0, sizeof(streamRec));
    streamRec.base = 0;
    streamRec.pos = 0;
    streamRec.size = file.size();
    streamRec.descriptor.pointer = file.get();
    streamRec.read  = ft_read_cb;
    streamRec.close = nullptr;
    args.flags = FT_OPEN_STREAM;
    args.stream = &streamRec;
    int num_faces = 0;
    bool success = false;
    // some font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < num_faces; ++i )
    {
        // if face is null then this is the first face
        FT_Error error = FT_Open_Face(library.get(), &args, i, &face);
        if (error) break;
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (num_faces == 0)
            num_faces = face->num_faces;
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                // http://stackoverflow.com/a/24795559/2333354
                auto range = font_file_mapping.equal_range(name);
                if (range.first == range.second) // the key was previously absent; insert a pair
                {
                    font_file_mapping.emplace_hint(range.first, name, std::make_pair(i,file_name));
                }
                else // the key was present, replace the associated value
                { /* some action with value range.first->second about to be overwritten here */
                    MAPNIK_LOG_WARN(font_engine_freetype) << "registering new " << name << " at '" << file_name << "'";
                    range.first->second = std::make_pair(i,file_name); // replace value
                }
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            s << "Warning: unable to load font file '" << file_name << "' ";
            if (!face->family_name && !face->style_name)
                s << "which lacks both a family name and style name";
            else if (face->family_name)
                s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name";
            else if (face->style_name)
                s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name";
            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
        if (face) FT_Done_Face(face);
    }
    return success;
}
void grid_renderer<T>::process(line_pattern_symbolizer const& sym,
                               mapnik::feature_impl & feature,
                               proj_transform const& prj_trans)
{
    std::string filename = get<std::string>(sym, keys::file, 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;

    bool clip = get<value_bool>(sym, keys::clip, feature);
    double offset = get<value_double>(sym, keys::offset, feature, 0.0);
    double simplify_tolerance = get<value_double>(sym, keys::simplify_tolerance, feature, 0.0);
    double smooth = get<value_double>(sym, keys::smooth, feature, false);

    typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type;
    typedef typename grid_renderer_base_type::pixfmt_type::color_type color_type;
    typedef agg::renderer_scanline_bin_solid<grid_renderer_base_type> renderer_type;
    typedef boost::mpl::vector<clip_line_tag, transform_tag,
                               offset_transform_tag, affine_transform_tag,
                               simplify_tag, smooth_tag, stroke_tag> conv_types;
    agg::scanline_bin sl;

    grid_rendering_buffer buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_);
    pixfmt_type pixf(buf);

    grid_renderer_base_type renb(pixf);
    renderer_type ren(renb);

    ras_ptr->reset();

    int stroke_width = (*pat)->width();

    agg::trans_affine tr;
    auto transform = get_optional<transform_type>(sym, keys::geometry_transform);
    if (transform) { evaluate_transform(tr, feature, *transform, common_.scale_factor_); }

    box2d<double> clipping_extent = common_.query_extent_;
    if (clip)
    {
        double padding = (double)(common_.query_extent_.width()/pixmap_.width());
        double half_stroke = stroke_width/2.0;
        if (half_stroke > 1)
            padding *= half_stroke;
        if (std::fabs(offset) > 0)
            padding *= std::fabs(offset) * 1.2;
        padding *= common_.scale_factor_;
        clipping_extent.pad(padding);
    }
    
    // to avoid the complexity of using an agg pattern filter instead
    // we create a line_symbolizer in order to fake the pattern
    line_symbolizer line;
    put<value_double>(line, keys::stroke_width, value_double(stroke_width));
    // TODO: really should pass the offset to the fake line too, but
    // this wasn't present in the previous version and makes the test
    // fail - in this case, probably the test should be updated.
    //put<value_double>(line, keys::offset, value_double(offset));
    put<value_double>(line, keys::simplify_tolerance, value_double(simplify_tolerance));
    put<value_double>(line, keys::smooth, value_double(smooth));

    vertex_converter<box2d<double>, grid_rasterizer, line_symbolizer,
                     CoordTransform, proj_transform, agg::trans_affine, conv_types, feature_impl>
        converter(clipping_extent,*ras_ptr,line,common_.t_,prj_trans,tr,feature,common_.scale_factor_);
    if (clip) converter.set<clip_line_tag>(); // optional clip (default: true)
    converter.set<transform_tag>(); // always transform
    if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
    converter.set<affine_transform_tag>(); // optional affine transform
    if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter
    if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter
    converter.set<stroke_tag>(); //always stroke

    for (geometry_type & geom : feature.paths())
    {
        if (geom.size() > 1)
        {
            converter.apply(geom);
        }
    }

    // render id
    ren.color(color_type(feature.id()));
    agg::render_scanlines(*ras_ptr, sl, ren);

    // add feature properties to grid cache
    pixmap_.add_feature(feature);

}
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);
}
Пример #6
0
void Map::zoom_all()
{
    try
    {
        if (layers_.empty())
        {
            return;
        }
        projection proj0(srs_);
        box2d<double> ext;
        bool success = false;
        bool first = true;
        std::vector<layer>::const_iterator itr = layers_.begin();
        std::vector<layer>::const_iterator end = layers_.end();
        while (itr != end)
        {
            if (itr->active())
            {
                std::string const& layer_srs = itr->srs();
                projection proj1(layer_srs);
                proj_transform prj_trans(proj0,proj1);
                box2d<double> layer_ext = itr->envelope();
                if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS))
                {
                    success = true;
                    MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " original ext=" << itr->envelope();
                    MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " transformed to map srs=" << layer_ext;
                    if (first)
                    {
                        ext = layer_ext;
                        first = false;
                    }
                    else
                    {
                        ext.expand_to_include(layer_ext);
                    }
                }
            }
            ++itr;
        }
        if (success)
        {
            if (maximum_extent_) {
                ext.clip(*maximum_extent_);
            }
            zoom_to_box(ext);
        }
        else
        {
            if (maximum_extent_)
            {
                MAPNIK_LOG_ERROR(map) << "could not zoom to combined layer extents"
                    << " so falling back to maximum-extent for zoom_all result";
                zoom_to_box(*maximum_extent_);
            }
            else
            {
                std::ostringstream s;
                s << "could not zoom to combined layer extents "
                  << "using zoom_all because proj4 could not "
                  << "back project any layer extents into the map srs "
                  << "(set map 'maximum-extent' to override layer extents)";
                throw std::runtime_error(s.str());
            }
        }
    }
    catch (proj_init_error const& ex)
    {
        throw mapnik::config_error(std::string("Projection error during map.zoom_all: ") + ex.what());
    }
}
Пример #7
0
void agg_renderer<T>::end_layer_processing(layer const&)
{
    MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End layer processing";
}
Пример #8
0
mapnik::raster_ptr
pgraster_wkb_reader::get_raster() {

    /* Read endianness */
    endian_ = *ptr_;
    ptr_ += 1;

    /* Read version of protocol */
    uint16_t version = read_uint16(&ptr_, endian_);
    if (version != 0) {
       MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: WKB version "
          << version << " unsupported";
      return mapnik::raster_ptr();
    }

    numBands_ = read_uint16(&ptr_, endian_);
    double scaleX = read_float64(&ptr_, endian_);
    double scaleY = read_float64(&ptr_, endian_);
    double ipX = read_float64(&ptr_, endian_);
    double ipY = read_float64(&ptr_, endian_);
    double skewX = read_float64(&ptr_, endian_);
    double skewY = read_float64(&ptr_, endian_);
    int32_t srid = read_int32(&ptr_, endian_);
    width_ = read_uint16(&ptr_, endian_);
    height_ = read_uint16(&ptr_, endian_);

    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: numBands=" << numBands_;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: scaleX=" << scaleX;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: scaleY=" << scaleY;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: ipX=" << ipX;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: ipY=" << ipY;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: skewX=" << skewX;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: skewY=" << skewY;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: srid=" << srid;
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: size="
      << width_ << "x" << height_;

    // this is for color interpretation
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: bandno=" << bandno_;

    if ( skewX || skewY ) {
      MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: raster rotation is not supported";
      return mapnik::raster_ptr();
    }

    mapnik::box2d<double> ext(ipX,ipY,ipX+(width_*scaleX),ipY+(height_*scaleY));
    MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: Raster extent=" << ext;

    if ( bandno_ )
    {
      if ( bandno_ != 1 )
      {
          MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: "
              "reading bands other than 1st as indexed is unsupported";
          return mapnik::raster_ptr();
      }
      MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: requested band " << bandno_;
      return read_indexed(ext, width_, height_);
    }
    else
    {
      switch (numBands_)
      {
        case 1:
          return read_grayscale(ext, width_, height_);
          break;
        case 3:
        case 4:
          return read_rgba(ext, width_, height_);
          break;
        default:
          std::ostringstream err;
          err << "pgraster_wkb_reader: raster with "
              << numBands_
              << " bands is not supported, specify a band number";
          //MAPNIK_LOG_WARN(pgraster) << err.str();
          throw mapnik::datasource_exception(err.str());
          return mapnik::raster_ptr();
      }
    }
    return mapnik::raster_ptr();
}
Пример #9
0
void png_reader::init()
{
    FILE *fp=fopen(fileName_.c_str(),"rb");
    if (!fp) throw image_reader_exception("cannot open image file "+fileName_);
    png_byte header[8];
    memset(header,0,8);
    if ( fread(header,1,8,fp) != 8)
    {
        fclose(fp);
        throw image_reader_exception("Could not read " + fileName_);
    }
    int is_png=!png_sig_cmp(header,0,8);
    if (!is_png)
    {
        fclose(fp);
        throw image_reader_exception(fileName_ + " is not a png file");
    }
    png_structp png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING,0,0,0);

    if (!png_ptr)
    {
        fclose(fp);
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    try
    {
        info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_read_struct(&png_ptr,0,0);
            fclose(fp);
            throw image_reader_exception("failed to create info_ptr");
        }
    }
    catch (std::exception const& ex)
    {
        png_destroy_read_struct(&png_ptr,0,0);
        fclose(fp);
        throw;
    }

    png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data);

    png_set_sig_bytes(png_ptr,8);
    png_read_info(png_ptr, info_ptr);

    png_uint_32  width, height;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth_, &color_type_,0,0,0);

    width_=width;
    height_=height;

    MAPNIK_LOG_DEBUG(png_reader) << "png_reader: bit_depth=" << bit_depth_ << ",color_type=" << color_type_;

    png_destroy_read_struct(&png_ptr,&info_ptr,0);
    fclose(fp);
}
void grid_renderer<T>::process(line_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;

    typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type;
    typedef typename grid_renderer_base_type::pixfmt_type::color_type color_type;
    typedef agg::renderer_scanline_bin_solid<grid_renderer_base_type> renderer_type;
    typedef boost::mpl::vector<clip_line_tag, transform_tag,
                               offset_transform_tag, affine_transform_tag,
                               simplify_tag, smooth_tag, stroke_tag> conv_types;
    agg::scanline_bin sl;

    grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_);
    pixfmt_type pixf(buf);

    grid_renderer_base_type renb(pixf);
    renderer_type ren(renb);

    ras_ptr->reset();

    int stroke_width = (*pat)->width();

    agg::trans_affine tr;
    evaluate_transform(tr, feature, sym.get_transform(), scale_factor_);

    box2d<double> clipping_extent = query_extent_;
    if (sym.clip())
    {
        double padding = (double)(query_extent_.width()/pixmap_.width());
        double half_stroke = stroke_width/2.0;
        if (half_stroke > 1)
            padding *= half_stroke;
        if (std::fabs(sym.offset()) > 0)
            padding *= std::fabs(sym.offset()) * 1.2;
        padding *= scale_factor_;
        clipping_extent.pad(padding);
    }
    
    // to avoid the complexity of using an agg pattern filter instead
    // we create a line_symbolizer in order to fake the pattern
    stroke str;
    str.set_width(stroke_width);
    line_symbolizer line(str);
    vertex_converter<box2d<double>, grid_rasterizer, line_symbolizer,
                     CoordTransform, proj_transform, agg::trans_affine, conv_types>
        converter(clipping_extent,*ras_ptr,line,t_,prj_trans,tr,scale_factor_);
    if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
    converter.set<transform_tag>(); // always transform
    if (std::fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
    converter.set<affine_transform_tag>(); // optional affine transform
    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
    converter.set<stroke_tag>(); //always stroke

    for (geometry_type & geom : feature.paths())
    {
        if (geom.size() > 1)
        {
            converter.apply(geom);
        }
    }

    // render id
    ren.color(color_type(feature.id()));
    agg::render_scanlines(*ras_ptr, sl, ren);

    // add feature properties to grid cache
    pixmap_.add_feature(feature);

}
void feature_style_processor<Processor>::prepare_layer(layer_rendering_material & mat,
                                                       feature_style_context_map & ctx_map,
                                                       Processor & p,
                                                       double scale,
                                                       double scale_denom,
                                                       unsigned width,
                                                       unsigned height,
                                                       box2d<double> const& extent,
                                                       int buffer_size,
                                                       std::set<std::string>& names)
{
    layer const& lay = mat.lay_;

    std::vector<std::string> const& style_names = lay.styles();

    std::size_t num_styles = style_names.size();
    if (num_styles == 0)
    {
        MAPNIK_LOG_DEBUG(feature_style_processor)
            << "feature_style_processor: No style for layer=" << lay.name();
        return;
    }

    mapnik::datasource_ptr ds = lay.datasource();
    if (!ds)
    {
        MAPNIK_LOG_DEBUG(feature_style_processor)
            << "feature_style_processor: No datasource for layer=" << lay.name();
        return;
    }

    processor_context_ptr current_ctx = ds->get_context(ctx_map);
    proj_transform prj_trans(mat.proj0_,mat.proj1_);

    box2d<double> query_ext = extent; // unbuffered
    box2d<double> buffered_query_ext(query_ext);  // buffered

    double buffer_padding = 2.0 * scale;
    boost::optional<int> layer_buffer_size = lay.buffer_size();
    if (layer_buffer_size) // if layer overrides buffer size, use this value to compute buffered extent
    {
        buffer_padding *= *layer_buffer_size;
    }
    else
    {
        buffer_padding *= buffer_size;
    }
    buffered_query_ext.width(query_ext.width() + buffer_padding);
    buffered_query_ext.height(query_ext.height() + buffer_padding);

    // clip buffered extent by maximum extent, if supplied
    boost::optional<box2d<double> > const& maximum_extent = m_.maximum_extent();
    if (maximum_extent)
    {
        buffered_query_ext.clip(*maximum_extent);
    }

    box2d<double> layer_ext = lay.envelope();
    const box2d<double> buffered_query_ext_map_srs = buffered_query_ext;
    bool fw_success = false;
    bool early_return = false;

    // first, try intersection of map extent forward projected into layer srs
    if (prj_trans.forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext))
    {
        fw_success = true;
        layer_ext.clip(buffered_query_ext);
    }
    // if no intersection and projections are also equal, early return
    else if (prj_trans.equal())
    {
        early_return = true;
    }
    // next try intersection of layer extent back projected into map srs
    else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext_map_srs.intersects(layer_ext))
    {
        layer_ext.clip(buffered_query_ext_map_srs);
        // forward project layer extent back into native projection
        if (! prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS))
        {
            MAPNIK_LOG_ERROR(feature_style_processor)
                << "feature_style_processor: Layer=" << lay.name()
                << " extent=" << layer_ext << " in map projection "
                << " did not reproject properly back to layer projection";
        }
    }
    else
    {
        // if no intersection then nothing to do for layer
        early_return = true;
    }

    std::vector<feature_type_style const*> & active_styles = mat.active_styles_;

    if (early_return)
    {
        // check for styles needing compositing operations applied
        // https://github.com/mapnik/mapnik/issues/1477
        for (std::string const& style_name : style_names)
        {
            boost::optional<feature_type_style const&> style=m_.find_style(style_name);
            if (!style)
            {
                continue;
            }

            if (style->comp_op() || style->image_filters().size() > 0)
            {
                if (style->active(scale_denom))
                {
                    // we'll have to handle compositing ops
                    active_styles.push_back(&(*style));
                }
            }
        }
        return;
    }

    // if we've got this far, now prepare the unbuffered extent
    // which is used as a bbox for clipping geometries
    if (maximum_extent)
    {
        query_ext.clip(*maximum_extent);
    }

    box2d<double> & layer_ext2 = mat.layer_ext2_;

    layer_ext2 = lay.envelope();
    if (fw_success)
    {
        if (prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS))
        {
            layer_ext2.clip(query_ext);
        }
    }
    else
    {
        if (prj_trans.backward(layer_ext2, PROJ_ENVELOPE_POINTS))
        {
            layer_ext2.clip(query_ext);
            prj_trans.forward(layer_ext2, PROJ_ENVELOPE_POINTS);
        }
    }

    std::vector<rule_cache> & rule_caches = mat.rule_caches_;
    attribute_collector collector(names);

    // iterate through all named styles collecting active styles and attribute names
    for (std::string const& style_name : style_names)
    {
        boost::optional<feature_type_style const&> style=m_.find_style(style_name);
        if (!style)
        {
            MAPNIK_LOG_ERROR(feature_style_processor)
                << "feature_style_processor: Style=" << style_name
                << " required for layer=" << lay.name() << " does not exist.";

            continue;
        }

        std::vector<rule> const& style_rules = style->get_rules();
        bool active_rules = false;
        rule_cache rc;
        for(rule const& r : style_rules)
        {
            if (r.active(scale_denom))
            {
                rc.add_rule(r);
                active_rules = true;
                collector(r);
            }
        }
        if (active_rules)
        {
            rule_caches.push_back(std::move(rc));
            active_styles.push_back(&(*style));
        }
    }

    // Don't even try to do more work if there are no active styles.
    if (active_styles.empty())
    {
        return;
    }

    double qw = query_ext.width()>0 ? query_ext.width() : 1;
    double qh = query_ext.height()>0 ? query_ext.height() : 1;
    query::resolution_type res(width/qw,
                               height/qh);

    query q(layer_ext,res,scale_denom,extent);
    q.set_variables(p.variables());

    if (p.attribute_collection_policy() == COLLECT_ALL)
    {
        layer_descriptor lay_desc = ds->get_descriptor();
        for (attribute_descriptor const& desc : lay_desc.get_descriptors())
        {
            q.add_property_name(desc.get_name());
        }
    }
    else
    {
        for (std::string const& name : names)
        {
            q.add_property_name(name);
        }
    }
    q.set_filter_factor(collector.get_filter_factor());

    // Also query the group by attribute
    std::string const& group_by = lay.group_by();
    if (!group_by.empty())
    {
        q.add_property_name(group_by);
    }

    bool cache_features = lay.cache_features() && active_styles.size() > 1;

    std::vector<featureset_ptr> & featureset_ptr_list = mat.featureset_ptr_list_;
    if (!group_by.empty() || cache_features)
    {
        featureset_ptr_list.push_back(ds->features_with_context(q,current_ctx));
    }
    else
    {
        for(std::size_t i = 0; i < active_styles.size(); ++i)
        {
            featureset_ptr_list.push_back(ds->features_with_context(q,current_ctx));
        }
    }
}
Пример #12
0
void agg_renderer<T>::start_map_processing(Map const& map)
{
    MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Start map processing bbox=" << map.get_current_extent();
    ras_ptr->clip_box(0,0,width_,height_);
}
Пример #13
0
static void write_features(T const& grid_type,
                           boost::python::dict& feature_data,
                           std::vector<typename T::lookup_type> const& key_order)
{
    std::string const& key = grid_type.get_key();
    std::set<std::string> const& attributes = grid_type.property_names();
    typename T::feature_type const& g_features = grid_type.get_grid_features();
    typename T::feature_type::const_iterator feat_itr = g_features.begin();
    typename T::feature_type::const_iterator feat_end = g_features.end();
    bool include_key = (attributes.find(key) != attributes.end());
    for (; feat_itr != feat_end; ++feat_itr)
    {
        mapnik::feature_ptr feature = feat_itr->second;
        boost::optional<std::string> join_value;
        if (key == grid_type.key_name())
        {
            std::stringstream s;
            s << feature->id();
            join_value = s.str();
        }
        else if (feature->has_key(key))
        {
            join_value = feature->get(key).to_string();
        }

        if (join_value)
        {
            // only serialize features visible in the grid
            if(std::find(key_order.begin(), key_order.end(), *join_value) != key_order.end()) {
                boost::python::dict feat;
                bool found = false;
                if (key == grid_type.key_name())
                {
                    // drop key unless requested
                    if (include_key) {
                        found = true;
                        //TODO - add __id__ as data key?
                        //feat[key] = *join_value;
                    }
                }

                feature_kv_iterator itr = feature->begin();
                feature_kv_iterator end = feature->end();
                for ( ;itr!=end; ++itr)
                {
                    std::string const& key_name = boost::get<0>(*itr);
                    if (key_name == key) {
                        // drop key unless requested
                        if (include_key) {
                            found = true;
                            feat[key_name] = boost::get<1>(*itr);
                        }
                    }
                    else if ( (attributes.find(key_name) != attributes.end()) )
                    {
                        found = true;
                        feat[key_name] = boost::get<1>(*itr);
                    }
                }

                if (found)
                {
                    feature_data[feat_itr->first] = feat;
                }
            }
        }
        else
        {
            MAPNIK_LOG_DEBUG(bindings) << "write_features: Should not get here: key " << key << " not found in grid feature properties";
        }
    }
}
Пример #14
0
stroker::~stroker()
{
    MAPNIK_LOG_DEBUG(font_engine_freetype) << "stroker: Destroy stroker=" << s_;

    FT_Stroker_Done(s_);
}
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);
}
void grid_renderer<T>::process(line_pattern_symbolizer const& sym,
                               mapnik::feature_impl & feature,
                               proj_transform const& prj_trans)
{
    std::string filename = get<std::string, keys::file>(sym, feature, common_.vars_);
    if (filename.empty()) return;
    std::shared_ptr<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;
    }

    value_bool clip = get<value_bool, keys::clip>(sym, feature, common_.vars_);
    value_double offset = get<value_double, keys::offset>(sym, feature, common_.vars_);
    value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym, feature, common_.vars_);
    value_double smooth = get<value_double, keys::smooth>(sym, feature, common_.vars_);

    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>;

    agg::scanline_bin sl;

    grid_rendering_buffer buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_);
    pixfmt_type pixf(buf);

    grid_renderer_base_type renb(pixf);
    renderer_type ren(renb);

    ras_ptr->reset();

    line_pattern_enum pattern = get<line_pattern_enum, keys::line_pattern>(sym, feature, common_.vars_);
    std::size_t stroke_width = (pattern == LINE_PATTERN_WARP) ? mark->width() :
        get<value_double, keys::stroke_width>(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_);
    }

    box2d<double> clipping_extent = common_.query_extent_;
    if (clip)
    {
        double pad_per_pixel = static_cast<double>(common_.query_extent_.width()/common_.width_);
        double pixels = std::ceil(std::max(stroke_width / 2.0 + std::fabs(offset),
                                          (std::fabs(offset) * offset_converter_default_threshold)));
        double padding = pad_per_pixel * pixels * common_.scale_factor_;

        clipping_extent.pad(padding);
    }

    // to avoid the complexity of using an agg pattern filter instead
    // we create a line_symbolizer in order to fake the pattern
    line_symbolizer line;
    put<value_double>(line, keys::stroke_width, value_double(stroke_width));
    // TODO: really should pass the offset to the fake line too, but
    // this wasn't present in the previous version and makes the test
    // fail - in this case, probably the test should be updated.
    //put<value_double>(line, keys::offset, value_double(offset));
    put<value_double>(line, keys::simplify_tolerance, value_double(simplify_tolerance));
    put<value_double>(line, keys::smooth, value_double(smooth));

    using vertex_converter_type = vertex_converter<clip_line_tag, transform_tag,
                                                   affine_transform_tag,
                                                   simplify_tag,smooth_tag,
                                                   offset_transform_tag,stroke_tag>;
    vertex_converter_type converter(clipping_extent,line,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_);
    if (clip) converter.set<clip_line_tag>();
    converter.set<transform_tag>(); // always transform
    if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
    converter.set<affine_transform_tag>(); // optional affine transform
    if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter
    if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter
    converter.set<stroke_tag>(); //always stroke
    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());

    // render id
    ren.color(color_type(feature.id()));
    agg::render_scanlines(*ras_ptr, sl, ren);

    // add feature properties to grid cache
    pixmap_.add_feature(feature);

}
Пример #17
0
mapnik::raster_ptr pgraster_wkb_reader::read_indexed(mapnik::box2d<double> const& bbox,
                                                     uint16_t width, uint16_t height)
{
  uint8_t type = read_uint8(&ptr_);

  int pixtype = BANDTYPE_PIXTYPE(type);
  int offline = BANDTYPE_IS_OFFDB(type) ? 1 : 0;
  int hasnodata = BANDTYPE_HAS_NODATA(type) ? 1 : 0;

  MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: band type:"
        << pixtype << " offline:" << offline
        << " hasnodata:" << hasnodata;

  if ( offline ) {
    MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band "
          " unsupported";
    return mapnik::raster_ptr();
  }

  MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: reading " << height_ << "x" << width_ << " pixels";

  switch (pixtype) {
    case PT_1BB:
    case PT_2BUI:
    case PT_4BUI:
      // all <8BPP values are wrote in full bytes anyway
    case PT_8BSI:
      // mapnik does not support signed anyway
    case PT_8BUI:
      return read_data_band(bbox, width_, height_, hasnodata,
                     std::bind(read_uint8, &ptr_));
      break;
    case PT_16BSI:
      // mapnik does not support signed anyway
    case PT_16BUI:
      return read_data_band(bbox, width_, height_, hasnodata,
                     std::bind(read_uint16, &ptr_, endian_));
      break;
    case PT_32BSI:
      // mapnik does not support signed anyway
    case PT_32BUI:
      return read_data_band(bbox, width_, height_, hasnodata,
                     std::bind(read_uint32, &ptr_, endian_));
      break;
    case PT_32BF:
      return read_data_band(bbox, width_, height_, hasnodata,
                     std::bind(read_float32, &ptr_, endian_));
      break;
    case PT_64BF:
      return read_data_band(bbox, width_, height_, hasnodata,
                     std::bind(read_float64, &ptr_, endian_));
      break;
    default:
      std::ostringstream err;
      err << "pgraster_wkb_reader: data band type " << pixtype << " unsupported";
      // TODO: accept policy to decide on throw-or-skip ?
      //MAPNIK_LOG_WARN(pgraster) << err.str();
      throw mapnik::datasource_exception(err.str());
  }
  return mapnik::raster_ptr();
}