Merge branch 'master' into static-libc++-WIP

This commit is contained in:
Artem Pavlenko 2018-04-10 10:11:14 +02:00
commit 3ede8c1c26
13 changed files with 178 additions and 34 deletions

View file

@ -38,9 +38,9 @@ using x3::lit;
using x3::lexeme; using x3::lexeme;
using ascii::char_; using ascii::char_;
struct csv_unesc_chars_ : x3::symbols<char> struct unesc_char_ : x3::symbols<char>
{ {
csv_unesc_chars_() unesc_char_()
{ {
add("\\a", '\a') add("\\a", '\a')
("\\b", '\b') ("\\b", '\b')
@ -55,7 +55,7 @@ struct csv_unesc_chars_ : x3::symbols<char>
("\"\"", '\"') // double quote ("\"\"", '\"') // double quote
; ;
} }
} csv_unesc_chars; } unesc_char;
template <typename T> template <typename T>
struct literal : x3::parser<literal<T>> struct literal : x3::parser<literal<T>>
@ -97,7 +97,7 @@ auto const column_def = quoted_text | *(char_ - separator)
auto const quoted_text_def = quote > text > quote // support unmatched quotes or not (??) auto const quoted_text_def = quote > text > quote // support unmatched quotes or not (??)
; ;
auto const text_def = *(csv_unesc_chars | (char_ - quote)) auto const text_def = *(unesc_char | (char_ - quote))
; ;
BOOST_SPIRIT_DEFINE ( BOOST_SPIRIT_DEFINE (

View file

@ -74,7 +74,7 @@ public:
static constexpr image_dtype dtype = T::id; static constexpr image_dtype dtype = T::id;
static constexpr std::size_t pixel_size = sizeof(pixel_type); static constexpr std::size_t pixel_size = sizeof(pixel_type);
private: private:
detail::image_dimensions<65535> dimensions_; detail::image_dimensions<4294836225> dimensions_;
detail::buffer buffer_; detail::buffer buffer_;
double offset_; double offset_;
double scaling_; double scaling_;

View file

@ -39,8 +39,10 @@ image_dimensions<max_size>::image_dimensions(int width, int height)
: width_(width), : width_(width),
height_(height) height_(height)
{ {
if (width < 0 || static_cast<std::size_t>(width) > max_size) throw std::runtime_error("Invalid width for image dimensions requested"); int64_t area = (int64_t)width * (int64_t)height;
if (height < 0 || static_cast<std::size_t>(height) > max_size) throw std::runtime_error("Invalid height for image dimensions requested"); if (width < 0) throw std::runtime_error("Invalid width for image dimensions requested");
if (height < 0) throw std::runtime_error("Invalid height for image dimensions requested");
if (area > max_size) throw std::runtime_error("Image area too large based on image dimensions");
} }
template <std::size_t max_size> template <std::size_t max_size>

View file

@ -33,6 +33,7 @@ namespace mapnik { namespace json { namespace grammar {
namespace x3 = boost::spirit::x3; namespace x3 = boost::spirit::x3;
using unicode_string_grammar_type = x3::rule<class unicode_string_tag, std::string>; using unicode_string_grammar_type = x3::rule<class unicode_string_tag, std::string>;
BOOST_SPIRIT_DECLARE(unicode_string_grammar_type); BOOST_SPIRIT_DECLARE(unicode_string_grammar_type);
} }

View file

@ -32,6 +32,8 @@
#include <gdal_version.h> #include <gdal_version.h>
#include <mutex>
using mapnik::datasource; using mapnik::datasource;
using mapnik::parameters; using mapnik::parameters;
@ -83,6 +85,13 @@ gdal_datasource::gdal_datasource(parameters const& params)
shared_dataset_ = *params.get<mapnik::boolean_type>("shared", false); shared_dataset_ = *params.get<mapnik::boolean_type>("shared", false);
band_ = *params.get<mapnik::value_integer>("band", -1); band_ = *params.get<mapnik::value_integer>("band", -1);
// Maximum memory limitation for image will be simply based on the maximum
// area we allow for an image. The true memory footprint therefore will vary based
// on the type of imagery that exists. This is not the maximum size of an image
// on disk but rather the maximum size we will load into mapnik from GDAL.
// max_im_area based on 50 mb limit for RGBA
max_image_area_ = *params.get<mapnik::value_integer>("max_image_area", (50*1024*1024) / 4);
#if GDAL_VERSION_NUM >= 1600 #if GDAL_VERSION_NUM >= 1600
if (shared_dataset_) if (shared_dataset_)
{ {
@ -235,7 +244,8 @@ featureset_ptr gdal_datasource::features(query const& q) const
dx_, dx_,
dy_, dy_,
nodata_value_, nodata_value_,
nodata_tolerance_); nodata_tolerance_,
max_image_area_);
} }
featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol) const featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol) const
@ -254,5 +264,6 @@ featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol)
dx_, dx_,
dy_, dy_,
nodata_value_, nodata_value_,
nodata_tolerance_); nodata_tolerance_,
max_image_area_);
} }

View file

@ -68,6 +68,7 @@ private:
bool shared_dataset_; bool shared_dataset_;
boost::optional<double> nodata_value_; boost::optional<double> nodata_value_;
double nodata_tolerance_; double nodata_tolerance_;
int64_t max_image_area_;
}; };
#endif // GDAL_DATASOURCE_HPP #endif // GDAL_DATASOURCE_HPP

View file

@ -89,7 +89,8 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset,
double dx, double dx,
double dy, double dy,
boost::optional<double> const& nodata, boost::optional<double> const& nodata,
double nodata_tolerance) double nodata_tolerance,
int64_t max_image_area)
: dataset_(dataset), : dataset_(dataset),
ctx_(std::make_shared<mapnik::context_type>()), ctx_(std::make_shared<mapnik::context_type>()),
band_(band), band_(band),
@ -102,6 +103,7 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset,
nbands_(nbands), nbands_(nbands),
nodata_value_(nodata), nodata_value_(nodata),
nodata_tolerance_(nodata_tolerance), nodata_tolerance_(nodata_tolerance),
max_image_area_(max_image_area),
first_(true) first_(true)
{ {
ctx_->push("nodata"); ctx_->push("nodata");
@ -153,6 +155,8 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
//size of resized output pixel in source image domain //size of resized output pixel in source image domain
double margin_x = 1.0 / (std::fabs(dx_) * std::get<0>(q.resolution())); double margin_x = 1.0 / (std::fabs(dx_) * std::get<0>(q.resolution()));
double margin_y = 1.0 / (std::fabs(dy_) * std::get<1>(q.resolution())); double margin_y = 1.0 / (std::fabs(dy_) * std::get<1>(q.resolution()));
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: margin_x=" << margin_x;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: margin_y=" << margin_y;
if (margin_x < 1) if (margin_x < 1)
{ {
margin_x = 1.0; margin_x = 1.0;
@ -167,6 +171,10 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
int y_off = rint(box.miny() - margin_y); int y_off = rint(box.miny() - margin_y);
int end_x = rint(box.maxx() + margin_x); int end_x = rint(box.maxx() + margin_x);
int end_y = rint(box.maxy() + margin_y); int end_y = rint(box.maxy() + margin_y);
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: x_off=" << x_off;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: y_off=" << y_off;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: end_x=" << end_x;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: end_y=" << end_y;
//clip to available data //clip to available data
if (x_off < 0) if (x_off < 0)
@ -185,21 +193,134 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
{ {
end_y = raster_height_; end_y = raster_height_;
} }
// width and height of the portion of the source image we are requesting
int width = end_x - x_off; int width = end_x - x_off;
int height = end_y - y_off; int height = end_y - y_off;
// In many cases we want GDAL to simply return the exact image so we
// can handle resampling internally in mapnik. In other cases such as
// when overviews exist or when the image allocated might be too large
// we want to utilize some resampling in GDAL instead.
int im_height = height;
int im_width = width;
double im_offset_x = x_off;
double im_offset_y = y_off;
int current_width = (int)raster_width_;
int current_height = (int)raster_height_;
// loop through overviews -- snap up in resolution to closest overview if necessary
// we find an image size that most resembles the resolution of our output image.
double width_res = std::get<0>(q.resolution());
double height_res = std::get<1>(q.resolution());
int res_adjusted_raster_width = static_cast<int>(std::floor(((double)raster_width_ * width_res) + .5));
int res_adjusted_raster_height = static_cast<int>(std::floor(((double)raster_height_ * height_res) + .5));
if (band_ > 0 && band_ < nbands_)
{
GDALRasterBand * band = dataset_.GetRasterBand(band_);
int band_overviews = band->GetOverviewCount();
if (band_overviews > 0)
{
for (int b = 0; b < band_overviews; b++)
{
GDALRasterBand * overview = band->GetOverview(b);
int overview_width = overview->GetXSize();
int overview_height = overview->GetYSize();
if ((overview_width < current_width || overview_height < current_height) &&
res_adjusted_raster_width <= overview_width &&
res_adjusted_raster_height <= overview_height)
{
current_width = overview_width;
current_height = overview_height;
}
}
}
}
else
{
for (int i = 0; i < nbands_; ++i)
{
GDALRasterBand * band = dataset_.GetRasterBand(i + 1);
int band_overviews = band->GetOverviewCount();
if (band_overviews > 0)
{
for (int b = 0; b < band_overviews; b++)
{
GDALRasterBand * overview = band->GetOverview(b);
int overview_width = overview->GetXSize();
int overview_height = overview->GetYSize();
if ((overview_width < current_width || overview_height < current_height) &&
res_adjusted_raster_width <= overview_width &&
res_adjusted_raster_height <= overview_height)
{
current_width = overview_width;
current_height = overview_height;
}
}
}
}
}
if (current_width != (int)raster_width_ || current_height != (int)raster_height_)
{
if (current_width != (int)raster_width_)
{
double ratio = (double)current_width / (double)raster_width_;
int adjusted_width = static_cast<int>(std::floor((ratio * im_width) + 0.5));
double adjusted_ratio = (double)adjusted_width / (double)im_width;
im_offset_x = adjusted_ratio * im_offset_x;
im_width = adjusted_width;
}
if (current_height != (int)raster_height_)
{
double ratio = (double)current_height / (double)raster_height_;
int adjusted_height = static_cast<int>(std::floor((ratio * im_height) + 0.5));
double adjusted_ratio = (double)adjusted_height / (double)im_height;
im_offset_y = adjusted_ratio * im_offset_y;
im_height = adjusted_height;
}
}
int64_t im_area = (int64_t)im_width * (int64_t)im_height;
if (im_area > max_image_area_)
{
int adjusted_width = static_cast<int>(std::round(std::sqrt(max_image_area_ * ((double)im_width / (double)im_height))));
int adjusted_height = static_cast<int>(std::round(std::sqrt(max_image_area_ * ((double)im_height / (double)im_width))));
if (adjusted_width < 1)
{
adjusted_width = 1;
}
if (adjusted_height < 1)
{
adjusted_height = 1;
}
double ratio_x = (double)adjusted_width / (double)im_width;
double ratio_y = (double)adjusted_height / (double)im_height;
im_offset_x = ratio_x * im_offset_x;
im_offset_y = ratio_y * im_offset_y;
im_width = adjusted_width;
im_height = adjusted_height;
current_width = static_cast<int>(std::floor((ratio_x * current_width) + 0.5));
current_height = static_cast<int>(std::floor((ratio_y * current_height) + 0.5));
}
//calculate actual box2d of returned raster //calculate actual box2d of returned raster
box2d<double> feature_raster_extent(x_off, y_off, x_off + width, y_off + height); view_transform t2(current_width, current_height, raster_extent_, 0, 0);
feature_raster_extent = t.backward(feature_raster_extent); box2d<double> feature_raster_extent(im_offset_x, im_offset_y, im_offset_x + im_width, im_offset_y + im_height);
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Feature Raster extent=" << feature_raster_extent;
feature_raster_extent = t2.backward(feature_raster_extent);
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Raster extent=" << raster_extent_; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Raster extent=" << raster_extent_;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Feature Raster extent=" << feature_raster_extent;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: View extent=" << intersect; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: View extent=" << intersect;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Query resolution=" << std::get<0>(q.resolution()) << "," << std::get<1>(q.resolution()); MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Query resolution=" << std::get<0>(q.resolution()) << "," << std::get<1>(q.resolution());
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: StartX=" << x_off << " StartY=" << y_off << " Width=" << width << " Height=" << height; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: StartX=" << x_off << " StartY=" << y_off << " Width=" << width << " Height=" << height;
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: IM StartX=" << im_offset_x << " StartY=" << im_offset_y << " Width=" << im_width << " Height=" << im_height;
if (width > 0 && height > 0) if (width > 0 && height > 0)
{ {
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << width << "," << height << ")";
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Requested Image Size=(" << width << "," << height << ")";
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << im_width << "," << im_height << ")";
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_;
if (band_ > 0) // we are querying a single band if (band_ > 0) // we are querying a single band
{ {
@ -215,7 +336,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
{ {
case GDT_Byte: case GDT_Byte:
{ {
mapnik::image_gray8 image(width, height); mapnik::image_gray8 image(im_width, im_height);
image.set(std::numeric_limits<std::uint8_t>::max()); image.set(std::numeric_limits<std::uint8_t>::max());
raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_nodata = band->GetNoDataValue(&raster_has_nodata);
raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
@ -235,7 +356,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
case GDT_Float64: case GDT_Float64:
case GDT_Float32: case GDT_Float32:
{ {
mapnik::image_gray32f image(width, height); mapnik::image_gray32f image(im_width, im_height);
image.set(std::numeric_limits<float>::max()); image.set(std::numeric_limits<float>::max());
raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_nodata = band->GetNoDataValue(&raster_has_nodata);
raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
@ -254,7 +375,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
} }
case GDT_UInt16: case GDT_UInt16:
{ {
mapnik::image_gray16 image(width, height); mapnik::image_gray16 image(im_width, im_height);
image.set(std::numeric_limits<std::uint16_t>::max()); image.set(std::numeric_limits<std::uint16_t>::max());
raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_nodata = band->GetNoDataValue(&raster_has_nodata);
raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
@ -274,7 +395,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
default: default:
case GDT_Int16: case GDT_Int16:
{ {
mapnik::image_gray16s image(width, height); mapnik::image_gray16s image(im_width, im_height);
image.set(std::numeric_limits<std::int16_t>::max()); image.set(std::numeric_limits<std::int16_t>::max());
raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_nodata = band->GetNoDataValue(&raster_has_nodata);
raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
@ -295,7 +416,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
} }
else // working with all bands else // working with all bands
{ {
mapnik::image_rgba8 image(width, height); mapnik::image_rgba8 image(im_width, im_height);
image.set(std::numeric_limits<std::uint32_t>::max()); image.set(std::numeric_limits<std::uint32_t>::max());
for (int i = 0; i < nbands_; ++i) for (int i = 0; i < nbands_; ++i)
{ {

View file

@ -66,7 +66,8 @@ public:
double dx, double dx,
double dy, double dy,
boost::optional<double> const& nodata, boost::optional<double> const& nodata,
double nodata_tolerance); double nodata_tolerance,
int64_t max_image_area);
virtual ~gdal_featureset(); virtual ~gdal_featureset();
mapnik::feature_ptr next(); mapnik::feature_ptr next();
@ -85,6 +86,7 @@ private:
int nbands_; int nbands_;
boost::optional<double> nodata_value_; boost::optional<double> nodata_value_;
double nodata_tolerance_; double nodata_tolerance_;
int64_t max_image_area_;
bool first_; bool first_;
}; };

View file

@ -41,6 +41,7 @@
// stl // stl
#include <fstream> #include <fstream>
#include <mutex>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>

View file

@ -84,7 +84,7 @@ void buffer::swap(buffer & rhs)
std::swap(owns_, rhs.owns_); std::swap(owns_, rhs.owns_);
} }
template struct MAPNIK_DECL image_dimensions<65535>; template struct MAPNIK_DECL image_dimensions<4294836225>;
} // end ns detail } // end ns detail

View file

@ -129,20 +129,25 @@ void raster_colorizer::colorize(image_rgba8 & out, T const& in,
{ {
using image_type = T; using image_type = T;
using pixel_type = typename image_type::pixel_type; using pixel_type = typename image_type::pixel_type;
// TODO: assuming in/out have the same width/height for now
std::uint32_t * out_data = out.data(); const std::size_t width = std::min(in.width(), out.width());
pixel_type const* in_data = in.data(); const std::size_t height = std::min(in.height(), out.height());
int len = out.width() * out.height();
for (int i=0; i<len; ++i) for (std::size_t y = 0; y < height; ++y)
{ {
pixel_type val = in_data[i]; pixel_type const * in_row = in.get_row(y);
image_rgba8::pixel_type * out_row = out.get_row(y);
for (std::size_t x = 0; x < width; ++x)
{
pixel_type val = in_row[x];
if (nodata && (std::fabs(val - *nodata) < epsilon_)) if (nodata && (std::fabs(val - *nodata) < epsilon_))
{ {
out_data[i] = 0; // rgba(0,0,0,0) out_row[x] = 0; // rgba(0,0,0,0)
} }
else else
{ {
out_data[i] = get_color(val); out_row[x] = get_color(val);
}
} }
} }
} }

@ -1 +1 @@
Subproject commit 96d52a79df7e20c5543321baa177811dc72bc93a Subproject commit a44457cc063249e0d204cde7249d37706bf8844c

@ -1 +1 @@
Subproject commit d374baac6cd72e7de665a27ded9b129e92661e18 Subproject commit c113ce13267124332cc2ecd049d7d2d7397f9a51