diff --git a/plugins/input/raster/raster_datasource.cpp b/plugins/input/raster/raster_datasource.cpp index e7bf0b445..589f269c8 100644 --- a/plugins/input/raster/raster_datasource.cpp +++ b/plugins/input/raster/raster_datasource.cpp @@ -65,6 +65,10 @@ raster_datasource::raster_datasource(const parameters& params, bool bind) else filename_ = *file; + multi_tiles_ = *params_.get("multi", false); + tile_size_ = *params_.get("tile-size", 256); + tile_stride_ = *params_.get("tile-stride", 1); + format_=*params_.get("format","tiff"); boost::optional lox = params_.get("lox"); @@ -96,33 +100,50 @@ void raster_datasource::bind() const { if (is_bound_) return; - if (! boost::filesystem::exists(filename_)) - throw datasource_exception("Raster Plugin: " + filename_ + " does not exist"); - - try - { - std::auto_ptr reader(mapnik::get_image_reader(filename_, format_)); - if (reader.get()) - { - width_ = reader->width(); - height_ = reader->height(); + if (multi_tiles_) + { + boost::optional x_width = params_.get("x-width"); + boost::optional y_width = params_.get("y-width"); -#ifdef MAPNIK_DEBUG - std::clog << "Raster Plugin: RASTER SIZE(" << width_ << "," << height_ << ")" << std::endl; -#endif - } + if (!x_width) + throw datasource_exception("Raster Plugin: x-width parameter not supplied for multi-tiled data source."); + + if (!y_width) + throw datasource_exception("Raster Plugin: y-width parameter not supplied for multi-tiled data source."); + + width_ = x_width.get() * tile_size_; + height_ = y_width.get() * tile_size_; } - catch (mapnik::image_reader_exception const& ex) + else { - std::cerr << "Raster Plugin: image reader exception caught: " << ex.what() << std::endl; - throw; - } - catch (...) - { - std::cerr << "Raster Plugin: exception caught" << std::endl; - throw; + if (! boost::filesystem::exists(filename_)) + throw datasource_exception("Raster Plugin: " + filename_ + " does not exist"); + + try + { + std::auto_ptr reader(mapnik::get_image_reader(filename_, format_)); + if (reader.get()) + { + width_ = reader->width(); + height_ = reader->height(); + } + } + catch (mapnik::image_reader_exception const& ex) + { + std::cerr << "Raster Plugin: image reader exception caught: " << ex.what() << std::endl; + throw; + } + catch (...) + { + std::cerr << "Raster Plugin: exception caught" << std::endl; + throw; + } } +#ifdef MAPNIK_DEBUG + std::clog << "Raster Plugin: RASTER SIZE(" << width_ << "," << height_ << ")" << std::endl; +#endif + is_bound_ = true; } @@ -165,7 +186,16 @@ featureset_ptr raster_datasource::features(query const& q) const std::clog << "Raster Plugin: BOX SIZE(" << width << " " << height << ")" << std::endl; #endif - if (width * height > 512*512) + if (multi_tiles_) + { +#ifdef MAPNIK_DEBUG + std::clog << "Raster Plugin: MULTI-TILED policy" << std::endl; +#endif + + tiled_multi_file_policy policy(filename_, format_, tile_size_, extent_, q.get_bbox(), width_, height_, tile_stride_); + return boost::make_shared >(policy, extent_, q); + } + else if (width * height > 512*512) { #ifdef MAPNIK_DEBUG std::clog << "Raster Plugin: TILED policy" << std::endl; diff --git a/plugins/input/raster/raster_datasource.hpp b/plugins/input/raster/raster_datasource.hpp index c8f5f4745..d88c45a96 100644 --- a/plugins/input/raster/raster_datasource.hpp +++ b/plugins/input/raster/raster_datasource.hpp @@ -37,6 +37,9 @@ class raster_datasource : public mapnik::datasource std::string format_; mapnik::box2d extent_; bool extent_initialized_; + bool multi_tiles_; + unsigned tile_size_; + unsigned tile_stride_; mutable unsigned width_; mutable unsigned height_; public: diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index 57a797f50..1c463a92b 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -27,6 +27,7 @@ #include "raster_featureset.hpp" +#include using mapnik::query; using mapnik::CoordTransform; @@ -67,16 +68,18 @@ feature_ptr raster_featureset::next() std::clog << "Raster Plugin: READER = " << curIter_->format() << " " << curIter_->file() << " size(" << curIter_->width() << "," << curIter_->height() << ")" << std::endl; #endif + if (reader.get()) { - int image_width=reader->width(); - int image_height=reader->height(); + int image_width = policy_.img_width(reader->width()); + int image_height = policy_.img_height(reader->height()); if (image_width>0 && image_height>0) { CoordTransform t(image_width,image_height,extent_,0,0); 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 @@ -96,7 +99,8 @@ feature_ptr raster_featureset::next() int width = end_x - x_off; int height = end_y - y_off; //calculate actual box2d of returned raster - box2d feature_raster_extent(x_off, y_off, x_off+width, y_off+height); + 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); image_data_32 image(width,height); @@ -121,5 +125,20 @@ feature_ptr raster_featureset::next() return feature_ptr(); } +std::string +tiled_multi_file_policy::interpolate(std::string const &pattern, int x, int y) const +{ + // TODO: make from some sort of configurable interpolation + int tms_y = tile_stride_ * ((image_height_ / tile_size_) - y - 1); + int tms_x = tile_stride_ * x; + std::string xs = (boost::format("%03d/%03d/%03d") % (tms_x / 1000000) % ((tms_x / 1000) % 1000) % (tms_x % 1000)).str(); + std::string ys = (boost::format("%03d/%03d/%03d") % (tms_y / 1000000) % ((tms_y / 1000) % 1000) % (tms_y % 1000)).str(); + std::string rv(pattern); + boost::algorithm::replace_all(rv, "${x}", xs); + boost::algorithm::replace_all(rv, "${y}", ys); + return rv; +} + template class raster_featureset; template class raster_featureset; +template class raster_featureset; diff --git a/plugins/input/raster/raster_featureset.hpp b/plugins/input/raster/raster_featureset.hpp index 879b2e848..4c2bb9816 100644 --- a/plugins/input/raster/raster_featureset.hpp +++ b/plugins/input/raster/raster_featureset.hpp @@ -29,7 +29,7 @@ // boost #include - +#include class single_file_policy { @@ -95,6 +95,21 @@ public: { return const_iterator(); } + + inline int img_width(int reader_width) const + { + return reader_width; + } + + inline int img_height(int reader_height) const + { + return reader_height; + } + + inline box2d transform(box2d &) const + { + return box2d(0, 0, 0, 0); + } }; class tiled_file_policy @@ -154,11 +169,125 @@ public: return infos_.end(); } + inline int img_width(int reader_width) const + { + return reader_width; + } + + inline int img_height(int reader_height) const + { + return reader_height; + } + + inline box2d transform(box2d &) const + { + return box2d(0, 0, 0, 0); + } + private: std::vector infos_; }; +class tiled_multi_file_policy +{ +public: + + typedef std::vector::const_iterator const_iterator; + + tiled_multi_file_policy(std::string const& file_pattern, std::string const& format, unsigned tile_size, + box2d extent, box2d bbox,unsigned width, unsigned height, + unsigned tile_stride) + : image_width_(width), image_height_(height), tile_size_(tile_size), tile_stride_(tile_stride) + { + + double lox = extent.minx(); + double loy = extent.miny(); + + int max_x = int(std::ceil(double(width)/double(tile_size))); + int max_y = int(std::ceil(double(height)/double(tile_size))); + + double pixel_x = extent.width()/double(width); + double pixel_y = extent.height()/double(height); + +#ifdef MAPNIK_DEBUG + std::clog << "Raster Plugin: PIXEL SIZE("<< pixel_x << "," << pixel_y << ")" << std::endl; +#endif + + // intersection of query with extent => new query + box2d e = bbox.intersect(extent); + + const int x_min = int(std::floor((e.minx() - lox) / (tile_size * pixel_x))); + const int y_min = int(std::floor((e.miny() - loy) / (tile_size * pixel_y))); + const int x_max = int(std::ceil((e.maxx() - lox) / (tile_size * pixel_x))); + const int y_max = int(std::ceil((e.maxy() - loy) / (tile_size * pixel_y))); + + for (int x = x_min ; x < x_max ; ++x) + { + for (int y = y_min ; y < y_max ; ++y) + { + // x0, y0, x1, y1 => projection-space image coordinates. + double x0 = lox + x*tile_size*pixel_x; + double y0 = loy + y*tile_size*pixel_y; + double x1 = x0 + tile_size*pixel_x; + double y1 = y0 + tile_size*pixel_y; + + // check if it intersects the query + if (e.intersects(box2d(x0,y0,x1,y1))) + { + // tile_box => intersection of tile with query in projection-space. + box2d tile_box = e.intersect(box2d(x0,y0,x1,y1)); + std::string file = interpolate(file_pattern, x, y); + raster_info info(file,format,tile_box,tile_size,tile_size); + infos_.push_back(info); + } + } + } +#ifdef MAPNIK_DEBUG + std::clog << "Raster Plugin: INFO SIZE=" << infos_.size() << " " << file_pattern << std::endl; +#endif + } + + const_iterator begin() + { + return infos_.begin(); + } + + const_iterator end() + { + return infos_.end(); + } + + inline int img_width(int) const + { + return image_width_; + } + + inline int img_height(int) const + { + return image_height_; + } + + inline box2d transform(box2d &box) const + { + int x_offset = int(std::floor(box.minx() / tile_size_)); + int y_offset = int(std::floor(box.miny() / tile_size_)); + box2d rem(x_offset * tile_size_, y_offset * tile_size_, + x_offset * tile_size_, y_offset * tile_size_); + box.init(box.minx() - rem.minx(), + box.miny() - rem.miny(), + box.maxx() - rem.maxx(), + box.maxy() - rem.maxy()); + return rem; + } + +private: + + std::string interpolate(std::string const &pattern, int x, int y) const; + + unsigned int image_width_, image_height_, tile_size_, tile_stride_; + std::vector infos_; +}; template class raster_featureset : public mapnik::Featureset