diff --git a/include/mapnik/feature_style_processor_impl.hpp b/include/mapnik/feature_style_processor_impl.hpp index b0a5fe9b7..144e8d86e 100644 --- a/include/mapnik/feature_style_processor_impl.hpp +++ b/include/mapnik/feature_style_processor_impl.hpp @@ -255,8 +255,18 @@ void feature_style_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(mat.proj0_, mat.proj1_)).first->second.get(); + } + else + { + proj_trans_ptr = itr->second.get(); + } box2d query_ext = extent; // unbuffered box2d buffered_query_ext(query_ext); // buffered @@ -286,22 +296,22 @@ void feature_style_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::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::render_material(layer_rendering_materia std::vector 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(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::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::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::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::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); } } } diff --git a/include/mapnik/map.hpp b/include/mapnik/map.hpp index e62f966b7..b53c26a11 100644 --- a/include/mapnik/map.hpp +++ b/include/mapnik/map.hpp @@ -33,7 +33,7 @@ #include #include #include - +#include #include MAPNIK_DISABLE_WARNING_PUSH #include @@ -104,7 +104,7 @@ private: boost::optional font_directory_; freetype_engine::font_file_mapping_type font_file_mapping_; freetype_engine::font_memory_cache_type font_memory_cache_; - + mutable std::map> proj_cache_; public: using const_style_iterator = std::map::const_iterator; @@ -502,6 +502,10 @@ public: { return font_memory_cache_; } + std::map> & proj_cache() const + { + return proj_cache_; + } private: friend void swap(Map & rhs, Map & lhs); diff --git a/src/map.cpp b/src/map.cpp index 9d6eabfcf..22bd01f8f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -517,7 +517,6 @@ void Map::zoom_all() { return; } - projection proj0(srs_); box2d 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(proj0, proj1)).first->second.get(); + } + else + { + proj_trans_ptr = itr->second.get(); + } + box2d 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(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 diff --git a/src/proj_transform.cpp b/src/proj_transform.cpp index 2d393f03b..529780eb7 100644 --- a/src/proj_transform.cpp +++ b/src/proj_transform.cpp @@ -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 } } diff --git a/src/projection.cpp b/src/projection.cpp index bfe13ad89..2da83a9e4 100644 --- a/src/projection.cpp +++ b/src/projection.cpp @@ -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 }