Add proj_transform caching to minimise expensive initialisations calls in libproj >= 6 [WIP]
This commit is contained in:
parent
db9829d702
commit
5c086b0cd5
5 changed files with 94 additions and 45 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
43
src/map.cpp
43
src/map.cpp
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue