From 170e20e864c2ca8bd1ccc2a94f412bed518d29d4 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 8 May 2017 22:37:35 -0500 Subject: [PATCH] First attempt at making raster overzooming and scaling work correctly and handle offsets properly. --- include/mapnik/raster.hpp | 13 ++++- .../process_raster_symbolizer.hpp | 48 ++++++++++------- plugins/input/raster/raster_featureset.cpp | 51 ++++++++++--------- src/image_scaling.cpp | 10 ++-- test/data-visual | 2 +- 5 files changed, 76 insertions(+), 48 deletions(-) diff --git a/include/mapnik/raster.hpp b/include/mapnik/raster.hpp index 02022d359..215611946 100644 --- a/include/mapnik/raster.hpp +++ b/include/mapnik/raster.hpp @@ -40,15 +40,27 @@ class raster : private util::noncopyable { public: box2d ext_; + box2d query_ext_; image_any data_; double filter_factor_; boost::optional nodata_; + + template + raster(box2d const& ext, + box2d const& query_ext, + ImageData && data, + double filter_factor) + : ext_(ext), + query_ext_(query_ext), + data_(std::move(data)), + filter_factor_(filter_factor) {} template raster(box2d const& ext, ImageData && data, double filter_factor) : ext_(ext), + query_ext_(ext), data_(std::move(data)), filter_factor_(filter_factor) {} @@ -71,7 +83,6 @@ public: { filter_factor_ = factor; } - }; } diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 7ca90a0af..9c2853fdf 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -53,6 +53,7 @@ struct image_dispatcher image_dispatcher(int start_x, int start_y, int width, int height, double scale_x, double scale_y, + double offset_x, double offset_y, scaling_method_e method, double filter_factor, double opacity, composite_mode_e comp_op, raster_symbolizer const& sym, feature_impl const& feature, @@ -63,15 +64,17 @@ struct image_dispatcher height_(height), scale_x_(scale_x), scale_y_(scale_y), + offset_x_(offset_x), + offset_y_(offset_y), method_(method), filter_factor_(filter_factor), - opacity_(opacity), - comp_op_(comp_op), - sym_(sym), - feature_(feature), - composite_(composite), - nodata_(nodata), - need_scaling_(need_scaling) {} + opacity_(opacity), + comp_op_(comp_op), + sym_(sym), + feature_(feature), + composite_(composite), + nodata_(nodata), + need_scaling_(need_scaling) {} void operator() (image_null const&) const {} //no-op void operator() (image_rgba8 const& data_in) const @@ -79,7 +82,7 @@ struct image_dispatcher if (need_scaling_) { image_rgba8 data_out(width_, height_, true, true); - scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_, nodata_); + scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, offset_x_, offset_y_, filter_factor_, nodata_); composite_(data_out, comp_op_, opacity_, start_x_, start_y_); } else @@ -97,7 +100,7 @@ struct image_dispatcher if (need_scaling_) { image_type data_out(width_, height_); - scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_, nodata_); + scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, offset_x_, offset_y_, filter_factor_, nodata_); if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_); } else @@ -114,6 +117,8 @@ private: int height_; double scale_x_; double scale_y_; + double offset_x_; + double offset_y_; scaling_method_e method_; double filter_factor_; double opacity_; @@ -210,12 +215,17 @@ void render_raster_symbolizer(raster_symbolizer const& sym, if (source) { box2d target_ext = box2d(source->ext_); - prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); + box2d target_query_ext = box2d(source->query_ext_); + if (!prj_trans.equal()) { + prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); + prj_trans.backward(target_query_ext, PROJ_ENVELOPE_POINTS); + } box2d ext = common.t_.forward(target_ext); - int start_x = static_cast(std::floor(ext.minx()+.5)); - int start_y = static_cast(std::floor(ext.miny()+.5)); - int end_x = static_cast(std::floor(ext.maxx()+.5)); - int end_y = static_cast(std::floor(ext.maxy()+.5)); + box2d query_ext = common.t_.forward(target_query_ext); + int start_x = static_cast(std::floor(query_ext.minx()+.5)); + int start_y = static_cast(std::floor(query_ext.miny()+.5)); + int end_x = static_cast(std::floor(query_ext.maxx()+.5)); + int end_y = static_cast(std::floor(query_ext.maxy()+.5)); int raster_width = end_x - start_x; int raster_height = end_y - start_y; if (raster_width > 0 && raster_height > 0) @@ -236,17 +246,20 @@ void render_raster_symbolizer(raster_symbolizer const& sym, if (!prj_trans.equal()) { - double offset_x = ext.minx() - start_x; - double offset_y = ext.miny() - start_y; + // This path does not currently work and is still being figured out. + double offset_x = query_ext.minx() - start_x; + double offset_y = query_ext.miny() - start_y; unsigned mesh_size = static_cast(get(sym,keys::mesh_size,feature, common.vars_, 16)); detail::image_warp_dispatcher dispatcher(prj_trans, start_x, start_y, raster_width, raster_height, - target_ext, source->ext_, offset_x, offset_y, mesh_size, + target_query_ext, source->ext_, offset_x, offset_y, mesh_size, scaling_method, source->get_filter_factor(), opacity, comp_op, sym, feature, composite, source->nodata()); util::apply_visitor(dispatcher, source->data_); } else { + double offset_x = query_ext.minx() - ext.minx(); + double offset_y = query_ext.miny() - ext.miny(); double image_ratio_x = ext.width() / source->data_.width(); double image_ratio_y = ext.height() / source->data_.height(); double eps = 1e-5; @@ -256,6 +269,7 @@ void render_raster_symbolizer(raster_symbolizer const& sym, (std::abs(start_y) > eps); detail::image_dispatcher dispatcher(start_x, start_y, raster_width, raster_height, image_ratio_x, image_ratio_y, + offset_x, offset_y, scaling_method, source->get_filter_factor(), opacity, comp_op, sym, feature, composite, source->nodata(), scale); util::apply_visitor(dispatcher, source->data_); diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index 26cac964f..3228ce529 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -89,33 +89,36 @@ feature_ptr raster_featureset::next() box2d intersect = bbox_.intersect(curIter_->envelope()); box2d ext = t.forward(intersect); box2d rem = policy_.transform(ext); - if (ext.width() > 0.5 && ext.height() > 0.5 ) - { - // select minimum raster containing whole ext - int x_off = static_cast(std::floor(ext.minx())); - int y_off = static_cast(std::floor(ext.miny())); - int end_x = static_cast(std::ceil(ext.maxx())); - int end_y = static_cast(std::ceil(ext.maxy())); + // select minimum raster containing whole ext + int x_off = static_cast(std::floor(ext.minx())); + int y_off = static_cast(std::floor(ext.miny())); + int end_x = static_cast(std::ceil(ext.maxx())); + int end_y = static_cast(std::ceil(ext.maxy())); - // clip to available data - if (x_off < 0) x_off = 0; - if (y_off < 0) y_off = 0; - if (end_x > image_width) end_x = image_width; - if (end_y > image_height) end_y = image_height; + // clip to available data + if (x_off < 0) x_off = 0; + if (y_off < 0) y_off = 0; + if (end_x > image_width) end_x = image_width; + if (end_y > image_height) end_y = image_height; - int width = end_x - x_off; - int height = end_y - y_off; - - // calculate actual box2d of returned raster - box2d feature_raster_extent(rem.minx() + x_off, - rem.miny() + y_off, - rem.maxx() + x_off + width, - rem.maxy() + y_off + height); - intersect = t.backward(feature_raster_extent); - mapnik::image_any data = reader->read(x_off, y_off, width, height); - mapnik::raster_ptr raster = std::make_shared(intersect, std::move(data), 1.0); - feature->set_raster(raster); + int width = end_x - x_off; + int height = end_y - y_off; + if (width < 1) { + width = 1; } + if (height < 1) { + height = 1; + } + + // calculate actual box2d of returned raster + box2d feature_raster_extent(rem.minx() + x_off, + rem.miny() + y_off, + rem.maxx() + x_off + width, + rem.maxy() + y_off + height); + feature_raster_extent = t.backward(feature_raster_extent); + mapnik::image_any data = reader->read(x_off, y_off, width, height); + mapnik::raster_ptr raster = std::make_shared(feature_raster_extent, intersect, std::move(data), 1.0); + feature->set_raster(raster); } } } diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index 413948c64..4c6bb49c1 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -133,6 +133,7 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho // create a scaling matrix agg::trans_affine img_mtx; + img_mtx *= agg::trans_affine_translation(x_off_f, y_off_f); img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y); // create a linear interpolator for our scaling matrix @@ -141,11 +142,10 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho double scaled_width = target.width(); double scaled_height = target.height(); ras.reset(); - ras.move_to_d(x_off_f, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); - ras.line_to_d(x_off_f, y_off_f + scaled_height); - + ras.move_to_d(0.0, 0.0); + ras.line_to_d(scaled_width, 0.0); + ras.line_to_d(scaled_width, scaled_height); + ras.line_to_d(0.0, scaled_height); if (scaling_method == SCALING_NEAR) { using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; diff --git a/test/data-visual b/test/data-visual index 17a3e7122..d96d10677 160000 --- a/test/data-visual +++ b/test/data-visual @@ -1 +1 @@ -Subproject commit 17a3e712266a6fac4d89c8473fc0429f6c54fae3 +Subproject commit d96d1067796f1fe99da27941b216cb6991661a6a