void occi_datasource::bind() const { if (is_bound_) return; #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::bind"); #endif // connect to environment if (use_connection_pool_) { try { Environment* env = occi_environment::get_environment(); pool_ = env->createStatelessConnectionPool( *params_.get<std::string>("user"), *params_.get<std::string>("password"), *params_.get<std::string>("host"), *params_.get<int>("max_size", 5), *params_.get<int>("initial_size", 1), 1, StatelessConnectionPool::HOMOGENEOUS); } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } else { try { Environment* env = occi_environment::get_environment(); conn_ = env->createConnection( *params_.get<std::string>("user"), *params_.get<std::string>("password"), *params_.get<std::string>("host")); } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } // extract real table name table_name_ = mapnik::sql_utils::table_from_sql(table_); // get SRID and/or GEOMETRY_FIELD from metadata table only if we need to if (! srid_initialized_ || geometry_field_ == "") { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_srid_and_geometry_field"); #endif std::ostringstream s; s << "SELECT srid, column_name FROM " << METADATA_TABLE << " WHERE"; s << " LOWER(table_name) = LOWER('" << table_name_ << "')"; if (geometry_field_ != "") { s << " AND LOWER(column_name) = LOWER('" << geometry_field_ << "')"; } MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); try { occi_connection_ptr conn; if (use_connection_pool_) conn.set_pool(pool_); else conn.set_connection(conn_, false); ResultSet* rs = conn.execute_query(s.str()); if (rs && rs->next ()) { if (! srid_initialized_) { srid_ = rs->getInt(1); srid_initialized_ = true; } if (geometry_field_ == "") { geometry_field_ = rs->getString(2); } } } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } // get columns description { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_column_description"); #endif std::ostringstream s; s << "SELECT " << fields_ << " FROM (" << table_name_ << ") WHERE rownum < 1"; MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); try { occi_connection_ptr conn; if (use_connection_pool_) conn.set_pool(pool_); else conn.set_connection(conn_, false); ResultSet* rs = conn.execute_query(s.str()); if (rs) { std::vector<MetaData> listOfColumns = rs->getColumnListMetaData(); for (unsigned int i = 0; i < listOfColumns.size(); ++i) { MetaData columnObj = listOfColumns[i]; std::string fld_name = columnObj.getString(MetaData::ATTR_NAME); int type_oid = columnObj.getInt(MetaData::ATTR_DATA_TYPE); /* int type_code = columnObj.getInt(MetaData::ATTR_TYPECODE); if (type_code == OCCI_TYPECODE_OBJECT) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object)); continue; } */ switch (type_oid) { case oracle::occi::OCCIBOOL: case oracle::occi::OCCIINT: case oracle::occi::OCCIUNSIGNED_INT: case oracle::occi::OCCIROWID: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); break; case oracle::occi::OCCIFLOAT: case oracle::occi::OCCIBFLOAT: case oracle::occi::OCCIDOUBLE: case oracle::occi::OCCIBDOUBLE: case oracle::occi::OCCINUMBER: case oracle::occi::OCCI_SQLT_NUM: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); break; case oracle::occi::OCCICHAR: case oracle::occi::OCCISTRING: case oracle::occi::OCCI_SQLT_AFC: case oracle::occi::OCCI_SQLT_AVC: case oracle::occi::OCCI_SQLT_CHR: case oracle::occi::OCCI_SQLT_LVC: case oracle::occi::OCCI_SQLT_RDD: case oracle::occi::OCCI_SQLT_STR: case oracle::occi::OCCI_SQLT_VCS: case oracle::occi::OCCI_SQLT_VNU: case oracle::occi::OCCI_SQLT_VBI: case oracle::occi::OCCI_SQLT_VST: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); break; case oracle::occi::OCCIDATE: case oracle::occi::OCCITIMESTAMP: case oracle::occi::OCCIINTERVALDS: case oracle::occi::OCCIINTERVALYM: case oracle::occi::OCCI_SQLT_DAT: case oracle::occi::OCCI_SQLT_DATE: case oracle::occi::OCCI_SQLT_TIME: case oracle::occi::OCCI_SQLT_TIME_TZ: case oracle::occi::OCCI_SQLT_TIMESTAMP: case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ: case oracle::occi::OCCI_SQLT_TIMESTAMP_TZ: case oracle::occi::OCCI_SQLT_INTERVAL_YM: case oracle::occi::OCCI_SQLT_INTERVAL_DS: case oracle::occi::OCCIANYDATA: case oracle::occi::OCCIBLOB: case oracle::occi::OCCIBFILE: case oracle::occi::OCCIBYTES: case oracle::occi::OCCICLOB: case oracle::occi::OCCIVECTOR: case oracle::occi::OCCIMETADATA: case oracle::occi::OCCIPOBJECT: case oracle::occi::OCCIREF: case oracle::occi::OCCIREFANY: case oracle::occi::OCCISTREAM: case oracle::occi::OCCICURSOR: case oracle::occi::OCCI_SQLT_FILE: case oracle::occi::OCCI_SQLT_CFILE: case oracle::occi::OCCI_SQLT_REF: case oracle::occi::OCCI_SQLT_CLOB: case oracle::occi::OCCI_SQLT_BLOB: case oracle::occi::OCCI_SQLT_RSET: MAPNIK_LOG_WARN(occi) << "occi_datasource: Unsupported datatype " << occi_enums::resolve_datatype(type_oid) << " (type_oid=" << type_oid << ")"; break; default: MAPNIK_LOG_WARN(occi) << "occi_datasource: Unknown datatype " << "(type_oid=" << type_oid << ")"; break; } } } } catch (SQLException& ex) { throw datasource_exception(ex.getMessage()); } } is_bound_ = true; }
geos_datasource::geos_datasource(parameters const& params) : datasource(params), extent_(), extent_initialized_(false), type_(datasource::Vector), desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding", "utf-8")), geometry_data_(""), geometry_data_name_("name"), geometry_id_(1) { boost::optional<std::string> geometry = params.get<std::string>("wkt"); if (! geometry) throw datasource_exception("missing <wkt> parameter"); geometry_string_ = *geometry; boost::optional<std::string> ext = params.get<std::string>("extent"); if (ext) extent_initialized_ = extent_.from_string(*ext); boost::optional<int> id = params.get<int>("gid"); if (id) geometry_id_ = *id; boost::optional<std::string> gdata = params.get<std::string>("field_data"); if (gdata) geometry_data_ = *gdata; boost::optional<std::string> gdata_name = params.get<std::string>("field_name"); if (gdata_name) geometry_data_name_ = *gdata_name; desc_.add_descriptor(attribute_descriptor(geometry_data_name_, mapnik::String)); #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "geos_datasource::init"); #endif // open geos driver initGEOS(geos_notice, geos_error); // parse the string into geometry geometry_.set_feature(GEOSGeomFromWKT(geometry_string_.c_str())); if (*geometry_ == NULL || ! GEOSisValid(*geometry_)) { throw datasource_exception("GEOS Plugin: invalid <wkt> geometry specified"); } // try to obtain the extent from the geometry itself if (! extent_initialized_) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats2__(std::clog, "geos_datasource::init(initialize_extent)"); #endif MAPNIK_LOG_DEBUG(geos) << "geos_datasource: Initializing extent from geometry"; if (GEOSGeomTypeId(*geometry_) == GEOS_POINT) { double x, y; unsigned int size; const GEOSCoordSequence* cs = GEOSGeom_getCoordSeq(*geometry_); GEOSCoordSeq_getSize(cs, &size); GEOSCoordSeq_getX(cs, 0, &x); GEOSCoordSeq_getY(cs, 0, &y); extent_.init(x, y, x, y); extent_initialized_ = true; } else { geos_feature_ptr envelope (GEOSEnvelope(*geometry_)); if (*envelope != NULL && GEOSisValid(*envelope)) { #ifdef MAPNIK_LOG char* wkt = GEOSGeomToWKT(*envelope); MAPNIK_LOG_DEBUG(geos) << "geos_datasource: Getting coord sequence from=" << wkt; GEOSFree(wkt); #endif const GEOSGeometry* exterior = GEOSGetExteriorRing(*envelope); if (exterior != NULL && GEOSisValid(exterior)) { const GEOSCoordSequence* cs = GEOSGeom_getCoordSeq(exterior); if (cs != NULL) { MAPNIK_LOG_DEBUG(geos) << "geos_datasource: Iterating boundary points"; double x, y; double minx = std::numeric_limits<float>::max(), miny = std::numeric_limits<float>::max(), maxx = -std::numeric_limits<float>::max(), maxy = -std::numeric_limits<float>::max(); unsigned int num_points; GEOSCoordSeq_getSize(cs, &num_points); for (unsigned int i = 0; i < num_points; ++i) { GEOSCoordSeq_getX(cs, i, &x); GEOSCoordSeq_getY(cs, i, &y); if (x < minx) minx = x; if (x > maxx) maxx = x; if (y < miny) miny = y; if (y > maxy) maxy = y; } extent_.init(minx, miny, maxx, maxy); extent_initialized_ = true; } } } } } if (! extent_initialized_) { throw datasource_exception("GEOS Plugin: cannot determine extent for <wkt> geometry"); } }
sqlite_datasource::sqlite_datasource(parameters const& params) : datasource(params), extent_(), extent_initialized_(false), type_(datasource::Vector), table_(*params.get<std::string>("table", "")), fields_(*params.get<std::string>("fields", "*")), metadata_(*params.get<std::string>("metadata", "")), geometry_table_(*params.get<std::string>("geometry_table", "")), geometry_field_(*params.get<std::string>("geometry_field", "")), index_table_(*params.get<std::string>("index_table", "")), key_field_(*params.get<std::string>("key_field", "")), row_offset_(*params.get<mapnik::value_integer>("row_offset", 0)), row_limit_(*params.get<mapnik::value_integer>("row_limit", 0)), intersects_token_("!intersects!"), desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding", "utf-8")), format_(mapnik::wkbAuto) { /* TODO - throw if no primary key but spatial index is present? - remove auto-indexing - if spatialite - leverage more of the metadata for geometry type detection */ #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "sqlite_datasource::init"); #endif boost::optional<std::string> file = params.get<std::string>("file"); if (! file) throw datasource_exception("Sqlite Plugin: missing <file> parameter"); boost::optional<std::string> base = params.get<std::string>("base"); if (base) dataset_name_ = *base + "/" + *file; else dataset_name_ = *file; if ((dataset_name_.compare(":memory:") != 0) && (!mapnik::util::exists(dataset_name_))) { throw datasource_exception("Sqlite Plugin: " + dataset_name_ + " does not exist"); } use_spatial_index_ = *params.get<mapnik::boolean>("use_spatial_index", true); // TODO - remove this option once all datasources have an indexing api bool auto_index = *params.get<mapnik::boolean>("auto_index", true); boost::optional<std::string> ext = params.get<std::string>("extent"); if (ext) extent_initialized_ = extent_.from_string(*ext); boost::optional<std::string> wkb = params.get<std::string>("wkb_format"); if (wkb) { if (*wkb == "spatialite") { format_ = mapnik::wkbSpatiaLite; } else if (*wkb == "generic") { format_ = mapnik::wkbGeneric; } else { format_ = mapnik::wkbAuto; } } // Populate init_statements_ // 1. Build attach database statements from the "attachdb" parameter // 2. Add explicit init statements from "initdb" parameter // Note that we do some extra work to make sure that any attached // databases are relative to directory containing dataset_name_. Sqlite // will default to attaching from cwd. Typicaly usage means that the // map loader will produce full paths here. boost::optional<std::string> attachdb = params.get<std::string>("attachdb"); if (attachdb) { parse_attachdb(*attachdb); } boost::optional<std::string> initdb = params.get<std::string>("initdb"); if (initdb) { init_statements_.push_back(*initdb); } // now actually create the connection and start executing setup sql dataset_ = std::make_shared<sqlite_connection>(dataset_name_); boost::optional<mapnik::value_integer> table_by_index = params.get<mapnik::value_integer>("table_by_index"); int passed_parameters = 0; passed_parameters += params.get<std::string>("table") ? 1 : 0; passed_parameters += table_by_index ? 1 : 0; if (passed_parameters > 1) { throw datasource_exception("SQLite Plugin: you can only select an by name " "('table' parameter), by number ('table_by_index' parameter), " "do not supply 2 or more of them at the same time" ); } if (table_by_index) { std::vector<std::string> tables; sqlite_utils::get_tables(dataset_,tables); if (*table_by_index < 0 || *table_by_index >= static_cast<int>(tables.size())) { std::ostringstream s; s << "SQLite Plugin: only " << tables.size() << " table(s) exist, cannot find table by index '" << *table_by_index << "'"; throw datasource_exception(s.str()); } table_ = tables[*table_by_index]; } if (table_.empty()) { throw mapnik::datasource_exception("Sqlite Plugin: missing <table> parameter"); } if (geometry_table_.empty()) { geometry_table_ = mapnik::sql_utils::table_from_sql(table_); } // if 'table_' is a subquery then we try to deduce names // and types from the first row returned from that query using_subquery_ = false; if (table_ != geometry_table_) { using_subquery_ = true; } else { // attempt to auto-quote table if needed if (sqlite_utils::needs_quoting(table_)) { table_ = std::string("[") + table_ + "]"; geometry_table_ = table_; } } // Execute init_statements_ for (std::vector<std::string>::const_iterator iter = init_statements_.begin(); iter != init_statements_.end(); ++iter) { MAPNIK_LOG_DEBUG(sqlite) << "sqlite_datasource: Execute init sql=" << *iter; dataset_->execute(*iter); } bool found_types_via_subquery = false; if (using_subquery_) { std::ostringstream s; std::string query = populate_tokens(table_); s << "SELECT " << fields_ << " FROM (" << query << ") LIMIT 1"; found_types_via_subquery = sqlite_utils::detect_types_from_subquery( s.str(), geometry_field_, desc_, dataset_); } // TODO - consider removing this if (key_field_ == "rowid") { desc_.add_descriptor(attribute_descriptor("rowid", mapnik::Integer)); } bool found_table = sqlite_utils::table_info(key_field_, found_types_via_subquery, geometry_field_, geometry_table_, desc_, dataset_); if (! found_table) { std::ostringstream s; s << "Sqlite Plugin: could not query table '" << geometry_table_ << "'"; if (using_subquery_) { s << " from subquery '" << table_ << "'"; } // report get available tables std::vector<std::string> tables; sqlite_utils::get_tables(dataset_,tables); if (tables.size() > 0) { s << " (available tables for " << dataset_name_ << " are: '" << boost::algorithm::join(tables, ", ") << "')"; } throw datasource_exception(s.str()); } if (geometry_field_.empty()) { std::ostringstream s; s << "Sqlite Plugin: unable to detect the column " << "containing a valid geometry on table '" << geometry_table_ << "'. " << "Please provide a column name by passing the 'geometry_field' option " << "or indicate a different spatial table to use by passing the 'geometry_table' option"; throw datasource_exception(s.str()); } if (index_table_.empty()) { // Generate implicit index_table name - need to do this after // we have discovered meta-data or else we don't know the column name index_table_ = sqlite_utils::index_for_table(geometry_table_,geometry_field_); } std::string index_db = sqlite_utils::index_for_db(dataset_name_); has_spatial_index_ = false; if (use_spatial_index_) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats2__(std::clog, "sqlite_datasource::init(use_spatial_index)"); #endif if (mapnik::util::exists(index_db)) { dataset_->execute("attach database '" + index_db + "' as " + index_table_); } has_spatial_index_ = sqlite_utils::has_rtree(index_table_,dataset_); if (!has_spatial_index_ && auto_index) { if (! key_field_.empty()) { std::ostringstream query; query << "SELECT " << geometry_field_ << "," << key_field_ << " FROM (" << geometry_table_ << ")"; #ifdef MAPNIK_STATS mapnik::progress_timer __stats2__(std::clog, "sqlite_datasource::init(create_spatial_index)"); #endif std::shared_ptr<sqlite_resultset> rs = dataset_->execute_query(query.str()); if (sqlite_utils::create_spatial_index(index_db,index_table_,rs)) { //extent_initialized_ = true; has_spatial_index_ = true; if (mapnik::util::exists(index_db)) { dataset_->execute("attach database '" + index_db + "' as " + index_table_); } } } else { std::ostringstream s; s << "Sqlite Plugin: could not generate spatial index" << " for table '" << geometry_table_ << "'" << " as no primary key can be detected." << " You should either declare an INTEGER PRIMARY KEY" << " or set the 'key_field' option to force a" << " given field to be used as the primary key"; throw datasource_exception(s.str()); } } } if (! extent_initialized_) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats2__(std::clog, "sqlite_datasource::init(detect_extent)"); #endif // TODO - clean this up - reducing arguments std::string query = populate_tokens(table_); if (!sqlite_utils::detect_extent(dataset_, has_spatial_index_, extent_, index_table_, metadata_, geometry_field_, geometry_table_, key_field_, query)) { std::ostringstream s; s << "Sqlite Plugin: extent could not be determined for table '" << geometry_table_ << "' and geometry field '" << geometry_field_ << "'" << " because an rtree spatial index is missing or empty." << " - either set the table 'extent' or create an rtree spatial index"; throw datasource_exception(s.str()); } } }
raster_datasource::raster_datasource(parameters const& params) : datasource(params), desc_(*params.get<std::string>("type"), "utf-8"), extent_initialized_(false) { MAPNIK_LOG_DEBUG(raster) << "raster_datasource: Initializing..."; boost::optional<std::string> file = params.get<std::string>("file"); if (! file) throw datasource_exception("Raster Plugin: missing <file> parameter "); boost::optional<std::string> base = params.get<std::string>("base"); if (base) filename_ = *base + "/" + *file; else filename_ = *file; multi_tiles_ = *params.get<mapnik::boolean>("multi", false); tile_size_ = *params.get<int>("tile_size", 256); tile_stride_ = *params.get<int>("tile_stride", 1); boost::optional<std::string> format_from_filename = mapnik::type_from_filename(*file); format_ = *params.get<std::string>("format",format_from_filename?(*format_from_filename) : "tiff"); boost::optional<double> lox = params.get<double>("lox"); boost::optional<double> loy = params.get<double>("loy"); boost::optional<double> hix = params.get<double>("hix"); boost::optional<double> hiy = params.get<double>("hiy"); boost::optional<std::string> ext = params.get<std::string>("extent"); if (lox && loy && hix && hiy) { extent_.init(*lox, *loy, *hix, *hiy); extent_initialized_ = true; } else if (ext) { extent_initialized_ = extent_.from_string(*ext); } if (! extent_initialized_) { throw datasource_exception("Raster Plugin: valid <extent> or <lox> <loy> <hix> <hiy> are required"); } if (multi_tiles_) { boost::optional<int> x_width = params.get<int>("x_width"); boost::optional<int> y_width = params.get<int>("y_width"); 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_; } else { if (!mapnik::util::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) { throw datasource_exception("Raster Plugin: image reader exception: " + std::string(ex.what())); } catch (std::exception const& ex) { throw datasource_exception("Raster Plugin: " + std::string(ex.what())); } catch (...) { throw datasource_exception("Raster Plugin: image reader unknown exception caught"); } } MAPNIK_LOG_DEBUG(raster) << "raster_datasource: Raster size=" << width_ << "," << height_; }
void spatialite_datasource::bind() const { if (is_bound_) return; boost::optional<std::string> file = params_.get<std::string>("file"); if (!file) throw datasource_exception("Spatialite Plugin: missing <file> parameter"); boost::optional<std::string> key_field_name = params_.get<std::string>("key_field"); if (key_field_name) { std::string const& key_field_string = *key_field_name; if (key_field_string.empty()) { key_field_ = "rowid"; } else { key_field_ = key_field_string; } } else { key_field_ = "rowid"; } boost::optional<std::string> wkb = params_.get<std::string>("wkb_format"); if (wkb) { if (*wkb == "spatialite") format_ = mapnik::wkbSpatiaLite; } multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false); use_spatial_index_ = *params_.get<mapnik::boolean>("use_spatial_index",true); has_spatial_index_ = false; using_subquery_ = false; boost::optional<std::string> ext = params_.get<std::string>("extent"); if (ext) extent_initialized_ = extent_.from_string(*ext); boost::optional<std::string> base = params_.get<std::string>("base"); if (base) dataset_name_ = *base + "/" + *file; else dataset_name_ = *file; // Populate init_statements_ // 1. Build attach database statements from the "attachdb" parameter // 2. Add explicit init statements from "initdb" parameter // Note that we do some extra work to make sure that any attached // databases are relative to directory containing dataset_name_. Sqlite // will default to attaching from cwd. Typicaly usage means that the // map loader will produce full paths here. boost::optional<std::string> attachdb = params_.get<std::string>("attachdb"); if (attachdb) { parse_attachdb(*attachdb); } boost::optional<std::string> initdb = params_.get<std::string>("initdb"); if (initdb) { init_statements_.push_back(*initdb); } if (!boost::filesystem::exists(dataset_name_)) throw datasource_exception("Spatialite Plugin: " + dataset_name_ + " does not exist"); dataset_ = new sqlite_connection (dataset_name_); // Execute init_statements_ for (std::vector<std::string>::const_iterator iter=init_statements_.begin(); iter!=init_statements_.end(); ++iter) { #ifdef MAPNIK_DEBUG std::clog << "Spatialite Plugin: Execute init sql: " << *iter << std::endl; #endif dataset_->execute(*iter); } if(geometry_table_.empty()) { geometry_table_ = mapnik::table_from_sql(table_); } // should we deduce column names and types using PRAGMA? bool use_pragma_table_info = true; if (table_ != geometry_table_) { // if 'table_' is a subquery then we try to deduce names // and types from the first row returned from that query using_subquery_ = true; use_pragma_table_info = false; } if (!use_pragma_table_info) { std::ostringstream s; s << "SELECT " << fields_ << " FROM (" << table_ << ") LIMIT 1"; boost::scoped_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str())); if (rs->is_valid() && rs->step_next()) { for (int i = 0; i < rs->column_count (); ++i) { const int type_oid = rs->column_type (i); const char* fld_name = rs->column_name (i); switch (type_oid) { case SQLITE_INTEGER: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); break; case SQLITE_FLOAT: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); break; case SQLITE_TEXT: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); break; case SQLITE_NULL: // sqlite reports based on value, not actual column type unless // PRAGMA table_info is used so here we assume the column is a string // which is a lesser evil than altogether dropping the column desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); case SQLITE_BLOB: if (geometry_field_.empty() && (boost::algorithm::icontains(fld_name,"geom") || boost::algorithm::icontains(fld_name,"point") || boost::algorithm::icontains(fld_name,"linestring") || boost::algorithm::icontains(fld_name,"polygon")) ) geometry_field_ = std::string(fld_name); break; default: #ifdef MAPNIK_DEBUG std::clog << "Spatialite Plugin: unknown type_oid=" << type_oid << std::endl; #endif break; } } } else { // if we do not have at least a row and // we cannot determine the right columns types and names // as all column_type are SQLITE_NULL // so we fallback to using PRAGMA table_info use_pragma_table_info = true; } } if (key_field_ == "rowid") desc_.add_descriptor(attribute_descriptor("rowid",mapnik::Integer)); if (use_pragma_table_info) { std::ostringstream s; s << "PRAGMA table_info(" << geometry_table_ << ")"; boost::scoped_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str())); bool found_table = false; while (rs->is_valid() && rs->step_next()) { found_table = true; // TODO - support unicode strings? const char* fld_name = rs->column_text(1); std::string fld_type(rs->column_text(2)); boost::algorithm::to_lower(fld_type); // see 2.1 "Column Affinity" at http://www.sqlite.org/datatype3.html if (geometry_field_.empty() && ( (boost::algorithm::icontains(fld_name,"geom") || boost::algorithm::icontains(fld_name,"point") || boost::algorithm::icontains(fld_name,"linestring") || boost::algorithm::icontains(fld_name,"polygon")) || (boost::algorithm::contains(fld_type,"geom") || boost::algorithm::contains(fld_type,"point") || boost::algorithm::contains(fld_type,"linestring") || boost::algorithm::contains(fld_type,"polygon")) ) ) geometry_field_ = std::string(fld_name); else if (boost::algorithm::contains(fld_type,"int")) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); } else if (boost::algorithm::contains(fld_type,"text") || boost::algorithm::contains(fld_type,"char") || boost::algorithm::contains(fld_type,"clob")) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); } else if (boost::algorithm::contains(fld_type,"real") || boost::algorithm::contains(fld_type,"float") || boost::algorithm::contains(fld_type,"double")) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); } else if (boost::algorithm::contains(fld_type,"blob") && !geometry_field_.empty()) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); } #ifdef MAPNIK_DEBUG else { // "Column Affinity" says default to "Numeric" but for now we pass.. //desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); std::clog << "Spatialite Plugin: column '" << std::string(fld_name) << "' unhandled due to unknown type: " << fld_type << std::endl; } #endif } if (!found_table) { std::ostringstream s; s << "Spatialite Plugin: could not query table '" << geometry_table_ << "' "; if (using_subquery_) s << " from subquery '" << table_ << "' "; s << "using 'PRAGMA table_info(" << geometry_table_ << ")' "; std::string sq_err = std::string(sqlite3_errmsg(*(*dataset_))); if (sq_err != "unknown error") s << ": " << sq_err; throw datasource_exception(s.str()); } } if (geometry_field_.empty()) { throw datasource_exception("Spatialite Plugin: cannot detect geometry_field, please supply the name of the geometry_field to use."); } if (index_table_.size() == 0) { // Generate implicit index_table name - need to do this after // we have discovered meta-data or else we don't know the column name index_table_ = "\"idx_" + mapnik::unquote_sql2(geometry_table_) + "_" + geometry_field_ + "\""; } if (use_spatial_index_) { std::ostringstream s; s << "SELECT pkid,xmin,xmax,ymin,ymax FROM " << index_table_; s << " LIMIT 0"; if (dataset_->execute_with_code(s.str()) == SQLITE_OK) { has_spatial_index_ = true; } #ifdef MAPNIK_DEBUG else { std::clog << "Spatialite Plugin: rtree index lookup did not succeed: '" << sqlite3_errmsg(*(*dataset_)) << "'\n"; } #endif } if (metadata_ != "" && !extent_initialized_) { std::ostringstream s; s << "SELECT xmin, ymin, xmax, ymax FROM " << metadata_; s << " WHERE LOWER(f_table_name) = LOWER('" << geometry_table_ << "')"; boost::scoped_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str())); if (rs->is_valid() && rs->step_next()) { double xmin = rs->column_double (0); double ymin = rs->column_double (1); double xmax = rs->column_double (2); double ymax = rs->column_double (3); extent_.init (xmin,ymin,xmax,ymax); extent_initialized_ = true; } } if (!extent_initialized_ && has_spatial_index_) { std::ostringstream s; s << "SELECT MIN(xmin), MIN(ymin), MAX(xmax), MAX(ymax) FROM " << index_table_; boost::scoped_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str())); if (rs->is_valid() && rs->step_next()) { if (!rs->column_isnull(0)) { try { double xmin = lexical_cast<double>(rs->column_double(0)); double ymin = lexical_cast<double>(rs->column_double(1)); double xmax = lexical_cast<double>(rs->column_double(2)); double ymax = lexical_cast<double>(rs->column_double(3)); extent_.init (xmin,ymin,xmax,ymax); extent_initialized_ = true; } catch (bad_lexical_cast &ex) { std::clog << boost::format("Spatialite Plugin: warning: could not determine extent from query: %s\nError was: '%s'\n") % s.str() % ex.what() << std::endl; } } } } #ifdef MAPNIK_DEBUG if (!has_spatial_index_ && use_spatial_index_ && using_subquery_ && key_field_ == "rowid" && !boost::algorithm::icontains(table_,"rowid")) { // this is an impossible situation because rowid will be null via a subquery std::clog << "Spatialite Plugin: WARNING: spatial index usage will fail because rowid is not present in your subquery. You have 4 options: 1) Add rowid into your select statement, 2) alias your primary key as rowid, 3) supply a 'key_field' value that references the primary key of your spatial table, or 4) avoid using a spatial index by setting 'use_spatial_index'=false"; } #endif // final fallback to gather extent if (!extent_initialized_ || !has_spatial_index_) { std::ostringstream s; s << "SELECT " << geometry_field_ << "," << key_field_ << " FROM " << geometry_table_; if (row_limit_ > 0) { s << " LIMIT " << row_limit_; } if (row_offset_ > 0) { s << " OFFSET " << row_offset_; } #ifdef MAPNIK_DEBUG std::clog << "Spatialite Plugin: " << s.str() << std::endl; #endif boost::shared_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str())); // spatial index sql std::string spatial_index_sql = "create virtual table " + index_table_ + " using rtree(pkid, xmin, xmax, ymin, ymax)"; std::string spatial_index_insert_sql = "insert into " + index_table_ + " values (?,?,?,?,?)" ; sqlite3_stmt* stmt = 0; if (use_spatial_index_) { dataset_->execute(spatial_index_sql); int rc = sqlite3_prepare_v2 (*(*dataset_), spatial_index_insert_sql.c_str(), -1, &stmt, 0); if (rc != SQLITE_OK) { std::ostringstream index_error; index_error << "Spatialite Plugin: auto-index table creation failed: '" << sqlite3_errmsg(*(*dataset_)) << "' query was: " << spatial_index_insert_sql; throw datasource_exception(index_error.str()); } } bool first = true; while (rs->is_valid() && rs->step_next()) { int size; const char* data = (const char *) rs->column_blob (0, size); if (data) { // create a tmp feature to be able to parse geometry // ideally we would not have to do this. // see: http://trac.mapnik.org/ticket/745 mapnik::feature_ptr feature(mapnik::feature_factory::create(0)); mapnik::geometry_utils::from_wkb(feature->paths(),data,size,multiple_geometries_,format_); mapnik::box2d<double> const& bbox = feature->envelope(); if (bbox.valid()) { extent_initialized_ = true; if (first) { first = false; extent_ = bbox; } else { extent_.expand_to_include(bbox); } // index creation if (use_spatial_index_) { const int type_oid = rs->column_type(1); if (type_oid != SQLITE_INTEGER) { std::ostringstream type_error; type_error << "Spatialite Plugin: invalid type for key field '" << key_field_ << "' when creating index '" << index_table_ << "' type was: " << type_oid << ""; throw datasource_exception(type_error.str()); } sqlite_int64 pkid = rs->column_integer64(1); if (sqlite3_bind_int64(stmt, 1 , pkid ) != SQLITE_OK) { throw datasource_exception("invalid value for for key field while generating index"); } if ((sqlite3_bind_double(stmt, 2 , bbox.minx() ) != SQLITE_OK) || (sqlite3_bind_double(stmt, 3 , bbox.maxx() ) != SQLITE_OK) || (sqlite3_bind_double(stmt, 4 , bbox.miny() ) != SQLITE_OK) || (sqlite3_bind_double(stmt, 5 , bbox.maxy() ) != SQLITE_OK)) { throw datasource_exception("invalid value for for extent while generating index"); } int res = sqlite3_step(stmt); if (res != SQLITE_DONE) { std::ostringstream s; s << "Spatialite Plugin: inserting bbox into rtree index failed: " << "error code " << sqlite3_errcode(*(*dataset_)) << ": '" << sqlite3_errmsg(*(*dataset_)) << "' query was: " << spatial_index_insert_sql; throw datasource_exception(s.str()); } sqlite3_reset(stmt); } } else { std::ostringstream index_error; index_error << "Spatialite Plugin: encountered invalid bbox at '" << key_field_ << "' == " << rs->column_integer64(1); throw datasource_exception(index_error.str()); } } } int res = sqlite3_finalize(stmt); if (res != SQLITE_OK) { throw datasource_exception("auto-indexing failed: set use_spatial_index=false to disable auto-indexing and avoid this error"); } } if (!extent_initialized_) { std::ostringstream s; s << "Spatialite Plugin: extent could not be determined for table '" << geometry_table_ << "' and geometry field '" << geometry_field_ << "'" << " because an rtree spatial index is missing or empty." << " - either set the table 'extent' or create an rtree spatial index"; throw datasource_exception(s.str()); } is_bound_ = true; }
shape_datasource::shape_datasource(parameters const& params) : datasource (params), type_(datasource::Vector), file_length_(0), indexed_(false), row_limit_(*params.get<mapnik::value_integer>("row_limit",0)), desc_(shape_datasource::name(), *params.get<std::string>("encoding","utf-8")) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "shape_datasource::init"); #endif boost::optional<std::string> file = params.get<std::string>("file"); if (!file) throw datasource_exception("Shape Plugin: missing <file> parameter"); boost::optional<std::string> base = params.get<std::string>("base"); if (base) shape_name_ = *base + "/" + *file; else shape_name_ = *file; boost::algorithm::ireplace_last(shape_name_,".shp",""); if (!mapnik::util::exists(shape_name_ + ".shp")) { throw datasource_exception("Shape Plugin: shapefile '" + shape_name_ + ".shp' does not exist"); } if (mapnik::util::is_directory(shape_name_ + ".shp")) { throw datasource_exception("Shape Plugin: shapefile '" + shape_name_ + ".shp' appears to be a directory not a file"); } if (!mapnik::util::exists(shape_name_ + ".dbf")) { throw datasource_exception("Shape Plugin: shapefile '" + shape_name_ + ".dbf' does not exist"); } try { #ifdef MAPNIK_STATS mapnik::progress_timer __stats2__(std::clog, "shape_datasource::init(get_column_description)"); #endif std::unique_ptr<shape_io> shape_ref = std::make_unique<shape_io>(shape_name_); init(*shape_ref); for (int i=0;i<shape_ref->dbf().num_fields();++i) { field_descriptor const& fd=shape_ref->dbf().descriptor(i); std::string fld_name=fd.name_; switch (fd.type_) { case 'C': // character case 'D': // date desc_.add_descriptor(attribute_descriptor(fld_name, String)); break; case 'L': // logical desc_.add_descriptor(attribute_descriptor(fld_name, Boolean)); break; case 'N': // numeric case 'O': // double case 'F': // float { if (fd.dec_>0) { desc_.add_descriptor(attribute_descriptor(fld_name,Double,false,8)); } else { desc_.add_descriptor(attribute_descriptor(fld_name,Integer,false,4)); } break; } default: // I - long // G - ole // + - autoincrement // @ - timestamp // B - binary // l - long // M - memo MAPNIK_LOG_ERROR(shape) << "shape_datasource: Unknown type=" << fd.type_; break; } } } catch (datasource_exception const& ex) { MAPNIK_LOG_ERROR(shape) << "Shape Plugin: error processing field attributes, " << ex.what(); throw; } catch (const std::exception& ex) { MAPNIK_LOG_ERROR(shape) << "Shape Plugin: error processing field attributes, " << ex.what(); throw; } catch (...) // exception: pipe_select_interrupter: Too many open files { MAPNIK_LOG_ERROR(shape) << "Shape Plugin: error processing field attributes"; throw; } }
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(); }
occi_datasource::occi_datasource(parameters const& params) : datasource (params), type_(datasource::Vector), fields_(*params.get<std::string>("fields", "*")), geometry_field_(*params.get<std::string>("geometry_field", "")), srid_initialized_(false), extent_initialized_(false), bbox_token_("!bbox!"), scale_denom_token_("!scale_denominator!"), pixel_width_token_("!pixel_width!"), pixel_height_token_("!pixel_height!"), desc_(occi_datasource::name(), *params.get<std::string>("encoding", "utf-8")), use_wkb_(*params.get<mapnik::boolean_type>("use_wkb", false)), row_limit_(*params.get<mapnik::value_integer>("row_limit", 0)), row_prefetch_(*params.get<mapnik::value_integer>("row_prefetch", 100)), pool_(0), conn_(0) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::init"); #endif if (! params.get<std::string>("user")) throw datasource_exception("OCCI Plugin: no <user> specified"); if (! params.get<std::string>("password")) throw datasource_exception("OCCI Plugin: no <password> specified"); if (! params.get<std::string>("host")) throw datasource_exception("OCCI Plugin: no <host> string specified"); boost::optional<std::string> table = params.get<std::string>("table"); if (! table) { throw datasource_exception("OCCI Plugin: no <table> parameter specified"); } else { table_ = *table; } estimate_extent_ = *params.get<mapnik::boolean_type>("estimate_extent",false); use_spatial_index_ = *params.get<mapnik::boolean_type>("use_spatial_index",true); use_connection_pool_ = *params.get<mapnik::boolean_type>("use_connection_pool",true); boost::optional<std::string> ext = params.get<std::string>("extent"); if (ext) extent_initialized_ = extent_.from_string(*ext); boost::optional<mapnik::value_integer> srid = params.get<mapnik::value_integer>("srid"); if (srid) { srid_ = *srid; srid_initialized_ = true; } // connect to environment if (use_connection_pool_) { try { pool_ = occi_environment::instance().create_pool( *params.get<std::string>("user"), *params.get<std::string>("password"), *params.get<std::string>("host"), *params.get<mapnik::value_integer>("max_size", 5), *params.get<mapnik::value_integer>("initial_size", 1), 1); } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } else { try { conn_ = occi_environment::instance().create_connection( *params.get<std::string>("user"), *params.get<std::string>("password"), *params.get<std::string>("host")); } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } // extract real table name table_name_ = mapnik::sql_utils::table_from_sql(table_); // get SRID and/or GEOMETRY_FIELD from metadata table only if we need to if (! srid_initialized_ || geometry_field_ == "") { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_srid_and_geometry_field"); #endif std::ostringstream s; s << "SELECT srid, column_name FROM " << METADATA_TABLE << " WHERE"; s << " LOWER(table_name) = LOWER('" << table_name_ << "')"; if (geometry_field_ != "") { s << " AND LOWER(column_name) = LOWER('" << geometry_field_ << "')"; } MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); try { occi_connection_ptr conn; if (use_connection_pool_) conn.set_pool(pool_); else conn.set_connection(conn_, false); ResultSet* rs = conn.execute_query(s.str()); if (rs && rs->next ()) { if (! srid_initialized_) { srid_ = rs->getInt(1); srid_initialized_ = true; } if (geometry_field_ == "") { geometry_field_ = rs->getString(2); } } } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } // get columns description { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::get_column_description"); #endif std::ostringstream s; s << "SELECT " << fields_ << " FROM (" << table_name_ << ") WHERE ROWNUM < 1"; MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); try { occi_connection_ptr conn; if (use_connection_pool_) conn.set_pool(pool_); else conn.set_connection(conn_, false); ResultSet* rs = conn.execute_query(s.str()); if (rs) { std::vector<MetaData> listOfColumns = rs->getColumnListMetaData(); for (unsigned int i = 0; i < listOfColumns.size(); ++i) { MetaData columnObj = listOfColumns[i]; std::string fld_name = columnObj.getString(MetaData::ATTR_NAME); int type_oid = columnObj.getInt(MetaData::ATTR_DATA_TYPE); /* int type_code = columnObj.getInt(MetaData::ATTR_TYPECODE); if (type_code == OCCI_TYPECODE_OBJECT) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object)); continue; } */ switch (type_oid) { case oracle::occi::OCCIBOOL: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Boolean)); break; case oracle::occi::OCCIINT: case oracle::occi::OCCIUNSIGNED_INT: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); break; case oracle::occi::OCCIFLOAT: case oracle::occi::OCCIBFLOAT: case oracle::occi::OCCIDOUBLE: case oracle::occi::OCCIBDOUBLE: case oracle::occi::OCCINUMBER: case oracle::occi::OCCI_SQLT_NUM: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); break; case oracle::occi::OCCICHAR: case oracle::occi::OCCISTRING: case oracle::occi::OCCI_SQLT_AFC: case oracle::occi::OCCI_SQLT_AVC: case oracle::occi::OCCI_SQLT_CHR: case oracle::occi::OCCI_SQLT_LNG: case oracle::occi::OCCI_SQLT_LVC: case oracle::occi::OCCI_SQLT_STR: case oracle::occi::OCCI_SQLT_VCS: case oracle::occi::OCCI_SQLT_VNU: case oracle::occi::OCCI_SQLT_VBI: case oracle::occi::OCCI_SQLT_VST: case oracle::occi::OCCIROWID: case oracle::occi::OCCI_SQLT_RDD: case oracle::occi::OCCI_SQLT_RID: case oracle::occi::OCCIDATE: case oracle::occi::OCCI_SQLT_DAT: case oracle::occi::OCCI_SQLT_DATE: case oracle::occi::OCCI_SQLT_TIME: case oracle::occi::OCCI_SQLT_TIME_TZ: case oracle::occi::OCCITIMESTAMP: case oracle::occi::OCCI_SQLT_TIMESTAMP: case oracle::occi::OCCI_SQLT_TIMESTAMP_LTZ: case oracle::occi::OCCI_SQLT_TIMESTAMP_TZ: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); break; case oracle::occi::OCCIINTERVALDS: case oracle::occi::OCCIINTERVALYM: case oracle::occi::OCCI_SQLT_INTERVAL_YM: case oracle::occi::OCCI_SQLT_INTERVAL_DS: case oracle::occi::OCCIANYDATA: case oracle::occi::OCCIBLOB: case oracle::occi::OCCIBFILE: case oracle::occi::OCCIBYTES: case oracle::occi::OCCICLOB: case oracle::occi::OCCIVECTOR: case oracle::occi::OCCIMETADATA: case oracle::occi::OCCIPOBJECT: case oracle::occi::OCCIREF: case oracle::occi::OCCIREFANY: case oracle::occi::OCCISTREAM: case oracle::occi::OCCICURSOR: case oracle::occi::OCCI_SQLT_FILE: case oracle::occi::OCCI_SQLT_CFILE: case oracle::occi::OCCI_SQLT_REF: case oracle::occi::OCCI_SQLT_CLOB: case oracle::occi::OCCI_SQLT_BLOB: case oracle::occi::OCCI_SQLT_RSET: MAPNIK_LOG_WARN(occi) << "occi_datasource: Unsupported datatype " << occi_enums::resolve_datatype(type_oid) << " (type_oid=" << type_oid << ")"; break; default: MAPNIK_LOG_WARN(occi) << "occi_datasource: Unknown datatype " << "(type_oid=" << type_oid << ")"; break; } } } } catch (SQLException& ex) { throw datasource_exception(ex.getMessage()); } } }
void osm_datasource::bind() const { if (is_bound_) return; osm_data_ = NULL; std::string osm_filename = *params_.get<std::string>("file", ""); std::string parser = *params_.get<std::string>("parser", "libxml2"); std::string url = *params_.get<std::string>("url", ""); std::string bbox = *params_.get<std::string>("bbox", ""); bool do_process = false; // load the data // if we supplied a filename, load from file if (url != "" && bbox != "") { // otherwise if we supplied a url and a bounding box, load from the url #ifdef MAPNIK_DEBUG std::clog << "Osm Plugin: loading_from_url: url=" << url << " bbox=" << bbox << std::endl; #endif if ((osm_data_ = dataset_deliverer::load_from_url(url, bbox, parser)) == NULL) { throw datasource_exception("Error loading from URL"); } do_process = true; } else if (osm_filename != "") { if ((osm_data_= dataset_deliverer::load_from_file(osm_filename, parser)) == NULL) { throw datasource_exception("Error loading from file"); } do_process = true; } if (do_process == true) { osm_tag_types tagtypes; tagtypes.add_type("maxspeed", mapnik::Integer); tagtypes.add_type("z_order", mapnik::Integer); osm_data_->rewind(); // Need code to get the attributes of all the data std::set<std::string> keys = osm_data_->get_keys(); // Add the attributes to the datasource descriptor - assume they are // all of type String for (std::set<std::string>::iterator i = keys.begin(); i != keys.end(); i++) { desc_.add_descriptor(attribute_descriptor(*i, tagtypes.get_type(*i))); } // Get the bounds of the data and set extent_ accordingly bounds b = osm_data_->get_bounds(); extent_ = box2d<double>(b.w, b.s, b.e, b.n); } is_bound_ = true; }
void geos_datasource::bind() const { if (is_bound_) return; // open geos driver initGEOS(geos_notice, geos_error); // parse the string into geometry geometry_.set_feature(GEOSGeomFromWKT(geometry_string_.c_str())); if (*geometry_ == NULL || ! GEOSisValid(*geometry_)) { throw datasource_exception("GEOS Plugin: invalid <wkt> geometry specified"); } // try to obtain the extent from the geometry itself if (! extent_initialized_) { #ifdef MAPNIK_DEBUG clog << "GEOS Plugin: initializing extent from geometry" << endl; #endif if (GEOSGeomTypeId(*geometry_) == GEOS_POINT) { double x, y; unsigned int size; const GEOSCoordSequence* cs = GEOSGeom_getCoordSeq(*geometry_); GEOSCoordSeq_getSize(cs, &size); GEOSCoordSeq_getX(cs, 0, &x); GEOSCoordSeq_getY(cs, 0, &y); extent_.init(x,y,x,y); extent_initialized_ = true; } else { geos_feature_ptr envelope (GEOSEnvelope(*geometry_)); if (*envelope != NULL && GEOSisValid(*envelope)) { #ifdef MAPNIK_DEBUG char* wkt = GEOSGeomToWKT(*envelope); clog << "GEOS Plugin: getting coord sequence from: " << wkt << endl; GEOSFree(wkt); #endif const GEOSGeometry* exterior = GEOSGetExteriorRing(*envelope); if (exterior != NULL && GEOSisValid(exterior)) { const GEOSCoordSequence* cs = GEOSGeom_getCoordSeq(exterior); if (cs != NULL) { #ifdef MAPNIK_DEBUG clog << "GEOS Plugin: iterating boundary points" << endl; #endif double x, y; double minx = std::numeric_limits<float>::max(), miny = std::numeric_limits<float>::max(), maxx = -std::numeric_limits<float>::max(), maxy = -std::numeric_limits<float>::max(); unsigned int num_points; GEOSCoordSeq_getSize(cs, &num_points); for (unsigned int i = 0; i < num_points; ++i) { GEOSCoordSeq_getX(cs, i, &x); GEOSCoordSeq_getY(cs, i, &y); if (x < minx) minx = x; if (x > maxx) maxx = x; if (y < miny) miny = y; if (y > maxy) maxy = y; } extent_.init(minx,miny,maxx,maxy); extent_initialized_ = true; } } } } } if (! extent_initialized_) throw datasource_exception("GEOS Plugin: cannot determine extent for <wkt> geometry"); is_bound_ = true; }
void ogr_datasource::init(mapnik::parameters const& params) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "ogr_datasource::init"); #endif boost::optional<std::string> file = params.get<std::string>("file"); boost::optional<std::string> string = params.get<std::string>("string"); if (!string) string = params.get<std::string>("inline"); if (! file && ! string) { throw datasource_exception("missing <file> or <string> parameter"); } if (string) { dataset_name_ = *string; } else { boost::optional<std::string> base = params.get<std::string>("base"); if (base) { dataset_name_ = *base + "/" + *file; } else { dataset_name_ = *file; } } std::string driver = *params.get<std::string>("driver",""); if (! driver.empty()) { #if GDAL_VERSION_MAJOR >= 2 unsigned int nOpenFlags = GDAL_OF_READONLY | GDAL_OF_VECTOR; const char* papszAllowedDrivers[] = { driver.c_str(), nullptr }; dataset_ = reinterpret_cast<gdal_dataset_type>(GDALOpenEx(dataset_name_.c_str(),nOpenFlags,papszAllowedDrivers, nullptr, nullptr)); #else OGRSFDriver * ogr_driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver.c_str()); if (ogr_driver && ogr_driver != nullptr) { dataset_ = ogr_driver->Open((dataset_name_).c_str(), false); } #endif } else { // open ogr driver #if GDAL_VERSION_MAJOR >= 2 dataset_ = reinterpret_cast<gdal_dataset_type>(OGROpen(dataset_name_.c_str(), false, nullptr)); #else dataset_ = OGRSFDriverRegistrar::Open(dataset_name_.c_str(), false); #endif } if (! dataset_) { const std::string err = CPLGetLastErrorMsg(); if (err.size() == 0) { throw datasource_exception("OGR Plugin: connection failed: " + dataset_name_ + " was not found or is not a supported format"); } else { throw datasource_exception("OGR Plugin: " + err); } } // initialize layer boost::optional<std::string> layer_by_name = params.get<std::string>("layer"); boost::optional<mapnik::value_integer> layer_by_index = params.get<mapnik::value_integer>("layer_by_index"); boost::optional<std::string> layer_by_sql = params.get<std::string>("layer_by_sql"); int passed_parameters = 0; passed_parameters += layer_by_name ? 1 : 0; passed_parameters += layer_by_index ? 1 : 0; passed_parameters += layer_by_sql ? 1 : 0; if (passed_parameters > 1) { throw datasource_exception("OGR Plugin: you can only select an ogr layer by name " "('layer' parameter), by number ('layer_by_index' parameter), " "or by sql ('layer_by_sql' parameter), " "do not supply 2 or more of them at the same time" ); } if (layer_by_name) { layer_name_ = *layer_by_name; layer_.layer_by_name(dataset_, layer_name_); } else if (layer_by_index) { int num_layers = dataset_->GetLayerCount(); if (*layer_by_index >= num_layers) { std::ostringstream s; s << "OGR Plugin: only " << num_layers << " layer(s) exist, cannot find layer by index '" << *layer_by_index << "'"; throw datasource_exception(s.str()); } layer_.layer_by_index(dataset_, *layer_by_index); layer_name_ = layer_.layer_name(); } else if (layer_by_sql) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats_sql__(std::clog, "ogr_datasource::init(layer_by_sql)"); #endif layer_.layer_by_sql(dataset_, *layer_by_sql); layer_name_ = layer_.layer_name(); } else { std::string s("OGR Plugin: missing <layer> or <layer_by_index> or <layer_by_sql> parameter, available layers are: "); unsigned num_layers = dataset_->GetLayerCount(); bool layer_found = false; std::vector<std::string> layer_names; for (unsigned i = 0; i < num_layers; ++i ) { OGRLayer* ogr_layer = dataset_->GetLayer(i); OGRFeatureDefn* ogr_layer_def = ogr_layer->GetLayerDefn(); if (ogr_layer_def != 0) { layer_found = true; layer_names.push_back(std::string("'") + ogr_layer_def->GetName() + std::string("'")); } } if (! layer_found) { s += "None (no layers were found in dataset)"; } else { s += boost::algorithm::join(layer_names,", "); } throw datasource_exception(s); } if (! layer_.is_valid()) { std::ostringstream s; s << "OGR Plugin: "; if (layer_by_name) { s << "cannot find layer by name '" << *layer_by_name; } else if (layer_by_index) { s << "cannot find layer by index number '" << *layer_by_index; } else if (layer_by_sql) { s << "cannot find layer by sql query '" << *layer_by_sql; } s << "' in dataset '" << dataset_name_ << "'"; throw datasource_exception(s.str()); } // work with real OGR layer OGRLayer* layer = layer_.layer(); // initialize envelope boost::optional<std::string> ext = params.get<std::string>("extent"); if (ext && !ext->empty()) { extent_.from_string(*ext); } else { OGREnvelope envelope; OGRErr e = layer->GetExtent(&envelope); if (e == OGRERR_FAILURE) { if (layer->GetFeatureCount() == 0) { MAPNIK_LOG_ERROR(ogr) << "could not determine extent, layer '" << layer->GetLayerDefn()->GetName() << "' appears to have no features"; } else { std::ostringstream s; s << "OGR Plugin: Cannot determine extent for layer '" << layer->GetLayerDefn()->GetName() << "'. Please provide a manual extent string (minx,miny,maxx,maxy)."; throw datasource_exception(s.str()); } } extent_.init(envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY); } // scan for index file // TODO - layer names don't match dataset name, so this will break for // any layer types of ogr than shapefiles, etc // fix here and in ogrindex size_t breakpoint = dataset_name_.find_last_of("."); if (breakpoint == std::string::npos) { breakpoint = dataset_name_.length(); } index_name_ = dataset_name_.substr(0, breakpoint) + ".ogrindex"; #if defined (_WINDOWS) std::ifstream index_file(mapnik::utf8_to_utf16(index_name_), std::ios::in | std::ios::binary); #else std::ifstream index_file(index_name_.c_str(), std::ios::in | std::ios::binary); #endif if (index_file) { indexed_ = true; index_file.close(); } #if 0 // TODO - enable this warning once the ogrindex tool is a bit more stable/mature else { MAPNIK_LOG_DEBUG(ogr) << "ogr_datasource: no ogrindex file found for " << dataset_name_ << ", use the 'ogrindex' program to build an index for faster rendering"; } #endif #ifdef MAPNIK_STATS mapnik::progress_timer __stats2__(std::clog, "ogr_datasource::init(get_column_description)"); #endif // deal with attributes descriptions OGRFeatureDefn* def = layer->GetLayerDefn(); if (def != 0) { const int fld_count = def->GetFieldCount(); for (int i = 0; i < fld_count; i++) { OGRFieldDefn* fld = def->GetFieldDefn(i); const std::string fld_name = fld->GetNameRef(); const OGRFieldType type_oid = fld->GetType(); switch (type_oid) { case OFTInteger: #if GDAL_VERSION_MAJOR >= 2 case OFTInteger64: #endif desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Integer)); break; case OFTReal: desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Double)); break; case OFTString: case OFTWideString: // deprecated desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::String)); break; case OFTBinary: desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Object)); break; case OFTIntegerList: #if GDAL_VERSION_MAJOR >= 2 case OFTInteger64List: #endif case OFTRealList: case OFTStringList: case OFTWideStringList: // deprecated ! MAPNIK_LOG_WARN(ogr) << "ogr_datasource: Unhandled type_oid=" << type_oid; break; case OFTDate: case OFTTime: case OFTDateTime: // unhandled ! desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Object)); MAPNIK_LOG_WARN(ogr) << "ogr_datasource: Unhandled type_oid=" << type_oid; break; } } } mapnik::parameters & extra_params = desc_.get_extra_parameters(); OGRSpatialReference * srs_ref = layer->GetSpatialRef(); char * srs_output = nullptr; if (srs_ref && srs_ref->exportToProj4( &srs_output ) == OGRERR_NONE ) { extra_params["proj4"] = mapnik::util::trim_copy(srs_output); } CPLFree(srs_output); }
ogr_datasource::ogr_datasource(parameters const& params) : datasource(params), extent_(), type_(datasource::Vector), desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8")), indexed_(false) { OGRRegisterAll(); boost::optional<std::string> file = params.get<std::string>("file"); if (!file) throw datasource_exception("missing <file> parameter"); multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false); boost::optional<std::string> base = params.get<std::string>("base"); if (base) dataset_name_ = *base + "/" + *file; else dataset_name_ = *file; // open ogr driver dataset_ = OGRSFDriverRegistrar::Open ((dataset_name_).c_str(), FALSE); if (!dataset_) { std::string err = CPLGetLastErrorMsg(); if( err.size() == 0 ) { throw datasource_exception("Connection failed: " + dataset_name_ + " was not found or is not a supported format"); } else { throw datasource_exception(err); } } // initialize layer boost::optional<std::string> layer = params.get<std::string>("layer"); if (!layer) { std::string s ("missing <layer> parameter, available layers are: "); unsigned num_layers = dataset_->GetLayerCount(); for (unsigned i = 0; i < num_layers; ++i ) { OGRLayer *ogr_layer = dataset_->GetLayer(i); OGRFeatureDefn* def = ogr_layer->GetLayerDefn(); if (def != 0) { s += " '"; s += def->GetName(); s += "' "; } else { s += "No layers found!"; } } throw datasource_exception(s); } layerName_ = *layer; layer_ = dataset_->GetLayerByName (layerName_.c_str()); if (! layer_) throw datasource_exception("cannot find <layer> in dataset"); // initialize envelope OGREnvelope envelope; layer_->GetExtent (&envelope); extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY); // scan for index file size_t breakpoint = dataset_name_.find_last_of ("."); if (breakpoint == std::string::npos) breakpoint = dataset_name_.length(); index_name_ = dataset_name_.substr(0, breakpoint) + ".index"; std::ifstream index_file (index_name_.c_str(), std::ios::in | std::ios::binary); if (index_file) { indexed_=true; index_file.close(); } // deal with attributes descriptions OGRFeatureDefn* def = layer_->GetLayerDefn (); if (def != 0) { int fld_count = def->GetFieldCount (); for (int i = 0; i < fld_count; i++) { OGRFieldDefn* fld = def->GetFieldDefn (i); std::string fld_name = fld->GetNameRef (); OGRFieldType type_oid = fld->GetType (); switch (type_oid) { case OFTInteger: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); break; case OFTReal: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); break; case OFTString: case OFTWideString: // deprecated desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); break; case OFTBinary: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object)); break; case OFTIntegerList: case OFTRealList: case OFTStringList: case OFTWideStringList: // deprecated ! #ifdef MAPNIK_DEBUG clog << "unhandled type_oid=" << type_oid << endl; #endif break; case OFTDate: case OFTTime: case OFTDateTime: // unhandled ! #ifdef MAPNIK_DEBUG clog << "unhandled type_oid=" << type_oid << endl; #endif desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object)); break; default: // unknown #ifdef MAPNIK_DEBUG clog << "unknown type_oid=" << type_oid << endl; #endif break; } } } }
void sqlite_datasource::bind() const { if (is_bound_) return; if (!boost::filesystem::exists(dataset_name_)) throw datasource_exception("Sqlite Plugin: " + dataset_name_ + " does not exist"); dataset_ = new sqlite_connection (dataset_name_); std::string table_name = mapnik::table_from_sql(table_); if (metadata_ != "" && ! extent_initialized_) { std::ostringstream s; s << "SELECT xmin, ymin, xmax, ymax FROM " << metadata_; s << " WHERE LOWER(f_table_name) = LOWER('" << table_name << "')"; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); if (rs->is_valid () && rs->step_next()) { double xmin = rs->column_double (0); double ymin = rs->column_double (1); double xmax = rs->column_double (2); double ymax = rs->column_double (3); extent_.init (xmin,ymin,xmax,ymax); extent_initialized_ = true; } } if (use_spatial_index_) { std::ostringstream s; s << "SELECT COUNT (*) FROM sqlite_master"; s << " WHERE LOWER(name) = LOWER('idx_" << table_name << "_" << geometry_field_ << "')"; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); if (rs->is_valid () && rs->step_next()) { use_spatial_index_ = rs->column_integer (0) == 1; } #ifdef MAPNIK_DEBUG if (! use_spatial_index_) std::clog << "Sqlite Plugin: cannot use the spatial index " << std::endl; #endif } { /* XXX - This is problematic, if we do not have at least a row, we cannot determine the right columns types and names as all column_type are SQLITE_NULL */ std::ostringstream s; s << "SELECT " << fields_ << " FROM (" << table_name << ") LIMIT 1"; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); if (rs->is_valid () && rs->step_next()) { for (int i = 0; i < rs->column_count (); ++i) { const int type_oid = rs->column_type (i); const char* fld_name = rs->column_name (i); switch (type_oid) { case SQLITE_INTEGER: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); break; case SQLITE_FLOAT: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); break; case SQLITE_TEXT: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); break; case SQLITE_NULL: case SQLITE_BLOB: break; default: #ifdef MAPNIK_DEBUG std::clog << "Sqlite Plugin: unknown type_oid=" << type_oid << std::endl; #endif break; } } } } is_bound_ = true; }
void rasterlite_datasource::bind() const { if (is_bound_) return; if (!boost::filesystem::exists(dataset_name_)) throw datasource_exception(dataset_name_ + " does not exist"); void *dataset = open_dataset(); double x0, y0, x1, y1; if (rasterliteGetExtent (dataset, &x0, &y0, &x1, &y1) != RASTERLITE_OK) { std::string error (rasterliteGetLastError(dataset)); rasterliteClose (dataset); throw datasource_exception(error); } extent_.init(x0,y0,x1,y1); #ifdef MAPNIK_DEBUG int srid, auth_srid; const char *auth_name; const char *ref_sys_name; const char *proj4text; int tile_count; double pixel_x_size, pixel_y_size; int levels = rasterliteGetLevels (dataset); if (rasterliteGetSrid(dataset, &srid, &auth_name, &auth_srid, &ref_sys_name, &proj4text) != RASTERLITE_OK) { std::string error (rasterliteGetLastError(dataset)); rasterliteClose (dataset); throw datasource_exception(error); } std::clog << "Rasterlite Plugin: Data Source=" << rasterliteGetTablePrefix(dataset) << std::endl; std::clog << "Rasterlite Plugin: SRID=" << srid << std::endl; std::clog << "Rasterlite Plugin: Authority=" << auth_name << std::endl; std::clog << "Rasterlite Plugin: AuthSRID=" << auth_srid << std::endl; std::clog << "Rasterlite Plugin: RefSys Name=" << ref_sys_name << std::endl; std::clog << "Rasterlite Plugin: Proj4Text=" << proj4text << std::endl; std::clog << "Rasterlite Plugin: Extent(" << x0 << "," << y0 << " " << x1 << "," << y1 << ")" << std::endl; std::clog << "Rasterlite Plugin: Levels=" << levels << std::endl; for (int i = 0; i < levels; i++) { if (rasterliteGetResolution(dataset, i, &pixel_x_size, &pixel_y_size, &tile_count) == RASTERLITE_OK) { std::clog << "Rasterlite Plugin: Level=" << i << " x=" << pixel_x_size << " y=" << pixel_y_size << " tiles=" << tile_count << std::endl; } } #endif rasterliteClose(dataset); is_bound_ = true; }
box2d<double> occi_datasource::envelope() const { if (extent_initialized_) return extent_; if (! is_bound_) bind(); double lox = 0.0, loy = 0.0, hix = 0.0, hiy = 0.0; boost::optional<mapnik::boolean> estimate_extent = params_.get<mapnik::boolean>("estimate_extent",false); if (estimate_extent && *estimate_extent) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(estimate_extent)"); #endif std::ostringstream s; s << "SELECT MIN(c.x), MIN(c.y), MAX(c.x), MAX(c.y) FROM "; s << " (SELECT SDO_AGGR_MBR(" << geometry_field_ << ") shape FROM " << table_ << ") a, "; s << " TABLE(SDO_UTIL.GETVERTICES(a.shape)) c"; MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); try { occi_connection_ptr conn; if (use_connection_pool_) conn.set_pool(pool_); else conn.set_connection(conn_, false); ResultSet* rs = conn.execute_query(s.str()); if (rs && rs->next()) { try { lox = lexical_cast<double>(rs->getDouble(1)); loy = lexical_cast<double>(rs->getDouble(2)); hix = lexical_cast<double>(rs->getDouble(3)); hiy = lexical_cast<double>(rs->getDouble(4)); extent_.init(lox, loy, hix, hiy); extent_initialized_ = true; } catch (bad_lexical_cast& ex) { MAPNIK_LOG_WARN(occi) << "OCCI Plugin: " << ex.what(); } } } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } else if (use_spatial_index_) { #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "occi_datasource::envelope(use_spatial_index)"); #endif std::ostringstream s; s << "SELECT dim.sdo_lb, dim.sdo_ub FROM "; s << METADATA_TABLE << " m, TABLE(m.diminfo) dim "; s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'X'"; s << " UNION "; s << "SELECT dim.sdo_lb, dim.sdo_ub FROM "; s << METADATA_TABLE << " m, TABLE(m.diminfo) dim "; s << " WHERE LOWER(m.table_name) = LOWER('" << table_name_ << "') AND dim.sdo_dimname = 'Y'"; MAPNIK_LOG_DEBUG(occi) << "occi_datasource: " << s.str(); try { occi_connection_ptr conn; if (use_connection_pool_) conn.set_pool(pool_); else conn.set_connection(conn_, false); ResultSet* rs = conn.execute_query(s.str()); if (rs) { if (rs->next()) { try { lox = lexical_cast<double>(rs->getDouble(1)); hix = lexical_cast<double>(rs->getDouble(2)); } catch (bad_lexical_cast& ex) { MAPNIK_LOG_WARN(occi) << "OCCI Plugin: " << ex.what(); } } if (rs->next()) { try { loy = lexical_cast<double>(rs->getDouble(1)); hiy = lexical_cast<double>(rs->getDouble(2)); } catch (bad_lexical_cast& ex) { MAPNIK_LOG_WARN(occi) << "OCCI Plugin: " << ex.what(); } } extent_.init(lox, loy, hix, hiy); extent_initialized_ = true; } } catch (SQLException& ex) { throw datasource_exception("OCCI Plugin: " + ex.getMessage()); } } if (! extent_initialized_) { throw datasource_exception("OCCI Plugin: unable to determine the extent of a <occi> table"); } return extent_; }
rasterlite_datasource::rasterlite_datasource(parameters const& params) : datasource(params), desc_(rasterlite_datasource::name(),"utf-8") { MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: Initializing..."; boost::optional<std::string> file = params.get<std::string>("file"); if (!file) throw datasource_exception("missing <file> parameter"); boost::optional<std::string> table = params.get<std::string>("table"); if (!table) throw datasource_exception("missing <table> parameter"); table_name_ = *table; boost::optional<std::string> base = params.get<std::string>("base"); if (base) dataset_name_ = *base + "/" + *file; else dataset_name_ = *file; if (!mapnik::util::exists(dataset_name_)) throw datasource_exception(dataset_name_ + " does not exist"); void *dataset = open_dataset(); double x0, y0, x1, y1; if (rasterliteGetExtent (dataset, &x0, &y0, &x1, &y1) != RASTERLITE_OK) { std::string error (rasterliteGetLastError(dataset)); rasterliteClose (dataset); throw datasource_exception(error); } extent_.init(x0,y0,x1,y1); #ifdef MAPNIK_LOG int srid, auth_srid; const char *auth_name; const char *ref_sys_name; const char *proj4text; int tile_count; double pixel_x_size, pixel_y_size; int levels = rasterliteGetLevels (dataset); if (rasterliteGetSrid(dataset, &srid, &auth_name, &auth_srid, &ref_sys_name, &proj4text) != RASTERLITE_OK) { std::string error (rasterliteGetLastError(dataset)); rasterliteClose (dataset); throw datasource_exception(error); } MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: Data Source=" << rasterliteGetTablePrefix(dataset); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: SRID=" << srid; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: Authority=" << auth_name; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: AuthSRID=" << auth_srid; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: RefSys Name=" << ref_sys_name; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: Proj4Text=" << proj4text; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: Extent=" << x0 << "," << y0 << " " << x1 << "," << y1 << ")"; MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: Levels=" << levels; for (int i = 0; i < levels; i++) { if (rasterliteGetResolution(dataset, i, &pixel_x_size, &pixel_y_size, &tile_count) == RASTERLITE_OK) { MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_datasource: Level=" << i << " x=" << pixel_x_size << " y=" << pixel_y_size << " tiles=" << tile_count; } } #endif rasterliteClose(dataset); }
void ogr_datasource::bind() const { if (is_bound_) return; // initialize ogr formats OGRRegisterAll(); std::string driver = *params_.get<std::string>("driver",""); if (! driver.empty()) { OGRSFDriver * ogr_driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver.c_str()); if (ogr_driver && ogr_driver != NULL) { dataset_ = ogr_driver->Open((dataset_name_).c_str(), FALSE); } } else { // open ogr driver dataset_ = OGRSFDriverRegistrar::Open((dataset_name_).c_str(), FALSE); } if (! dataset_) { const std::string err = CPLGetLastErrorMsg(); if (err.size() == 0) { throw datasource_exception("OGR Plugin: connection failed: " + dataset_name_ + " was not found or is not a supported format"); } else { throw datasource_exception("OGR Plugin: " + err); } } // initialize layer boost::optional<std::string> layer_by_name = params_.get<std::string>("layer"); boost::optional<unsigned> layer_by_index = params_.get<unsigned>("layer_by_index"); boost::optional<std::string> layer_by_sql = params_.get<std::string>("layer_by_sql"); int passed_parameters = 0; passed_parameters += layer_by_name ? 1 : 0; passed_parameters += layer_by_index ? 1 : 0; passed_parameters += layer_by_sql ? 1 : 0; if (passed_parameters > 1) { throw datasource_exception("OGR Plugin: you can only select an ogr layer by name " "('layer' parameter), by number ('layer_by_index' parameter), " "or by sql ('layer_by_sql' parameter), " "do not supply 2 or more of them at the same time" ); } if (layer_by_name) { layer_name_ = *layer_by_name; layer_.layer_by_name(dataset_, layer_name_); } else if (layer_by_index) { const unsigned num_layers = dataset_->GetLayerCount(); if (*layer_by_index >= num_layers) { std::ostringstream s; s << "OGR Plugin: only "; s << num_layers; s << " layer(s) exist, cannot find layer by index '" << *layer_by_index << "'"; throw datasource_exception(s.str()); } layer_.layer_by_index(dataset_, *layer_by_index); layer_name_ = layer_.layer_name(); } else if (layer_by_sql) { layer_.layer_by_sql(dataset_, *layer_by_sql); layer_name_ = layer_.layer_name(); } else { std::ostringstream s; s << "OGR Plugin: missing <layer> or <layer_by_index> or <layer_by_sql> " << "parameter, available layers are: "; unsigned num_layers = dataset_->GetLayerCount(); bool layer_found = false; for (unsigned i = 0; i < num_layers; ++i ) { OGRLayer* ogr_layer = dataset_->GetLayer(i); OGRFeatureDefn* ogr_layer_def = ogr_layer->GetLayerDefn(); if (ogr_layer_def != 0) { layer_found = true; s << " '" << ogr_layer_def->GetName() << "' "; } } if (! layer_found) { s << "None (no layers were found in dataset)"; } throw datasource_exception(s.str()); } if (! layer_.is_valid()) { std::string s("OGR Plugin: "); if (layer_by_name) { s += "cannot find layer by name '" + *layer_by_name; } else if (layer_by_index) { s += "cannot find layer by index number '" + *layer_by_index; } else if (layer_by_sql) { s += "cannot find layer by sql query '" + *layer_by_sql; } s += "' in dataset '" + dataset_name_ + "'"; throw datasource_exception(s); } // work with real OGR layer OGRLayer* layer = layer_.layer(); // initialize envelope OGREnvelope envelope; layer->GetExtent(&envelope); extent_.init(envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY); // scan for index file // TODO - layer names don't match dataset name, so this will break for // any layer types of ogr than shapefiles, etc // fix here and in ogrindex size_t breakpoint = dataset_name_.find_last_of("."); if (breakpoint == std::string::npos) { breakpoint = dataset_name_.length(); } index_name_ = dataset_name_.substr(0, breakpoint) + ".ogrindex"; std::ifstream index_file(index_name_.c_str(), std::ios::in | std::ios::binary); if (index_file) { indexed_ = true; index_file.close(); } #if 0 // TODO - enable this warning once the ogrindex tool is a bit more stable/mature else { std::clog << "### Notice: no ogrindex file found for " << dataset_name_ << ", use the 'ogrindex' program to build an index for faster rendering" << std::endl; } #endif // deal with attributes descriptions OGRFeatureDefn* def = layer->GetLayerDefn(); if (def != 0) { const int fld_count = def->GetFieldCount(); for (int i = 0; i < fld_count; i++) { OGRFieldDefn* fld = def->GetFieldDefn(i); const std::string fld_name = fld->GetNameRef(); const OGRFieldType type_oid = fld->GetType(); switch (type_oid) { case OFTInteger: desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Integer)); break; case OFTReal: desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Double)); break; case OFTString: case OFTWideString: // deprecated desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::String)); break; case OFTBinary: desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Object)); break; case OFTIntegerList: case OFTRealList: case OFTStringList: case OFTWideStringList: // deprecated ! #ifdef MAPNIK_DEBUG std::clog << "OGR Plugin: unhandled type_oid=" << type_oid << std::endl; #endif break; case OFTDate: case OFTTime: case OFTDateTime: // unhandled ! #ifdef MAPNIK_DEBUG std::clog << "OGR Plugin: unhandled type_oid=" << type_oid << std::endl; #endif desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Object)); break; default: // unknown #ifdef MAPNIK_DEBUG std::clog << "OGR Plugin: unknown type_oid=" << type_oid << std::endl; #endif break; } } } is_bound_ = true; }
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(); }
void sqlite_datasource::bind() const { if (is_bound_) return; if (!boost::filesystem::exists(dataset_name_)) throw datasource_exception("Sqlite Plugin: " + dataset_name_ + " does not exist"); dataset_ = new sqlite_connection (dataset_name_); if(geometry_table_.empty()) { geometry_table_ = mapnik::table_from_sql(table_); } // should we deduce column names and types using PRAGMA? bool use_pragma_table_info = true; if (table_ != geometry_table_) { // if 'table_' is a subquery then we try to deduce names // and types from the first row returned from that query use_pragma_table_info = false; } if (!use_pragma_table_info) { std::ostringstream s; s << "SELECT " << fields_ << " FROM (" << table_ << ") LIMIT 1"; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); if (rs->is_valid () && rs->step_next()) { for (int i = 0; i < rs->column_count (); ++i) { const int type_oid = rs->column_type (i); const char* fld_name = rs->column_name (i); switch (type_oid) { case SQLITE_INTEGER: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); break; case SQLITE_FLOAT: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); break; case SQLITE_TEXT: desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); break; case SQLITE_NULL: // sqlite reports based on value, not actual column type unless // PRAGMA table_info is used so here we assume the column is a string // which is a lesser evil than altogether dropping the column desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); case SQLITE_BLOB: if (geometry_field_.empty() && (boost::algorithm::icontains(fld_name,"geom") || boost::algorithm::icontains(fld_name,"point") || boost::algorithm::icontains(fld_name,"linestring") || boost::algorithm::icontains(fld_name,"polygon")) ) geometry_field_ = std::string(fld_name); break; default: #ifdef MAPNIK_DEBUG std::clog << "Sqlite Plugin: unknown type_oid=" << type_oid << std::endl; #endif break; } } } else { // if we do not have at least a row and // we cannot determine the right columns types and names // as all column_type are SQLITE_NULL // so we fallback to using PRAGMA table_info use_pragma_table_info = true; } } // TODO - ensure that the supplied key_field is a valid "integer primary key" desc_.add_descriptor(attribute_descriptor("rowid",mapnik::Integer)); if (use_pragma_table_info) { std::ostringstream s; s << "PRAGMA table_info(" << geometry_table_ << ")"; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); bool found_table = false; while (rs->is_valid () && rs->step_next()) { found_table = true; const char* fld_name = rs->column_text(1); std::string fld_type(rs->column_text(2)); boost::algorithm::to_lower(fld_type); // see 2.1 "Column Affinity" at http://www.sqlite.org/datatype3.html if (geometry_field_.empty() && ( (boost::algorithm::icontains(fld_name,"geom") || boost::algorithm::icontains(fld_name,"point") || boost::algorithm::icontains(fld_name,"linestring") || boost::algorithm::icontains(fld_name,"polygon")) || (boost::algorithm::contains(fld_type,"geom") || boost::algorithm::contains(fld_type,"point") || boost::algorithm::contains(fld_type,"linestring") || boost::algorithm::contains(fld_type,"polygon")) ) ) geometry_field_ = std::string(fld_name); else if (boost::algorithm::contains(fld_type,"int")) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); } else if (boost::algorithm::contains(fld_type,"text") || boost::algorithm::contains(fld_type,"char") || boost::algorithm::contains(fld_type,"clob")) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); } else if (boost::algorithm::contains(fld_type,"real") || boost::algorithm::contains(fld_type,"float") || boost::algorithm::contains(fld_type,"double")) { desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); } else if (boost::algorithm::contains(fld_type,"blob") && !geometry_field_.empty()) desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); #ifdef MAPNIK_DEBUG else { // "Column Affinity" says default to "Numeric" but for now we pass.. //desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); std::clog << "Sqlite Plugin: column '" << std::string(fld_name) << "' unhandled due to unknown type: " << fld_type << std::endl; } #endif } if (!found_table) { throw datasource_exception("Sqlite Plugin: could not query table '" + geometry_table_ + "' using pragma table_info(" + geometry_table_ + ");"); } } if (geometry_field_.empty()) { throw datasource_exception("Sqlite Plugin: cannot detect geometry_field, please supply the name of the geometry_field to use."); } if (use_spatial_index_) { std::ostringstream s; s << "SELECT COUNT (*) FROM sqlite_master"; s << " WHERE LOWER(name) = LOWER('idx_" << geometry_table_ << "_" << geometry_field_ << "')"; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); if (rs->is_valid () && rs->step_next()) { use_spatial_index_ = rs->column_integer (0) == 1; } if (!use_spatial_index_) std::clog << "Sqlite Plugin: spatial index not found for table '" << geometry_table_ << "'" << std::endl; } if (metadata_ != "" && !extent_initialized_) { std::ostringstream s; s << "SELECT xmin, ymin, xmax, ymax FROM " << metadata_; s << " WHERE LOWER(f_table_name) = LOWER('" << geometry_table_ << "')"; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); if (rs->is_valid () && rs->step_next()) { double xmin = rs->column_double (0); double ymin = rs->column_double (1); double xmax = rs->column_double (2); double ymax = rs->column_double (3); extent_.init (xmin,ymin,xmax,ymax); extent_initialized_ = true; } } if (!extent_initialized_ && use_spatial_index_) { std::ostringstream s; s << "SELECT MIN(xmin), MIN(ymin), MAX(xmax), MAX(ymax) FROM " << "idx_" << geometry_table_ << "_" << geometry_field_; boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str())); if (rs->is_valid () && rs->step_next()) { double xmin = rs->column_double (0); double ymin = rs->column_double (1); double xmax = rs->column_double (2); double ymax = rs->column_double (3); extent_.init (xmin,ymin,xmax,ymax); extent_initialized_ = true; } } if (!extent_initialized_) { std::ostringstream s; s << "Sqlite Plugin: extent could not be determined for table|geometry '" << geometry_table_ << "|" << geometry_field_ << "'" << " because an rtree spatial index is missing." << " - either set the table 'extent' or create an rtree spatial index"; throw datasource_exception(s.str()); } is_bound_ = true; }
void shape_datasource::init(shape_io& shape) const { //first read header from *.shp int file_code=shape.shp().read_xdr_integer(); if (file_code!=9994) { //invalid file code throw datasource_exception("Shape Plugin: " + (boost::format("wrong file code : %d") % file_code).str()); } shape.shp().skip(5*4); file_length_=shape.shp().read_xdr_integer(); int version=shape.shp().read_ndr_integer(); if (version!=1000) { //invalid version number throw datasource_exception("Shape Plugin: " + (boost::format("invalid version number: %d") % version).str()); } shape_type_ = static_cast<shape_io::shapeType>(shape.shp().read_ndr_integer()); if (shape_type_ == shape_io::shape_multipatch) throw datasource_exception("Shape Plugin: shapefile multipatch type is not supported"); shape.shp().read_envelope(extent_); #ifdef MAPNIK_DEBUG double zmin = shape.shp().read_double(); double zmax = shape.shp().read_double(); double mmin = shape.shp().read_double(); double mmax = shape.shp().read_double(); std::clog << "Shape Plugin: Z min/max " << zmin << "," << zmax << std::endl; std::clog << "Shape Plugin: M min/max " << mmin << "," << mmax << "\n"; #else shape.shp().skip(4*8); #endif // check if we have an index file around indexed_ = shape.has_index(); //std::string index_name(shape_name_+".index"); //std::ifstream file(index_name.c_str(),std::ios::in | std::ios::binary); //if (file) //{ // indexed_=true; // file.close(); //} //else //{ // std::clog << "### Notice: no .index file found for " + shape_name_ + ".shp, use the 'shapeindex' program to build an index for faster rendering\n"; //} #ifdef MAPNIK_DEBUG std::clog << "Shape Plugin: extent=" << extent_ << std::endl; std::clog << "Shape Plugin: file_length=" << file_length_ << std::endl; std::clog << "Shape Plugin: shape_type=" << shape_type_ << std::endl; #endif }
void gdal_datasource::bind() const { if (is_bound_) return; shared_dataset_ = *params_.get<mapnik::boolean>("shared", false); band_ = *params_.get<int>("band", -1); GDALDataset *dataset = open_dataset(); nbands_ = dataset->GetRasterCount(); width_ = dataset->GetRasterXSize(); height_ = dataset->GetRasterYSize(); double tr[6]; bool bbox_override = false; boost::optional<std::string> bbox_s = params_.get<std::string>("bbox"); if (bbox_s) { #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: bbox parameter=" << *bbox_s << std::endl; #endif bbox_override = extent_.from_string(*bbox_s); if (! bbox_override) { throw datasource_exception("GDAL Plugin: bbox parameter '" + *bbox_s + "' invalid"); } } if (bbox_override) { tr[0] = extent_.minx(); tr[1] = extent_.width() / (double)width_; tr[2] = 0; tr[3] = extent_.maxy(); tr[4] = 0; tr[5] = -extent_.height() / (double)height_; } else { dataset->GetGeoTransform(tr); } #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: geotransform=" << tr[0] << "," << tr[1] << "," << tr[2] << "," << tr[3] << "," << tr[4] << "," << tr[5] << std::endl; #endif // TODO - We should throw for true non-north up images, but the check // below is clearly too restrictive. // https://github.com/mapnik/mapnik/issues/970 /* if (tr[2] != 0 || tr[4] != 0) { throw datasource_exception("GDAL Plugin: only 'north up' images are supported"); } */ dx_ = tr[1]; dy_ = tr[5]; if (! bbox_override) { double x0 = tr[0]; double y0 = tr[3]; double x1 = tr[0] + width_ * dx_ + height_ *tr[2]; double y1 = tr[3] + width_ *tr[4] + height_ * dy_; /* double x0 = tr[0] + (height_) * tr[2]; // minx double y0 = tr[3] + (height_) * tr[5]; // miny double x1 = tr[0] + (width_) * tr[1]; // maxx double y1 = tr[3] + (width_) * tr[4]; // maxy */ extent_.init(x0, y0, x1, y1); } GDALClose(dataset); #ifdef MAPNIK_DEBUG std::clog << "GDAL Plugin: Raster Size=" << width_ << "," << height_ << std::endl; std::clog << "GDAL Plugin: Raster Extent=" << extent_ << std::endl; #endif is_bound_ = true; }
void shape_datasource::bind() const { if (is_bound_) return; if (!boost::filesystem::exists(shape_name_ + ".shp")) { throw datasource_exception("Shape Plugin: shapefile '" + shape_name_ + ".shp' does not exist"); } if (boost::filesystem::is_directory(shape_name_ + ".shp")) { throw datasource_exception("Shape Plugin: shapefile '" + shape_name_ + ".shp' appears to be a directory not a file"); } if (!boost::filesystem::exists(shape_name_ + ".dbf")) { throw datasource_exception("Shape Plugin: shapefile '" + shape_name_ + ".dbf' does not exist"); } try { boost::shared_ptr<shape_io> shape_ref = boost::make_shared<shape_io>(shape_name_); init(*shape_ref); for (int i=0;i<shape_ref->dbf().num_fields();++i) { field_descriptor const& fd=shape_ref->dbf().descriptor(i); std::string fld_name=fd.name_; switch (fd.type_) { case 'C': // character case 'D': // Date case 'M': // Memo, a string case 'L': // logical case '@': // timestamp desc_.add_descriptor(attribute_descriptor(fld_name, String)); break; case 'N': case 'O': // double case 'F': // float { if (fd.dec_>0) { desc_.add_descriptor(attribute_descriptor(fld_name,Double,false,8)); } else { desc_.add_descriptor(attribute_descriptor(fld_name,Integer,false,4)); } break; } default: #ifdef MAPNIK_DEBUG // I - long // G - ole // + - autoincrement std::clog << "Shape Plugin: unknown type " << fd.type_ << std::endl; #endif break; } } // for indexed shapefiles we keep open the file descriptor for fast reads if (indexed_) { shape_ = shape_ref; } } catch (const datasource_exception& ex) { std::clog << "Shape Plugin: error processing field attributes, " << ex.what() << std::endl; throw; } catch (const std::exception& ex) { std::clog << "Shape Plugin: error processing field attributes, " << ex.what() << std::endl; throw; } catch (...) // exception: pipe_select_interrupter: Too many open files { std::clog << "Shape Plugin: error processing field attributes" << std::endl; throw; } is_bound_ = true; }
gdal_datasource::gdal_datasource(parameters const& params) : datasource(params), desc_(gdal_datasource::name(), "utf-8"), nodata_value_(params.get<double>("nodata")), nodata_tolerance_(*params.get<double>("nodata_tolerance",1e-12)) { MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource: Initializing..."; #ifdef MAPNIK_STATS mapnik::progress_timer __stats__(std::clog, "gdal_datasource::init"); #endif GDALAllRegister(); boost::optional<std::string> file = params.get<std::string>("file"); if (! file) throw datasource_exception("missing <file> parameter"); boost::optional<std::string> base = params.get<std::string>("base"); if (base) { dataset_name_ = *base + "/" + *file; } else { dataset_name_ = *file; } shared_dataset_ = *params.get<mapnik::boolean_type>("shared", false); band_ = *params.get<mapnik::value_integer>("band", -1); GDALDataset *dataset = open_dataset(); nbands_ = dataset->GetRasterCount(); width_ = dataset->GetRasterXSize(); height_ = dataset->GetRasterYSize(); desc_.add_descriptor(mapnik::attribute_descriptor("nodata", mapnik::Double)); double tr[6]; bool bbox_override = false; boost::optional<std::string> bbox_s = params.get<std::string>("extent"); if (bbox_s) { MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource: BBox Parameter=" << *bbox_s; bbox_override = extent_.from_string(*bbox_s); if (! bbox_override) { throw datasource_exception("GDAL Plugin: bbox parameter '" + *bbox_s + "' invalid"); } } if (bbox_override) { tr[0] = extent_.minx(); tr[1] = extent_.width() / (double)width_; tr[2] = 0; tr[3] = extent_.maxy(); tr[4] = 0; tr[5] = -extent_.height() / (double)height_; MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource extent override gives Geotransform=" << tr[0] << "," << tr[1] << "," << tr[2] << "," << tr[3] << "," << tr[4] << "," << tr[5]; } else { if (dataset->GetGeoTransform(tr) != CPLE_None) { MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource GetGeotransform failure gives=" << tr[0] << "," << tr[1] << "," << tr[2] << "," << tr[3] << "," << tr[4] << "," << tr[5]; } else { MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource Geotransform=" << tr[0] << "," << tr[1] << "," << tr[2] << "," << tr[3] << "," << tr[4] << "," << tr[5]; } } // TODO - We should throw for true non-north up images, but the check // below is clearly too restrictive. // https://github.com/mapnik/mapnik/issues/970 /* if (tr[2] != 0 || tr[4] != 0) { throw datasource_exception("GDAL Plugin: only 'north up' images are supported"); } */ dx_ = tr[1]; dy_ = tr[5]; if (! bbox_override) { double x0 = tr[0]; double y0 = tr[3]; double x1 = tr[0] + width_ * dx_ + height_ *tr[2]; double y1 = tr[3] + width_ *tr[4] + height_ * dy_; /* double x0 = tr[0] + (height_) * tr[2]; // minx double y0 = tr[3] + (height_) * tr[5]; // miny double x1 = tr[0] + (width_) * tr[1]; // maxx double y1 = tr[3] + (width_) * tr[4]; // maxy */ extent_.init(x0, y0, x1, y1); } GDALClose(dataset); MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource: Raster Size=" << width_ << "," << height_; MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource: Raster Extent=" << extent_; }
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(); }