feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q) { MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Running get_feature"; feature_ptr feature(feature_factory::create(ctx_,1)); double x0, y0, x1, y1; rasterliteGetExtent (dataset_, &x0, &y0, &x1, &y1); box2d<double> raster_extent(x0, y0, x1, y1); box2d<double> intersect = raster_extent.intersect(q.get_bbox()); const int width = static_cast<int>(std::get<0>(q.resolution()) * intersect.width() + 0.5); const int height = static_cast<int>(std::get<0>(q.resolution()) * intersect.height() + 0.5); const double pixel_size = (intersect.width() >= intersect.height()) ? (intersect.width() / (double) width) : (intersect.height() / (double) height); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Raster extent=" << raster_extent; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: View extent=" << q.get_bbox(); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Intersect extent=" << intersect; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Query resolution=" << std::get<0>(q.resolution()) << "," << std::get<1>(q.resolution()); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Size=" << width << " " << height; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Pixel Size=" << pixel_size; if (width > 0 && height > 0) { int size = 0; void* raster = 0; if (rasterliteGetRawImageByRect(dataset_, intersect.minx(), intersect.miny(), intersect.maxx(), intersect.maxy(), pixel_size, width, height, GAIA_RGBA_ARRAY, &raster, &size) == RASTERLITE_OK) { if (size > 0) { mapnik::image_rgba8 image(width,height); unsigned char* raster_data = static_cast<unsigned char*>(raster); std::memcpy(image.bytes(), raster_data, size); feature->set_raster(std::make_shared<mapnik::raster>(intersect, std::move(image), 1.0)); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Done"; } else { MAPNIK_LOG_ERROR(rasterlite) << "Rasterlite Plugin: Error " << rasterliteGetLastError (dataset_); } } return feature; } return feature_ptr(); }
mapnik::featureset_ptr geojson_datasource::features(mapnik::query const& q) const { // if the query box intersects our world extent then query for features mapnik::box2d<double> const& box = q.get_bbox(); if (extent_.intersects(box)) { geojson_featureset::array_type index_array; if (tree_) { tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array)); // sort index array to preserve original feature ordering in GeoJSON std::sort(index_array.begin(),index_array.end(), [] (item_type const& item0, item_type const& item1) { return item0.second.first < item1.second.first; }); if (cache_features_) { return std::make_shared<geojson_featureset>(features_, std::move(index_array)); } else { return std::make_shared<geojson_memory_index_featureset>(filename_, std::move(index_array)); } } else if (has_disk_index_) { mapnik::filter_in_box filter(q.get_bbox()); return std::make_shared<geojson_index_featureset>(filename_, filter); } } // otherwise return an empty featureset return mapnik::make_invalid_featureset(); }
mapnik::featureset_ptr csv_datasource::features(mapnik::query const& q) const { for (auto const& name : q.property_names()) { bool found_name = false; for (auto const& header : headers_) { if (header == name) { found_name = true; break; } } if (!found_name) { std::ostringstream s; s << "CSV Plugin: no attribute '" << name << "'. Valid attributes are: " << boost::algorithm::join(headers_, ",") << "."; throw mapnik::datasource_exception(s.str()); } } mapnik::box2d<double> const& box = q.get_bbox(); if (extent_.intersects(box)) { if (tree_) { csv_featureset::array_type index_array; tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array)); std::sort(index_array.begin(),index_array.end(), [] (item_type const& item0, item_type const& item1) { return item0.second.first < item1.second.first; }); if (inline_string_.empty()) { return std::make_shared<csv_featureset>(filename_, locator_, separator_, quote_, headers_, ctx_, std::move(index_array)); } else { return std::make_shared<csv_inline_featureset>(inline_string_, locator_, separator_, quote_, headers_, ctx_, std::move(index_array)); } } else if (has_disk_index_) { mapnik::filter_in_box filter(q.get_bbox()); return std::make_shared<csv_index_featureset>(filename_, filter, locator_, separator_, quote_, headers_, ctx_); } } return mapnik::featureset_ptr(); }
virtual mapnik::featureset_ptr features(mapnik::query const& q) const { mapnik::box2d<double> const& actual_bbox = q.get_bbox(); REQUIRE(actual_bbox.minx() == Approx(expected_query_bbox_.minx())); REQUIRE(actual_bbox.miny() == Approx(expected_query_bbox_.miny())); REQUIRE(actual_bbox.maxx() == Approx(expected_query_bbox_.maxx())); REQUIRE(actual_bbox.maxy() == Approx(expected_query_bbox_.maxy())); return mapnik::memory_datasource::features(q); }
mapnik::featureset_ptr geojson_datasource::features(mapnik::query const& q) const { // if the query box intersects our world extent then query for features mapnik::box2d<double> const& b = q.get_bbox(); if (extent_.intersects(b)) { box_type box(point_type(b.minx(),b.miny()),point_type(b.maxx(),b.maxy())); return std::make_shared<geojson_featureset>(features_, tree_.find(box)); } // otherwise return an empty featureset pointer return mapnik::featureset_ptr(); }
mapnik::featureset_ptr rasterizer_datasource::features(const mapnik::query& q) const { std::clog << "Rasterizer::features" << ", resolution_type=(" << q.resolution().head << "," << q.resolution().tail.head << ")" << ", scale_denominator=" << q.scale_denominator() << ", bbox=[" << q.get_bbox().minx() << "," << q.get_bbox().miny() << "," << q.get_bbox().maxx() << "," << q.get_bbox().maxy() << "]" << std::endl; double resx=q.resolution().head, resy=q.resolution().tail.head, bbox_width=q.get_bbox().width(), bbox_height=q.get_bbox().height(); int pixel_width=round(bbox_width * resx), pixel_height=round(bbox_height * resy); if (pixel_width<=0 || pixel_height<=0) { std::clog << "Illegal rasterizer display metrics" << std::endl; return mapnik::featureset_ptr(); } std::clog << "Rasterizer generating image of size (" << pixel_width << "," << pixel_height << ")" << std::endl; // Setup for render mapnik::feature_ptr feature(mapnik::feature_factory::create(1)); mapnik::image_data_32 image(pixel_width, pixel_height); rasterize_params params(q, image); rasterize(params); // Prepare and return the raster feature feature->set_raster(boost::make_shared<mapnik::raster>(q.get_bbox(), image)); return boost::make_shared<singleton_featureset>(singleton_featureset(feature)); }
mapnik::featureset_ptr topojson_datasource::features(mapnik::query const& q) const { // if the query box intersects our world extent then query for features mapnik::box2d<double> const& box = q.get_bbox(); if (extent_.intersects(box)) { topojson_featureset::array_type index_array; if (tree_) { tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array)); return std::make_shared<topojson_featureset>(topo_, *tr_, std::move(index_array)); } } // otherwise return an empty featureset pointer return mapnik::featureset_ptr(); }
mapnik::featureset_ptr python_datasource::features(mapnik::query const& q) const { try { // if the query box intersects our world extent then query for features if (envelope().intersects(q.get_bbox())) { ensure_gil lock; boost::python::object features(datasource_.attr("features")(q)); // if 'None' was returned, return an empty feature set if(features.ptr() == boost::python::object().ptr()) { return mapnik::featureset_ptr(); } return std::make_shared<python_featureset>(features); } // otherwise return an empty featureset pointer return mapnik::featureset_ptr(); } catch ( boost::python::error_already_set ) { throw mapnik::datasource_exception(extractException()); } }
mapnik::featureset_ptr geojson_datasource::features(mapnik::query const& q) const { // if the query box intersects our world extent then query for features mapnik::box2d<double> const& b = q.get_bbox(); if (extent_.intersects(b)) { box_type box(point_type(b.minx(),b.miny()),point_type(b.maxx(),b.maxy())); #if BOOST_VERSION >= 105600 geojson_featureset::array_type index_array; if (tree_) { tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array)); return std::make_shared<geojson_featureset>(features_, std::move(index_array)); } #else if (tree_) { return std::make_shared<geojson_featureset>(features_, tree_->find(box)); } #endif } // otherwise return an empty featureset pointer return mapnik::featureset_ptr(); }
feature_ptr gdal_featureset::get_feature(mapnik::query const& q) { feature_ptr feature = feature_factory::create(ctx_,1); GDALRasterBand * red = 0; GDALRasterBand * green = 0; GDALRasterBand * blue = 0; GDALRasterBand * alpha = 0; GDALRasterBand * grey = 0; /* #ifdef MAPNIK_LOG double tr[6]; dataset_.GetGeoTransform(tr); const double dx = tr[1]; const double dy = tr[5]; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: dx_=" << dx_ << " dx=" << dx << " dy_=" << dy_ << "dy=" << dy; #endif */ CoordTransform t(raster_width_, raster_height_, raster_extent_, 0, 0); box2d<double> intersect = raster_extent_.intersect(q.get_bbox()); box2d<double> box = t.forward(intersect); //size of resized output pixel in source image domain double margin_x = 1.0 / (fabs(dx_) * boost::get<0>(q.resolution())); double margin_y = 1.0 / (fabs(dy_) * boost::get<1>(q.resolution())); if (margin_x < 1) { margin_x = 1.0; } if (margin_y < 1) { margin_y = 1.0; } //select minimum raster containing whole box int x_off = rint(box.minx() - margin_x); int y_off = rint(box.miny() - margin_y); int end_x = rint(box.maxx() + margin_x); int end_y = rint(box.maxy() + margin_y); //clip to available data if (x_off < 0) { x_off = 0; } if (y_off < 0) { y_off = 0; } if (end_x > (int)raster_width_) { end_x = raster_width_; } if (end_y > (int)raster_height_) { end_y = raster_height_; } int width = end_x - x_off; int height = end_y - y_off; // don't process almost invisible data if (box.width() < 0.5) { width = 0; } if (box.height() < 0.5) { height = 0; } //calculate actual box2d of returned raster box2d<double> feature_raster_extent(x_off, y_off, x_off + width, y_off + height); intersect = t.backward(feature_raster_extent); MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Raster extent=" << raster_extent_; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: View extent=" << intersect; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Query resolution=" << boost::get<0>(q.resolution()) << "," << boost::get<1>(q.resolution()); MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: StartX=" << x_off << " StartY=" << y_off << " Width=" << width << " Height=" << height; if (width > 0 && height > 0) { double width_res = boost::get<0>(q.resolution()); double height_res = boost::get<1>(q.resolution()); int im_width = int(width_res * intersect.width() + 0.5); int im_height = int(height_res * intersect.height() + 0.5); // if layer-level filter_factor is set, apply it if (filter_factor_) { im_width *= filter_factor_; im_height *= filter_factor_; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Applying layer filter_factor=" << filter_factor_; } // otherwise respect symbolizer level factor applied to query, default of 1.0 else { double sym_downsample_factor = q.get_filter_factor(); im_width *= sym_downsample_factor; im_height *= sym_downsample_factor; } // case where we need to avoid upsampling so that the // image can be later scaled within raster_symbolizer if (im_width >= width || im_height >= height) { im_width = width; im_height = height; } if (im_width > 0 && im_height > 0) { mapnik::raster_ptr raster = boost::make_shared<mapnik::raster>(intersect, im_width, im_height); feature->set_raster(raster); mapnik::image_data_32 & image = raster->data_; image.set(0xffffffff); MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << im_width << "," << im_height << ")"; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_; if (band_ > 0) // we are querying a single band { if (band_ > nbands_) { throw datasource_exception((boost::format("GDAL Plugin: '%d' is an invalid band, dataset only has '%d' bands\n") % band_ % nbands_).str()); } float* imageData = (float*)image.getBytes(); GDALRasterBand * band = dataset_.GetRasterBand(band_); int hasNoData(0); double nodata(0); if (nodata_value_) { hasNoData = 1; nodata = *nodata_value_; } else { nodata = band->GetNoDataValue(&hasNoData); } band->RasterIO(GF_Read, x_off, y_off, width, height, imageData, image.width(), image.height(), GDT_Float32, 0, 0); if (hasNoData) { feature->put("NODATA",nodata); } } else // working with all bands { for (int i = 0; i < nbands_; ++i) { GDALRasterBand * band = dataset_.GetRasterBand(i + 1); #ifdef MAPNIK_LOG get_overview_meta(band); #endif GDALColorInterp color_interp = band->GetColorInterpretation(); switch (color_interp) { case GCI_RedBand: red = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found red band"; break; case GCI_GreenBand: green = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found green band"; break; case GCI_BlueBand: blue = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found blue band"; break; case GCI_AlphaBand: alpha = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found alpha band"; break; case GCI_GrayIndex: grey = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band"; break; case GCI_PaletteIndex: { grey = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band, and colortable..."; GDALColorTable *color_table = band->GetColorTable(); if (color_table) { int count = color_table->GetColorEntryCount(); MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color Table count=" << count; for (int j = 0; j < count; j++) { const GDALColorEntry *ce = color_table->GetColorEntry (j); if (! ce) continue; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color entry RGB=" << ce->c1 << "," <<ce->c2 << "," << ce->c3; } } break; } case GCI_Undefined: MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming gray band)"; grey = band; break; default: MAPNIK_LOG_WARN(gdal) << "gdal_featureset: Band type unknown!"; break; } } if (red && green && blue) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing rgb bands..."; int hasNoData = 0; double nodata = 0.0; if (nodata_value_) { hasNoData = 1; nodata = *nodata_value_; } else { nodata = red->GetNoDataValue(&hasNoData); } if (hasNoData) { feature->put("NODATA",nodata); } GDALColorTable *color_table = red->GetColorTable(); if (! alpha && hasNoData && ! color_table) { // first read the data in and create an alpha channel from the nodata values float* imageData = (float*)image.getBytes(); red->RasterIO(GF_Read, x_off, y_off, width, height, imageData, image.width(), image.height(), GDT_Float32, 0, 0); int len = image.width() * image.height(); for (int i = 0; i < len; ++i) { if (nodata == imageData[i]) { *reinterpret_cast<unsigned *>(&imageData[i]) = 0; } else { *reinterpret_cast<unsigned *>(&imageData[i]) = 0xFFFFFFFF; } } } red->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 0, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); green->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 1, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); blue->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 2, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); } else if (grey) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing gray band..."; int hasNoData(0); double nodata(0); if (nodata_value_) { hasNoData = 1; nodata = *nodata_value_; } else { nodata = grey->GetNoDataValue(&hasNoData); } GDALColorTable* color_table = grey->GetColorTable(); if (hasNoData && ! color_table) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: No data value for layer=" << nodata; feature->put("NODATA",nodata); // first read the data in and create an alpha channel from the nodata values float* imageData = (float*)image.getBytes(); grey->RasterIO(GF_Read, x_off, y_off, width, height, imageData, image.width(), image.height(), GDT_Float32, 0, 0); int len = image.width() * image.height(); for (int i = 0; i < len; ++i) { if (nodata == imageData[i]) { *reinterpret_cast<unsigned *>(&imageData[i]) = 0; } else { *reinterpret_cast<unsigned *> (&imageData[i]) = 0xFFFFFFFF; } } } grey->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 0, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 1, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 2, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (color_table) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Loading colour table..."; unsigned nodata_value = static_cast<unsigned>(nodata); if (hasNoData) { feature->put("NODATA",static_cast<int>(nodata_value)); } for (unsigned y = 0; y < image.height(); ++y) { unsigned int* row = image.getRow(y); for (unsigned x = 0; x < image.width(); ++x) { unsigned value = row[x] & 0xff; if (hasNoData && (value == nodata_value)) { // make no data fully alpha row[x] = 0; } else { const GDALColorEntry *ce = color_table->GetColorEntry(value); if (ce) { // TODO - big endian support row[x] = (ce->c4 << 24)| (ce->c3 << 16) | (ce->c2 << 8) | (ce->c1) ; } else { // make lacking color entry fully alpha // note - gdal_translate makes black row[x] = 0; } } } } } } if (alpha) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: processing alpha band..."; alpha->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 3, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); } } return feature; } } return feature_ptr(); }
feature_ptr gdal_featureset::get_feature(mapnik::query const& q) { feature_ptr feature = feature_factory::create(ctx_,1); int raster_has_nodata = 0; double raster_nodata = 0; GDALRasterBand * red = 0; GDALRasterBand * green = 0; GDALRasterBand * blue = 0; GDALRasterBand * alpha = 0; GDALRasterBand * grey = 0; CPLErr raster_io_error = CE_None; /* #ifdef MAPNIK_LOG double tr[6]; dataset_.GetGeoTransform(tr); const double dx = tr[1]; const double dy = tr[5]; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: dx_=" << dx_ << " dx=" << dx << " dy_=" << dy_ << "dy=" << dy; #endif */ view_transform t(raster_width_, raster_height_, raster_extent_, 0, 0); box2d<double> intersect = raster_extent_.intersect(q.get_bbox()); box2d<double> box = t.forward(intersect); //size of resized output pixel in source image domain 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())); if (margin_x < 1) { margin_x = 1.0; } if (margin_y < 1) { margin_y = 1.0; } //select minimum raster containing whole box int x_off = rint(box.minx() - margin_x); int y_off = rint(box.miny() - margin_y); int end_x = rint(box.maxx() + margin_x); int end_y = rint(box.maxy() + margin_y); //clip to available data if (x_off < 0) { x_off = 0; } if (y_off < 0) { y_off = 0; } if (end_x > (int)raster_width_) { end_x = raster_width_; } if (end_y > (int)raster_height_) { end_y = raster_height_; } int width = end_x - x_off; int height = end_y - y_off; // don't process almost invisible data if (box.width() < 0.5) { width = 0; } if (box.height() < 0.5) { height = 0; } //calculate actual box2d of returned raster box2d<double> feature_raster_extent(x_off, y_off, x_off + width, y_off + height); intersect = t.backward(feature_raster_extent); MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Raster extent=" << raster_extent_; 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: StartX=" << x_off << " StartY=" << y_off << " Width=" << width << " Height=" << height; if (width > 0 && height > 0) { double width_res = std::get<0>(q.resolution()); double height_res = std::get<1>(q.resolution()); int im_width = int(width_res * intersect.width() + 0.5); int im_height = int(height_res * intersect.height() + 0.5); double filter_factor = q.get_filter_factor(); im_width = int(im_width * filter_factor + 0.5); im_height = int(im_height * filter_factor + 0.5); // case where we need to avoid upsampling so that the // image can be later scaled within raster_symbolizer if (im_width >= width || im_height >= height) { im_width = width; im_height = height; } if (im_width > 0 && im_height > 0) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << im_width << "," << im_height << ")"; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_; if (band_ > 0) // we are querying a single band { GDALRasterBand * band = dataset_.GetRasterBand(band_); if (band_ > nbands_) { std::ostringstream s; s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands"; throw datasource_exception(s.str()); } GDALDataType band_type = band->GetRasterDataType(); switch (band_type) { case GDT_Byte: { mapnik::image_gray8 image(im_width, im_height); image.set(std::numeric_limits<std::uint8_t>::max()); raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, image.data(), image.width(), image.height(), GDT_Byte, 0, 0); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor); // set nodata value to be used in raster colorizer if (nodata_value_) raster->set_nodata(*nodata_value_); else raster->set_nodata(raster_nodata); feature->set_raster(raster); break; } case GDT_Float64: case GDT_Float32: { mapnik::image_gray32f image(im_width, im_height); image.set(std::numeric_limits<float>::max()); raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, image.data(), image.width(), image.height(), GDT_Float32, 0, 0); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor); // set nodata value to be used in raster colorizer if (nodata_value_) raster->set_nodata(*nodata_value_); else raster->set_nodata(raster_nodata); feature->set_raster(raster); break; } case GDT_UInt16: { mapnik::image_gray16 image(im_width, im_height); image.set(std::numeric_limits<std::uint16_t>::max()); raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, image.data(), image.width(), image.height(), GDT_UInt16, 0, 0); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor); // set nodata value to be used in raster colorizer if (nodata_value_) raster->set_nodata(*nodata_value_); else raster->set_nodata(raster_nodata); feature->set_raster(raster); break; } default: case GDT_Int16: { mapnik::image_gray16s image(im_width, im_height); image.set(std::numeric_limits<std::int16_t>::max()); raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, image.data(), image.width(), image.height(), GDT_Int16, 0, 0); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor); // set nodata value to be used in raster colorizer if (nodata_value_) raster->set_nodata(*nodata_value_); else raster->set_nodata(raster_nodata); feature->set_raster(raster); break; } } } else // working with all bands { mapnik::image_rgba8 image(im_width, im_height); image.set(std::numeric_limits<std::uint32_t>::max()); for (int i = 0; i < nbands_; ++i) { GDALRasterBand * band = dataset_.GetRasterBand(i + 1); #ifdef MAPNIK_LOG get_overview_meta(band); #endif GDALColorInterp color_interp = band->GetColorInterpretation(); switch (color_interp) { case GCI_RedBand: red = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found red band"; break; case GCI_GreenBand: green = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found green band"; break; case GCI_BlueBand: blue = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found blue band"; break; case GCI_AlphaBand: alpha = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found alpha band"; break; case GCI_GrayIndex: grey = band; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band"; break; case GCI_PaletteIndex: { grey = band; #ifdef MAPNIK_LOG MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band, and colortable..."; GDALColorTable *color_table = band->GetColorTable(); if (color_table) { int count = color_table->GetColorEntryCount(); MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color Table count=" << count; for (int j = 0; j < count; j++) { const GDALColorEntry *ce = color_table->GetColorEntry (j); if (! ce) continue; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color entry RGB=" << ce->c1 << "," <<ce->c2 << "," << ce->c3; } } #endif break; } case GCI_Undefined: #if GDAL_VERSION_NUM <= 1730 if (nbands_ == 4) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming alpha band)"; alpha = band; } else { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming gray band)"; grey = band; } #else MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming gray band)"; grey = band; #endif break; default: MAPNIK_LOG_WARN(gdal) << "gdal_featureset: Band type unknown!"; break; } } if (red && green && blue) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing rgb bands..."; raster_nodata = red->GetNoDataValue(&raster_has_nodata); GDALColorTable *color_table = red->GetColorTable(); bool has_nodata = nodata_value_ || raster_has_nodata; // we can deduce the alpha channel from nodata in the Byte case // by reusing the reading of R,G,B bands directly if (has_nodata && !color_table && red->GetRasterDataType() == GDT_Byte) { double apply_nodata = nodata_value_ ? *nodata_value_ : raster_nodata; // read the data in and create an alpha channel from the nodata values // TODO - we assume here the nodata value for the red band applies to all bands // more details about this at http://trac.osgeo.org/gdal/ticket/2734 float* imageData = (float*)image.bytes(); raster_io_error = red->RasterIO(GF_Read, x_off, y_off, width, height, imageData, image.width(), image.height(), GDT_Float32, 0, 0); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } int len = image.width() * image.height(); for (int i = 0; i < len; ++i) { if (std::fabs(apply_nodata - imageData[i]) < nodata_tolerance_) { *reinterpret_cast<unsigned *>(&imageData[i]) = 0; } else { *reinterpret_cast<unsigned *>(&imageData[i]) = 0xFFFFFFFF; } } } /* Use dataset RasterIO in priority in 99.9% of the cases */ if( red->GetBand() == 1 && green->GetBand() == 2 && blue->GetBand() == 3 ) { int nBandsToRead = 3; if( alpha != NULL && alpha->GetBand() == 4 && !raster_has_nodata ) { nBandsToRead = 4; alpha = NULL; // to avoid reading it again afterwards } raster_io_error = dataset_.RasterIO(GF_Read, x_off, y_off, width, height, image.bytes(), image.width(), image.height(), GDT_Byte, nBandsToRead, NULL, 4, 4 * image.width(), 1); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } } else { raster_io_error = red->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 0, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } raster_io_error = green->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 1, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } raster_io_error = blue->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 2, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } } // In the case we skipped initializing the alpha channel if (has_nodata && !color_table && red->GetRasterDataType() == GDT_Byte) { double apply_nodata = nodata_value_ ? *nodata_value_ : raster_nodata; if( apply_nodata >= 0 && apply_nodata <= 255 ) { int len = image.width() * image.height(); GByte* pabyBytes = (GByte*) image.bytes(); for (int i = 0; i < len; ++i) { // TODO - we assume here the nodata value for the red band applies to all bands // more details about this at http://trac.osgeo.org/gdal/ticket/2734 if (std::fabs(apply_nodata - pabyBytes[4*i]) < nodata_tolerance_) pabyBytes[4*i + 3] = 0; else pabyBytes[4*i + 3] = 255; } } } } else if (grey) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing gray band..."; raster_nodata = grey->GetNoDataValue(&raster_has_nodata); GDALColorTable* color_table = grey->GetColorTable(); bool has_nodata = nodata_value_ || raster_has_nodata; if (!color_table && has_nodata) { double apply_nodata = nodata_value_ ? *nodata_value_ : raster_nodata; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: applying nodata value for layer=" << apply_nodata; // first read the data in and create an alpha channel from the nodata values float* imageData = (float*)image.bytes(); raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height, imageData, image.width(), image.height(), GDT_Float32, 0, 0); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } int len = image.width() * image.height(); for (int i = 0; i < len; ++i) { if (std::fabs(apply_nodata - imageData[i]) < nodata_tolerance_) { *reinterpret_cast<unsigned *>(&imageData[i]) = 0; } else { *reinterpret_cast<unsigned *>(&imageData[i]) = 0xFFFFFFFF; } } } raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 0, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.bytes() + 1, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.bytes() + 2, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } if (color_table) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Loading color table..."; for (unsigned y = 0; y < image.height(); ++y) { unsigned int* row = image.get_row(y); for (unsigned x = 0; x < image.width(); ++x) { unsigned value = row[x] & 0xff; const GDALColorEntry *ce = color_table->GetColorEntry(value); if (ce) { row[x] = (ce->c4 << 24)| (ce->c3 << 16) | (ce->c2 << 8) | (ce->c1) ; } else { // make lacking color entry fully alpha // note - gdal_translate makes black row[x] = 0; } } } } } if (alpha) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: processing alpha band..."; if (!raster_has_nodata) { raster_io_error = alpha->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 3, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); } } else { MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of alpha band"; } } mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor); // set nodata value to be used in raster colorizer if (nodata_value_) raster->set_nodata(*nodata_value_); else raster->set_nodata(raster_nodata); feature->set_raster(raster); } // report actual/original source nodata in feature attributes if (raster_has_nodata) { feature->put("nodata",raster_nodata); } return feature; } } return feature_ptr(); }
feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q) { #ifdef MAPNIK_DEBUG std::clog << "Rasterlite Plugin: get_feature" << "\n"; #endif feature_ptr feature(new Feature(1)); double x0, y0, x1, y1; rasterliteGetExtent (dataset_, &x0, &y0, &x1, &y1); box2d<double> raster_extent(x0,y0,x1,y1); box2d<double> intersect = raster_extent.intersect(q.get_bbox()); int width = static_cast<int>(q.resolution() * intersect.width() + 0.5); int height = static_cast<int>(q.resolution() * intersect.height() + 0.5); double pixel_size = (intersect.width() >= intersect.height()) ? (intersect.width() / (double) width) : (intersect.height() / (double) height); #ifdef MAPNIK_DEBUG std::clog << "Rasterlite Plugin: Raster extent=" << raster_extent << "\n"; std::clog << "Rasterlite Plugin: View extent=" << q.get_bbox() << "\n"; std::clog << "Rasterlite Plugin: Intersect extent=" << intersect << "\n"; std::clog << "Rasterlite Plugin: Query resolution=" << q.resolution() << "\n"; std::clog << "Rasterlite Plugin: Size=" << width << " " << height << "\n"; std::clog << "Rasterlite Plugin: Pixel Size=" << pixel_size << "\n"; #endif if (width > 0 && height > 0) { int size; void *raster; if (rasterliteGetRawImageByRect(dataset_, intersect.minx(), intersect.miny(), intersect.maxx(), intersect.maxy(), pixel_size, width, height, GAIA_RGBA_ARRAY, &raster, &size) == RASTERLITE_OK) { if (size > 0) { mapnik::image_data_32 image(width, height); image.set(0xffffffff); unsigned char* raster_data = static_cast<unsigned char*>(raster); unsigned char* image_data = image.getBytes(); memcpy (image_data, raster_data, size); feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect,image))); free (raster); #ifdef MAPNIK_DEBUG std::clog << "Rasterlite Plugin: Done" << "\n"; #endif } else { #ifdef MAPNIK_DEBUG std::clog << "Rasterlite Plugin: Error=" << rasterliteGetLastError (dataset_) << "\n"; #endif } } return feature; } return feature_ptr(); }
feature_ptr gdal_featureset::get_feature(mapnik::query const& q) { feature_ptr feature(new Feature(1)); GDALRasterBand * red = 0; GDALRasterBand * green = 0; GDALRasterBand * blue = 0; GDALRasterBand * alpha = 0; GDALRasterBand * grey = 0; /* double tr[6]; dataset_.GetGeoTransform(tr); double dx = tr[1]; double dy = tr[5]; std::clog << "dx_: " << dx_ << " dx: " << dx << " dy_: " << dy_ << "dy: " << dy << "\n"; */ CoordTransform t(raster_width_,raster_height_,raster_extent_,0,0); box2d<double> intersect = raster_extent_.intersect(q.get_bbox()); box2d<double> box = t.forward(intersect); //size of resized output pixel in source image domain double margin_x = 1.0/(fabs(dx_)*boost::get<0>(q.resolution())); double margin_y = 1.0/(fabs(dy_)*boost::get<1>(q.resolution())); if (margin_x < 1) margin_x = 1.0; if (margin_y < 1) margin_y = 1.0; //select minimum raster containing whole box int x_off = rint(box.minx() - margin_x); int y_off = rint(box.miny() - margin_y); int end_x = rint(box.maxx() + margin_x); int end_y = rint(box.maxy() + margin_y); //clip to available data if (x_off < 0) x_off = 0; if (y_off < 0) y_off = 0; if (end_x > (int)raster_width_) end_x = raster_width_; if (end_y > (int)raster_height_) end_y = raster_height_; int width = end_x - x_off; int height = end_y - y_off; // don't process almost invisible data if (box.width() < 0.5) width = 0; if (box.height() < 0.5) height = 0; //calculate actual box2d of returned raster box2d<double> feature_raster_extent(x_off, y_off, x_off+width, y_off+height); intersect = t.backward(feature_raster_extent); #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Raster extent=" << raster_extent_ << std::endl; std::clog << "GDAL Plugin: View extent=" << intersect << std::endl; std::clog << "GDAL Plugin: Query resolution=" << boost::get<0>(q.resolution()) << "," << boost::get<1>(q.resolution()) << std::endl; std::clog << boost::format("GDAL Plugin: StartX=%d StartY=%d Width=%d Height=%d") % x_off % y_off % width % height << std::endl; #endif if (width > 0 && height > 0) { double width_res = boost::get<0>(q.resolution()); double height_res = boost::get<1>(q.resolution()); int im_width = int(width_res * intersect.width() + 0.5); int im_height = int(height_res * intersect.height() + 0.5); // if layer-level filter_factor is set, apply it if (filter_factor_) { im_width *= filter_factor_; im_height *= filter_factor_; } // otherwise respect symbolizer level factor applied to query, default of 1.0 else { double sym_downsample_factor = q.get_filter_factor(); im_width *= sym_downsample_factor; im_height *= sym_downsample_factor; } // case where we need to avoid upsampling so that the // image can be later scaled within raster_symbolizer if (im_width >= width || im_height >= height) { im_width = width; im_height = height; } if (im_width > 0 && im_height > 0) { mapnik::image_data_32 image(im_width, im_height); image.set(0xffffffff); #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Image Size=(" << im_width << "," << im_height << ")" << std::endl; std::clog << "GDAL Plugin: Reading band " << band_ << std::endl; #endif typedef std::vector<int,int> pallete; if (band_ > 0) // we are querying a single band { if (band_ > nbands_) throw datasource_exception((boost::format("GDAL Plugin: '%d' is an invalid band, dataset only has '%d' bands\n") % band_ % nbands_).str()); float *imageData = (float*)image.getBytes(); GDALRasterBand * band = dataset_.GetRasterBand(band_); band->RasterIO(GF_Read, x_off, y_off, width, height, imageData, image.width(), image.height(), GDT_Float32, 0, 0); feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect,image))); } else // working with all bands { for (int i = 0; i < nbands_; ++i) { GDALRasterBand * band = dataset_.GetRasterBand(i+1); #ifdef MAPNIK_DEBUG get_overview_meta(band); #endif GDALColorInterp color_interp = band->GetColorInterpretation(); switch (color_interp) { case GCI_RedBand: red = band; #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Found red band" << std::endl; #endif break; case GCI_GreenBand: green = band; #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Found green band" << std::endl; #endif break; case GCI_BlueBand: blue = band; #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Found blue band" << std::endl; #endif break; case GCI_AlphaBand: alpha = band; #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Found alpha band" << std::endl; #endif break; case GCI_GrayIndex: grey = band; #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Found gray band" << std::endl; #endif break; case GCI_PaletteIndex: { grey = band; #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Found gray band, and colortable..." << std::endl; #endif GDALColorTable *color_table = band->GetColorTable(); if ( color_table) { int count = color_table->GetColorEntryCount(); #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Color Table count = " << count << std::endl; #endif for (int j = 0; j < count; j++) { const GDALColorEntry *ce = color_table->GetColorEntry (j); if (! ce) continue; #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Color entry RGB (" << ce->c1 << "," <<ce->c2 << "," << ce->c3 << ")" << std::endl; #endif } } break; } case GCI_Undefined: #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Found undefined band (assumming gray band)" << std::endl; #endif grey = band; break; default: #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: band type unknown!" << std::endl; #endif break; } } if (red && green && blue) { #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: processing rgb bands..." << std::endl; #endif red->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 0, image.width(),image.height(),GDT_Byte,4,4*image.width()); green->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 1, image.width(),image.height(),GDT_Byte,4,4*image.width()); blue->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 2, image.width(),image.height(),GDT_Byte,4,4*image.width()); } else if (grey) { #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: processing gray band..." << std::endl; #endif // TODO : apply colormap if present grey->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 0, image.width(),image.height(),GDT_Byte, 4, 4 * image.width()); grey->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 1, image.width(),image.height(),GDT_Byte, 4, 4 * image.width()); grey->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 2, image.width(),image.height(),GDT_Byte, 4, 4 * image.width()); } if (alpha) { #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: processing alpha band..." << std::endl; #endif alpha->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 3, image.width(),image.height(),GDT_Byte,4,4*image.width()); } feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect,image))); } return feature; } } return feature_ptr(); }