Added a 'multi' tiled raster plugin reader for virtual images
already present as tiles on disk.
This commit is contained in:
parent
8fba4b11da
commit
d29f609052
4 changed files with 208 additions and 27 deletions
|
@ -65,6 +65,10 @@ raster_datasource::raster_datasource(const parameters& params, bool bind)
|
|||
else
|
||||
filename_ = *file;
|
||||
|
||||
multi_tiles_ = *params_.get<bool>("multi", false);
|
||||
tile_size_ = *params_.get<unsigned>("tile-size", 256);
|
||||
tile_stride_ = *params_.get<unsigned>("tile-stride", 1);
|
||||
|
||||
format_=*params_.get<std::string>("format","tiff");
|
||||
|
||||
boost::optional<double> lox = params_.get<double>("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<image_reader> reader(mapnik::get_image_reader(filename_, format_));
|
||||
if (reader.get())
|
||||
{
|
||||
width_ = reader->width();
|
||||
height_ = reader->height();
|
||||
if (multi_tiles_)
|
||||
{
|
||||
boost::optional<unsigned> x_width = params_.get<unsigned>("x-width");
|
||||
boost::optional<unsigned> y_width = params_.get<unsigned>("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<image_reader> 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<raster_featureset<tiled_multi_file_policy> >(policy, extent_, q);
|
||||
}
|
||||
else if (width * height > 512*512)
|
||||
{
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "Raster Plugin: TILED policy" << std::endl;
|
||||
|
|
|
@ -37,6 +37,9 @@ class raster_datasource : public mapnik::datasource
|
|||
std::string format_;
|
||||
mapnik::box2d<double> extent_;
|
||||
bool extent_initialized_;
|
||||
bool multi_tiles_;
|
||||
unsigned tile_size_;
|
||||
unsigned tile_stride_;
|
||||
mutable unsigned width_;
|
||||
mutable unsigned height_;
|
||||
public:
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "raster_featureset.hpp"
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
using mapnik::query;
|
||||
using mapnik::CoordTransform;
|
||||
|
@ -67,16 +68,18 @@ feature_ptr raster_featureset<LookupPolicy>::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<double> intersect=bbox_.intersect(curIter_->envelope());
|
||||
box2d<double> ext=t.forward(intersect);
|
||||
box2d<double> 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<LookupPolicy>::next()
|
|||
int width = end_x - x_off;
|
||||
int height = end_y - y_off;
|
||||
//calculate actual box2d of returned raster
|
||||
box2d<double> feature_raster_extent(x_off, y_off, x_off+width, y_off+height);
|
||||
box2d<double> 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<LookupPolicy>::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<single_file_policy>;
|
||||
template class raster_featureset<tiled_file_policy>;
|
||||
template class raster_featureset<tiled_multi_file_policy>;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
// boost
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
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<double> transform(box2d<double> &) const
|
||||
{
|
||||
return box2d<double>(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<double> transform(box2d<double> &) const
|
||||
{
|
||||
return box2d<double>(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<raster_info> infos_;
|
||||
};
|
||||
|
||||
class tiled_multi_file_policy
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<raster_info>::const_iterator const_iterator;
|
||||
|
||||
tiled_multi_file_policy(std::string const& file_pattern, std::string const& format, unsigned tile_size,
|
||||
box2d<double> extent, box2d<double> 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<double> 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<double>(x0,y0,x1,y1)))
|
||||
{
|
||||
// tile_box => intersection of tile with query in projection-space.
|
||||
box2d<double> tile_box = e.intersect(box2d<double>(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<double> transform(box2d<double> &box) const
|
||||
{
|
||||
int x_offset = int(std::floor(box.minx() / tile_size_));
|
||||
int y_offset = int(std::floor(box.miny() / tile_size_));
|
||||
box2d<double> 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<raster_info> infos_;
|
||||
};
|
||||
|
||||
template <typename LookupPolicy>
|
||||
class raster_featureset : public mapnik::Featureset
|
||||
|
|
Loading…
Reference in a new issue