diff --git a/plugins/input/gdal/gdal_datasource.cpp b/plugins/input/gdal/gdal_datasource.cpp index f9ec48738..b12377eee 100644 --- a/plugins/input/gdal/gdal_datasource.cpp +++ b/plugins/input/gdal/gdal_datasource.cpp @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2007 Artem Pavlenko + * Copyright (C) 2011 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -45,7 +45,7 @@ using mapnik::datasource_exception; * Opens a GDALDataset and returns a pointer to it. * Caller is responsible for calling GDALClose on it */ -inline GDALDataset *gdal_datasource::open_dataset() const +inline GDALDataset* gdal_datasource::open_dataset() const { #ifdef MAPNIK_DEBUG @@ -55,21 +55,28 @@ inline GDALDataset *gdal_datasource::open_dataset() const GDALDataset *dataset; #if GDAL_VERSION_NUM >= 1600 if (shared_dataset_) - dataset = reinterpret_cast(GDALOpenShared((dataset_name_).c_str(),GA_ReadOnly)); + { + dataset = reinterpret_cast(GDALOpenShared((dataset_name_).c_str(), GA_ReadOnly)); + } else #endif - dataset = reinterpret_cast(GDALOpen((dataset_name_).c_str(),GA_ReadOnly)); + { + dataset = reinterpret_cast(GDALOpen((dataset_name_).c_str(), GA_ReadOnly)); + } + + if (! dataset) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } - if (! dataset) throw datasource_exception(CPLGetLastErrorMsg()); return dataset; } - gdal_datasource::gdal_datasource(parameters const& params, bool bind) - : datasource(params), - desc_(*params.get("type"),"utf-8"), - filter_factor_(*params_.get("filter_factor",0.0)) + : datasource(params), + desc_(*params.get("type"), "utf-8"), + filter_factor_(*params_.get("filter_factor", 0.0)) { #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Initializing..." << std::endl; @@ -78,13 +85,17 @@ gdal_datasource::gdal_datasource(parameters const& params, bool bind) GDALAllRegister(); boost::optional file = params.get("file"); - if (!file) throw datasource_exception("missing parameter"); + if (! file) throw datasource_exception("missing parameter"); boost::optional base = params_.get("base"); if (base) + { dataset_name_ = *base + "/" + *file; + } else + { dataset_name_ = *file; + } if (bind) { @@ -96,7 +107,7 @@ void gdal_datasource::bind() const { if (is_bound_) return; - shared_dataset_ = *params_.get("shared",false); + shared_dataset_ = *params_.get("shared", false); band_ = *params_.get("band", -1); GDALDataset *dataset = open_dataset(); @@ -105,7 +116,6 @@ void gdal_datasource::bind() const width_ = dataset->GetRasterXSize(); height_ = dataset->GetRasterYSize(); - double tr[6]; bool bbox_override = false; boost::optional bbox_s = params_.get("bbox"); @@ -114,8 +124,9 @@ void gdal_datasource::bind() const #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: bbox parameter=" << *bbox_s << std::endl; #endif + bbox_override = extent_.from_string(*bbox_s); - if (!bbox_override) + if (! bbox_override) { throw datasource_exception("GDAL Plugin: bbox parameter '" + *bbox_s + "' invalid"); } @@ -141,7 +152,7 @@ void gdal_datasource::bind() const << tr[4] << "," << tr[5] << std::endl; #endif - if (tr[2] !=0 || tr[4] != 0) + if (tr[2] != 0 || tr[4] != 0) { throw datasource_exception("GDAL Plugin: only 'north up' images are supported"); } @@ -149,7 +160,7 @@ void gdal_datasource::bind() const dx_ = tr[1]; dy_ = tr[5]; - if (!bbox_override) + if (! bbox_override) { double x0 = tr[0]; double y0 = tr[3]; @@ -164,8 +175,9 @@ void gdal_datasource::bind() const double y1 = tr[3] + (width_) * tr[4]; // maxy */ - extent_.init(x0,y0,x1,y1); + extent_.init(x0, y0, x1, y1); } + GDALClose(dataset); #ifdef MAPNIK_DEBUG @@ -192,7 +204,7 @@ std::string gdal_datasource::name() box2d gdal_datasource::envelope() const { - if (!is_bound_) bind(); + if (! is_bound_) bind(); return extent_; } @@ -204,18 +216,38 @@ layer_descriptor gdal_datasource::get_descriptor() const featureset_ptr gdal_datasource::features(query const& q) const { - if (!is_bound_) bind(); + if (! is_bound_) bind(); gdal_query gq = q; + // TODO - move to boost::make_shared, but must reduce # of args to <= 9 - return featureset_ptr(new gdal_featureset(*open_dataset(), band_, gq, extent_, width_, height_, nbands_, dx_, dy_, filter_factor_)); + return featureset_ptr(new gdal_featureset(*open_dataset(), + band_, + gq, + extent_, + width_, + height_, + nbands_, + dx_, + dy_, + filter_factor_)); } featureset_ptr gdal_datasource::features_at_point(coord2d const& pt) const { - if (!is_bound_) bind(); + if (! is_bound_) bind(); gdal_query gq = pt; - return featureset_ptr(new gdal_featureset(*open_dataset(), band_, gq, extent_, width_, height_, nbands_, dx_, dy_, filter_factor_)); -} + // TODO - move to boost::make_shared, but must reduce # of args to <= 9 + return featureset_ptr(new gdal_featureset(*open_dataset(), + band_, + gq, + extent_, + width_, + height_, + nbands_, + dx_, + dy_, + filter_factor_)); +} diff --git a/plugins/input/gdal/gdal_datasource.hpp b/plugins/input/gdal/gdal_datasource.hpp index e3c778c5e..d3e8c12c8 100644 --- a/plugins/input/gdal/gdal_datasource.hpp +++ b/plugins/input/gdal/gdal_datasource.hpp @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2007 Artem Pavlenko + * Copyright (C) 2011 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,29 +35,29 @@ class gdal_datasource : public mapnik::datasource { - public: - gdal_datasource(mapnik::parameters const& params, bool bind=true); - virtual ~gdal_datasource (); - int type() const; - static std::string name(); - mapnik::featureset_ptr features( mapnik::query const& q) const; - mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; - mapnik::box2d envelope() const; - mapnik::layer_descriptor get_descriptor() const; - void bind() const; - private: - mutable mapnik::box2d extent_; - std::string dataset_name_; - mutable int band_; - mapnik::layer_descriptor desc_; - mutable unsigned width_; - mutable unsigned height_; - mutable double dx_; - mutable double dy_; - mutable int nbands_; - mutable bool shared_dataset_; - double filter_factor_; - inline GDALDataset *open_dataset() const; +public: + gdal_datasource(mapnik::parameters const& params, bool bind = true); + virtual ~gdal_datasource(); + int type() const; + static std::string name(); + mapnik::featureset_ptr features(mapnik::query const& q) const; + mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; + mapnik::box2d envelope() const; + mapnik::layer_descriptor get_descriptor() const; + void bind() const; +private: + mutable mapnik::box2d extent_; + std::string dataset_name_; + mutable int band_; + mapnik::layer_descriptor desc_; + mutable unsigned width_; + mutable unsigned height_; + mutable double dx_; + mutable double dy_; + mutable int nbands_; + mutable bool shared_dataset_; + double filter_factor_; + inline GDALDataset* open_dataset() const; }; diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 648da2ebd..1c489f240 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2007 Artem Pavlenko + * Copyright (C) 2011 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -41,20 +41,27 @@ using mapnik::datasource_exception; using mapnik::feature_factory; -gdal_featureset::gdal_featureset(GDALDataset & dataset, int band, gdal_query q, - mapnik::box2d extent, double width, double height, int nbands, - double dx, double dy, double filter_factor) - : dataset_(dataset), - band_(band), - gquery_(q), - raster_extent_(extent), - raster_width_(width), - raster_height_(height), - dx_(dx), - dy_(dy), - nbands_(nbands), - filter_factor_(filter_factor), - first_(true) +gdal_featureset::gdal_featureset(GDALDataset& dataset, + int band, + gdal_query q, + mapnik::box2d extent, + double width, + double height, + int nbands, + double dx, + double dy, + double filter_factor) + : dataset_(dataset), + band_(band), + gquery_(q), + raster_extent_(extent), + raster_width_(width), + raster_height_(height), + dx_(dx), + dy_(dy), + nbands_(nbands), + filter_factor_(filter_factor), + first_(true) { } @@ -63,6 +70,7 @@ gdal_featureset::~gdal_featureset() #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: closing dataset = " << &dataset_ << std::endl; #endif + GDALClose(&dataset_); } @@ -76,11 +84,15 @@ feature_ptr gdal_featureset::next() #endif query *q = boost::get(&gquery_); - if(q) { + if (q) + { return get_feature(*q); - } else { + } + else + { coord2d *p = boost::get(&gquery_); - if(p) { + if (p) + { return get_feature_at_point(*p); } } @@ -108,40 +120,60 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) std::clog << "dx_: " << dx_ << " dx: " << dx << " dy_: " << dy_ << "dy: " << dy << "\n"; */ - CoordTransform t(raster_width_,raster_height_,raster_extent_,0,0); + CoordTransform t(raster_width_, raster_height_, raster_extent_, 0, 0); box2d intersect = raster_extent_.intersect(q.get_bbox()); box2d 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())); + 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 feature_raster_extent(x_off, y_off, x_off+width, y_off+height); + box2d feature_raster_extent(x_off, y_off, x_off + width, y_off + height); intersect = t.backward(feature_raster_extent); #ifdef MAPNIK_DEBUG @@ -197,9 +229,11 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) 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(); + float* imageData = (float*)image.getBytes(); GDALRasterBand * band = dataset_.GetRasterBand(band_); int hasNoData; double nodata = band->GetNoDataValue(&hasNoData); @@ -209,17 +243,18 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) feature->set_raster(mapnik::raster_ptr(boost::make_shared(intersect,image))); if (hasNoData) - feature->props()["NODATA"]=nodata; + { + feature->props()["NODATA"] = nodata; + } } - else // working with all bands { for (int i = 0; i < nbands_; ++i) { - GDALRasterBand * band = dataset_.GetRasterBand(i+1); + GDALRasterBand * band = dataset_.GetRasterBand(i + 1); #ifdef MAPNIK_DEBUG - get_overview_meta(band); + get_overview_meta(band); #endif GDALColorInterp color_interp = band->GetColorInterpretation(); @@ -263,7 +298,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) #endif GDALColorTable *color_table = band->GetColorTable(); - if ( color_table) + if (color_table) { int count = color_table->GetColorEntryCount(); #ifdef MAPNIK_DEBUG @@ -303,33 +338,36 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) float nodata = red->GetNoDataValue(&hasNoData); GDALColorTable *color_table = red->GetColorTable(); - if (!alpha && hasNoData && !color_table) + if (! alpha && hasNoData && ! color_table) { // first read the data in and create an alpha channel from the nodata values - float *imageData = (float*)image.getBytes(); + float* imageData = (float*)image.getBytes(); red->RasterIO(GF_Read, x_off, y_off, width, height, - imageData, image.width(), image.height(), - GDT_Float32, 0, 0); + imageData, image.width(), image.height(), + GDT_Float32, 0, 0); int len = image.width() * image.height(); - for (int i=0; i (&imageData[i]) = 0; + { + *reinterpret_cast(&imageData[i]) = 0; + } else - *reinterpret_cast (&imageData[i]) = 0xFFFFFFFF; + { + *reinterpret_cast(&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()); - + 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) { @@ -338,36 +376,40 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) #endif int hasNoData; float nodata = grey->GetNoDataValue(&hasNoData); - GDALColorTable *color_table = grey->GetColorTable(); + GDALColorTable* color_table = grey->GetColorTable(); - if (hasNoData && !color_table) + if (hasNoData && ! color_table) { #ifdef MAPNIK_DEBUG std::clog << "\tno data value for layer: " << nodata << std::endl; #endif // first read the data in and create an alpha channel from the nodata values - float *imageData = (float*)image.getBytes(); + float* imageData = (float*)image.getBytes(); grey->RasterIO(GF_Read, x_off, y_off, width, height, - imageData, image.width(), image.height(), - GDT_Float32, 0, 0); + imageData, image.width(), image.height(), + GDT_Float32, 0, 0); int len = image.width() * image.height(); - for (int i=0; i (&imageData[i]) = 0; + { + *reinterpret_cast(&imageData[i]) = 0; + } else + { *reinterpret_cast (&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()); + 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) { @@ -380,8 +422,9 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) for (unsigned x = 0; x < image.width(); ++x) { unsigned value = row[x] & 0xff; - const GDALColorEntry *ce = color_table->GetColorEntry ( value ); - if (ce ){ + 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) ; } @@ -395,11 +438,11 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) #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()); + 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))); + feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect, image))); } return feature; } @@ -418,7 +461,7 @@ feature_ptr gdal_featureset::get_feature_at_point(mapnik::coord2d const& pt) double gt[6]; dataset_.GetGeoTransform(gt); - double det = gt[1]*gt[5] - gt[2]*gt[4]; + double det = gt[1] * gt[5] - gt[2] * gt[4]; // subtract half a pixel width & height because gdal coord reference // is the top-left corner of a pixel, not the center. double X = pt.x - gt[0] - gt[1]/2; @@ -433,7 +476,7 @@ feature_ptr gdal_featureset::get_feature_at_point(mapnik::coord2d const& pt) std::clog << boost::format("GDAL Plugin: pt.x=%f pt.y=%f") % pt.x % pt.y << std::endl; std::clog << boost::format("GDAL Plugin: x=%f y=%f") % x % y << std::endl; #endif - GDALRasterBand * band = dataset_.GetRasterBand(band_); + GDALRasterBand* band = dataset_.GetRasterBand(band_); int hasNoData; double nodata = band->GetNoDataValue(&hasNoData); double value; @@ -455,7 +498,7 @@ feature_ptr gdal_featureset::get_feature_at_point(mapnik::coord2d const& pt) } #ifdef MAPNIK_DEBUG -void gdal_featureset::get_overview_meta(GDALRasterBand * band) +void gdal_featureset::get_overview_meta(GDALRasterBand* band) { int band_overviews = band->GetOverviewCount(); if (band_overviews > 0) @@ -464,7 +507,7 @@ void gdal_featureset::get_overview_meta(GDALRasterBand * band) for (int b = 0; b < band_overviews; b++) { - GDALRasterBand * overview = band->GetOverview (b); + GDALRasterBand * overview = band->GetOverview(b); std::clog << boost::format("GDAL Plugin: Overview=%d Width=%d Height=%d") % b % overview->GetXSize() % overview->GetYSize() << std::endl; } @@ -476,7 +519,7 @@ void gdal_featureset::get_overview_meta(GDALRasterBand * band) int bsx,bsy; double scale; - band->GetBlockSize(&bsx,&bsy); + band->GetBlockSize(&bsx, &bsy); scale = band->GetScale(); std::clog << boost::format("GDAL Plugin: Block=%dx%d Scale=%f Type=%s Color=%s") % bsx % bsy % scale @@ -484,4 +527,3 @@ void gdal_featureset::get_overview_meta(GDALRasterBand * band) % GDALGetColorInterpretationName(band->GetColorInterpretation()) << std::endl; } #endif - diff --git a/plugins/input/gdal/gdal_featureset.hpp b/plugins/input/gdal/gdal_featureset.hpp index 99261773f..3ae0d6716 100644 --- a/plugins/input/gdal/gdal_featureset.hpp +++ b/plugins/input/gdal/gdal_featureset.hpp @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2007 Artem Pavlenko + * Copyright (C) 2011 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,33 +33,40 @@ class GDALDataset; class GDALRasterBand; -typedef boost::variant gdal_query; +typedef boost::variant gdal_query; class gdal_featureset : public mapnik::Featureset { - public: - gdal_featureset(GDALDataset & dataset, int band, gdal_query q, - mapnik::box2d extent, double width, double height, int nbands, - double dx, double dy, double filter_factor); - virtual ~gdal_featureset(); - mapnik::feature_ptr next(); - private: - mapnik::feature_ptr get_feature(mapnik::query const& q); - mapnik::feature_ptr get_feature_at_point(mapnik::coord2d const& p); +public: + gdal_featureset(GDALDataset& dataset, + int band, + gdal_query q, + mapnik::box2d extent, + double width, + double height, + int nbands, + double dx, + double dy, + double filter_factor); + virtual ~gdal_featureset(); + mapnik::feature_ptr next(); +private: + mapnik::feature_ptr get_feature(mapnik::query const& q); + mapnik::feature_ptr get_feature_at_point(mapnik::coord2d const& p); #ifdef MAPNIK_DEBUG - void get_overview_meta(GDALRasterBand * band); + void get_overview_meta(GDALRasterBand * band); #endif - GDALDataset & dataset_; - int band_; - gdal_query gquery_; - mapnik::box2d raster_extent_; - unsigned raster_width_; - unsigned raster_height_; - double dx_; - double dy_; - int nbands_; - double filter_factor_; - bool first_; + GDALDataset & dataset_; + int band_; + gdal_query gquery_; + mapnik::box2d raster_extent_; + unsigned raster_width_; + unsigned raster_height_; + double dx_; + double dy_; + int nbands_; + double filter_factor_; + bool first_; }; #endif // GDAL_FEATURESET_HPP