From f414843c4fc74d2254e70d6fc531e394e7c0fce5 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 Jan 2009 20:16:31 +0000 Subject: [PATCH] + First implementation of OGR(vector) input plugin. Patch from kunitoki. Thanks! Closes #170 --- AUTHORS | 1 + CHANGELOG | 2 + SConstruct | 17 ++- bindings/python/mapnik/__init__.py | 6 +- plugins/input/Makefile.am | 1 + plugins/input/ogr/Makefile.am | 24 +++ plugins/input/ogr/SConscript | 43 ++++++ plugins/input/ogr/ogr_datasource.cpp | 216 +++++++++++++++++++++++++++ plugins/input/ogr/ogr_datasource.hpp | 60 ++++++++ plugins/input/ogr/ogr_featureset.cpp | 206 +++++++++++++++++++++++++ plugins/input/ogr/ogr_featureset.hpp | 51 +++++++ 11 files changed, 620 insertions(+), 7 deletions(-) create mode 100644 plugins/input/ogr/Makefile.am create mode 100644 plugins/input/ogr/SConscript create mode 100644 plugins/input/ogr/ogr_datasource.cpp create mode 100644 plugins/input/ogr/ogr_datasource.hpp create mode 100644 plugins/input/ogr/ogr_featureset.cpp create mode 100644 plugins/input/ogr/ogr_featureset.hpp diff --git a/AUTHORS b/AUTHORS index aebd7cf1a..99a739f9d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -19,6 +19,7 @@ Patches ======= - Andy Allen + - Lucio Asnaghi - Justin Bronn - Christopher Brown - Jon Burgess diff --git a/CHANGELOG b/CHANGELOG index 34f7db52c..a6d01bac9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,8 @@ For a complete change history, see the SVN log. Current Version (0.6.0-dev, SVN trunk): --------------------------------------- +- Plugins: Added OGR driver for reading all OGR supported formats (kunitoki) (r836) (#170) + - Python: Made available the scale_denominator property from the map in c++ and python (r793) - Python: Added ability to resize map and clear all layers and styles from python (r793) diff --git a/SConstruct b/SConstruct index fdb4960b9..d2070a04e 100644 --- a/SConstruct +++ b/SConstruct @@ -94,11 +94,13 @@ opts.Add(BoolVariable('INTERNAL_LIBAGG', 'Use provided libagg', 'True')) # Note: cairo, cairomm, and pycairo all optional but configured automatically through pkg-config # Therefore, we use a single boolean for whether to attempt to build cairo support. opts.Add(BoolVariable('CAIRO', 'Attempt to build with Cairo rendering support', 'True')) -opts.Add(ListVariable('INPUT_PLUGINS','Input drivers to include','all',['postgis','shape','raster','gdal'])) +opts.Add(ListVariable('INPUT_PLUGINS','Input drivers to include','all',['postgis','shape','raster','gdal','ogr'])) opts.Add(PathVariable('PGSQL_INCLUDES', 'Search path for PostgreSQL include files', '/usr/include/postgresql', PathVariable.PathAccept)) opts.Add(PathVariable('PGSQL_LIBS', 'Search path for PostgreSQL library files', '/usr/' + LIBDIR_SCHEMA)) -opts.Add(PathVariable('GDAL_INCLUDES', 'Search path for GDAL include files', '/usr/include/gdal', PathVariable.PathAccept)) -opts.Add(PathVariable('GDAL_LIBS', 'Search path for GDAL library files', '/usr/' + LIBDIR_SCHEMA)) +opts.Add(PathVariable('GDAL_INCLUDES', 'Search path for GDAL include files', '/usr/local/include', PathVariable.PathAccept)) +opts.Add(PathVariable('GDAL_LIBS', 'Search path for GDAL library files', '/usr/local/' + LIBDIR_SCHEMA)) +opts.Add(PathVariable('OGR_INCLUDES', 'Search path for OGR include files', '/usr/local/include', PathVariable.PathAccept)) +opts.Add(PathVariable('OGR_LIBS', 'Search path for OGR library files', '/usr/local/' + LIBDIR_SCHEMA)) # Other variables opts.Add(PathVariable('PYTHON','Python executable', sys.executable)) @@ -237,7 +239,7 @@ else: # Adding the prerequisite library directories to the include path for # compiling and the library path for linking, respectively. -for prereq in ('BOOST', 'PNG', 'JPEG', 'TIFF', 'PGSQL', 'PROJ', 'GDAL',): +for prereq in ('BOOST', 'PNG', 'JPEG', 'TIFF', 'PGSQL', 'PROJ', 'GDAL', 'OGR',): inc_path = env['%s_INCLUDES' % prereq] lib_path = env['%s_LIBS' % prereq] uniq_add(env, 'CPPPATH', inc_path) @@ -277,7 +279,7 @@ else: CXX_LIBSHEADERS = [ ['icuuc','unicode/unistr.h',True], ['icudata','unicode/utypes.h' , True], - ['gdal', 'gdal_priv.h',False] + ['gdal', ['gdal_priv.h', 'ogrsf_frmts.h'],False] ] @@ -425,6 +427,9 @@ else: if 'gdal' in inputplugins and 'gdal' in env['LIBS']: SConscript('plugins/input/gdal/SConscript') + + if 'ogr' in inputplugins and 'gdal' in env['LIBS']: + SConscript('plugins/input/ogr/SConscript') if 'gigabase' in inputplugins and 'gigabase_r' in env['LIBS']: SConscript('plugins/input/gigabase/SConscript') @@ -491,4 +496,4 @@ else: env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -finline-functions -Wno-inline %s' % (env['OPTIMIZATION'],ndebug_flags)) - SConscript('fonts/SConscript') \ No newline at end of file + SConscript('fonts/SConscript') diff --git a/bindings/python/mapnik/__init__.py b/bindings/python/mapnik/__init__.py index 60bcff95d..0da0c553a 100644 --- a/bindings/python/mapnik/__init__.py +++ b/bindings/python/mapnik/__init__.py @@ -87,10 +87,14 @@ def Raster(**keywords): keywords['type'] = 'raster' return CreateDatasource(keywords) -def Gdal (**keywords): +def Gdal(**keywords): keywords['type'] = 'gdal' return CreateDatasource(keywords) +def Ogr(**keywords): + keywords['type'] = 'ogr' + return CreateDatasource(keywords) + #register datasources from mapnik import DatasourceCache DatasourceCache.instance().register_datasources('%s' % inputpluginspath) diff --git a/plugins/input/Makefile.am b/plugins/input/Makefile.am index 4615e11ff..37f22c27d 100644 --- a/plugins/input/Makefile.am +++ b/plugins/input/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = \ postgis\ + ogr \ gdal \ raster \ shape \ diff --git a/plugins/input/ogr/Makefile.am b/plugins/input/ogr/Makefile.am new file mode 100644 index 000000000..214410263 --- /dev/null +++ b/plugins/input/ogr/Makefile.am @@ -0,0 +1,24 @@ +if HAVE_OGR + +pkglib_LTLIBRARIES = \ + ogr.la + +ogr_la_SOURCES = \ + ogr_datasource.cpp\ + ogr_featureset.cpp + +ogr_la_LIBADD = \ + ${OGR_LDFLAGS} + +ogr_la_CXXFLAGS = \ + ${OGR_CFLAGS} \ + -I../../../include + +ogr_la_LDFLAGS = \ + -module \ + -avoid-version \ + -shrext .input + +endif + +## File created by the gnome-build tools diff --git a/plugins/input/ogr/SConscript b/plugins/input/ogr/SConscript new file mode 100644 index 000000000..6623026d1 --- /dev/null +++ b/plugins/input/ogr/SConscript @@ -0,0 +1,43 @@ +# +# This file is part of Mapnik (c++ mapping toolkit) +# +# Copyright (C) 2007 Artem Pavlenko, Jean-Francois Doyon +# +# Mapnik is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# $Id$ + +Import ('env') + +prefix = env['PREFIX'] +install_prefix = env['DESTDIR'] + '/' + prefix + +ogr_src = Split( + """ + ogr_datasource.cpp + ogr_featureset.cpp + """ + ) + +libraries = [ 'gdal' ] +if env['PLATFORM'] == 'Darwin': + libraries.append('mapnik') + libraries.append('icuuc') + libraries.append('icudata') + +ogr_inputdriver = env.SharedLibrary('ogr', source=ogr_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries) + +env.Install(install_prefix + '/' + env['LIBDIR_SCHEMA'] + '/mapnik/input', ogr_inputdriver) +env.Alias('install', install_prefix + '/' + env['LIBDIR_SCHEMA'] + '/mapnik/input') diff --git a/plugins/input/ogr/ogr_datasource.cpp b/plugins/input/ogr/ogr_datasource.cpp new file mode 100644 index 000000000..9c0a0dfb6 --- /dev/null +++ b/plugins/input/ogr/ogr_datasource.cpp @@ -0,0 +1,216 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2007 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +// $Id$ + +#include "ogr_datasource.hpp" +#include "ogr_featureset.hpp" + +using std::clog; +using std::endl; + +using mapnik::datasource; +using mapnik::parameters; + +DATASOURCE_PLUGIN(ogr_datasource) + +using mapnik::Envelope; +using mapnik::coord2d; +using mapnik::query; +using mapnik::featureset_ptr; +using mapnik::layer_descriptor; +using mapnik::attribute_descriptor; +using mapnik::datasource_exception; + + +ogr_datasource::ogr_datasource(parameters const& params) + : datasource(params), + extent_(), + desc_(*params.get("type"),"utf-8") +{ + OGRRegisterAll(); + + boost::optional file = params.get("file"); + if (!file) throw datasource_exception("missing paramater"); + + boost::optional layer = params.get("layer"); + if (!layer) throw datasource_exception("missing paramater"); + + dataset_ = OGRSFDriverRegistrar::Open ((*file).c_str(), FALSE); + if (!dataset_) throw datasource_exception(CPLGetLastErrorMsg()); + +#if 0 + double x0 = -std::numeric_limits::max(), + y0 = -std::numeric_limits::max(), + x1 = std::numeric_limits::max(), + y1 = std::numeric_limits::max(); + + for (int i = 0; i < dataset_->GetLayerCount (); i++) + { + OGRLayer* layer = dataset_->GetLayer (i); + + layer->GetExtent (&envelope); + + x0 = std::min (envelope.MinX, x0); + y0 = std::min (envelope.MinY, y0); + x1 = std::max (envelope.MaxX, x1); + y1 = std::max (envelope.MaxY, y1); + } +#endif + + layer_ = dataset_->GetLayerByName ((*layer).c_str()); + if (! layer_) throw datasource_exception("cannot find in dataset"); + + OGREnvelope envelope; + layer_->GetExtent (&envelope); + extent_.init (envelope.MinX, envelope.MinY, envelope.MaxX, envelope.MaxY); + + OGRFeatureDefn* def = layer_->GetLayerDefn (); + if (def != 0) + { + for (int i = 0; i < def->GetFieldCount (); i++) + { + OGRFieldDefn* fld = def->GetFieldDefn (i); + + std_string fld_name = fld->GetNameRef (); + OGRFieldType type_oid = fld->GetType (); + + switch (type_oid) + { + case OFTInteger: + // case OFTIntegerList: + desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); + break; + + case OFTReal: + //case OFTRealList: + desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); + break; + + case OFTString: + //case OFTStringList: + desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String)); + break; + + case OFTBinary: + desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Object)); + break; + + case OFTDate: + case OFTTime: + case OFTDateTime: // unhandled ! +#ifdef MAPNIK_DEBUG + clog << "unhandled type_oid="< ogr_datasource::envelope() const +{ + return extent_; +} + +layer_descriptor ogr_datasource::get_descriptor() const +{ + return desc_; +} + +featureset_ptr ogr_datasource::features(query const& q) const +{ + if (dataset_ && layer_) + { + mapnik::Envelope const& query_extent = q.get_bbox(); + + OGRLinearRing ring; + ring.addPoint (query_extent.minx(), query_extent.miny()); + ring.addPoint (query_extent.maxx(), query_extent.miny()); + ring.addPoint (query_extent.maxx(), query_extent.maxy()); + ring.addPoint (query_extent.minx(), query_extent.maxy()); + + OGRPolygon* boxPoly = new OGRPolygon(); + boxPoly->addRing (&ring); + boxPoly->closeRings(); + +#if 0 + std::ostringstream s; + + s << "select "; + std::set const& props=q.property_names(); + std::set::const_iterator pos=props.begin(); + std::set::const_iterator end=props.end(); + while (pos != end) + { + s <<",\""<<*pos<<"\""; + ++pos; + } + s << " from " << table_<<" where "<ExecuteSQL(const char *pszSQLCommand, + OGRGeometry *poSpatialFilter, + const char *pszDialect ); +#endif + + return featureset_ptr(new ogr_featureset(*dataset_, *layer_, boxPoly, false)); + } + return featureset_ptr(); +} + +featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const +{ + return featureset_ptr(); +} + diff --git a/plugins/input/ogr/ogr_datasource.hpp b/plugins/input/ogr/ogr_datasource.hpp new file mode 100644 index 000000000..fd85f31e2 --- /dev/null +++ b/plugins/input/ogr/ogr_datasource.hpp @@ -0,0 +1,60 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2007 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +#ifndef OGR_DATASOURCE_HPP +#define OGR_DATASOURCE_HPP + +#include +#include +#include + +using mapnik::datasource; +using mapnik::parameters; +using mapnik::query; +using mapnik::coord2d; +using mapnik::featureset_ptr; +using mapnik::layer_descriptor; +using mapnik::Envelope; + + +class ogr_datasource : public datasource +{ + public: + ogr_datasource(parameters const& params); + virtual ~ogr_datasource (); + int type() const; + static std::string name(); + featureset_ptr features(query const& q) const; + featureset_ptr features_at_point(coord2d const& pt) const; + Envelope envelope() const; + layer_descriptor get_descriptor() const; + private: + static const std::string name_; + Envelope extent_; + OGRDataSource* dataset_; + OGRLayer* layer_; + layer_descriptor desc_; +}; + + +#endif // OGR_DATASOURCE_HPP diff --git a/plugins/input/ogr/ogr_featureset.cpp b/plugins/input/ogr/ogr_featureset.cpp new file mode 100644 index 000000000..c6761dc51 --- /dev/null +++ b/plugins/input/ogr/ogr_featureset.cpp @@ -0,0 +1,206 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2007 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +#include +#include +#include +#include +#include +#include +#include + +#include "ogr_featureset.hpp" +#include + +using std::clog; +using std::endl; + +using mapnik::query; +using mapnik::Envelope; +using mapnik::Feature; +using mapnik::feature_ptr; +using mapnik::geometry_utils; +using mapnik::CoordTransform; + +ogr_featureset::ogr_featureset(OGRDataSource & dataset, + OGRLayer & layer, + OGRPolygon * extent, + bool multiple_geometries) + : dataset_(dataset), + layer_(layer), + extent_(extent), + fidcolumn_(layer_.GetFIDColumn ()), + multiple_geometries_(multiple_geometries) +{ + layer_.SetSpatialFilter (extent_); + layer_.ResetReading (); +} + +ogr_featureset::~ogr_featureset() {} + +feature_ptr ogr_featureset::next() +{ + OGRFeature* feat = layer_.GetNextFeature(); + if (feat != NULL) + { + OGRGeometry* geom=feat->GetGeometryRef(); + if (geom != NULL) + { + long fid=feat->GetFID(); + int size=geom->WkbSize (); + + feature_ptr feature(new Feature(fid)); + + // XXX: here we can improve allocation + char data[size]; + geom->exportToWkb ((OGRwkbByteOrder) endian(), reinterpret_cast(&data[0])); + geometry_utils::from_wkb(*feature,&data[0],size,multiple_geometries_); + + OGRFeatureDefn* def = layer_.GetLayerDefn(); + for (int i = 0; i < def->GetFieldCount(); i++) + { + OGRFieldDefn* fld = def->GetFieldDefn (i); + OGRFieldType type_oid = fld->GetType (); + std_string name = fld->GetNameRef (); + + switch (type_oid) + { + case OFTInteger: + // case OFTIntegerList: // TODO + boost::put(*feature,name,feat->GetFieldAsInteger (i)); + break; + + case OFTReal: + //case OFTRealList: // TODO + boost::put(*feature,name,feat->GetFieldAsDouble (i)); + break; + + case OFTString: + //case OFTStringList: // TODO + boost::put(*feature,name,feat->GetFieldAsString (i)); + break; + + case OFTBinary: +#if 0 + boost::put(*feature,name,feat->GetFieldAsBinary (i, size)); +#endif + break; + + case OFTDate: + case OFTTime: + case OFTDateTime: // unhandled ! +#ifdef MAPNIK_DEBUG + clog << "unhandled type_oid="<transcode(feat->GetFieldAsString (i))); + clog << "deprecated type_oid="<getX(), poPoint->getY() ); + break; + } + case wkbLineString: { + OGRLineString *poLineString = (OGRLineString *) geom; + break; + } + case wkbPolygon: { + OGRPolygon *poPolygon = (OGRPolygon *) geom; + break; + } + case wkbMultiPoint: { + OGRMultiPoint *poMultiPoint = (OGRMultiPoint *) geom; + break; + } + case wkbMultiLineString: { + OGRMultiLineString *poMultiLineString = (OGRMultiLineString *) geom; + break; + } + case wkbMultiPolygon: { + OGRMultiPolygon *poMultiPolygon = (OGRMultiPolygon *) geom; + break; + } + case wkbGeometryCollection: { + OGRGeometryCollection *poGeometryCollection = (OGRGeometryCollection *) geom; + break; + } + case wkbLinearRing: { + OGRLinearRing *poLinearRing = (OGRLinearRing *) geom; + break; + } + case wkbPoint25D: + case wkbLineString25D: + case wkbPolygon25D: + case wkbMultiPoint25D: + case wkbMultiLineString25D: + case wkbMultiPolygon25D: + case wkbGeometryCollection25D: { + break; + } + case wkbNone: + case wkbUnknown: + default: { + break; + } + } + } +*/ + diff --git a/plugins/input/ogr/ogr_featureset.hpp b/plugins/input/ogr/ogr_featureset.hpp new file mode 100644 index 000000000..375ae20ca --- /dev/null +++ b/plugins/input/ogr/ogr_featureset.hpp @@ -0,0 +1,51 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2007 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +//$Id$ + +#ifndef OGR_FEATURESET_HPP +#define OGR_FEATURESET_HPP + +#include + +class OGRDataSource; +class OGRLayer; +class OGRPolygon; + +class ogr_featureset : public mapnik::Featureset +{ + public: + ogr_featureset(OGRDataSource & dataset, + OGRLayer & layer, + OGRPolygon * extent, + bool multiple_geometries); + virtual ~ogr_featureset(); + mapnik::feature_ptr next(); + private: + int endian(); + OGRDataSource & dataset_; + OGRLayer & layer_; + OGRPolygon * extent_; + const char* fidcolumn_; + bool multiple_geometries_; +}; + +#endif // OGR_FEATURESET_HPP