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);
|
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> query_ext = extent; // unbuffered
|
||||||
box2d<double> buffered_query_ext(query_ext); // buffered
|
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;
|
bool early_return = false;
|
||||||
|
|
||||||
// first, try intersection of map extent forward projected into layer srs
|
// 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;
|
fw_success = true;
|
||||||
layer_ext.clip(buffered_query_ext);
|
layer_ext.clip(buffered_query_ext);
|
||||||
}
|
}
|
||||||
// if no intersection and projections are also equal, early return
|
// if no intersection and projections are also equal, early return
|
||||||
else if (prj_trans.equal())
|
else if (proj_trans_ptr->equal())
|
||||||
{
|
{
|
||||||
early_return = true;
|
early_return = true;
|
||||||
}
|
}
|
||||||
// next try intersection of layer extent back projected into map srs
|
// 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);
|
layer_ext.clip(buffered_query_ext_map_srs);
|
||||||
// forward project layer extent back into native projection
|
// 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)
|
MAPNIK_LOG_ERROR(feature_style_processor)
|
||||||
<< "feature_style_processor: Layer=" << lay.name()
|
<< "feature_style_processor: Layer=" << lay.name()
|
||||||
|
@ -353,17 +363,17 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
|
||||||
layer_ext2 = lay.envelope();
|
layer_ext2 = lay.envelope();
|
||||||
if (fw_success)
|
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);
|
layer_ext2.clip(query_ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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);
|
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_;
|
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;
|
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();
|
cache->prepare();
|
||||||
render_style(p, style,
|
render_style(p, style,
|
||||||
rule_caches[i],
|
rule_caches[i++],
|
||||||
cache,
|
cache,
|
||||||
prj_trans);
|
*proj_trans_ptr);
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
cache->clear();
|
cache->clear();
|
||||||
}
|
}
|
||||||
|
@ -540,8 +560,7 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
|
||||||
for (feature_type_style const* style : active_styles)
|
for (feature_type_style const* style : active_styles)
|
||||||
{
|
{
|
||||||
cache->prepare();
|
cache->prepare();
|
||||||
render_style(p, style, rule_caches[i], cache, prj_trans);
|
render_style(p, style, rule_caches[i++], cache, *proj_trans_ptr);
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
cache->clear();
|
cache->clear();
|
||||||
}
|
}
|
||||||
|
@ -565,9 +584,8 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
|
||||||
{
|
{
|
||||||
cache->prepare();
|
cache->prepare();
|
||||||
render_style(p, style,
|
render_style(p, style,
|
||||||
rule_caches[i],
|
rule_caches[i++],
|
||||||
cache, prj_trans);
|
cache, *proj_trans_ptr);
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We only have a single style and no grouping.
|
// 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++;
|
featureset_ptr features = *featuresets++;
|
||||||
render_style(p, style,
|
render_style(p, style,
|
||||||
rule_caches[i],
|
rule_caches[i++],
|
||||||
features,
|
features,
|
||||||
prj_trans);
|
*proj_trans_ptr);
|
||||||
++i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#include <mapnik/well_known_srs.hpp>
|
#include <mapnik/well_known_srs.hpp>
|
||||||
#include <mapnik/image_compositing.hpp>
|
#include <mapnik/image_compositing.hpp>
|
||||||
#include <mapnik/font_engine_freetype.hpp>
|
#include <mapnik/font_engine_freetype.hpp>
|
||||||
|
#include <mapnik/proj_transform.hpp>
|
||||||
#include <mapnik/warning.hpp>
|
#include <mapnik/warning.hpp>
|
||||||
MAPNIK_DISABLE_WARNING_PUSH
|
MAPNIK_DISABLE_WARNING_PUSH
|
||||||
#include <mapnik/warning_ignore.hpp>
|
#include <mapnik/warning_ignore.hpp>
|
||||||
|
@ -104,7 +104,7 @@ private:
|
||||||
boost::optional<std::string> font_directory_;
|
boost::optional<std::string> font_directory_;
|
||||||
freetype_engine::font_file_mapping_type font_file_mapping_;
|
freetype_engine::font_file_mapping_type font_file_mapping_;
|
||||||
freetype_engine::font_memory_cache_type font_memory_cache_;
|
freetype_engine::font_memory_cache_type font_memory_cache_;
|
||||||
|
mutable std::map<std::string, std::unique_ptr<proj_transform>> proj_cache_;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using const_style_iterator = std::map<std::string,feature_type_style>::const_iterator;
|
using const_style_iterator = std::map<std::string,feature_type_style>::const_iterator;
|
||||||
|
@ -502,6 +502,10 @@ public:
|
||||||
{
|
{
|
||||||
return font_memory_cache_;
|
return font_memory_cache_;
|
||||||
}
|
}
|
||||||
|
std::map<std::string, std::unique_ptr<proj_transform>> & proj_cache() const
|
||||||
|
{
|
||||||
|
return proj_cache_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend void swap(Map & rhs, Map & lhs);
|
friend void swap(Map & rhs, Map & lhs);
|
||||||
|
|
43
src/map.cpp
43
src/map.cpp
|
@ -517,7 +517,6 @@ void Map::zoom_all()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
projection proj0(srs_);
|
|
||||||
box2d<double> ext;
|
box2d<double> ext;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -526,10 +525,24 @@ void Map::zoom_all()
|
||||||
if (layer.active())
|
if (layer.active())
|
||||||
{
|
{
|
||||||
std::string const& layer_srs = layer.srs();
|
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();
|
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;
|
success = true;
|
||||||
MAPNIK_LOG_DEBUG(map) << "map: Layer " << layer.name() << " original ext=" << layer.envelope();
|
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();
|
mapnik::datasource_ptr ds = layer.datasource();
|
||||||
if (ds)
|
if (ds)
|
||||||
{
|
{
|
||||||
mapnik::projection dest(srs_);
|
std::string key = srs_ + layer.srs();
|
||||||
mapnik::projection source(layer.srs());
|
auto itr = proj_cache_.find(key);
|
||||||
proj_transform prj_trans(source,dest);
|
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;
|
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");
|
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_);
|
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;
|
std::ostringstream s;
|
||||||
s << "query_point: could not project map extent '" << map_ex
|
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);
|
dest.params().c_str(), nullptr);
|
||||||
if (transform_ == 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_);
|
PJ* transform_gis = proj_normalize_for_visualization(ctx_, transform_);
|
||||||
if (transform_gis == nullptr)
|
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_);
|
proj_destroy(transform_);
|
||||||
transform_ = transform_gis;
|
transform_ = transform_gis;
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,8 @@ void projection::init_proj() const
|
||||||
if (!proj_)
|
if (!proj_)
|
||||||
{
|
{
|
||||||
proj_ctx_ = proj_context_create();
|
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_ || !proj_ctx_)
|
||||||
{
|
{
|
||||||
if (proj_ctx_) {
|
if (proj_ctx_) {
|
||||||
|
@ -108,15 +109,17 @@ void projection::init_proj() const
|
||||||
throw proj_init_error(params_);
|
throw proj_init_error(params_);
|
||||||
}
|
}
|
||||||
// determine the type of CRS
|
// determine the type of CRS
|
||||||
PJ* crs = proj_create(proj_ctx_, params_.c_str());
|
//PJ* crs = proj_create(proj_ctx_, params_.c_str());
|
||||||
if (crs)
|
//if (crs)
|
||||||
{
|
//if (proj_)
|
||||||
PJ_TYPE type = proj_get_type(crs);
|
//{
|
||||||
is_geographic_ = (type == PJ_TYPE_GEOGRAPHIC_2D_CRS
|
//PJ_TYPE type = proj_get_type(crs);
|
||||||
||
|
PJ_TYPE type = proj_get_type(proj_);
|
||||||
type == PJ_TYPE_GEOGRAPHIC_3D_CRS) ? true : false;
|
is_geographic_ = (type == PJ_TYPE_GEOGRAPHIC_2D_CRS
|
||||||
}
|
||
|
||||||
proj_destroy(crs);
|
type == PJ_TYPE_GEOGRAPHIC_3D_CRS) ? true : false;
|
||||||
|
//}
|
||||||
|
//proj_destroy(crs);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue