Add proj_transform caching to minimise expensive initialisations calls in libproj >= 6 [WIP]

This commit is contained in:
Artem Pavlenko 2021-01-27 09:40:28 +00:00
parent db9829d702
commit 5c086b0cd5
5 changed files with 94 additions and 45 deletions

View file

@ -255,8 +255,18 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
}
processor_context_ptr current_ctx = ds->get_context(ctx_map);
proj_transform prj_trans(mat.proj0_,mat.proj1_);
std::string key = mat.proj0_.params() + mat.proj1_.params();
auto itr = m_.proj_cache().find(key);
proj_transform * proj_trans_ptr;
if (itr == m_.proj_cache().end())
{
proj_trans_ptr = m_.proj_cache().emplace(key,
std::make_unique<proj_transform>(mat.proj0_, mat.proj1_)).first->second.get();
}
else
{
proj_trans_ptr = itr->second.get();
}
box2d<double> query_ext = extent; // unbuffered
box2d<double> buffered_query_ext(query_ext); // buffered
@ -286,22 +296,22 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
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))
if (proj_trans_ptr->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())
else if (proj_trans_ptr->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))
else if (proj_trans_ptr->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))
if (! proj_trans_ptr->forward(layer_ext, PROJ_ENVELOPE_POINTS))
{
MAPNIK_LOG_ERROR(feature_style_processor)
<< "feature_style_processor: Layer=" << lay.name()
@ -353,17 +363,17 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
layer_ext2 = lay.envelope();
if (fw_success)
{
if (prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS))
if (proj_trans_ptr->forward(query_ext, PROJ_ENVELOPE_POINTS))
{
layer_ext2.clip(query_ext);
}
}
else
{
if (prj_trans.backward(layer_ext2, PROJ_ENVELOPE_POINTS))
if (proj_trans_ptr->backward(layer_ext2, PROJ_ENVELOPE_POINTS))
{
layer_ext2.clip(query_ext);
prj_trans.forward(layer_ext2, PROJ_ENVELOPE_POINTS);
proj_trans_ptr->forward(layer_ext2, PROJ_ENVELOPE_POINTS);
}
}
@ -496,7 +506,18 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
std::vector<rule_cache> const & rule_caches = mat.rule_caches_;
proj_transform prj_trans(mat.proj0_,mat.proj1_);
std::string key = mat.proj0_.params() + mat.proj1_.params();
auto itr = m_.proj_cache().find(key);
proj_transform * proj_trans_ptr;
if (itr == m_.proj_cache().end())
{
proj_trans_ptr = m_.proj_cache().emplace(key,
std::make_unique<proj_transform>(mat.proj0_, mat.proj1_)).first->second.get();
}
else
{
proj_trans_ptr = itr->second.get();
}
bool cache_features = lay.cache_features() && active_styles.size() > 1;
@ -525,10 +546,9 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
cache->prepare();
render_style(p, style,
rule_caches[i],
rule_caches[i++],
cache,
prj_trans);
++i;
*proj_trans_ptr);
}
cache->clear();
}
@ -540,8 +560,7 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
for (feature_type_style const* style : active_styles)
{
cache->prepare();
render_style(p, style, rule_caches[i], cache, prj_trans);
++i;
render_style(p, style, rule_caches[i++], cache, *proj_trans_ptr);
}
cache->clear();
}
@ -565,9 +584,8 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
{
cache->prepare();
render_style(p, style,
rule_caches[i],
cache, prj_trans);
++i;
rule_caches[i++],
cache, *proj_trans_ptr);
}
}
// We only have a single style and no grouping.
@ -579,10 +597,9 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
{
featureset_ptr features = *featuresets++;
render_style(p, style,
rule_caches[i],
rule_caches[i++],
features,
prj_trans);
++i;
*proj_trans_ptr);
}
}
}

View file

@ -33,7 +33,7 @@
#include <mapnik/well_known_srs.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/warning.hpp>
MAPNIK_DISABLE_WARNING_PUSH
#include <mapnik/warning_ignore.hpp>
@ -104,7 +104,7 @@ private:
boost::optional<std::string> font_directory_;
freetype_engine::font_file_mapping_type font_file_mapping_;
freetype_engine::font_memory_cache_type font_memory_cache_;
mutable std::map<std::string, std::unique_ptr<proj_transform>> proj_cache_;
public:
using const_style_iterator = std::map<std::string,feature_type_style>::const_iterator;
@ -502,6 +502,10 @@ public:
{
return font_memory_cache_;
}
std::map<std::string, std::unique_ptr<proj_transform>> & proj_cache() const
{
return proj_cache_;
}
private:
friend void swap(Map & rhs, Map & lhs);

View file

@ -517,7 +517,6 @@ void Map::zoom_all()
{
return;
}
projection proj0(srs_);
box2d<double> ext;
bool success = false;
bool first = true;
@ -526,10 +525,24 @@ void Map::zoom_all()
if (layer.active())
{
std::string const& layer_srs = layer.srs();
projection proj1(layer_srs);
proj_transform prj_trans(proj0,proj1);
std::string key = srs_ + layer_srs;
auto itr = proj_cache_.find(key);
proj_transform * proj_trans_ptr;
if (itr == proj_cache_.end())
{
projection proj0(srs_, true);
projection proj1(layer_srs, true);
proj_trans_ptr = proj_cache_.emplace(key,
std::make_unique<proj_transform>(proj0, proj1)).first->second.get();
}
else
{
proj_trans_ptr = itr->second.get();
}
box2d<double> layer_ext = layer.envelope();
if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS))
if (proj_trans_ptr->backward(layer_ext, PROJ_ENVELOPE_POINTS))
{
success = true;
MAPNIK_LOG_DEBUG(map) << "map: Layer " << layer.name() << " original ext=" << layer.envelope();
@ -707,11 +720,23 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const
mapnik::datasource_ptr ds = layer.datasource();
if (ds)
{
mapnik::projection dest(srs_);
mapnik::projection source(layer.srs());
proj_transform prj_trans(source,dest);
std::string key = srs_ + layer.srs();
auto itr = proj_cache_.find(key);
proj_transform * proj_trans_ptr;
if (itr == proj_cache_.end())
{
mapnik::projection dest(srs_, true);
mapnik::projection source(layer.srs(), true);
proj_trans_ptr = proj_cache_.emplace(key,
std::make_unique<proj_transform>(source, dest)).first->second.get();
}
else
{
proj_trans_ptr = itr->second.get();
}
double z = 0;
if (!prj_trans.equal() && !prj_trans.backward(x,y,z))
if (!proj_trans_ptr->equal() && !proj_trans_ptr->backward(x,y,z))
{
throw std::runtime_error("query_point: could not project x,y into layer srs");
}
@ -721,7 +746,7 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const
{
map_ex.clip(*maximum_extent_);
}
if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS))
if (!proj_trans_ptr->backward(map_ex,PROJ_ENVELOPE_POINTS))
{
std::ostringstream s;
s << "query_point: could not project map extent '" << map_ex

View file

@ -131,17 +131,17 @@ proj_transform::proj_transform(projection const& source,
dest.params().c_str(), nullptr);
if (transform_ == nullptr)
{
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj4 support (-DMAPNIK_USE_PROJ): '") + source.params() + "'->'" + dest.params() + "'");
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections: '") + source.params() + "'->'" + dest.params() + "'");
}
PJ* transform_gis = proj_normalize_for_visualization(ctx_, transform_);
if (transform_gis == nullptr)
{
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj4 support (-DMAPNIK_USE_PROJ): '") + source.params() + "'->'" + dest.params() + "'");
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections: '") + source.params() + "'->'" + dest.params() + "'");
}
proj_destroy(transform_);
transform_ = transform_gis;
#else
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj4 support (-DMAPNIK_USE_PROJ): '") + source.params() + "'->'" + dest.params() + "'");
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj support (-DMAPNIK_USE_PROJ): '") + source.params() + "'->'" + dest.params() + "'");
#endif
}
}

View file

@ -94,7 +94,8 @@ void projection::init_proj() const
if (!proj_)
{
proj_ctx_ = proj_context_create();
proj_ = proj_create_crs_to_crs(proj_ctx_, "epsg:4326", params_.c_str(), nullptr);
//proj_ = proj_create_crs_to_crs(proj_ctx_, "epsg:4326", params_.c_str(), nullptr);
proj_ = proj_create(proj_ctx_, params_.c_str());
if (!proj_ || !proj_ctx_)
{
if (proj_ctx_) {
@ -108,15 +109,17 @@ void projection::init_proj() const
throw proj_init_error(params_);
}
// determine the type of CRS
PJ* crs = proj_create(proj_ctx_, params_.c_str());
if (crs)
{
PJ_TYPE type = proj_get_type(crs);
is_geographic_ = (type == PJ_TYPE_GEOGRAPHIC_2D_CRS
||
type == PJ_TYPE_GEOGRAPHIC_3D_CRS) ? true : false;
}
proj_destroy(crs);
//PJ* crs = proj_create(proj_ctx_, params_.c_str());
//if (crs)
//if (proj_)
//{
//PJ_TYPE type = proj_get_type(crs);
PJ_TYPE type = proj_get_type(proj_);
is_geographic_ = (type == PJ_TYPE_GEOGRAPHIC_2D_CRS
||
type == PJ_TYPE_GEOGRAPHIC_3D_CRS) ? true : false;
//}
//proj_destroy(crs);
}
#endif
}