void render(mapnik::geometry_type & geom,
            mapnik::box2d<double> const& extent,
            std::string const& name)
{
    using path_type = mapnik::coord_transform<mapnik::CoordTransform,mapnik::geometry_type>;
    using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>;
    using renderer = agg::renderer_scanline_aa_solid<ren_base>;
    mapnik::image_32 im(256,256);
    im.set_background(mapnik::color("white"));
    mapnik::box2d<double> padded_extent = extent;
    padded_extent.pad(10);
    mapnik::CoordTransform tr(im.width(),im.height(),padded_extent,0,0);
    agg::rendering_buffer buf(im.raw_data(),im.width(),im.height(), im.width() * 4);
    agg::pixfmt_rgba32_plain pixf(buf);
    ren_base renb(pixf);
    renderer ren(renb);
    ren.color(agg::rgba8(127,127,127,255));
    agg::rasterizer_scanline_aa<> ras;
    mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326"));
    geom.rewind(0);
    path_type path(tr,geom,prj_trans);
    ras.add_path(path);
    agg::scanline_u8 sl;
    agg::render_scanlines(ras, sl, ren);
    mapnik::save_to_file(im,name);
    geom.rewind(0);
}
Esempio n. 2
0
void render(mapnik::geometry_type const& geom,
            mapnik::box2d<double> const& extent,
            std::string const& name)
{
    using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::vertex_adapter>;
    using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>;
    using renderer = agg::renderer_scanline_aa_solid<ren_base>;
    mapnik::vertex_adapter va(geom);
    mapnik::image_rgba8 im(256,256);
    mapnik::fill(im, mapnik::color("white"));
    mapnik::box2d<double> padded_extent = extent;
    padded_extent.pad(10);
    mapnik::view_transform tr(im.width(),im.height(),padded_extent,0,0);
    agg::rendering_buffer buf(im.getBytes(),im.width(),im.height(), im.getRowSize());
    agg::pixfmt_rgba32_plain pixf(buf);
    ren_base renb(pixf);
    renderer ren(renb);
    ren.color(agg::rgba8(127,127,127,255));
    agg::rasterizer_scanline_aa<> ras;
    mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326"));
    path_type path(tr,va,prj_trans);
    ras.add_path(path);
    agg::scanline_u8 sl;
    agg::render_scanlines(ras, sl, ren);
    mapnik::save_to_file(im,name);
}
Esempio n. 3
0
featureset_ptr Map::query_point(unsigned index, double x, double y) const
{
    if (!current_extent_.valid())
    {
        throw std::runtime_error("query_point: map extent is not intialized, you need to set a valid extent before querying");
    }
    if (!current_extent_.intersects(x,y))
    {
        throw std::runtime_error("query_point: x,y coords do not intersect map extent");
    }
    if (index < layers_.size())
    {
        mapnik::layer const& layer = layers_[index];
        mapnik::datasource_ptr ds = layer.datasource();
        if (ds)
        {
            mapnik::projection dest(srs_);
            mapnik::projection source(layer.srs());
            proj_transform prj_trans(source,dest);
            double z = 0;
            if (!prj_trans.equal() && !prj_trans.backward(x,y,z))
            {
                throw std::runtime_error("query_point: could not project x,y into layer srs");
            }
            // calculate default tolerance
            mapnik::box2d<double> map_ex = current_extent_;
            if (maximum_extent_)
            {
                map_ex.clip(*maximum_extent_);
            }
            if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS))
            {
                std::ostringstream s;
                s << "query_point: could not project map extent '" << map_ex
                  << "' into layer srs for tolerance calculation";
                throw std::runtime_error(s.str());
            }
            double tol = (map_ex.maxx() - map_ex.minx()) / width_ * 3;
            featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y), tol);
            MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")";
            if (fs)
            {
                return boost::make_shared<filter_featureset<hit_test_filter> >(fs,
                                                                               hit_test_filter(x,y,tol));
            }
        }
    }
    else
    {
        std::ostringstream s;
        s << "Invalid layer index passed to query_point: '" << index << "'";
        if (!layers_.empty()) s << " for map with " << layers_.size() << " layers(s)";
        else s << " (map has no layers)";
        throw std::out_of_range(s.str());
    }
    return featureset_ptr();
}
int main() {
    mapnik::projection merc("+init=epsg:3857",true);
    mapnik::proj_transform prj_trans(merc,merc); // no-op
    unsigned tile_size = 256;
    mapnik::vector_tile_impl::spherical_mercator merc_tiler(tile_size);
    double minx,miny,maxx,maxy;
    merc_tiler.xyz(9664,20435,15,minx,miny,maxx,maxy);
    mapnik::box2d<double> z15_extent(minx,miny,maxx,maxy);
    mapnik::view_transform tr(tile_size,tile_size,z15_extent,0,0);
    std::string geojson_file("./test/data/poly.geojson");
    mapnik::util::file input(geojson_file);
    if (!input.open())
    {
        throw std::runtime_error("failed to open geojson");
    }
    mapnik::geometry::geometry<double> geom;
    std::string json_string(input.data().get(), input.size());
    if (!mapnik::json::from_geojson(json_string, geom))
    {
        throw std::runtime_error("failed to parse geojson");
    }
    mapnik::geometry::correct(geom);

    unsigned count = 0;
    unsigned count2 = 0;
    {
        mapnik::vector_tile_impl::vector_tile_strategy vs(prj_trans, tr, 16);
        mapnik::progress_timer __stats__(std::clog, "boost::geometry::transform");
        for (unsigned i=0;i<10000;++i)
        {
            mapnik::geometry::geometry<std::int64_t> new_geom = mapnik::geometry::transform<std::int64_t>(geom, vs);
            auto const& poly = mapnik::util::get<mapnik::geometry::multi_polygon<std::int64_t>>(new_geom);
            count += poly.size();
        }
    }
    {
        mapnik::vector_tile_impl::vector_tile_strategy vs(prj_trans, tr, 16);
        mapnik::progress_timer __stats__(std::clog, "transform_visitor with reserve");
        mapnik::vector_tile_impl::transform_visitor transit(vs);
        for (unsigned i=0;i<10000;++i)
        {
            mapnik::geometry::geometry<std::int64_t> new_geom = mapnik::util::apply_visitor(transit,geom);        
            auto const& poly = mapnik::util::get<mapnik::geometry::multi_polygon<std::int64_t>>(new_geom);
            count2 += poly.size();
        }
        if (count != count2)
        {
            std::clog << "tests did not run as expected!\n";
            return -1;
        }
    }
    return 0;
}
Esempio n. 5
0
featureset_ptr Map::query_map_point(unsigned index, double x, double y) const
{
    if ( index< layers_.size())
    {
        mapnik::layer const& layer = layers_[index];
        CoordTransform tr = view_transform();
        tr.backward(&x,&y);

        try
        {
            mapnik::projection dest(srs_);
            mapnik::projection source(layer.srs());
            proj_transform prj_trans(source,dest);
            double z = 0;
            prj_trans.backward(x,y,z);

            double minx = current_extent_.minx();
            double miny = current_extent_.miny();
            double maxx = current_extent_.maxx();
            double maxy = current_extent_.maxy();

            prj_trans.backward(minx,miny,z);
            prj_trans.backward(maxx,maxy,z);
            double tol = (maxx - minx) / width_ * 3;
            mapnik::datasource_ptr ds = layer.datasource();
            if (ds)
            {
#ifdef MAPNIK_DEBUG
                std::clog << " query at point tol = " << tol << " (" << x << "," << y << ")\n";
#endif
                featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y));
                if (fs)
                    return boost::make_shared<filter_featureset<hit_test_filter> >(fs,
                                                                                   hit_test_filter(x,y,tol));
            }
        }
        catch (...)
        {
#ifdef MAPNIK_DEBUG
            std::clog << "exception caught in \"query_map_point\"\n";
#endif
        }
    }
    return featureset_ptr();
}
Esempio n. 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());
    }
}
Esempio n. 7
0
void Map::zoom_all() 
{
    if (maximum_extent_) {
        zoom_to_box(*maximum_extent_);
    }
    else
    {
        try 
        {
            if (!layers_.size() > 0)
                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->isActive())
                {
                    std::string const& layer_srs = itr->srs();
                    projection proj1(layer_srs);
                    
                    proj_transform prj_trans(proj0,proj1);
                        
                    box2d<double> layer_ext = itr->envelope();
                    // TODO - consider using more robust method: http://trac.mapnik.org/ticket/751
                    if (prj_trans.backward(layer_ext))
                    {
                        success = true;
            #ifdef MAPNIK_DEBUG
                        std::clog << " layer " << itr->name() << " original ext: " << itr->envelope() << "\n";
                        std::clog << " layer " << itr->name() << " transformed to map srs: " << layer_ext << "\n";
            #endif                
                        if (first)
                        {
                            ext = layer_ext;
                            first = false;
                        }
                        else 
                        {
                            ext.expand_to_include(layer_ext);
                        }
                    }
                }
                ++itr;
            }
            if (success) {
                zoom_to_box(ext);
            } 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 & ex)
        {
            std::clog << "proj_init_error:" << ex.what() << "\n";
        }    
    }
}
void feature_style_processor<Processor>::render_material(layer_rendering_material const & mat,
                                                         Processor & p)
{
    std::vector<feature_type_style const*> const & active_styles = mat.active_styles_;
    std::vector<featureset_ptr> const & featureset_ptr_list = mat.featureset_ptr_list_;
    if (featureset_ptr_list.empty())
    {
        // The datasource wasn't queried because of early return
        // but we have to apply compositing operations on styles
        for (feature_type_style const* style : active_styles)
        {
            p.start_style_processing(*style);
            p.end_style_processing(*style);
        }
        return;
    }

    layer const& lay = mat.lay_;

    std::vector<rule_cache> const & rule_caches = mat.rule_caches_;

    proj_transform prj_trans(mat.proj0_,mat.proj1_);

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

    datasource_ptr ds = lay.datasource();
    std::string group_by = lay.group_by();

    // Render incrementally when the column that we group by changes value.
    if (!group_by.empty())
    {
        featureset_ptr features = *featureset_ptr_list.begin();
        if (features)
        {
            // Cache all features into the memory_datasource before rendering.
            std::shared_ptr<featureset_buffer> cache = std::make_shared<featureset_buffer>();
            feature_ptr feature, prev;

            while ((feature = features->next()))
            {
                if (prev && prev->get(group_by) != feature->get(group_by))
                {
                    // We're at a value boundary, so render what we have
                    // up to this point.
                    std::size_t i = 0;
                    for (feature_type_style const* style : active_styles)
                    {

                        cache->prepare();
                        render_style(p, style,
                                     rule_caches[i],
                                     cache,
                                     prj_trans);
                        ++i;
                    }
                    cache->clear();
                }
                cache->push(feature);
                prev = feature;
            }

            std::size_t i = 0;
            for (feature_type_style const* style : active_styles)
            {
                cache->prepare();
                render_style(p, style, rule_caches[i], cache, prj_trans);
                ++i;
            }
            cache->clear();
        }
    }
    else if (cache_features)
    {
        std::shared_ptr<featureset_buffer> cache = std::make_shared<featureset_buffer>();
        featureset_ptr features = *featureset_ptr_list.begin();
        if (features)
        {
            // Cache all features into the memory_datasource before rendering.
            feature_ptr feature;
            while ((feature = features->next()))
            {

                cache->push(feature);
            }
        }
        std::size_t i = 0;
        for (feature_type_style const* style : active_styles)
        {
            cache->prepare();
            render_style(p, style,
                         rule_caches[i],
                         cache, prj_trans);
            ++i;
        }
    }
    // We only have a single style and no grouping.
    else
    {
        std::size_t i = 0;
        std::vector<featureset_ptr>::const_iterator featuresets = featureset_ptr_list.cbegin();
        for (feature_type_style const* style : active_styles)
        {
            featureset_ptr features = *featuresets++;
            render_style(p, style,
                         rule_caches[i],
                         features,
                         prj_trans);
            ++i;
        }
    }
}
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));
        }
    }
}